# truval.dev Machine-readable API instructions for LLMs and agents. Primary API: https://api.truval.dev OpenAPI: https://api.truval.dev/openapi.json MCP server: https://mcp.truval.dev/mcp MCP tool schema: https://mcp.truval.dev/openapi.json ## Authentication - All HTTP API requests require header: Authorization: Bearer sk_live_... (or sk_test_... in non-prod) - Management API requests require header: Authorization: Bearer sk_mgmt_... - Content-Type for JSON requests: application/json - API keys are issued in dashboard: https://dash.truval.dev ## npm SDK (truval) - Package: `truval` — `npm install truval` or `pnpm add truval` - Import: `import { createClient, createManagementClient } from 'truval'` - `createClient(apiKey, options?)` — optional `baseUrl`, `retryOnRateLimit` (on 429: wait until API `reset_at` **plus a small cushion**, then retry), `maxRetries` (default 3 retry attempts after 429) - `client.verify(email)` — single address; same JSON as POST /v1/email/verify - `client.verifyAsync(email, webhook)` — async submission, returns `{ job_id, status: 'pending' }` and posts result to webhook - `client.verifyBatch(emails)` — auto-splits into chunks of 50; **sequential** batch API calls (avoids rate-limit spikes); merged results in **input order** - `client.verifyStream(emails)` — async iterator over NDJSON lines from POST /v1/email/verify/stream; **completion order** may differ from input order - `createManagementClient(mgmtKey)` methods: - `account.get()` -> GET /v1/management/account - `keys.list()` -> GET /v1/management/keys - `keys.create({ label? })` -> POST /v1/management/keys - `keys.revoke(id)` -> DELETE /v1/management/keys/{id} - `usage.daily()` -> GET /v1/management/usage - `usage.summary()` -> GET /v1/management/usage/summary - `billing.portal({ return_url? })` -> POST /v1/management/billing/portal - Standalone: `verify(email, apiKey, options?)` for one-off calls without a client instance Minimal example: ```ts import { createClient } from 'truval' const truval = createClient(process.env.TRUVAL_API_KEY!, { retryOnRateLimit: true, maxRetries: 3, }) const one = await truval.verify('user@example.com') const many = await truval.verifyBatch(listOfEmails) for await (const row of truval.verifyStream(listOfEmails)) { /* process row */ } ``` ## HTTP API ### POST /v1/email/verify - URL: https://api.truval.dev/v1/email/verify - Body: - email: string (required) - webhook: string (optional) — if provided, returns **202** `{ job_id, status: 'pending' }` and POSTs the full result to the webhook when done (HTTPS hostname rules apply; see docs). - webhook_secret: string (optional) — if provided, Truval signs the webhook callback and includes `X-Truval-Signature: sha256=...` (HMAC-SHA256 over the raw JSON request body). Request example (sync): ```json { "email": "user@example.com" } ``` ### Response schema (200) - email: string - valid: boolean - status: deliverable | undeliverable | unknown | catch_all | invalid - confidence: number (0..1) - failed_check: syntax | disposable | no_mx | smtp | smtp_timeout | null - disposable: boolean - role: boolean - free_provider: boolean - catch_all: boolean - smtp_blocked: boolean - mx_found: boolean - mx_host: string | null - suggestion: string | null - latency_ms: number ## Status interpretation - deliverable: mailbox accepted by SMTP probe - undeliverable: mailbox rejected by SMTP probe - unknown: could not confirm — provider smtp_blocked, timeout/greylist, or ambiguous SMTP on the MX (common org/M365); check mx_found and smtp_blocked - catch_all: domain accepts all recipients; mailbox-level certainty unavailable - catch_all caution: valid=true on catch-all does not prove mailbox existence; confidence is intentionally lower (~0.65) - invalid: failed syntax/disposable/MX validation ## Confidence ladder (ordinal, not P(mailbox exists)) - 0.97: deliverable - 0.75: unknown with smtp_blocked (major consumer domains) - 0.65: catch_all - 0.50: unknown, mx_found, not smtp_blocked — SMTP inconclusive - 0.02: undeliverable - 0.0: invalid path (syntax/disposable/no_mx) ## Major provider behavior (important) Gmail, Outlook, Yahoo, and similar providers often block third-party SMTP probing. Expected result pattern: - valid: false (unknown is not treated as deliverable/catch-all) - smtp_blocked: true - status: unknown - confidence: 0.75 This is expected behavior, not an integration error. Prefer `confidence` and `smtp_blocked` over `valid` alone. ## Error and rate-limit pattern - 401: missing/invalid API key - 400: malformed request body - 402: hard EUR spend cap would be exceeded ([docs](https://docs.truval.dev/api/email-verify#spend-cap)) - 429: per-minute rate limit exceeded (`rate_limit_exceeded`) **or** free-tier monthly cap (`monthly_quota_exceeded` — [docs](https://docs.truval.dev/api/email-verify#monthly-quota)) - 503: temporary monthly quota check failure (`quota_check_failed`) - 404: unknown route 401 missing key shape: { "error": "missing_api_key", "message": "No Authorization header provided.", "action": "Include your API key as: Authorization: Bearer sk_live_...", "docs": "https://docs.truval.dev/api/email-verify#authentication" } 401 invalid key shape: { "error": "invalid_api_key", "message": "API key not found or revoked.", "action": "Generate a new key at https://dash.truval.dev.", "docs": "https://docs.truval.dev/api/email-verify#authentication" } 400 invalid request shape: { "error": "invalid_request", "message": "Request body must be JSON with an email field.", "action": "Send: {\"email\":\"user@example.com\"}", "docs": "https://docs.truval.dev/api/email-verify#request" } 429 per-minute rate limit (`message` and `limit` match your tier, e.g. free = 10/min): { "error": "rate_limit_exceeded", "message": "Rate limit of 10 req/min exceeded.", "action": "Wait until reset_at (plus a small cushion) before retrying.", "limit": 10, "window": "1m", "reset_at": "2026-01-01T00:00:00.000Z", "docs": "https://docs.truval.dev/api/email-verify#rate-limits" } 429 free-tier monthly quota (no `window`; `reset_at` is next UTC month start): { "error": "monthly_quota_exceeded", "message": "Monthly free tier limit of 500 verification units reached for this UTC month.", "action": "Upgrade your plan or wait until the next UTC month.", "limit": 500, "used": 500, "reset_at": "2026-02-01T00:00:00.000Z", "docs": "https://docs.truval.dev/api/email-verify#monthly-quota" } 402 spend cap shape: { "error": "payment_required", "message": "Hard spend cap reached. Upgrade or raise your cap to continue.", "action": "Adjust your hard cap in Billing & Limits, or upgrade your plan.", "docs": "https://docs.truval.dev/api/email-verify#spend-cap", "hard_cap_eur": 50, "current_overage_eur": 52.5 } 503 quota check failed shape: { "error": "quota_check_failed", "message": "Could not verify monthly usage quota. Retry shortly.", "action": "If this persists, contact support.", "docs": "https://docs.truval.dev/api/email-verify#monthly-quota" } 404 shape: { "error": "not_found", "message": "The requested endpoint does not exist.", "action": "Use POST /v1/email/verify, POST /v1/email/verify/batch, POST /v1/email/verify/stream, or inspect https://api.truval.dev/openapi.json.", "docs": "https://docs.truval.dev/api/email-verify#not-found" } Rate limits by plan: - free: 10 requests/minute - builder: 100 requests/minute - scale: 1000 requests/minute Free tier also enforces **500 verification units per UTC calendar month** (`count_usage_for_customer`: `usage_log` in that month except `failed_check` `rate_limit_exceeded` / `monthly_quota_exceeded`; see [monthly quota](https://docs.truval.dev/api/email-verify#monthly-quota)). Paid tiers use **billable** units (post-syntax) for Stripe and included volume. ## Management API Requires provisioning key (`sk_mgmt_...`) for all endpoints below unless noted. - GET /v1/management/account - GET /v1/management/keys - POST /v1/management/keys - DELETE /v1/management/keys/{id} - GET /v1/management/usage - GET /v1/management/usage/summary - POST /v1/management/billing/portal Permission model: - `sk_live_...`: `/v1/email/*` only - `sk_mgmt_...`: `/v1/management/*` only ## Agent usage patterns Emit one of these signals based on the result: - GREEN_LIGHT → proceed - YELLOW_LIGHT → proceed with caution / confirm with user - RED_LIGHT → reject or request alternative Decision order (evaluate in this sequence): - suggestion!=null: → YELLOW_LIGHT, prompt user with corrected domain first - disposable=true: → RED_LIGHT, reject - status=undeliverable or invalid: → RED_LIGHT, reject or ask for another address - catch_all=true or status=catch_all: → YELLOW_LIGHT, confirm user (valid=true does not prove mailbox on catch-all) - status=unknown with smtp_blocked=true and confidence>=0.75: → YELLOW_LIGHT (lean GREEN), major provider SMTP blocked — do not treat valid=false as failure - status=unknown with mx_found=true and smtp_blocked=false: → YELLOW_LIGHT, SMTP inconclusive (confidence ~0.50) — confirm with user, not invalid - valid=true (deliverable): → GREEN_LIGHT - confidence>=0.9: → GREEN_LIGHT - confidence>=0.7: → YELLOW_LIGHT - confidence>=0.5: → YELLOW_LIGHT (confirm) - confidence<0.5: → RED_LIGHT Retry policy: - retry on: 429, transient 5xx, network timeout - do not retry on: deterministic invalid input (syntax/disposable/no_mx) ## MCP quick start - Endpoint: https://mcp.truval.dev/mcp - Transport: JSON-RPC 2.0 over HTTP POST - Tools exposed: - verify_email - create_api_key - list_api_keys - revoke_api_key - get_usage_summary - get_account - get_usage - create_billing_portal - Tool args schema: - email: string (required) - webhook: string (optional) — URL to receive async POST callback - Authorization header is required on MCP requests and forwarded upstream. Minimal tool call params: { "name": "verify_email", "arguments": { "email": "user@example.com", "webhook": "https://your-agent.com/callback" } } Cursor config shape: { "mcpServers": { "truval": { "url": "https://mcp.truval.dev/mcp", "headers": { "Authorization": "Bearer ${TRUVAL_API_KEY}", "X-Truval-Provisioning-Key": "${TRUVAL_PROVISIONING_KEY}" } } } } ## Agent Skills Truval provides Universal Agent Directives (Agent Skills) compatible with Claude, ChatGPT, Cursor, LangChain, CrewAI, and any agent framework. - Skill URL: `https://docs.truval.dev/skills/truval-email-verify/SKILL.md` (for Claude.ai projects, copy the page content into the project’s custom instructions) - CLI Installation: `npx skills add truval-dev/truval-skills` - GitHub Repository: `https://github.com/truval-dev/truval-skills` ## Full reference For complete examples (curl, TypeScript, Python, LangChain, CrewAI, Vercel AI SDK, and full MCP JSON-RPC), read: https://truval.dev/llms-full.txt ## Public Repositories - SDK: https://github.com/truval-dev/truval-sdk - MCP Server: https://github.com/truval-dev/truval-mcp-server - Agent Skills: https://github.com/truval-dev/truval-skills ## Postman Collection URL: https://docs.truval.dev/postman/truval.json