Errors and recovery

An API error means the request could not be completed as asked. A false or uncertain verdict is different: it is a completed verification result and returns HTTP 200. Route those results for review rather than retrying them as service failures.

For example, an invoice with no purchase-order reference above the PO threshold can return HTTP 200 and verdict: "false". The failed po_present assertion is an accounts-payable control exception to investigate. It is not a malformed request and does not call for an automatic retry.

For an uncertain result, combined_bound means the applicable model-answer bounds exceed the gate budget even though individual answers hold. nothing_applicable means no assertion remained in scope. These are result reasons, not HTTP error codes. Review the scope and evidence before changing options; see Verification results.

The error response

Errors have one JSON shape. type gives the broad category, code identifies the condition, message explains it, and optional param names the field to correct.

{
  "error": {
    "type": "invalid_request",
    "code": "schema_violation",
    "message": "item.data.amount must be a nonnegative decimal string such as \"212.40\".",
    "param": "item.data.amount"
  }
}

Every API gateway response carries a Request-Id header. Save it with the status, error code and time when diagnosing a failure. It lets you identify the request without putting the submitted record or API key into a support message. The Server-Timing header lists where the time went, by stage name and duration only: the service's stages, such as parse, validate, run and model, then the gateway's admit, origin and worker.

Input and request-format errors

StatusCodeHow to recover
400invalid_jsonSend one valid JSON object. Remove duplicate keys, NaN and Infinity; check quoting and trailing commas.
400invalid_content_lengthSend the correct byte length. Prefer a client that calculates Content-Length from the final encoded body.
400invalid_filterCheck the audit-items query. verdict accepts true, false or uncertain; cursor and limit must have the expected numeric form.
405method_not_allowedUse the method listed for the endpoint in the API reference.
411length_requiredInclude Content-Length when sending a body.
413body_too_largeReduce the encoded body to the route's size limit. Count context and long text as well as items.
413too_many_itemsReduce an audit to at most 10,000 items, while also respecting account quotas.
413too_many_recordsReduce context to at most 50,000 records. Preserve the population needed by relationship checks.
415unsupported_media_typeSend JSON with Content-Type: application/json.
415unsupported_encodingSend an uncompressed body.
422schema_violationCorrect the field in param against the use-case schema. Amounts use decimal strings, not JSON numbers. In an audit, param names the item by its position, such as items.3.data.amount.
422unknown_use_case, unknown_item_typeChoose a published use case, alone or with a served version such as financial-audit@1, and one of its supported item types. param is use_case, or item.type (items.3.type in an audit). An unknown id in GET /api/v1/use-cases/{id} is also unknown_use_case, not a 404.
422unknown_record_type, unknown_referenceUse only the context record and reference names declared by that use case.
422unknown_field, missing_fieldRemove the extra field or supply the required one named by the error.
422unknown_parameter, invalid_parameterCheck options.parameters against the parameters of the use-case version you named; versions can differ. The message of unknown_parameter names another served version that has the parameter, if one does.
422duplicate_itemGive each item a unique type-and-id pair within the audit. This is a request-identity collision, not a duplicate-payment finding.

Retrying the same invalid body will produce the same error. Keep the original business record, correct the mapping or serialization, and send the corrected request.

Authentication and access

StatusCodeHow to recover
401missing_api_keySend Authorization: Bearer with a key created on your account page.
401invalid_api_keyCheck that the full key is configured. It may be malformed, unknown, expired or revoked; replace it if needed.
401session_requiredSign in again, then return to the console.
403cross_originUse the console on openauditor.ai. For your own server integration, use an API key rather than a browser session cookie.
404not_foundCheck the route, audit id and account. A deleted or expired audit is unavailable; an audit owned by another account is not exposed.

Keys belonging to the same account see that account's audits. Creating a key under another email account does not grant access to an existing audit.

Batch-state errors

409 not_completed means items or verification marks were requested before the audit completed. Read GET /api/v1/audits/{id} and wait if the state is queued or running. If it is failed, inspect the audit's error rather than continuing to request its items. A canceled audit has no results, so its items also answer not_completed.

To stop an audit you no longer need, send POST /api/v1/audits/{id}/cancel. A queued audit is canceled at once; a running one stops within its next 32 items and keeps no results. 409 not_cancelable means it had already completed or failed.

A successful batch submission returns HTTP 202 and an audit id. Record that id immediately. A connection failure or 504 origin_timeout during submission does not prove that no audit was created. Send an Idempotency-Key header, such as a UUID, with every submission, and repeat a failed one with the same key and body: within 24 hours the API returns the audit the first attempt created, with Idempotent-Replayed: true, instead of queuing and charging a second one. Without the header, repeating the POST can create a second audit.

409 idempotency_key_reused means the key was already used in the last 24 hours with a different request body. Use a new key for a new submission. 400 invalid_idempotency_key means the key is empty, longer than 255 characters, or not plain visible ASCII.

Rate limits and temporary failures

StatusCodeHow to recover
429rate_limitedWait for Retry-After. Coordinate callers sharing the account's 60-request rolling window.
429daily_item_quotaWait until the daily reset at 00:00 UTC. Existing results can still be read within the request-rate limit.
429daily_question_quotaThe daily single-verification model-question quota is exhausted. Wait for the reset; see Limits.
500internal_errorThe service failed. For safe reads, retry with a delay. If it persists, report the request id.
503overloadedToo many interactive verifications are waiting. Honor Retry-After and reduce concurrent submissions.
503service_unavailableThe service is temporarily unreachable or unable to serve the request. Retry later and preserve the request id.
504origin_timeoutThe origin did not answer within 60 seconds. Check what operation timed out before deciding whether a repeat is appropriate.

Use a bounded retry policy with increasing delays and some random variation between callers. Honor the server's longer Retry-After value when present. Do not retry authentication or schema errors without correcting them, and do not treat an uncertain verdict as a transient failure.

Email-code sign-in

A code works only in the browser where it was requested. no_code_requested means the matching challenge is absent; request a code in that browser. For invalid_code, check the six digits and whether the ten-minute window has expired. Sign-in can also return too_many_requests or email_unavailable; follow the retry interval rather than repeatedly submitting the form.

Report a reproducible problem

Contact ERP.AI through the ERP.AI contact page with the endpoint, HTTP status, error code, request id, approximate time and the smallest sanitized example that reproduces the issue. Omit API keys, session cookies, sign-in codes and confidential business records. For a security concern, follow the security reporting guidance.