message is one sentence you can show a person. errors lists the individual problems, and is [] (never absent or null) when there is only the message. Parse detail.message and detail.errors and your handler works for every failure.
code is a stable identifier for an error your code is expected to branch on, and null on every other. Branch on code, never on the wording of message. The codes today all come from posting into a conversation: whatsapp_window_closed, voice_session_live, chat_ended, chat_open_elsewhere, idempotency_conflict, channel_unsupported, no_agent and messages_off (an agent was sent for a WhatsApp number or Telegram bot whose messages trigger is off; WhatsApp batches answer it too).
Status codes
422: schema validation
Each line isfield.path: problem, with the body/query/path prefix stripped, so the path matches the key you sent. When there is exactly one problem, that line is also the message; with several, message is invalid request.
limit above an endpoint’s ceiling is a 422, not a silent clamp.
401 versus 403
402: out of credits
Returned only by the four operations that start a billable session:POST /v1/calls/token, POST /v1/calls/outbound, POST /v1/calls/{session_id}/resume and POST /v1/chats. Sessions already running are unaffected.
close_reason: "insufficient_credits". A batch pauses instead of failing. See pricing and credits.
Validation results are not errors
POST /v1/agents/{agent_id}/validate, POST /v1/tools/{tool_id}/validate and POST /v1/tasks/{task_id}/validate answer 200 with {"errors": [...], "warnings": [...]}, both always present. Errors block a publish; warnings do not, and a successful publish returns them in warnings. Publishing with errors present is a 400 carrying the same lines in detail.errors. See validation.
Retrying
Retry500, 502 and 503 with exponential backoff. Every other code is a verdict on the request; sending it again changes nothing. Neither SDK retries for you.
Elsewhere:
- Chat messages dedupe.
POST /v1/chats/{chat_id}/messagesrequires aclient_message_idUUID you generate. Re-sending the same id returns the original turn instead of posting twice. - Names are unique. A retried create of an agent, tool or task answers
409(an agent with that name already exists). Treat it as success and read the resource. - Read before re-dialling. After a timeout on
POST /v1/calls/outbound, list calls bycontact_keyorbatch_idbefore placing it again. - Let batches retry. Call batches carry their own
max_attemptsandretry_after_minutes.
How the SDKs raise
Both SDKs raise one error type for every non-2xx response, carrying the envelope’s fields.
A request that never got a response (DNS, abort, offline) is not a
TalqingApiError in TypeScript: the transport’s own error is rethrown. instanceof TalqingApiError holds across the ESM and CommonJS builds. TalqingClient also takes onUnauthorized, called once on any 401 before the error is thrown.
Limits
Sizes, counts and timeouts the API enforces.
Authentication
Tokens, roles, and where 401 and 403 come from.