Errors
The error vocabulary returned by the agent API — codes, data payloads, idempotency rules, and retry guidance.
Every call returns either {"json": <output>} or a structured error.
Error shape
{
"code": "request_expired",
"status": 409,
"message": "The request has expired.",
"data": {
"requestId": "apr_1234_v1"
}
}Client code should switch on code and read specifics out of data.
Error codes
| Code | Status | data | When it is thrown |
|---|---|---|---|
validation_error | 400 | issues | Input fails schema validation. Fix the payload; do not retry as-is. |
unauthorized | 401 | reason | Missing or invalid x-ai-agent-key. data.reason is ai_agent_access_key_required. |
not_found | 404 | resource, id | The resource does not exist or is out of your connection's scope. |
bad_request | 400 | — | A state guard failed — for example, submitRequest when routing resolves to no assignee. |
request_expired | 409 | requestId | The request's expiresAt has passed. |
decision_in_progress | 409 | requestId, idempotencyKey | A decision is already in flight for this request. |
decision_already_finalized | 409 | requestId, receiptId? | The request already has a final decision; receiptId (when present) points at the proof. |
idempotency_conflict | 409 | idempotencyKey, resource | The idempotency key was reused with a different payload. |
conflict | 409 | data.reason | A uniqueness or state conflict not covered by a more specific code. |
service_unavailable | 503 | retryable | A dependency failed transiently. |
too_many_requests | 429 | retryable | Rate limit exceeded. |
Idempotency rules
Every mutating call takes an idempotencyKey. The rules are uniform:
- Same key, same payload — the stored result is replayed; safe to retry.
- Same key, different payload —
idempotency_conflict(409). Mint a new key; do not mutate the key to mean something else. - Different key while a decision is in flight —
decision_in_progress(409).
submitRequest enforces uniqueness on both idempotencyKey and
externalRequestId per connection, so a retry after a network timeout
returns the originally created request instead of a duplicate.
Retry guidance
| Situation | Do this |
|---|---|
service_unavailable with retryable: true, too_many_requests | Retry with exponential backoff (1s, 2s, 4s) and a cap; reuse the same idempotency key. |
decision_in_progress | Do not spam retries — poll getStatus until the in-flight decision resolves. |
| Network timeout / no response | Retry with the same idempotency key — the call may have landed server-side. |
validation_error, unauthorized, not_found, idempotency_conflict, decision_already_finalized, request_expired | Not retryable as-is; fix the credential or payload first. |
Delivery failures
Webhook delivery has its own failure vocabulary (forbidden_address,
timeout, http_<status>, max_attempts:<cause>, …) — see
Webhooks → delivery error codes.