Skip to main content

Error Codes

Every Zihin API error returns the same JSON shape — an error code, a human-readable message, status: "error", and optional details. Codes are grouped below by category: authentication (401/403), rate limiting (429), request (400/404), provider (5xx), and session control. The HTTP status tells you the class of failure; the error code tells you the exact cause.

Error Format​

{
error: string; // Error code
message: string; // Human-readable description
status: "error";
details?: object; // Additional context (optional)
}

Authentication Errors​

CodeHTTP StatusDescription
authentication_required401No authentication provided
invalid_api_key401API key is invalid or expired
invalid_token401JWT token is invalid or expired
insufficient_permissions403User lacks required role

Rate Limiting Errors​

CodeHTTP StatusDescription
rate_limit_exceeded429Too many requests
quota_exceeded429Monthly/daily quota reached
token_limit_exceeded429Token pack exhausted

Request Errors​

CodeHTTP StatusDescription
invalid_request400Malformed request body
model_not_found400Specified model doesn't exist
agent_not_found404Agent ID not found
tenant_not_found404Tenant ID not found

Provider Errors​

CodeHTTP StatusDescription
provider_error502LLM provider returned an error
provider_timeout504LLM provider didn't respond in time
provider_unavailable503LLM provider is down

Session Control Errors​

CodeHTTP StatusDescription
INVALID_SESSION_STATE409POST /:id/manual-message was called while the session is in control_mode='engaged'. Call /handoff or /suspend first. The response details.current_mode confirms the current mode.
NO_TRIGGER_HISTORY422POST /:id/manual-message requires at least one previous webhook execution to know which outbound channel to use. Sessions started through SSE chat or other paths without a webhook can't accept manual messages.
NO_CALLBACK_CONFIG422The trigger that originated the session has no outbound callback configured in trigger_config.execution.callback. Configure a callback (e.g., Twilio Messages API) and retry.
DELIVERY_FAILED502The outbound channel (Twilio/Meta/webhook) returned an error. The response details.statusCode and details.latencyMs carry the provider response.

Idempotency and concurrency errors​

CodeHTTP StatusDescription
IDEMPOTENCY_CONFLICT409On /stream, the client_message_id was already used with a different message. Send a new id for a new message. It is not CONFLICT, which means the conversation belongs to another identity (consumer_key) or another access.
SESSION_BUSY409Another turn is still being answered in the same conversation (or the same client_message_id is in flight). Wait for done and send again.

Invalid filter values​

List endpoints with a closed set of values in the status filter (approvals, executions, tasks and sessions) now answer 400 VALIDATION_ERROR when the value is unknown, with the accepted values in details.allowed. Before, an unknown value returned an empty list with 200, which looked like "nothing found".

{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "…",
"details": { "allowed": ["active", "archived", "expired"] },
"request_id": "…"
}
}

Handling Errors​

# Example error response
HTTP/1.1 401 Unauthorized
{
"error": "invalid_api_key",
"message": "The provided API key is invalid or expired",
"status": "error"
}

For 429 errors, check the Retry-After header for when to retry.

Common questions​

How do I handle a 429?​

A 429 means a rate or quota limit was hit (rate_limit_exceeded, quota_exceeded, or token_limit_exceeded). Read the Retry-After header for how many seconds to wait, then retry — see Rate Limits.

What does insufficient_permissions (403) mean?​

The request authenticated successfully, but the user or API key role lacks permission for that operation. Check the role's permissions in API Keys → Role System.

What is the difference between a 4xx and a 5xx error?​

4xx codes mean the request itself needs to change (bad auth, malformed body, missing resource). 5xx codes — provider_error, provider_timeout, provider_unavailable — mean an upstream LLM provider failed; these are usually transient and safe to retry.