Plan limits can change independently of API semantics. See
Pricing for current allowances.
Warnings are not failures
A warning inmetadata.warnings never means the request failed. An analysis can return a complete decision while reporting that some optional evidence was unavailable or a quota threshold is near. Warnings tell you what to know about the response — not what to redo.
Each warning carries a code, a human-readable message, and — for plan-related warnings — upgrade context (upgrade_required, required_plan, recommended_plan, and where applicable an upgrade_url).
Public warning codes
UNKNOWN_INDUSTRY fires for any unrecognized value on any plan. IP_INTELLIGENCE_NOT_AVAILABLE fires only when you explicitly supply an ip in the request body; when no IP is supplied, the omission is silent.
Warnings about unavailable evidence affect the decision’s quality context: expect decision.assessment to widen (evidence_coverage down, uncertainty up) when evidence was omitted.
Plan feature gates
Features and request context are gated by plan. The failure mode differs per feature — this table is the authoritative map of what happens when a plan does not include something:FEATURE_NOT_AVAILABLE responses include remediation metadata: upgrade_required, required_plan, recommended_plan, and an upgrade action linking to your billing page.
Monthly usage quota
What is counted: one unit per analyzed email address — one for a single analysis, one per row in a batch request, one per processed row in a bulk job. Window: usage resets monthly. The window is anchored to your account (typically your subscription start date) —metadata.plan.reset_at always reports the exact reset time, and metadata.plan.billing_period shows the current window.
Grace buffer: requests keep succeeding for a grace allowance beyond the monthly limit (10% of the plan quota), accompanied by an IN_GRACE_BUFFER warning. At the hard limit, further requests fail.
Exhaustion: past the hard limit, analysis requests fail with 429 MONTHLY_QUOTA_EXCEEDED. The error body includes a details snapshot (plan, cap, grace, hard_stop, current_usage, requested_units, reset_date) and a retry_after_seconds value reflecting the reset time, mirrored in the Retry-After header. Retrying immediately does not help — upgrade the plan or wait for the reset.
Refunds: if the API fails internally while processing an analysis, the units for that request are returned to your quota. Requests that were analyzed are not refunded.
Batch accounting
POST /v1/analyze-email/batch analyzes up to 50 addresses per request.
- Each submitted row consumes one unit, committed when the batch is accepted.
- Rows that fail per-row validation (for example, a malformed address) still consume their unit — the analyzer was invoked for them; the failure is reported in that row’s
errorfield while the overall request returns200. - An oversized batch (more than 50 rows) is rejected with
400LIMIT_EXCEEDEDbefore units are committed — no quota is consumed. - If the connection drops mid-processing, rows that were never attempted are refunded.
Bulk accounting
Asynchronous bulk jobs (POST /v1/bulk/jobs) are accounted differently:
- Submitting a job consumes no units.
- While the job processes, units are reserved and then consumed per row actually analyzed.
- Rows that are never processed — because the job stops, fails, or hits the quota — are released back to your allowance. Net consumption equals rows analyzed.
- If the monthly quota is exhausted mid-job, the job stops with status
quota_exceeded; already-processed rows are available in the results.
Explanation allowance
Explanations (options.include_explanation) draw on a separate monthly allowance included in each plan; each analyzed row with an explanation requested consumes one explanation unit.
When the allowance is exhausted, the analysis itself still succeeds — this is not a 429:
explanation.explanation_availableisfalseandexplanation_omitted_reasonis"limit_exceeded"- the
X-Explanation-Omitted: trueresponse header is set - an
EXPLANATION_LIMIT_EXCEEDEDwarning appears inmetadata.warnings
Rate limiting
Rate limits are short-window throttles, independent of the monthly quota. Per-minute plan limit: each plan defines a requests-per-minute allowance, counted in analyzed units — a 50-row batch counts as 50 units against the minute. Exceeding it returns429 RATE_LIMIT_EXCEEDED with a details snapshot (rate_limit, window, retry_after, requested_units); the Retry-After header and error.retry_after_seconds both carry the seconds remaining in the current minute.
Anti-abuse limits: all endpoints are additionally protected by per-IP safeguards. These thresholds are intentionally not published, and their responses do not include Retry-After — if you receive a RATE_LIMIT_EXCEEDED without retry metadata, reduce your request frequency.
Duplicate protection: an identical request (same account, endpoint, email, and options) still in flight returns 429 DUPLICATE_REQUEST, which is not retryable — wait for the original request to finish.
Rate limiting (slow down, retry shortly) and quota exhaustion (upgrade or wait for the monthly reset) are different conditions with different remedies, even though both use HTTP 429.
Quota and rate-limit headers
Successful analysis and batch responses carry the full snapshot as headers:
Error responses carry
X-Request-ID, and Retry-After where applicable, instead of the quota headers.
Retry guidance
Next steps
Error Reference
Every public error code, its status, meaning, and whether to retry it.