{"openapi":"3.1.0","info":{"title":"truval.dev API","version":"1.0.0","description":"Email verification API built for AI agents. Single, batch, and NDJSON streaming verify endpoints, five verification layers, sub-500ms P90."},"servers":[{"url":"https://api.truval.dev","description":"Production"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"API key (sk_live_...; sk_test_... in non-prod)"}},"schemas":{"ApiError":{"type":"object","required":["error","message","action","docs"],"properties":{"error":{"type":"string"},"message":{"type":"string"},"action":{"type":"string"},"docs":{"type":"string","format":"uri"}}},"RateLimitError":{"allOf":[{"$ref":"#/components/schemas/ApiError"},{"type":"object","required":["limit","window","reset_at"],"properties":{"limit":{"type":"number"},"window":{"type":"string","example":"1m"},"reset_at":{"type":"string","format":"date-time","description":"Exact boundary timestamp when the current rate-limit window resets. Clients should retry after this time; add a small cushion for clock skew/latency."}}}]},"MonthlyQuotaError":{"allOf":[{"$ref":"#/components/schemas/ApiError"},{"type":"object","required":["limit","used","reset_at"],"properties":{"error":{"type":"string","enum":["monthly_quota_exceeded"]},"limit":{"type":"number","description":"Included verification units per UTC calendar month on the free tier"},"used":{"type":"number","description":"Units counted toward the free-tier monthly quota before this request (same rules as count_usage_for_customer; excludes usage_log rows with failed_check rate_limit_exceeded or monthly_quota_exceeded)"},"reset_at":{"type":"string","format":"date-time","description":"Exact boundary timestamp for the next UTC month when free-tier quota resets. Clients should retry after this time; add a small cushion for clock skew/latency."}}}]},"PaymentRequiredError":{"type":"object","required":["error","message","action","docs","hard_cap_eur","current_overage_eur"],"properties":{"error":{"type":"string","enum":["payment_required"]},"message":{"type":"string"},"action":{"type":"string"},"docs":{"type":"string","format":"uri"},"hard_cap_eur":{"type":["number","null"],"description":"Configured hard cap in EUR, or null"},"current_overage_eur":{"type":"number","description":"Projected period overage in EUR at time of check"}}},"VerifyEmailResult":{"type":"object","properties":{"email":{"type":"string","description":"The email address that was verified"},"valid":{"type":"boolean","description":"true when SMTP outcome is deliverable or catch-all. false for invalid, undeliverable, timeout, or unknown (including smtp_blocked major providers — use confidence). Catch-all: valid=true does not prove a specific mailbox exists."},"status":{"type":"string","enum":["deliverable","undeliverable","unknown","catch_all","invalid"],"description":"deliverable: SMTP confirmed. undeliverable: mailbox does not exist. unknown: could not confirm — major-provider smtp_blocked, SMTP timeout, or ambiguous/non-interpretable SMTP (e.g. some org/M365 hosts). catch_all: server accepts all addresses; mailbox existence remains unconfirmable. invalid: failed syntax, disposable, or MX check."},"confidence":{"type":"number","minimum":0,"maximum":1,"description":"Ordinal 0–1 summary of how decisive the verification was (not a statistical probability the mailbox exists). Typical values: 0.97 = deliverable (SMTP 250). 0.75 = unknown with smtp_blocked recipient domain (probe not meaningful). 0.65 = catch_all. 0.50 = unknown with MX but SMTP inconclusive. 0.02 = undeliverable. 0.0 = invalid path (syntax, disposable, or no_mx). Prefer status, failed_check, mx_found, and smtp_blocked together with confidence."},"failed_check":{"type":"string","nullable":true,"enum":["syntax","disposable","no_mx","smtp","smtp_timeout",null],"description":"Which verification layer failed. null if valid."},"disposable":{"type":"boolean","description":"Matched against 50k+ throwaway domain blocklist"},"role":{"type":"boolean","description":"Role address — admin@, info@, noreply@ etc"},"free_provider":{"type":"boolean","description":"Gmail, Yahoo, Hotmail etc"},"catch_all":{"type":"boolean","description":"Server accepts all addresses; specific mailbox existence is not confirmable and should be treated with caution"},"smtp_blocked":{"type":"boolean","description":"true for Gmail, Outlook, Yahoo — they block SMTP probing from all third parties. This is not a Truval limitation."},"mx_found":{"type":"boolean","description":"MX records exist for the domain"},"mx_host":{"type":"string","nullable":true,"description":"Primary MX hostname"},"suggestion":{"type":"string","nullable":true,"description":"Typo correction e.g. gmail.com when input was gnail.com"},"latency_ms":{"type":"number","description":"End-to-end processing time in milliseconds"}}},"BatchVerifyResponse":{"type":"object","required":["results","count","latency_ms"],"properties":{"results":{"type":"array","maxItems":50,"items":{"$ref":"#/components/schemas/VerifyEmailResult"},"description":"Per-email results in the same order as the request emails array"},"count":{"type":"integer","description":"Number of results (same as emails sent)"},"latency_ms":{"type":"number","description":"Total wall-clock time for the batch request"}}},"AsyncVerifyResponse":{"type":"object","required":["job_id","status"],"properties":{"job_id":{"type":"string","description":"Unique identifier for the background job","example":"job_abc123"},"status":{"type":"string","enum":["pending"],"description":"Current status of the job"}}},"ManagementAccountResponse":{"type":"object","required":["account_id","tier","limits","usage_this_month"],"properties":{"account_id":{"type":"string","format":"uuid"},"tier":{"type":"string","enum":["free","builder","scale"]},"subscription_status":{"type":"string","nullable":true},"current_period_end":{"type":"string","format":"date-time","nullable":true},"cancel_at_period_end":{"type":"boolean","nullable":true},"canceled_at":{"type":"string","format":"date-time","nullable":true},"cancel_at":{"type":"string","format":"date-time","nullable":true},"trial_start":{"type":"string","format":"date-time","nullable":true},"trial_end":{"type":"string","format":"date-time","nullable":true},"billing_cycle_anchor":{"type":"string","format":"date-time","nullable":true},"limits":{"type":"object","required":["monthly_calls","rate_limit_per_min","max_keys"],"properties":{"monthly_calls":{"type":"integer"},"rate_limit_per_min":{"type":"integer"},"max_keys":{"type":"integer"}}},"usage_this_month":{"type":"integer"}}},"ManagementKeysListResponse":{"type":"object","required":["keys","count","max"],"properties":{"keys":{"type":"array","items":{"type":"object","required":["id","prefix","created_at"],"properties":{"id":{"type":"string","format":"uuid"},"label":{"type":"string","nullable":true},"prefix":{"type":"string"},"created_at":{"type":"string","format":"date-time"}}}},"count":{"type":"integer"},"max":{"type":"integer"}}},"ManagementCreateKeyResponse":{"type":"object","required":["id","key","created_at","warning"],"properties":{"id":{"type":"string","format":"uuid"},"key":{"type":"string","description":"Raw standard key shown once","example":"sk_live_..."},"label":{"type":"string","nullable":true},"created_at":{"type":"string","format":"date-time"},"warning":{"type":"string"}}},"ManagementUsageResponse":{"type":"object","required":["days"],"properties":{"days":{"type":"array","items":{"type":"object","required":["date","calls"],"properties":{"date":{"type":"string","example":"2026-03-24"},"calls":{"type":"integer"}}}}}},"ManagementUsageSummaryResponse":{"type":"object","description":"Month-to-date counters in the current UTC calendar month. On **free** tier, `calls_used` / `calls_remaining` / `overage_calls` follow the same monthly verification quota rules as `GET /v1/management/account` `usage_this_month` and the public verify API (see docs monthly quota). On **builder** and **scale**, they follow **billable** verification counts (Stripe meter semantics).","required":["period","calls_used","calls_included","calls_remaining","overage_calls","estimated_cost_eur","tier"],"properties":{"period":{"type":"object","required":["start","end"],"properties":{"start":{"type":"string","format":"date-time"},"end":{"type":"string","format":"date-time"}}},"calls_used":{"type":"integer","description":"Free tier: units counted toward monthly quota. Paid tiers: billable verifications this month."},"calls_included":{"type":"integer"},"calls_remaining":{"type":"integer","description":"Free tier: `calls_included` minus quota-based `calls_used`. Paid tiers: included allowance minus billable `calls_used`."},"overage_calls":{"type":"integer"},"estimated_cost_eur":{"type":"number"},"tier":{"type":"string","enum":["free","builder","scale"]}}},"ManagementBillingPortalResponse":{"type":"object","required":["url"],"properties":{"url":{"type":"string","format":"uri"}}},"ManagementProvisioningKeyResponse":{"type":"object","required":["key","id"],"properties":{"key":{"type":"string","example":"sk_mgmt_..."},"id":{"type":"string","format":"uuid"}}}}},"paths":{"/v1/email/verify":{"post":{"operationId":"verifyEmail","summary":"Verify an email address","description":"Runs up to five verification layers: syntax, disposable domain check, MX lookup, SMTP probe, and signal extraction. Returns a confidence score and detailed breakdown. **Free tier:** monthly verification unit cap (500 by default) in UTC calendar months; counted like `count_usage_for_customer` (all qualifying `usage_log` rows in the month except `failed_check` `rate_limit_exceeded` / `monthly_quota_exceeded`; invalid requests after auth still count). **Paid tiers:** Stripe meter events only after syntax passes (billable units); see https://docs.truval.dev/api/email-verify#billing-and-billable-verifications. **Paid overage:** per-call EUR prices from your plan are aggregated for spend caps and billing; amounts are rounded up to whole euro cents (conservative for the customer).","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email"],"properties":{"email":{"type":"string","format":"email","description":"The email address to verify","example":"user@example.com"},"webhook":{"type":"string","pattern":"^https://","description":"Optional public HTTPS URL for the async callback. Must use a hostname (not an IP literal), no username/password in the URL, and not localhost or *.local. If provided, returns 202 immediately. The callback POST does not follow HTTP redirects.","example":"https://your-agent.com/truval-callback"},"webhook_secret":{"type":"string","description":"Optional secret used to sign webhook callbacks. When provided, Truval includes an HMAC-SHA256 signature header: X-Truval-Signature: sha256=... computed over the raw JSON request body.","example":"whsec_your_shared_secret"}}}}}},"responses":{"200":{"description":"Verification result (synchronous)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyEmailResult"},"example":{"email":"user@example.com","valid":true,"status":"deliverable","confidence":0.97,"failed_check":null,"disposable":false,"role":false,"free_provider":false,"catch_all":false,"smtp_blocked":false,"mx_found":true,"mx_host":"mail.example.com","suggestion":null,"latency_ms":187}}}},"202":{"description":"Accepted (asynchronous)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AsyncVerifyResponse"},"example":{"job_id":"job_1234567890abcdef","status":"pending"}}}},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"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"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"examples":{"missingApiKey":{"summary":"Missing Authorization header","value":{"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"}},"invalidApiKey":{"summary":"Invalid or revoked key","value":{"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"}}}}}},"402":{"description":"Hard spend cap would be exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentRequiredError"},"example":{"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}}}},"404":{"description":"Unknown route","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"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"}}}},"413":{"description":"Payload too large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"payload_too_large","message":"Request body exceeds 2MB limit.","action":"Reduce payload size; max payload is 2MB.","docs":"https://docs.truval.dev/api/email-verify#request"}}}},"429":{"description":"Rate limit exceeded, or (free tier only) monthly verification quota exceeded for the current UTC month","headers":{"Retry-After":{"description":"Seconds until the instant given by `reset_at` in the JSON body (delta-seconds form, RFC 9110).","schema":{"type":"string","example":"42"}}},"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/RateLimitError"},{"$ref":"#/components/schemas/MonthlyQuotaError"}]},"examples":{"rateLimit":{"summary":"Per-minute rate limit","value":{"error":"rate_limit_exceeded","message":"Rate limit of 100 req/min exceeded.","action":"Wait until reset_at (plus a small cushion) before retrying.","limit":100,"window":"1m","reset_at":"2026-03-24T12:01:00.000Z","docs":"https://docs.truval.dev/api/email-verify#rate-limits"}},"monthlyQuota":{"summary":"Free tier monthly cap (UTC month)","value":{"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.","docs":"https://docs.truval.dev/api/email-verify#monthly-quota","limit":500,"used":500,"reset_at":"2026-04-01T00:00:00.000Z"}}}}}},"503":{"description":"Monthly quota check could not be completed (temporary)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"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"}}}}}}},"/v1/email/verify/batch":{"post":{"operationId":"verifyEmailBatch","summary":"Verify up to 50 email addresses","description":"Runs the same verification pipeline as POST /v1/email/verify for each address in parallel. Results are returned in request order. Rate limit consumption equals the number of emails in the batch (e.g. 50 emails counts as 50 requests). **Free tier:** monthly quota counts one unit per email against the UTC cap (same exclusions as single verify for throttle / monthly-quota-only rows). Paid **billable** usage for spend caps and Stripe meters is summed per email (syntax-only outcomes are not billable). If rate or monthly quota would be exceeded, returns 429 before processing any address.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["emails"],"properties":{"emails":{"type":"array","minItems":1,"maxItems":50,"items":{"type":"string","format":"email"},"description":"Email addresses to verify (1–50)"}}}}}},"responses":{"200":{"description":"Batch verification results","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchVerifyResponse"},"example":{"results":[{"email":"a@b.com","valid":true,"status":"deliverable","confidence":0.97,"failed_check":null,"disposable":false,"role":false,"free_provider":false,"catch_all":false,"smtp_blocked":false,"mx_found":true,"mx_host":"mail.example.com","suggestion":null,"latency_ms":120},{"email":"c@d.com","valid":false,"status":"invalid","confidence":0,"failed_check":"syntax","disposable":false,"role":false,"free_provider":false,"catch_all":false,"smtp_blocked":false,"mx_found":false,"mx_host":null,"suggestion":null,"latency_ms":0}],"count":2,"latency_ms":312}}}},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"invalid_request","message":"Request body must be JSON with an emails array (1–50 addresses).","action":"Send: {\"emails\":[\"a@b.com\",\"c@d.com\"]}","docs":"https://docs.truval.dev/api/email-verify#batch"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"examples":{"missingApiKey":{"summary":"Missing Authorization header","value":{"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"}},"invalidApiKey":{"summary":"Invalid or revoked key","value":{"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"}}}}}},"402":{"description":"Hard spend cap would be exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentRequiredError"},"example":{"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}}}},"404":{"description":"Unknown route","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"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"}}}},"413":{"description":"Payload too large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"payload_too_large","message":"Request body exceeds 2MB limit.","action":"Reduce payload size; max payload is 2MB.","docs":"https://docs.truval.dev/api/email-verify#request"}}}},"429":{"description":"Rate limit exceeded, or (free tier only) monthly verification quota exceeded (batch email count applies to both)","headers":{"Retry-After":{"description":"Seconds until the instant given by `reset_at` in the JSON body (delta-seconds form, RFC 9110).","schema":{"type":"string","example":"42"}}},"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/RateLimitError"},{"$ref":"#/components/schemas/MonthlyQuotaError"}]},"examples":{"rateLimit":{"summary":"Per-minute rate limit","value":{"error":"rate_limit_exceeded","message":"Rate limit of 100 req/min exceeded.","action":"Wait until reset_at (plus a small cushion) before retrying.","limit":100,"window":"1m","reset_at":"2026-03-24T12:01:00.000Z","docs":"https://docs.truval.dev/api/email-verify#rate-limits"}},"monthlyQuota":{"summary":"Free tier monthly cap","value":{"error":"monthly_quota_exceeded","message":"Monthly free tier limit of 500 verification units reached for this UTC month.","action":"Upgrade your plan, use fewer addresses per batch, or wait until the next UTC month.","docs":"https://docs.truval.dev/api/email-verify#monthly-quota","limit":500,"used":498,"reset_at":"2026-04-01T00:00:00.000Z"}}}}}},"503":{"description":"Monthly quota check could not be completed (temporary)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"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"}}}}}}},"/v1/email/verify/stream":{"post":{"operationId":"verifyEmailStream","summary":"Verify up to 50 emails with NDJSON streaming","description":"Runs the same verification pipeline as POST /v1/email/verify for each address in parallel. Each result is written as one JSON object per line (newline-delimited JSON) in completion order as each verification finishes. Rate limit is per email; **free tier monthly quota** counts one unit per email with the same `usage_log` exclusions as single verify (429 throttle / monthly-cap rows are logged but not counted). Paid **billable** usage for spend caps and Stripe meters is summed per email (syntax-only outcomes are not billable). If rate or monthly quota would be exceeded, returns 429 before streaming.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["emails"],"properties":{"emails":{"type":"array","minItems":1,"maxItems":50,"items":{"type":"string","format":"email"},"description":"Email addresses to verify (1–50)"}}}}}},"responses":{"200":{"description":"NDJSON stream: each line is a complete VerifyEmailResult object (UTF-8). Lines are emitted in completion order as verifications finish.","content":{"application/x-ndjson":{"schema":{"type":"string","description":"Each line is a JSON object matching VerifyEmailResult"},"example":"{\"email\":\"a@b.com\",\"valid\":true,\"status\":\"deliverable\",\"confidence\":0.97,\"failed_check\":null,\"disposable\":false,\"role\":false,\"free_provider\":false,\"catch_all\":false,\"smtp_blocked\":false,\"mx_found\":true,\"mx_host\":\"mail.example.com\",\"suggestion\":null,\"latency_ms\":120}\n{\"email\":\"c@d.com\",\"valid\":false,\"status\":\"invalid\",\"confidence\":0.0,\"failed_check\":\"syntax\",\"disposable\":false,\"role\":false,\"free_provider\":false,\"catch_all\":false,\"smtp_blocked\":false,\"mx_found\":false,\"mx_host\":null,\"suggestion\":null,\"latency_ms\":0}\n"}}},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"invalid_request","message":"Request body must be JSON with an emails array (1–50 addresses).","action":"Send: {\"emails\":[\"a@b.com\",\"c@d.com\"]}","docs":"https://docs.truval.dev/api/email-verify#streaming"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"examples":{"missingApiKey":{"summary":"Missing Authorization header","value":{"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"}},"invalidApiKey":{"summary":"Invalid or revoked key","value":{"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"}}}}}},"402":{"description":"Hard spend cap would be exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentRequiredError"},"example":{"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}}}},"404":{"description":"Unknown route","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"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"}}}},"413":{"description":"Payload too large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"payload_too_large","message":"Request body exceeds 2MB limit.","action":"Reduce payload size; max payload is 2MB.","docs":"https://docs.truval.dev/api/email-verify#request"}}}},"429":{"description":"Rate limit exceeded, or (free tier only) monthly verification quota exceeded (stream email count applies to both)","headers":{"Retry-After":{"description":"Seconds until the instant given by `reset_at` in the JSON body (delta-seconds form, RFC 9110).","schema":{"type":"string","example":"42"}}},"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/RateLimitError"},{"$ref":"#/components/schemas/MonthlyQuotaError"}]},"examples":{"rateLimit":{"summary":"Per-minute rate limit","value":{"error":"rate_limit_exceeded","message":"Rate limit of 100 req/min exceeded.","action":"Wait until reset_at (plus a small cushion) before retrying.","limit":100,"window":"1m","reset_at":"2026-03-24T12:01:00.000Z","docs":"https://docs.truval.dev/api/email-verify#rate-limits"}},"monthlyQuota":{"summary":"Free tier monthly cap","value":{"error":"monthly_quota_exceeded","message":"Monthly free tier limit of 500 verification units reached for this UTC month.","action":"Upgrade your plan, use fewer addresses per request, or wait until the next UTC month.","docs":"https://docs.truval.dev/api/email-verify#monthly-quota","limit":500,"used":500,"reset_at":"2026-04-01T00:00:00.000Z"}}}}}},"503":{"description":"Monthly quota check could not be completed (temporary)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"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"}}}}}}},"/v1/management/account":{"get":{"operationId":"getManagementAccount","summary":"Get account state for management operations","description":"Requires provisioning key (sk_mgmt_...). Returns tier, limits, billing state, and usage this month.","responses":{"200":{"description":"Account state","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagementAccountResponse"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Wrong key type","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/v1/management/keys":{"get":{"operationId":"listManagementKeys","summary":"List active standard API keys","description":"Requires provisioning key (sk_mgmt_...). Returns active standard keys only.","responses":{"200":{"description":"Keys list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagementKeysListResponse"}}}}}},"post":{"operationId":"createManagementKey","summary":"Create a standard API key","description":"Requires provisioning key (sk_mgmt_...). Creates a new sk_live_ key and returns it once.","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"label":{"type":"string"}}}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagementCreateKeyResponse"}}}},"429":{"description":"Key limit reached","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/v1/management/keys/{id}":{"delete":{"operationId":"revokeManagementKey","summary":"Revoke a standard API key by id","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Revoked"},"404":{"description":"Key not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/v1/management/usage":{"get":{"operationId":"getManagementUsage","summary":"Get daily usage for last 30 days","description":"Daily **billable** verification counts (post-syntax, Stripe meter semantics) for all tiers. On **free** tier, totals here may differ from `GET /v1/management/usage/summary` `calls_used` (quota-based). For preflight against verify API limits on free, use **usage/summary** or **account**.","responses":{"200":{"description":"Daily usage breakdown","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagementUsageResponse"}}}}}}},"/v1/management/usage/summary":{"get":{"operationId":"getManagementUsageSummary","summary":"Get month-to-date usage summary","description":"Returns `calls_used`, `calls_remaining`, and related fields for the current UTC month. **Free** accounts use **monthly quota** counting (aligned with email verify enforcement and `GET /v1/management/account` `usage_this_month`). **Builder** and **scale** use **billable** counting (post-syntax, Stripe meter). Use this endpoint (or `GET /v1/management/account`) to preflight batches against verify limits; `GET /v1/management/usage` daily series remains billable for all tiers and may not sum to `calls_used` on free.","responses":{"200":{"description":"Usage summary","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagementUsageSummaryResponse"}}}}}}},"/v1/management/billing/portal":{"post":{"operationId":"createManagementBillingPortal","summary":"Create Stripe billing portal session","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"return_url":{"type":"string","format":"uri"}}}}}},"responses":{"200":{"description":"Billing portal URL","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagementBillingPortalResponse"}}}},"402":{"description":"No billing account","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/health":{"get":{"operationId":"health","summary":"Health check","security":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"ts":{"type":"number"}}}}}}}}}}}