# Enrichr API – for AI agents (llms.txt) > 50 billed utilities for AI agents and automation. One API key. Pay-per-call (fractions of a cent). 1,000 free calls/month. Machine-readable catalog: GET /v1/catalog. Base URL: https://enrichrapi.dev Authentication: pass `X-Api-Key: enr_...` (or `Authorization: Bearer enr_...`). Do not send both (HTTP 400). Sign up (free): POST /v1/account/signup with `{"email": "you@example.com"}` → returns a one-time `api_key`. Verify the mailbox (`POST /v1/account/verify`) to unlock the free tier and recovery. ## Why an agent should call Enrichr - Deterministic JSON utilities billed per call. Latency is **not a published SLO**. - Stable success envelope for priced utilities: `{"ok": bool, "data": {...}, "cost_usd": ..., "call_count_this_month": int}`. - One key for 50 billed utilities — token counting, slug generation, JWT decoding, and the rest. - Free tier means no billing setup for prototype work. - Prepaid credits are enabled. Checkout top-up is $10 (server-controlled). Signup creates a Stripe customer only — no metered subscription. ## This API will not do - Mailbox SMTP / recipient verification (MX ≠ mailbox/SMTP) - USPS validation or geocoding - Trained NLP / toxicity models (`/v1/classify/text` is keyword heuristics) - Unpublished latency SLOs (no sub-10ms or p50 claims) ## Endpoint catalog All billed utilities are POST + JSON unless noted. Headers: `X-Api-Key: enr_...` (or `Authorization: Bearer enr_...`) and `Content-Type: application/json`. Account, Stripe webhook, health, and docs routes are free and are **not** in this count. ### Enrich - POST /v1/enrich/email — Syntax + optional Cloudflare DoH MX; not mailbox/SMTP - POST /v1/enrich/email/batch — Up to 100 emails; syntax + optional MX; billed per item; not mailbox/SMTP - POST /v1/enrich/phone — Parse to E.164; line type and region (local, not carrier lookup) - POST /v1/enrich/address — Title-case normalization + US ZIP regex; not USPS/geocode - POST /v1/enrich/ip — HTTPS geolocation; private IPs local; degrades as geolocation_unavailable ### Classify - POST /v1/classify/text — Keyword/heuristic sentiment, toxicity, spam; not a trained model ### Validate - POST /v1/validate/vat — EU VAT format + live VIES check - POST /v1/validate/password — HIBP k-anonymity breach check + strength - POST /v1/validate/credit-card — Luhn checksum + card network; number is never stored - POST /v1/validate/iban — IBAN MOD-97 checksum, 77 countries - POST /v1/validate/json — Validate, format, and analyze a JSON string - POST /v1/validate/color — Validate and convert hex / rgb / hsl - POST /v1/validate/domain — Format + DNS A + MX (not mailbox) - POST /v1/validate/domain/batch — Up to 100 domains; format + DNS A + MX; billed per item; not mailbox - POST /v1/validate/regex — Test a regex and return matches - POST /v1/validate/uuid — Validate a UUID and detect version (v1–v5) ### Convert - POST /v1/convert/currency — Convert amounts using ECB rates via frankfurter.dev - POST /v1/convert/timezone — DST-aware conversion between IANA timezones - POST /v1/convert/units — Length, weight, temperature, area, or volume - POST /v1/convert/number — Decimal, binary, octal, hex, and Roman numerals - POST /v1/convert/case — camelCase, snake_case, PascalCase, and 6 more - POST /v1/convert/html-to-text — Strip HTML tags to plain text - POST /v1/convert/markdown — Markdown to HTML - POST /v1/convert/encoding — base64, base64url, hex, URL, HTML entities, rot13 ### Generate - POST /v1/generate/qr — QR code as base64 PNG + data URI - POST /v1/generate/uuid — UUID v1 or v4 (up to 100 per request) - POST /v1/generate/hash — MD5 / SHA-1 / SHA-256 / SHA-512 (hex or base64) - POST /v1/generate/password — Secure random password with entropy estimate - POST /v1/generate/slug — URL-safe slug (Unicode-aware) - POST /v1/generate/avatar — SVG initials avatar - POST /v1/generate/lorem — Lorem ipsum placeholder text - POST /v1/generate/token — Secure random token (hex, url_safe, alphanumeric, api_key) ### Analyze - POST /v1/analyze/text — Word count, reading time, Flesch readability - POST /v1/analyze/tokens — LLM token count (tiktoken / cl100k_base); prices dated via as_of - POST /v1/analyze/similarity — Levenshtein, Jaro-Winkler, token overlap ### Extract - POST /v1/extract/entities — Named entities with character offsets (heuristic person/org) ### Filter - POST /v1/filter/profanity — Detect and censor profanity ### Lookup - POST /v1/lookup/postal — City, state, coords from postal code via Zippopotam.us (60+ countries) - POST /v1/lookup/country — Country info by ISO code or name - POST /v1/lookup/timezone — IANA timezone offset, DST, abbreviation - POST /v1/lookup/mime-type — Extension → MIME or MIME → extensions ### Parse - POST /v1/parse/url — Scheme, host, domain, path, query params, UTM tags - POST /v1/parse/user-agent — Browser, OS, device type, bots - POST /v1/parse/csv — CSV string → structured rows - POST /v1/parse/date — Fuzzy date parse → ISO + components ### Tools - POST /v1/tools/jwt-decode — Decode a JWT; optional HMAC verify - POST /v1/tools/webhook-sign — HMAC signature for a webhook payload - POST /v1/tools/webhook-verify — Constant-time HMAC verify for a webhook signature - POST /v1/tools/cron-next — Next N runs of a 5-field cron expression ### Contacts - POST /v1/contacts/clean — CSV contact cleaner (syntax email + phone format); not EnrichResponse ### Account (free, not billed) - POST /v1/account/signup — `{ "email": "you@example.com" }` → `{ api_key, message }` (Stripe customer only; no metered subscription). Free tier starts after mailbox verification. - POST /v1/account/verify — `{ "token": "..." }` prove mailbox ownership; recovery may return a rotated `api_key` - POST /v1/account/recover — `{ "email": "..." }` email a verification link (does not reveal whether the address exists) - GET /v1/account/usage — current-month call count + prepaid balance - GET /v1/account/options — `{ topup_usd, purchases_enabled, free_tier_calls, billing_url, checkout_path }` (unauthenticated) - POST /v1/account/checkout — Stripe Checkout for a $10 prepaid top-up (amount from `PREPAID_TOPUP_CENTS`, not the client) - POST /v1/account/portal — open Stripe billing portal → `{ url }` - POST /v1/account/rotate — rotate API key (old key deactivated; same prepaid account) ## Response envelope Priced utilities (everything in `PRICES`) return: ```json { "ok": true, "data": { "...": "endpoint-specific" }, "cost_usd": 0.00001, "call_count_this_month": 42 } ``` Custom billed (not `EnrichResponse`): - `POST /v1/contacts/clean` — CSV cleaner payload, billed per row - `POST /v1/enrich/email/batch` / `POST /v1/validate/domain/batch` — `{ok, count, results, cost_usd, call_count_this_month}`, billed per item ## Errors FastAPI/Starlette always include `{"detail": ...}` for 401, 422, 402, 400, 413, 429, and 503. Additive fields (do not replace `detail`): `{"code": "...", "retryable": bool}`. 429 also sets `Retry-After` and `retry_after_seconds`. Examples: - 401 — `{"detail": "API key required. Pass via X-Api-Key header or Bearer token.", "code": "unauthorized", "retryable": false}` - 402 — `{"detail": "Free allowance used. Add credits at /billing to continue.", "code": "payment_required", "retryable": false, "purchases_enabled": false, "checkout_path": "/v1/account/checkout", "billing_url": "...", "topup_usd": 10}` (contacts/clean and batch wording may differ). If `purchases_enabled` is true, call `POST /v1/account/checkout` and open the returned Stripe URL. - 422 — validation errors (`detail` is a string or FastAPI error list) plus `code`/`retryable` - 429 — `{"detail": "...", "code": "rate_limited", "retryable": true, "retry_after_seconds": 60}` - 503 — `POST /v1/account/checkout` while prepaid is off: `{"detail": "Credit purchases are not enabled yet.", "code": "service_unavailable", "retryable": true, "purchases_enabled": false}` There is no `{"error", "free_tier_calls", "calls_this_month"}` error body. ## Discoverability - /docs — Swagger UI (OpenAPI) - /redoc — ReDoc UI - /openapi.json — full schema - /llms.txt — this file - /v1/llms.txt — same generated catalog - /v1/llms-full.txt — this file plus request/response examples - /v1/catalog — JSON billed catalog (unauthenticated, not billed) - /health — liveness probe - /health/deep — readiness probe (Postgres / Redis / Stripe components) The `/v1` HTTP contract is frozen. Breaking changes would ship as `/v2`. ## SDKs ``` npm install enrichrapi pip install enrichr-sdk ``` ## Pricing Amounts are read from server settings (not copied by hand). First **1,000 calls / month / key** are free. Prepaid credits are enabled. Checkout top-up is $10 (server-controlled). Signup creates a Stripe customer only — no metered subscription. | Path | Price | Outbound I/O | Rate limit | |------|-------|--------------|------------| | /v1/enrich/email | $0.0001 | yes | 60/minute | | /v1/enrich/email/batch | $0.0001 per item | yes | 30/minute | | /v1/enrich/phone | $0.0001 | no | 60/minute | | /v1/enrich/address | $0.00001 | no | 60/minute | | /v1/enrich/ip | $0.0001 | yes | 60/minute | | /v1/classify/text | $0.00001 | no | 60/minute | | /v1/validate/vat | $0.0005 | yes | 60/minute | | /v1/validate/password | $0.0001 | yes | 60/minute | | /v1/validate/credit-card | $0.0001 | no | 60/minute | | /v1/validate/iban | $0.0005 | no | 60/minute | | /v1/validate/json | $0.00001 | no | 120/minute | | /v1/validate/color | $0.00001 | no | 120/minute | | /v1/validate/domain | $0.0001 | yes | 60/minute | | /v1/validate/domain/batch | $0.0001 per item | yes | 30/minute | | /v1/validate/regex | $0.00001 | no | 120/minute | | /v1/validate/uuid | $0.00001 | no | 120/minute | | /v1/convert/currency | $0.00001 | yes | 60/minute | | /v1/convert/timezone | $0.00001 | no | 60/minute | | /v1/convert/units | $0.00001 | no | 120/minute | | /v1/convert/number | $0.00001 | no | 120/minute | | /v1/convert/case | $0.00001 | no | 120/minute | | /v1/convert/html-to-text | $0.00001 | no | 60/minute | | /v1/convert/markdown | $0.00001 | no | 60/minute | | /v1/convert/encoding | $0.00001 | no | 120/minute | | /v1/generate/qr | $0.00001 | no | 60/minute | | /v1/generate/uuid | $0.00001 | no | 120/minute | | /v1/generate/hash | $0.00001 | no | 120/minute | | /v1/generate/password | $0.00001 | no | 120/minute | | /v1/generate/slug | $0.00001 | no | 120/minute | | /v1/generate/avatar | $0.00001 | no | 120/minute | | /v1/generate/lorem | $0.00001 | no | 120/minute | | /v1/generate/token | $0.00001 | no | 120/minute | | /v1/analyze/text | $0.00001 | no | 120/minute | | /v1/analyze/tokens | $0.00001 | no | 300/minute | | /v1/analyze/similarity | $0.00001 | no | 300/minute | | /v1/extract/entities | $0.00001 | no | 120/minute | | /v1/filter/profanity | $0.00001 | no | 60/minute | | /v1/lookup/postal | $0.00001 | yes | 60/minute | | /v1/lookup/country | $0.00001 | no | 120/minute | | /v1/lookup/timezone | $0.00001 | no | 120/minute | | /v1/lookup/mime-type | $0.00001 | no | 120/minute | | /v1/parse/url | $0.00001 | no | 60/minute | | /v1/parse/user-agent | $0.00001 | no | 120/minute | | /v1/parse/csv | $0.00001 | no | 60/minute | | /v1/parse/date | $0.00001 | no | 120/minute | | /v1/tools/jwt-decode | $0.00001 | no | 120/minute | | /v1/tools/webhook-sign | $0.00001 | no | 120/minute | | /v1/tools/webhook-verify | $0.00001 | no | 120/minute | | /v1/tools/cron-next | $0.00001 | no | 120/minute | | /v1/contacts/clean | $0.001 per contact row | no | 5/minute | ## Support - https://enrichrapi.dev - https://github.com/crisjonblvx/enrichr-api - support@enrichrapi.dev