Errors
Every error code of the agent and identity API, with its status, its reason values, and what to do.
All errors under /api/v1 share one envelope:
{ "success": false, "error": "<code>", "message": "<text>" }Codes written in lower case come from the authentication and identity layer. They add error_code (same value as error) and, where useful, a reason. Codes written in upper case come from the agent routes and carry only error and message.
Authentication
| Status | error | reason values | What to do |
|---|---|---|---|
| 400 | ambiguous_auth | signature_and_authorization | Send either Signature-Input or Authorization, never both. |
| 401 | AGENT_AUTH_REQUIRED | Add a token or a signature. | |
| 401 | token_invalid | malformed, alg, kid, expired, nbf, aud, iss, signature, sub, sub_unknown, key_custody | Check the token: RS256, issued by https://auth.machine-identity.com, scope with the project audience, not expired. sub_unknown means no agent owns this machine user; key_custody means the agent uses a developer key and must sign instead. |
| 401 | signature_invalid | bad_signature, expired, digest_mismatch, replay, key_not_authorized, unresolvable, malformed, signer_type, unknown_agent | Check the profile: four components, tag ay-agent, fresh nonce, keyid is the current #dev-N. key_not_authorized means the key is not the agent's current developer key. |
| 401 | INVALID_AGENT_KEY | The legacy API key is unknown. Move to a token. | |
| 401 | AGENT_INACTIVE | The agent is deactivated or still pending_attestation. | |
| 403 | AGENT_HALTED | The kill switch is on. Turn it off with PATCH /agents/{id}/config. | |
| 403 | DAILY_LIMIT_EXCEEDED | Today's spend reached daily_limit_eur. Wait for the next day or raise the limit. | |
| 403 | OWNER_NOT_VERIFIED | The business that owns the agent is not verified, suspended, or revoked. | |
| 403 | OWNER_MANDATE_MISSING | owner_mandate | Only when mandate enforcement is on. The person who owns the agent has no valid mandate for their twin, or has revoked it. The person signs a new mandate in the AY app. |
| 503 | verifier_unavailable | not_configured, jwks, nonce_store, owner_credential | AY could not run a check and refused the request. Retry with backoff. |
Registration and attestation
| Status | error | What to do |
|---|---|---|
| 400 | TWIN_REQUIRED | The owner account has no twin yet. Finish onboarding first. |
| 422 | INVALID_PUBLIC_KEY | public_key_multibase is not an Ed25519 Multikey, or, on rotation, equals the current key. |
| 422 | AGENT_VISIBILITY_BUSINESS_PRIVATE | Business agents are always private. Omit visibility or send private. |
| 409 | IDENTITY_NOT_REGISTERED | The acting person has not paired the AY app. With X-Act-As this is the person acting for the business. Every agent passport needs a paired person behind it. Pair the app, then register or attest again. |
| 409 | TWIN_DID_MISSING | The business twin has no DID yet, so the passport would have no owner. Retry later or contact support. |
| 409 | MANDATE_REQUIRED | Only when mandate enforcement is on. The acting person has no valid mandate for their twin. Confirm the mandate in the AY app, then register or attest again. Not returned with X-Act-As: a business needs no mandate. |
| 409 | BUSINESS_NOT_VERIFIED | The business is not verified yet. Registration and attestation of business agents wait for the verification. |
| 429 | AGENT_LIMIT_REACHED | Ten active agents per account. Deactivate one first. |
| 502 | AGENT_CREDENTIAL_FAILED | The identity provider rejected the change. The registration was rolled back; retry. |
| 503 | AGENT_AUTH_NOT_CONFIGURED | The agents project is not configured in this environment. Contact support. |
| 409 | ATTESTATION_NOT_PENDING | The agent is not waiting for a proof of possession. |
| 410 | attestation_expired | The challenge is older than ten minutes. Register again, or request a new rotation challenge. |
| 422 | attestation_invalid | The challenge does not match or the signature does not verify. |
Rotation
| Status | error | What to do |
|---|---|---|
| 403 | ROTATION_REQUIRES_SIGNATURE | Self-rotation requires a signed request (tag ay-agent), not a token. |
| 409 | ROTATION_NOT_ALLOWED | The agent has no developer key or is not active. |
| 409 | IDENTITY_NOT_REGISTERED | The acting person (with X-Act-As: the person acting for the business) or the owner has not paired the AY app. Pair it, then rotate. |
| 409 | TWIN_DID_MISSING | The business twin has no DID yet. |
| 409 | MANDATE_REQUIRED | Only when mandate enforcement is on. The acting person has no valid mandate for their twin. Confirm it in the AY app, then rotate. |
| 409 | ROTATION_CHALLENGE_MISSING | Request a challenge first. |
| 409 | AGENT_CREDENTIAL_NOT_ROTATABLE | No Zitadel credential to rotate (developer custody or legacy agent). |
Identity
| Status | error | What to do |
|---|---|---|
| 404 | DID_NOT_FOUND | The DID is not published by its host. |
| 422 | INVALID_DID | Send a did:webvh identifier of at most 512 characters. |
| 422 | validation_failed | The request body did not match the schema; messages lists the fields. |
Generic
| Status | error | What to do |
|---|---|---|
| 404 | not_found | The agent does not exist or does not belong to you. |
| 429 | rate_limited | Slow down; read Retry-After. See Rate limits. |
A2A Agent Card GET
A2A v1.0 Agent Card of an active agent, served bare, `ETag`, `Cache-Control: public, max-age=300`. Carries the AY identity extension `https://aytwin.ai/a2a/ext/identity/v1` with `did`, `didDocument`, `passport`, `keyCustody` and `requestSigningKey`. For platform custody the card is JWS-signed with the agent's `#key-1` (EdDSA, RFC 7515 detached, over the JCS form of the card without `signatures`). For developer custody `signatures` is absent.
Rate limits
Request budgets per endpoint, and the headers that tell you where you stand.