> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Error Code Reference

> Reference for every code in Orbit's canonical `ERROR_CODES` registry, generated from the platform source.

# Error Code Reference

Every Orbit API error response carries a machine-readable `code`,
human-readable `message`, HTTP `status`, and contextual `details`.
This page is generated from the canonical `ERROR_CODES` registry in
`packages/shared/src/errors.ts` and lists every code in that
registry — 698 in total — grouped by domain. Every code
listed here is one the SDK and `meta.docs_url` link against. Some
route handlers also return operational codes that are not yet in the
registry and so are absent from the table below, so treat the `code`
on any server response as authoritative even when it is not listed
here.

<Note>
  HTTP status codes shown reflect the canonical status documented in the
  source. Some codes are reused at multiple call sites with different
  statuses (e.g. `VALIDATION_ERROR` may surface as 400 or 422); the
  table picks the dominant value. Treat the `status` field on the
  response envelope as authoritative for any given response.
</Note>

## Error Response Format

```json theme={null}
{
  "error": {
    "code": "INVALID_PHONE_NUMBER",
    "message": "The 'to' field must be a valid E.164 phone number",
    "status": 422,
    "details": {
      "field": "to",
      "value": "+1234",
      "expected": "E.164 format e.g. +14155552671"
    }
  },
  "meta": {
    "request_id": "req_abc123",
    "timestamp": "2026-03-08T00:00:00Z",
    "docs_url": "https://docs.orbit.devotel.io/errors/INVALID_PHONE_NUMBER"
  }
}
```

The `meta.docs_url` resolves to a stable per-code anchor on this
page (`/reference/error-codes#CODE_NAME` — case-insensitive).

***

## Authentication

| Code                            | HTTP   | Description                                                                                                                                                                                                                                    |
| ------------------------------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `UNAUTHORIZED`                  | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                |
| `INVALID_API_KEY`               | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                |
| `EXPIRED_TOKEN`                 | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                |
| `INSUFFICIENT_PERMISSIONS`      | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                |
| `IP_NOT_ALLOWED`                | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                |
| `NOT_OWNING_AGENT`              | 404    | 404 — `POST /voice/queues/:queueId/calls/:callId/disposition` refused to record a disposition because the authenticated agent is not the `assigned_agent_user_id` on the queue entry.                                                          |
| `WRONG_KEY_MODE`                | 403    | Audit #SANDBOX-1 — returned when an API key's mode (sandbox vs. live, derived from the `dv_test_sk_*` / `dv_live_sk_*` prefix and the `api_keys.mode` column) does not match the resolved organization's `is_sandbox` flag.                    |
| `SAML_USER_NOT_IN_ORG`          | varies | Returned by the SAML ACS when an IdP assertion succeeds cryptographically but the asserted email either belongs to a different Devotel organisation OR has no invitation / enforcement on the callback org.                                    |
| `SCIM_ROLE_CEILING_EXCEEDED`    | varies | Returned by the SCIM PATCH /Groups endpoint when the requested target role exceeds the org's configured `max_assignable_role` ceiling (default 'admin').                                                                                       |
| `WEBHOOK_BODY_MISSING`          | varies | Returned when a Clerk webhook arrives but the content-type parser that captures the raw request bytes for svix signature verification didn't run (e.g. non-JSON content-type).                                                                 |
| `INVALID_SIGNATURE`             | 401    | HTTP 401 — an inbound webhook receiver rejected a request because the provider signature (HMAC / svix / X-Hub-Signature-256 / Twilio `X-Twilio-Signature`, etc.) failed verification, or the timing-safe comparison against the configured sh… |
| `STALE_WEBHOOK`                 | 401    | HTTP 401 — an inbound webhook/DLR receiver rejected a request because the event timestamp is missing or falls outside the allowed replay window (a clock-skew / replay-attack guard).                                                          |
| `CANNOT_REVOKE_CURRENT_SESSION` | 400    | HTTP 400 — the session-revoke endpoint (`DELETE /settings/security/sessions/:sessionId`) refused to revoke the caller's own currently-signed-in session; end the current session through the sign-out flow instead.                            |

## Validation

| Code                                        | HTTP   | Description                                                                                                                                                                                                                             |
| ------------------------------------------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `VALIDATION_ERROR`                          | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                         |
| `DB_ERROR`                                  | 500    | 500 — generic database operation failure surfaced to clients by the inbox conversation-tags + SLA controllers (e.g. "Failed to create conversation tag definition").                                                                    |
| `NO_VARIANT_FOR_CHANNEL`                    | 422    | 422 — a content template (multi-channel message template) has no variant for the requested target channel and no fallback in `fallback_chain` resolved to a channel that does.                                                          |
| `WEAK_IDENTITY_MATCH_REQUIRES_CONFIRMATION` | 422    | 422 — `POST /conversations/:id/merge` refused a merge whose only cross-row identity overlap is phone OR email while the rows ALSO carry contradicting `contact_id` values (different ids, or one side has an id and the other doesn't). |
| `INVALID_PHONE_NUMBER`                      | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                         |
| `INVALID_FROM_NUMBER`                       | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                         |
| `INVALID_EMAIL`                             | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                         |
| `INVALID_TEMPLATE`                          | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                         |
| `MISSING_REQUIRED_FIELD`                    | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                         |
| `MMS_NANP_ONLY`                             | varies | MMS submitted to a non-NANP destination.                                                                                                                                                                                                |
| `ATTACHMENT_TOO_LARGE`                      | 422    | 422 — `POST /inbox/tickets/:id/attachments` refused to register a ticket attachment because the declared `size_bytes` exceeds the per-attachment ceiling (`TICKET_ATTACHMENT_MAX_BYTES`, 25 MiB).                                       |
| `INVALID_CURSOR`                            | 400    | HTTP 400 — a cursor-paginated list endpoint rejected the `cursor` query parameter because it is malformed, truncated, tampered, or no longer resolves to a row in the current result window.                                            |
| `TURNSTILE_REQUIRED`                        | 422    | 422 — a public, unauthenticated anti-bot endpoint rejected a submission because the Cloudflare Turnstile token was missing, malformed, or failed siteverify (fail-closed when the Turnstile secret is configured).                      |

## Resources

| Code                                    | HTTP   | Description                                                                                                                                                                   |
| --------------------------------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `NOT_FOUND`                             | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                               |
| `ALREADY_EXISTS`                        | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                               |
| `CONFLICT`                              | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                               |
| `DUPLICATE_SENDER_ID`                   | 409    | 409 — `POST /settings/sender-ids` refused to register a sender ID because an entry with the same value already exists on this workspace for the same channel.                 |
| `CONTACT_PHONE_ALREADY_EXISTS`          | 409    | 409 — POST /contacts or PATCH /contacts/:id collided with the tenant's partial UNIQUE index `contacts_phone_live_uq` (predicate: `deleted_at IS NULL AND phone IS NOT NULL`). |
| `CONTACT_EMAIL_ALREADY_EXISTS`          | 409    | 409 — same shape as CONTACT\_PHONE\_ALREADY\_EXISTS but for the partial UNIQUE index `contacts_email_live_uq`.                                                                |
| `CONTACT_WHATSAPP_BSUID_ALREADY_EXISTS` | 409    | 409 — partial UNIQUE index `idx_contacts_whatsapp_bsuid` collision.                                                                                                           |
| `CONTACT_ARCHIVED_REQUIRES_UNARCHIVE`   | 409    | 409 — PUT /contacts/:id attempted to move an archived contact to a non-archived lifecycle\_stage without the explicit `unarchive: true` companion flag.                       |
| `TEMPLATE_NAME_ALREADY_EXISTS`          | 409    | 409 — POST /messages/templates collided with the tenant's `uq_templates_channel_name` unique index `(channel, name)`.                                                         |
| `CONTACT_NOT_FOUND_FOR_IDENTIFIER`      | 404    | 404 — POST /contacts/lists/:id/members `identifier` resolver could not map the operator-supplied phone / email / contact id / name to any existing contact in the tenant.     |
| `GONE`                                  | 410    | HTTP 410 Gone — resource existed but is permanently unavailable (revoked / expired / single-use exhausted).                                                                   |

## Rate Limiting

| Code                     | HTTP   | Description                                                                                                                                                                |
| ------------------------ | ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `RATE_LIMIT_EXCEEDED`    | 429    | Per-recipient, per-tenant, and per-resource frequency-cap HTTP 429, raised by the messaging, verify, DSAR, and number-pool limiters with a `retry_after` value in seconds. |
| `QUOTA_EXCEEDED`         | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                            |
| `DAILY_CAP_EXCEEDED`     | 429    | Audit #WARMING-1 — per-DID 10DLC daily-cap reached on the pre-send gate (`apps/api/src/lib/sms-warming-cap.ts`).                                                           |
| `WARMING_QUOTA_EXCEEDED` | varies | NaaS number-warming progression (2026-05-28) — newly-acquired 10DLC numbers ramp gradually for carrier reputation.                                                         |
| `NUMBER_MPS_EXCEEDED`    | 429    | NaaS per-DID messaging throughput cap (2026-06-09) — operator-set hard per-second send ceiling on a single number, enforced by `apps/api/src/lib/per-number-mps-cap.ts`.   |

## Messaging

| Code                                               | HTTP   | Description                                                                                                                                                                                                                                    |
| -------------------------------------------------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `MESSAGE_SEND_FAILED`                              | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                |
| `EMAIL_SEND_FAILED`                                | 500    | 500 — `POST /messages` email send: a single recipient's send failed with a non-`DevotelError` rejection (e.g. a Resend 5xx, fetch `ECONNRESET`, or a Drizzle/postgres fault inside the send pipeline).                                         |
| `EMAIL_SEND_FAILED_ALL`                            | varies | `POST /messages` email fan-out: EVERY recipient failed.                                                                                                                                                                                        |
| `MESSAGE_NOT_EDITABLE`                             | 409    | 409 — `PATCH /messages/:id` (Twilio Message.update parity) refused to edit a scheduled message that is no longer in `scheduled` state.                                                                                                         |
| `MESSAGE_NOT_CANCELLABLE`                          | 409    | 409 — `DELETE /messages/:id` refused to cancel a scheduled message that is no longer in `scheduled` state.                                                                                                                                     |
| `CONVERSATION_NOT_FOUND`                           | 404    | 404 — `POST /messages` was given an optional `conversation_id` to thread a reply, but the id does not reference a conversation on your account.                                                                                                |
| `CONVERSATION_MISMATCH`                            | 422    | 422 — `POST /messages` `conversation_id` resolved to a real conversation, but it does not belong to this recipient and channel.                                                                                                                |
| `CHANNEL_UNAVAILABLE`                              | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                |
| `CHANNEL_NOT_CONFIGURED`                           | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                |
| `CHANNEL_COMING_SOON`                              | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                |
| `CHANNEL_NOT_REPLYABLE`                            | 422    | SCAN-INBOX-018 (2026-05-23) — caller selected a reply channel that is an inbox-only triage label (`agent`, `video`) rather than an outbound provider.                                                                                          |
| `MISSING_IDENTITY`                                 | varies | SCAN-INBOX-018 (2026-05-23) — caller asked to reply on a real channel but the conversation row carries no usable identity for that channel (e.g. `web_chat` thread with no `metadata.visitor_id`; SMS thread with no `contact_phone`).         |
| `SENDER_ID_NOT_REGISTERED`                         | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                |
| `SENDER_ID_NOT_APPROVED`                           | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                |
| `NO_SENDER_CONFIGURED`                             | 422    | #R3-ONB-T1-FIRSTSEND (2026-05-24) — first-send opaque error fix.                                                                                                                                                                               |
| `SENDER_REQUIRED`                                  | 422    | 422 — a direct API / SDK send omitted every sender selector (`from`, `sender_pool_id`, `messaging_service_id`, `from_extension`).                                                                                                              |
| `SENDER_INVALID_FOR_DESTINATION`                   | varies | Wave-W5-C — Sender ID violates the destination country's per-country format / prefix / length rules (see `packages/messaging/src/sender-id-rules.ts`).                                                                                         |
| `SENDER_ID_CHECK_UNAVAILABLE`                      | 503    | Wave-W1 CPA-001 — Alpha sender approval gate could not reach Redis or the DB to verify whether the supplied alphanumeric sender ID is approved for this tenant.                                                                                |
| `SENDER_NOT_OWNED`                                 | 422    | Wave-W1 SCAN-TI-005 — numeric E.164 sender that is NOT in the calling tenant's `phone_numbers` table BUT does exist in `public.platform_numbers` assigned to a different organization.                                                         |
| `SENDER_OWNERSHIP_CHECK_UNAVAILABLE`               | 503    | TI-2026-002 — companion to `SENDER_NOT_OWNED`.                                                                                                                                                                                                 |
| `SENDER_POOL_RESOLUTION_FAILED`                    | varies | Sender-pool resolution failed at send time.                                                                                                                                                                                                    |
| `SENDER_POOL_NOT_FOUND`                            | varies | The `sender_pool_id` on a send refers to a row that doesn't exist in this tenant.                                                                                                                                                              |
| `SENDER_POOL_EMPTY`                                | varies | The pool resolved fine but its `sender_dids` array is empty — the dashboard should prompt for at least one DID.                                                                                                                                |
| `FALLBACK_CARRIER_NOT_FOUND`                       | varies | `retry_policy.fallback_carriers` referenced a carrier id (or slug) that doesn't exist in this tenant's `smpp_carriers` table.                                                                                                                  |
| `TEMPLATE_NOT_APPROVED`                            | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                |
| `TEMPLATE_SEND_FAILED`                             | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                |
| `TEMPLATE_FETCH_FAILED`                            | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                |
| `TEMPLATE_CREATE_FAILED`                           | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                |
| `TEMPLATE_PARAMS_MISMATCH`                         | varies | Legacy — superseded by `WHATSAPP_TEMPLATE_VAR_COUNT_MISMATCH`.                                                                                                                                                                                 |
| `TEMPLATE_NOT_LOCALIZABLE`                         | 422    | 422 — `POST /messages/templates/:id/localize` refused to auto-localize a template that has no translatable body text, because there is nothing for the model to translate into the target locales.                                             |
| `WHATSAPP_TEMPLATE_VAR_COUNT_MISMATCH`             | 400    | Pre-flight check for WhatsApp template sends — caller supplied a `template_params` count that doesn't match the distinct `{{N}}` positional placeholders declared across the template's header + body components, OR supplied empty/whitespac… |
| `SANDBOX_MAGIC_NUMBER_BLOCKED`                     | 422    | Pre-send guard — recipient is a vendor-reserved sandbox magic number (Twilio +1 (500) 555-000X range).                                                                                                                                         |
| `SMS_BLOCKED_DESTINATION`                          | varies | SMS fraud guard: destination prefix on the platform blocklist (premium / pumped routes).                                                                                                                                                       |
| `SMS_RATE_LIMITED`                                 | varies | SMS fraud guard: tenant exceeded per-minute send cap.                                                                                                                                                                                          |
| `SMS_DAILY_SPEND_CAP`                              | varies | SMS fraud guard: tenant exceeded daily spend cap (estimate-based).                                                                                                                                                                             |
| `CHANNEL_BLOCKED_DESTINATION`                      | varies | Cross-channel fraud guard codes (audit #MSG-003, 2026-05-11).                                                                                                                                                                                  |
| `CHANNEL_RATE_LIMITED`                             | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                |
| `CHANNEL_DAILY_SPEND_CAP`                          | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                |
| `WHATSAPP_TIER_LIMIT_EXCEEDED`                     | 429    | WhatsApp tier-aware backpressure (CPaaS gap closure, 2026-05-30).                                                                                                                                                                              |
| `NOT_SMS_CAPABLE`                                  | varies | Reserved messaging-capability error code.                                                                                                                                                                                                      |
| `MEDIA_UPLOAD_FAILED`                              | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                |
| `INVALID_RECIPIENT`                                | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                |
| `FRAUD_BLOCKED`                                    | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                |
| `FRAUD_SHIELD_BLOCKED`                             | 403    | 403 — the SMS send was rejected by the tenant's Fraud Shield policy running in enforcement mode `block` (configured at `/settings/compliance/fraud-shield`).                                                                                   |
| `WHATSAPP_SESSION_EXPIRED`                         | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                |
| `MESSAGING_WINDOW_CLOSED`                          | varies | Meta's 24-hour messaging window has elapsed for this Messenger or Instagram conversation and the caller did not supply a messaging tag.                                                                                                        |
| `RCS_NOT_SUPPORTED`                                | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                |
| `PENDING_ACCEPTANCE`                               | 425    | Returned by /rcs/test-account/verify-otp while waiting for the user to tap "Make me tester" on the Dotgo RBM tester invite they received in Google Messages.                                                                                   |
| `INVITE_DECLINED`                                  | varies | The user tapped "Decline" on the Dotgo RBM tester invite.                                                                                                                                                                                      |
| `WHATSAPP_NOT_CONNECTED`                           | varies | Caller tried to use a WhatsApp feature (template create, send, etc.) but the org has no connected WABA.                                                                                                                                        |
| `WHATSAPP_CONNECTION_INVALID`                      | varies | The org has a WABA row but the encrypted access\_token failed to decrypt (key rotation, manual DB edit, encryption-version drift).                                                                                                             |
| `WHATSAPP_BYO_INCOMPLETE`                          | varies | TEST-USER K-004 (2026-05-26) — BYO WhatsApp half-config billing-leak guard.                                                                                                                                                                    |
| `WHATSAPP_PAY_NOT_ENABLED`                         | varies | WhatsApp Pay is not enabled on the tenant's WABA.                                                                                                                                                                                              |
| `TEMPLATE_REJECTED`                                | varies | Meta rejected a template submission for content reasons.                                                                                                                                                                                       |
| `WHATSAPP_CALL_PERMISSION_FAILED`                  | varies | Meta rejected a WhatsApp Business Calling permission request — the recipient hasn't granted call permission inside WhatsApp, or the conversation window is closed.                                                                             |
| `WHATSAPP_OUTSIDE_24H_WINDOW`                      | 422    | Meta's 24-hour customer-service-window gate.                                                                                                                                                                                                   |
| `WHATSAPP_CALLING_BLOCKED_COUNTRY`                 | 422    | The (E.164 country code of the) phone number is on the WA-Calling-blocked country list (US/CA/EG/VN/NG as of May 2026 per Meta's WhatsApp Business Calling rollout).                                                                           |
| `WHATSAPP_CALLING_PROVISION_FAILED`                | varies | Generic provisioning failure when toggling calling on/off via Meta.                                                                                                                                                                            |
| `WHATSAPP_CALLING_PERMISSION_MISSING`              | varies | The recipient contact has not granted business-calling permission (or it has expired / been revoked).                                                                                                                                          |
| `WHATSAPP_CALLING_NO_PERMISSION`                   | varies | Phase-2 alias of WHATSAPP\_CALLING\_PERMISSION\_MISSING surfaced specifically by the outbound `POST /whatsapp/calling/calls` route (initiateCall).                                                                                             |
| `WHATSAPP_CALLING_INSUFFICIENT_BALANCE`            | 402    | 402 (or 503) — WA Calling wallet pre-flight on `POST /whatsapp/calling/calls`: 402 when the wallet can't cover the worst-case (max-call-minutes × per-minute rate) cost, 503 when the balance read itself fails (fail-closed, retryable).      |
| `WHATSAPP_CALLING_DAILY_CAP_EXCEEDED`              | 429    | Outbound or inbound WA Calling event was admitted past the country gate but the per-tenant daily cost cap (configured in `organizations.settings.whatsapp_calling_daily_cap_cents`) is already exhausted.                                      |
| `WHATSAPP_NO_CALLING_PHONE`                        | 422    | Shared-WABA calling resolver fell through with no callable phone (audit #WABA-SHARED-CALLING-1, 2026-05-11).                                                                                                                                   |
| `WHATSAPP_CALLING_MEDIA_NOT_PROVISIONED`           | 503    | Outbound WA Calling refused because the platform's WhatsApp media gateway is not provisioned yet.                                                                                                                                              |
| `WHATSAPP_SHARED_CALLING_QUALITY_PAUSED`           | 503    | Devotel's shared calling phone has a `quality_rating=RED` per Meta Graph (audit #WABA-SHARED-CALLING-1).                                                                                                                                       |
| `VERIFIED_PHONE_OVERWRITE_REQUIRES_CONFIRMATION`   | 409    | Audit #WABA-TEST-EDITABLE-1 — caller attempted to send a test-account OTP to a phone different from the org's currently-verified number WITHOUT passing `allow_overwrite=true`.                                                                |
| `WHATSAPP_CALL_ACTION_FAILED`                      | varies | Meta rejected a call-control action (pre\_accept / accept / reject / terminate).                                                                                                                                                               |
| `WHATSAPP_CALL_INITIATE_FAILED`                    | varies | Outbound WhatsApp call initiate failed (POST /{phone-number-id}/calls).                                                                                                                                                                        |
| `WHATSAPP_BLOCK_OPERATION_FAILED`                  | varies | Block-list management failed (POST/DELETE/GET /{phone-number-id}/block\_users).                                                                                                                                                                |
| `WHATSAPP_BLOCK_LIST_FAILED`                       | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                |
| `WHATSAPP_PROFILE_GET_FAILED`                      | varies | Business profile read / update via /whatsapp\_business\_profile.                                                                                                                                                                               |
| `WHATSAPP_PROFILE_UPDATE_FAILED`                   | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                |
| `WHATSAPP_CONVERSATIONAL_AUTOMATION_GET_FAILED`    | varies | Conversational automation (ice breakers / commands / welcome message) read + update via /conversational\_automation.                                                                                                                           |
| `WHATSAPP_CONVERSATIONAL_AUTOMATION_UPDATE_FAILED` | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                |
| `WHATSAPP_TEMPLATE_EDIT_FAILED`                    | varies | Template edit (POST /{template-id}) and delete (DELETE /{waba-id}/message\_templates).                                                                                                                                                         |
| `WHATSAPP_TEMPLATE_DELETE_FAILED`                  | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                |
| `WHATSAPP_REQUEST_CODE_FAILED`                     | varies | Display-name change verification (request\_code / verify\_code).                                                                                                                                                                               |
| `WHATSAPP_VERIFY_CODE_FAILED`                      | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                |
| `VERIFY_RECIPIENT_RATE_LIMITED`                    | 429    | Per-recipient verify OTP rate limit hit (anti-SMS-pumping / anti-harassment gate in `verify.service.sendVerification`).                                                                                                                        |
| `VERIFY_RESEND_COOLDOWN`                           | 429    | Per-recipient verify OTP resend cooldown hit.                                                                                                                                                                                                  |
| `WHATSAPP_CATALOG_API_FAILED`                      | varies | Catalog / product CRUD against /{business-id}/owned\_product\_catalogs.                                                                                                                                                                        |
| `CATALOG_ERROR`                                    | 500    | 500 — the WhatsApp commerce catalog-list surface (`GET /whatsapp/catalogs` and `GET /whatsapp/catalog`) hit an unexpected server-side failure while fetching the tenant's Meta product catalog.                                                |
| `CATALOG_SEND_ERROR`                               | 500    | 500 — a WhatsApp commerce product-message send hit an unexpected server-side failure while dispatching a catalog or single/multi product interactive to Meta.                                                                                  |
| `WHATSAPP_FLOW_SEND_FAILED`                        | varies | Send-flow as interactive message — POST /{phone-number-id}/messages type=flow.                                                                                                                                                                 |
| `WHATSAPP_INTERACTIVE_SEND_FAILED`                 | varies | Generic interactive (reply-button / list) send — POST /{phone-number-id}/messages type=interactive.                                                                                                                                            |
| `WHATSAPP_ANALYTICS_API_FAILED`                    | varies | /{waba-id}/pricing\_analytics or /template\_analytics fetch.                                                                                                                                                                                   |
| `WHATSAPP_UPLOAD_API_FAILED`                       | varies | Resumable upload session create / append chunk / finalize.                                                                                                                                                                                     |
| `WHATSAPP_TEMPLATE_PARAM_MISSING`                  | varies | Meta 131008 — required template parameter missing (commonly AUTH OTP button).                                                                                                                                                                  |
| `WHATSAPP_RE_ENGAGEMENT_WINDOW_CLOSED`             | varies | Meta 131026 — 24h customer-care window expired; only templates allowed.                                                                                                                                                                        |
| `WHATSAPP_RE_ENGAGEMENT_REQUIRED`                  | varies | Meta 131047 — re-engagement requires a template since contact's last message >24h ago.                                                                                                                                                         |
| `WHATSAPP_UNSUPPORTED_MESSAGE_TYPE`                | varies | Meta 131051 — message type unsupported on recipient device/region.                                                                                                                                                                             |
| `WHATSAPP_TEMPLATE_NOT_FOUND`                      | varies | Meta 132001 — template name does not exist in any of the requested languages.                                                                                                                                                                  |
| `WHATSAPP_TEMPLATE_PARAM_FORMAT`                   | varies | Meta 132012 — parameter format mismatch (named vs positional, type, length).                                                                                                                                                                   |
| `WHATSAPP_TEMPLATE_PAUSED`                         | varies | Meta 132016 — template paused due to low quality / high block rate.                                                                                                                                                                            |
| `WHATSAPP_TEMPLATE_DISABLED`                       | varies | Meta 132068/132069 — template disabled by Meta after policy violation.                                                                                                                                                                         |
| `WHATSAPP_ACCOUNT_NOT_REGISTERED`                  | varies | Meta 133010 — account hasn't completed registration; sends blocked.                                                                                                                                                                            |
| `WHATSAPP_BILLING_ISSUE`                           | varies | Meta 131042 — WABA payment method failing on Meta's side; sends blocked until the operator updates billing in Meta Business Manager.                                                                                                           |
| `WHATSAPP_INVALID_PARAMETER`                       | varies | Meta 100 — invalid parameter or deprecated field.                                                                                                                                                                                              |
| `WHATSAPP_TOKEN_EXPIRED`                           | varies | Meta 190 — access token expired / revoked / scopes removed.                                                                                                                                                                                    |
| `WHATSAPP_POLICY_BLOCK`                            | varies | Meta 368/470 — temporary policy block on account or recipient.                                                                                                                                                                                 |
| `WHATSAPP_RECIPIENT_INVALID`                       | varies | Meta 1304/2388042 — recipient phone number invalid for this region.                                                                                                                                                                            |
| `WHATSAPP_SERVICE_UNAVAILABLE`                     | varies | Meta 131016 — Cloud API service unavailable.                                                                                                                                                                                                   |
| `WHATSAPP_ACCOUNT_LOCKED`                          | varies | Meta 131031 — WABA locked by Meta after sustained policy issue.                                                                                                                                                                                |
| `WHATSAPP_SENDER_NOT_APPROVED`                     | varies | Meta 131045 — sender not approved for marketing templates yet.                                                                                                                                                                                 |
| `TEMPLATE_SYNC_FAILED`                             | 400    | Devotel — POST /whatsapp/templates/sync failed against Meta Graph (OAuth/token/IP-allowlist/WABA-state).                                                                                                                                       |
| `WHATSAPP_US_MARKETING_PAUSED`                     | 422    | Devotel preflight — marketing templates to US (+1, non-Canada NANP) recipients are paused by Meta since April 2025.                                                                                                                            |
| `WHATSAPP_MARKETING_FREQUENCY_CAPPED`              | varies | Meta 131049 — a MARKETING template was not delivered to this recipient "to maintain healthy ecosystem engagement" (Meta's per-recipient marketing-message frequency cap).                                                                      |
| `WHATSAPP_USER_OPTED_OUT`                          | varies | Meta 131050 — recipient opted out of marketing on WhatsApp.                                                                                                                                                                                    |
| `WHATSAPP_MEDIA_DOWNLOAD_FAILED`                   | varies | Meta 131052 — media at the supplied URL couldn't be downloaded.                                                                                                                                                                                |
| `WHATSAPP_MEDIA_UPLOAD_FAILED`                     | varies | Meta 131053 — media upload to WhatsApp failed (size / MIME).                                                                                                                                                                                   |
| `WHATSAPP_ACCOUNT_QUALITY_LOW`                     | varies | Meta 133000 — overall account quality dropped; sends still allowed but Meta will reduce the messaging tier if it persists.                                                                                                                     |
| `WHATSAPP_RATE_LIMITED`                            | varies | Meta 133004/133015 — short rate-limit / cooldown asked by Meta.                                                                                                                                                                                |
| `WHATSAPP_2FA_PIN_REQUIRED`                        | varies | Meta 133005-133009 — 2-step verification PIN required / mismatch / cooldown / wrong-attempt lock / wrong length.                                                                                                                               |
| `WHATSAPP_TOKEN_EXCHANGE_FAILED`                   | varies | Auth code expired / single-use / wrong redirect — re-run signup.                                                                                                                                                                               |
| `WHATSAPP_ACCESS_TOKEN_EXPIRED`                    | varies | Stored long-lived token expired (60d max) — reconnect to refresh.                                                                                                                                                                              |
| `WHATSAPP_NO_WABA`                                 | varies | No WABA on the user's Meta login.                                                                                                                                                                                                              |
| `WHATSAPP_NO_PHONE_NUMBER`                         | varies | WABA exists but no phone number is registered on it.                                                                                                                                                                                           |
| `WHATSAPP_INVALID_SELECTION`                       | varies | Selected (waba\_id, phone\_number\_id) pair isn't on the user's token.                                                                                                                                                                         |
| `WHATSAPP_PHONE_NOT_OWNED`                         | varies | Selected phone number isn't part of any WABA the user owns.                                                                                                                                                                                    |
| `WHATSAPP_BUSINESS_STATUS_PENDING`                 | varies | Business is still under Meta verification review.                                                                                                                                                                                              |
| `WHATSAPP_BUSINESS_VERIFICATION_REQUIRED`          | varies | Business hasn't completed verification at all.                                                                                                                                                                                                 |
| `WHATSAPP_PHONE_VERIFY_REQUIRED`                   | varies | Phone-number SMS/voice OTP not yet completed in WhatsApp Manager.                                                                                                                                                                              |
| `WHATSAPP_WABA_ALREADY_LINKED`                     | varies | WABA already linked to another Orbit organization.                                                                                                                                                                                             |
| `WHATSAPP_META_APP_DISABLED`                       | varies | Devotel's Meta app is temporarily disabled.                                                                                                                                                                                                    |
| `WHATSAPP_REGION_UNSUPPORTED`                      | varies | Region not in Meta's supported country list for WhatsApp Business API.                                                                                                                                                                         |
| `WHATSAPP_CONNECTION_NOT_FOUND`                    | varies | Existing connection not found on the org (reconnect / rename / default).                                                                                                                                                                       |

## Telegram

| Code                             | HTTP   | Description                                                                                                                   |
| -------------------------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------- |
| `TELEGRAM_PROVIDER_ERROR`        | varies | Telegram Bot API returned a non-2xx (`{ok:false, description}`) or a network failure on getMe/setWebhook/sendMessage.         |
| `TELEGRAM_BOT_ALREADY_CONNECTED` | varies | Org already has a BYO Telegram bot connected; reconnect by disconnecting first.                                               |
| `TELEGRAM_INVALID_BOT_TOKEN`     | varies | BotFather token failed regex / getMe validation.                                                                              |
| `TELEGRAM_CHANNEL_NOT_CONNECTED` | varies | Caller attempted a Telegram send (e.g. State 5 test send) but the org has no active row in `public.telegram_bot_credentials`. |

## Email (test-mode gate)

| Code                                | HTTP   | Description                                                                                                                                            |
| ----------------------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `EMAIL_TEST_RECIPIENT_NOT_VERIFIED` | varies | Shared-account test-mode recipient gate (mirrors WhatsApp test): only addresses the tenant has explicitly OTP-verified can receive shared-Resend mail. |

## Crypto envelope

| Code                | HTTP   | Description                                                                                                                             |
| ------------------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------- |
| `ENCRYPTION_FAILED` | varies | AES-256-GCM enc:v1: envelope failed during write (random IV / authTag generation failure, libsodium / WebCrypto unavailable).           |
| `DECRYPTION_FAILED` | 502    | AES-256-GCM enc:v1: envelope failed during read (key rotation left a stale ciphertext, authTag mismatch, or the master key is missing). |

## Voice

| Code                                    | HTTP   | Description                                                                                                                                                                                                                                        |
| --------------------------------------- | ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `CALL_FAILED`                           | 502    | 502 — generic voice call-control failure raised when the Jambonz REST control surface (`jambonz-rest.ts`) or the outbound call-create path cannot complete a call create / update / hangup.                                                        |
| `SIP_ERROR`                             | varies | Reserved SIP-layer call-control error code.                                                                                                                                                                                                        |
| `VOICE_GATEWAY_ERROR`                   | 502    | 502 — the voice gateway (Jambonz / SBC) returned a transient error or was unreachable during a call-control or media operation (outbound dispatch, voicemail-greeting TTS synthesis + GCS upload, mid-call actions).                               |
| `TTS_SYNTHESIS_FAILED`                  | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                    |
| `STT_TRANSCRIPTION_FAILED`              | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                    |
| `VOICE_BLOCKED_DESTINATION`             | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                    |
| `VOICE_DNO_BLOCKED`                     | 422    | Gap CSPAAS — Do-Not-Originate (DNO) origination-time block.                                                                                                                                                                                        |
| `EMERGENCY_CALLING_NOT_SUPPORTED`       | varies | Audit #E911-BLOCK-1 / invariant #49 — outbound voice rejected because the dialed number resolved to an emergency short code (911 / 112 / 999 / 000 — see EMERGENCY\_NUMBERS\_BLOCKED in `@devotel/shared/constants`).                              |
| `VOICE_RATE_LIMITED`                    | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                    |
| `VOICE_COUNTRY_RATE_LIMITED`            | 429    | HTTP 429 — outbound voice rejected by the per-destination-country sliding-window rate cap in `voice-fraud-guard.ts`.                                                                                                                               |
| `SOFTSWITCH_UNHEALTHY`                  | 503    | CCaaS dialer — wholesale softswitch / Jambonz transport-health circuit breaker tripped (failed-attempt rate above threshold in the recent window).                                                                                                 |
| `VOICE_DAILY_SPEND_CAP`                 | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                    |
| `VOICE_TRANSFER_FAILED`                 | 502    | 502 — the voice gateway rejected a mid-call transfer.                                                                                                                                                                                              |
| `VOICE_CALLER_ID_REJECTED`              | varies | Customer-trunk INVITE rejected — caller-id not in allowedCallerIds nor an org-owned DID.                                                                                                                                                           |
| `VOICE_CHALLENGE_FAILED`                | varies | Caller-ID ownership-challenge (OTP verify/resend) failed; infra detail redacted before re-throw (r3 S14).                                                                                                                                          |
| `UNVERIFIED_CALLER_ID`                  | varies | R16FIX3\_UNVERIFIED\_CALLER\_ID\_GATE (2026-05-30) — outbound voice/SMS preflight refused the supplied `from` because it is neither a platform-owned/assigned DID for the org NOR a `status='verified'` row in the tenant's `verified_caller_ids`… |
| `VOICE_TRUNK_HOURLY_CAP`                | varies | Customer-trunk hourly call cap exceeded for the trunk.                                                                                                                                                                                             |
| `VOICE_CLONE_CONSENT_REQUIRED`          | varies | Voice-clone creation refused for missing or invalid consent (SCAN-V-010).                                                                                                                                                                          |
| `DTMF_UNSUPPORTED`                      | varies | Mid-call DTMF inject not supported on this leg (B-237).                                                                                                                                                                                            |
| `RECORDING_TOGGLE_UNSUPPORTED`          | varies | Mid-call recording toggle not supported on this leg (B-242).                                                                                                                                                                                       |
| `EXPORT_TOO_LARGE`                      | varies | CDR / call-log export filter would exceed the 100k row hard cap (B-240).                                                                                                                                                                           |
| `TCPA_QUIET_HOURS`                      | varies | Outbound voice call blocked by TCPA quiet-hours policy (08:00-21:00).                                                                                                                                                                              |
| `TCPA_DIALING_WINDOW_BLOCKED`           | varies | Outbound voice call blocked by the TCPA dialing-window gate (8 AM–9 PM recipient-local).                                                                                                                                                           |
| `TCPA_FEDERAL_DIALING_WINDOW_BLOCKED`   | varies | Outbound voice call to a +1 NANP recipient blocked by the US TCPA FEDERAL dialing-window hard guard (47 U.S.C.                                                                                                                                     |
| `TCPA_STATE_DIALING_WINDOW_BLOCKED`     | 422    | Outbound voice call blocked by a STATE mini-TCPA dialing-window or day-of-week restriction (e.g. FL Fla.                                                                                                                                           |
| `FCC_AI_VOICE_WRITTEN_CONSENT_REQUIRED` | varies | Outbound voice call blocked because the recipient has not granted "prior express WRITTEN consent" for AI-generated / synthesized / cloned voice content.                                                                                           |
| `QUIET_HOURS_BLOCKED`                   | varies | Outbound non-voice send (SMS / MMS / WhatsApp / RCS / Email / Telegram / Viber / Instagram / Messenger / LINE / Apple Messages) blocked by the universal quiet-hours gate.                                                                         |
| `TCPA_TIMEZONE_UNKNOWN`                 | varies | Outbound voice call blocked because the recipient's timezone could not be resolved (neither NANP area-code nor E.164 country prefix matched).                                                                                                      |
| `QUIET_HOURS_TIMEZONE_UNKNOWN`          | varies | Non-voice channel equivalent of TCPA\_TIMEZONE\_UNKNOWN.                                                                                                                                                                                           |
| `DNC_CONTACT`                           | varies | Recipient contact row has dnc=true.                                                                                                                                                                                                                |
| `DNC_NUMBER`                            | varies | Recipient number found in dnc\_list table.                                                                                                                                                                                                         |
| `COMPLIANCE_CHECK_UNAVAILABLE`          | varies | Compliance-layer DB check could not run.                                                                                                                                                                                                           |
| `CAMPAIGN_VOICE_SPEND_CAP_REACHED`      | varies | Per-campaign voice-spend cap reached; campaign auto-paused.                                                                                                                                                                                        |
| `NOT_IMPLEMENTED`                       | varies | Returned when a request targets a provider integration or capability that is defined but not yet generally available — e.g. a compliance submission for a carrier without a live provider, or an upstream SMPP carrier type reserved for a fu…     |
| `FLIP_ALREADY_PULLED`                   | 410    | 410 — `POST /voice/call-flip/pull` refused: the one-time call-flip handoff token was already pulled by the targeted device.                                                                                                                        |
| `FLIP_EXPIRED`                          | 410    | 410 — call-flip pull refused: the handoff token expired before it was pulled.                                                                                                                                                                      |
| `FLIP_TARGET_MISMATCH`                  | 403    | 403 — call-flip pull refused: the handoff is pinned to a different target device than the caller's.                                                                                                                                                |
| `FLIP_NOT_FOUND`                        | 404    | 404 — no live call-flip handoff matches the supplied pull token.                                                                                                                                                                                   |
| `FLIP_ALREADY_CONSUMED`                 | 410    | 410 — call-flip cancel/pull refused: the handoff was already pulled or cancelled.                                                                                                                                                                  |
| `PARK_SLOTS_FULL`                       | 409    | 409 — auto-park refused: every park slot in the tenant's park orbit is already occupied.                                                                                                                                                           |
| `PARK_SLOT_OCCUPIED`                    | 409    | 409 — park-to-slot refused: the explicitly requested park slot is already occupied.                                                                                                                                                                |
| `PARK_ALREADY_RETRIEVED`                | 410    | 410 — park retrieve refused: the call previously parked in that slot was already retrieved.                                                                                                                                                        |
| `PARK_SLOT_EMPTY`                       | 404    | 404 — park retrieve refused: no call is currently parked in the requested slot.                                                                                                                                                                    |
| `PARK_ALREADY_RELEASED`                 | 410    | 410 — park release refused: the parked call was already released.                                                                                                                                                                                  |
| `PARK_NOT_FOUND`                        | 404    | 404 — parked call not found for the supplied identifier.                                                                                                                                                                                           |
| `HOT_DESK_RACE`                         | 409    | 409 — hot-desk sign-in lost a concurrent race for the device and should be retried.                                                                                                                                                                |
| `HOT_DESK_ALREADY_SIGNED_OUT`           | 410    | 410 — hot-desk sign-out refused: the user is already signed out.                                                                                                                                                                                   |
| `HOT_DESK_NO_ACTIVE_SESSION`            | 404    | 404 — hot-desk sign-out refused: the user has no active hot-desk session.                                                                                                                                                                          |
| `HOT_DESK_ALREADY_RELEASED`             | 410    | 410 — hot-desk session release refused: the session was already released.                                                                                                                                                                          |
| `HOT_DESK_NOT_FOUND`                    | 404    | 404 — hot-desk session not found for the supplied id.                                                                                                                                                                                              |
| `SECURE_PAYMENT_UNSUPPORTED`            | 422    | 422 — agent-assisted secure payment requires a Jambonz-bridged call leg and this call has none.                                                                                                                                                    |
| `SECURE_PAYMENT_ALREADY_ACTIVE`         | 409    | 409 — a secure-payment capture session is already active on this call.                                                                                                                                                                             |
| `SECURE_PAYMENT_SESSION_NOT_FOUND`      | 404    | 404 — no secure-payment session with the supplied id exists on this call.                                                                                                                                                                          |
| `SECURE_PAYMENT_NOT_ACTIVE`             | 409    | 409 — the secure-payment session is not in the capturing state (already completed or cancelled).                                                                                                                                                   |
| `SECURE_PAYMENT_INVALID_MASK`           | 422    | 422 — card\_last4 must be exactly the last four digits of the PAN, never the full card number.                                                                                                                                                     |
| `PICKUP_NO_RINGING_CALL`                | 404    | 404 — `POST /voice/pickup/directed` (or `/voice/pickup/group`) found no ringing call to answer: nothing is ringing on the target extension, or no call is ringing in the caller's pickup group.                                                    |
| `PICKUP_ALREADY_TAKEN`                  | 409    | 409 — a call-pickup request lost the atomic claim race: another device answered the ringing call first.                                                                                                                                            |

## Video rooms

| Code                                  | HTTP   | Description                                                                                                                                                                                                                                     |
| ------------------------------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `VIDEO_ROOM_CREATE_FAILED`            | varies | Returned when an Orbit Media call fails during video-room creation (immediate path).                                                                                                                                                            |
| `VIDEO_ROOM_OPEN_FAILED`              | varies | Returned when an Orbit Media call fails during the lazy-open of a scheduled room (first host/participant join).                                                                                                                                 |
| `VIDEO_PARTICIPANT_KICK_FAILED`       | varies | Returned when the Orbit Media `removeParticipant` call fails while removing a participant from a room.                                                                                                                                          |
| `VIDEO_PARTICIPANT_MUTE_FAILED`       | varies | Returned when the Orbit Media `mutePublishedTrack` call fails while muting a participant's track.                                                                                                                                               |
| `VIDEO_RECORDING_STOP_BACKEND_FAILED` | varies | Returned when the Orbit Media `stopEgress` call rejects while stopping a room recording.                                                                                                                                                        |
| `VIDEO_WEBHOOK_VERIFICATION_FAILED`   | varies | Returned when the Orbit Media webhook JWT signature cannot be verified.                                                                                                                                                                         |
| `RECORDING_SIGN_FAILED`               | 503    | P2-shard-F (2026-06-02) — Returned when `RecordingService.generateSignedUrl` fails to mint a V4 signed GCS playback URL (GCS auth failure, IAM denial, transient GCS outage, ADC misconfiguration).                                             |
| `VIDEO_BACKGROUND_INVALID`            | 400    | 400 — `POST /video/backgrounds` refused to register a branded virtual-background asset because the submitted asset failed library-side validation (e.g. duplicate name, malformed/blocked URL, or the per-tenant background limit was reached). |
| `VIDEO_BACKGROUND_NOT_FOUND`          | 404    | 404 — `DELETE /video/backgrounds/:assetId` could not find a registered virtual-background asset with that id in the tenant's background library.                                                                                                |
| `AGENT_NOT_DEPLOYABLE`                | 409    | 409 — `POST /video/rooms/:id/dispatch-agent` refused to dispatch an AI agent into a room because the referenced agent is not in the `active` state.                                                                                             |

## Call recordings (QC / legal-hold / integrity / share)

| Code                                       | HTTP | Description                                                                                                                                                                            |
| ------------------------------------------ | ---- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `RECORDING_QC_FETCH_FAILED`                | 500  | 500 — `GET /recordings/:id/qc` could not load the stored QC verdict for a call recording.                                                                                              |
| `RECORDING_QC_RUN_FAILED`                  | 500  | 500 — `POST /recordings/:id/qc/run` failed while synchronously re-running the recording QC scorer (the scorer threw, or a DB write failed).                                            |
| `RECORDING_QC_INVALID_ID`                  | 400  | 400 — the `:id` path param on a `GET /recordings/:id/qc` or `POST /recordings/:id/qc/run` operation failed param validation (empty / over the length cap).                             |
| `RECORDING_QC_NOT_FOUND`                   | 404  | 404 — `GET /recordings/:id/qc` or `POST /recordings/:id/qc/run` received a syntactically valid recording id that matched no recording row in the tenant schema (missing / tombstoned). |
| `RECORDING_LEGAL_HOLD_FETCH_FAILED`        | 500  | 500 — `GET /recordings/:id/legal-hold` could not load the legal-hold state for a recording (DB / tenant-schema fault).                                                                 |
| `RECORDING_LEGAL_HOLD_SET_FAILED`          | 500  | 500 — `PUT /recordings/:id/legal-hold` failed to place or release a legal hold (the compliance-governance write threw after passing validation / auth).                                |
| `RECORDING_INTEGRITY_FETCH_FAILED`         | 500  | 500 — `GET /recordings/:id/integrity` could not load the recording integrity seal (DB / tenant-schema fault).                                                                          |
| `RECORDING_INTEGRITY_VERIFY_FAILED`        | 500  | 500 — the recording integrity-seal verification path failed unexpectedly (the recompute-and-compare digest check threw before returning a pass/fail verdict).                          |
| `RECORDING_INTEGRITY_EXPORT_DIGEST_FAILED` | 500  | 500 — building the signed export digest for a recording's integrity evidence failed unexpectedly (digest assembly / signing threw).                                                    |
| `RECORDING_INTEGRITY_SEAL_FAILED`          | 500  | 500 — sealing a recording (minting and persisting its tamper-evidence integrity seal) failed unexpectedly.                                                                             |
| `RECORDING_SHARE_CREATE_FAILED`            | 500  | 500 — `POST /recordings/:id/shares` could not create a share link for a recording (DB write / token-mint fault after validation + auth).                                               |
| `RECORDING_SHARE_REVOKE_FAILED`            | 500  | 500 — revoking a recording's share link(s) failed unexpectedly (the revoke write threw).                                                                                               |

## Agent

| Code                                         | HTTP   | Description                                                                                                                                                                                       |
| -------------------------------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `AGENT_ERROR`                                | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                   |
| `AGENT_NOT_CONFIGURED`                       | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                   |
| `AGENT_RESPONSE_INVALID`                     | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                   |
| `INVALID_MODEL`                              | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                   |
| `LLM_PROVIDER_ERROR`                         | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                   |
| `LLM_TIMEOUT`                                | 504    | 504 — An AI-generation endpoint's LLM round-trip exceeded its abort deadline (`AbortSignal.timeout`).                                                                                             |
| `LLM_UPSTREAM_ERROR`                         | 502    | 502 — An AI-generation endpoint's upstream LLM call failed with a non-timeout provider/transport error.                                                                                           |
| `AI_PARSE_FAILED`                            | 422    | 422 — An AI-generation endpoint received model output that could not be parsed into the required structured shape (non-JSON / schema mismatch).                                                   |
| `GUARDRAIL_VIOLATION`                        | varies | Reserved AI-guardrail error code.                                                                                                                                                                 |
| `GRAPH_VALIDATION_FAILED`                    | 422    | 422 — Agent Studio graph publish validation failed; the submitted graph did not pass structural validation and `details` carries the per-node validation errors.                                  |
| `GRAPH_TOOL_NODES_NOT_SUPPORTED_IN_TEST_RUN` | 422    | 422 — Agent Studio test-run was asked to execute a graph containing tool nodes, which the sandboxed test-run does not execute; publish the graph and invoke the agent's /run endpoint instead.    |
| `RESERVED_TOOL_NAME`                         | 422    | 422 — Custom-tool registration rejected because the requested tool name is reserved for a built-in platform tool; pick a tenant-specific slug.                                                    |
| `INVALID_EXECUTOR_URL`                       | 422    | 422 — Custom-tool `executor_url` rejected by the SSRF write-time guard (non-https, private/loopback, cloud-metadata host, or a DNS record that resolves internally).                              |
| `TOOL_NAME_TAKEN`                            | 409    | 409 — Custom-tool create collided with an existing custom tool of the same name in the tenant.                                                                                                    |
| `TOOL_DISABLED`                              | 409    | 409 — Custom-tool invocation refused because the referenced custom tool is disabled.                                                                                                              |
| `INVALID_MCP_SERVER_URL`                     | 422    | 422 — MCP-server registration rejected by the SSRF write-time guard on the server URL (non-https, private/loopback, cloud-metadata host, or a DNS record that resolves internally).               |
| `INVALID_MCP_OAUTH_TOKEN_URL`                | 422    | 422 — MCP-server registration rejected by the SSRF write-time guard on the OAuth2 grant `token_url` (non-https, private/loopback, cloud-metadata host, or a DNS record that resolves internally). |
| `MCP_SERVER_NAME_CONFLICT`                   | 409    | 409 — MCP-server registration collided with a server of the same name already registered for the agent (`uq_mcp_servers_agent_name`).                                                             |
| `LABELING_NO_INPUT`                          | 422    | 422 — the agent fine-tuning labeling endpoint had nothing to label: the referenced conversation carries no user message and the caller did not supply an explicit `input`.                        |
| `LABELING_DATASET_FULL`                      | 409    | 409 — the agent's labeling dataset has reached its row ceiling, so no further labeled rows can be added.                                                                                          |

## Agent Eval

| Code                            | HTTP   | Description                                                                                                                                                                                                   |
| ------------------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `EVAL_COMPARE_DATASET_MISMATCH` | varies | compareEvalRuns: run\_a\_id and run\_b\_id reference different datasets.                                                                                                                                      |
| `EVAL_COMPARE_SAME_RUN`         | varies | compareEvalRuns: run\_a\_id === run\_b\_id.                                                                                                                                                                   |
| `EVAL_RUNS_AGENT_MISMATCH`      | varies | compareEvalRuns: one or both runs belong to a different agent (SCAN-AGT-R2-010).                                                                                                                              |
| `EVAL_GATE_FAILED`              | 422    | 422 — Agent Studio publish blocked by the eval gate because the agent has no completed eval run meeting the configured minimum pass rate; run an eval against the agent before publishing.                    |
| `EVAL_REGRESSION_GATE_FAILED`   | 422    | 422 — Agent Studio publish blocked by the eval regression gate because the latest eval run regressed beyond the configured tolerance versus the baseline run; investigate and re-run evals before publishing. |

## Billing

| Code                              | HTTP   | Description                                                                                                                                                                                                                                    |
| --------------------------------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `PAYMENT_REQUIRED`                | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                |
| `BUDGET_EXCEEDED`                 | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                |
| `BILLING_PROVIDER_ERROR`          | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                |
| `EMAIL_INTAKE_PARSE_ERROR`        | 422    | 422 — the admin rate-card email-intake preview could not parse the supplied raw MIME message into rate-card uploads (unreadable MIME, unsupported attachment, or an unparseable rate table).                                                   |
| `VOICE_BILLING_HOLD_FAILED`       | 503    | Security fix 2026-05-20 (exploit-voice-billing-hold-fail-open): Returned (503) when placeVoiceBillingHold cannot enforce spending controls due to an infrastructure error (Redis down, Lua error, etc.).                                       |
| `VOICE_BILLING_CURRENCY_DEFERRED` | varies | BIL-DEEP-012 (escalated P1, 2026-06-02): tenant wallet-currency could not be resolved at voice settle time (DB lookup threw / org row missing), AND the hold did not stamp a `voice_billing.tenant_currency`.                                  |
| `SENDING_PAUSED`                  | varies | A customer-configured billing\_alerts rule with action='pause\_outbound' tripped; outbound sending is temporarily paused until manually reset.                                                                                                 |
| `SENDING_BLOCKED`                 | varies | A customer-configured billing\_alerts rule with action='block\_outbound' tripped; outbound sending is hard-blocked until manually reset or the next billing cycle.                                                                             |
| `FREQUENCY_CAP_EXCEEDED`          | 429    | Per-org frequency-cap rule hit — too many sends to this recipient on this channel inside the configured window.                                                                                                                                |
| `MESSAGING_SERVICE_MPS_EXCEEDED`  | 429    | PARITY-R1-016 — per-MessagingService throughput cap (Twilio MessagingService MPS parity) hit on the API-direct send path.                                                                                                                      |
| `NO_REACHABLE_CHANNEL`            | 422    | 422 — `POST /billing/pay-by-link` (and its `/preview` companion) could not select a delivery channel for the hosted-checkout link: none of the caller's `preferred_channels` appears in `reachable_channels`, so there is no path to reach th… |
| `TRIAL_CREDIT_CAP_EXCEEDED`       | 422    | 422 — `POST /billing/trial-credits` refused a promotional trial-credit grant because the requested amount exceeds the effective per-tenant trial-credit cap (the platform default, optionally lowered — never raised — by a tenant override).  |
| `TRIAL_CREDITS_FAILED`            | 500    | 500 — `POST /billing/trial-credits` failed to grant a promotional trial-credit grant because of an upstream infrastructure fault while applying the grant.                                                                                     |

## Tenant / Multi-tenancy

| Code             | HTTP   | Description                                                                                     |
| ---------------- | ------ | ----------------------------------------------------------------------------------------------- |
| `MISSING_TENANT` | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context. |

## System

| Code                                  | HTTP   | Description                                                                                                                                                                                                                                     |
| ------------------------------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `INTERNAL_ERROR`                      | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                 |
| `SERVICE_UNAVAILABLE`                 | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                 |
| `SESSION_REPLAY_OFFLOAD_FAILED`       | 503    | 503 — the widget session-replay ingest endpoint could not offload the batch's overflow events to durable storage (the spill-to-GCS path that keeps replay capture lossless).                                                                    |
| `ADMIN_ORG_MISSING_TENANT`            | 422    | Admin attempted an operation on an org whose tenant\_id is NULL and whose slug also fails to derive a usable tenant — fail-fast 422 so the admin operator surfaces this to platform engineering instead of silently writing to a wrong tenant…  |
| `BALANCE_SERVICE_UNAVAILABLE`         | 503    | Balance / credit-resolver service is temporarily unavailable because the Redis idempotency dedup layer is unreachable.                                                                                                                          |
| `SMPP_BACKEND_UNAVAILABLE`            | 503    | SMPP credential issuance / rotation failed because a backing dependency (tenant DB schema, encryption key, Jasmin reconciler queue) is temporarily unavailable.                                                                                 |
| `A2A_PEER_ERROR`                      | 502    | Returned (502) when an outbound A2A (Agent-to-Agent) federation call to a peer agent failed — peer offline, peer card unreachable, peer JSON-RPC returned a non-2xx, or peer task envelope was malformed.                                       |
| `A2A_DISCOVERY_DISABLED`              | 422    | Issue #259 (TU-230 deep-tail) — the dashboard A2A tab requested a card for an agent whose `a2a_discovery_mode === 'disabled'` (the default).                                                                                                    |
| `WEBHOOK_DELIVERY_FAILED`             | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                 |
| `WEBHOOK_SIGNATURE_INVALID`           | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                 |
| `WEBHOOK_SECRET_DECRYPT_FAILED`       | 503    | Wave-W1 CPA-011 — Webhook signing secret could not be decrypted because the stored value carried the platform `enc:v1:` envelope but the active `DEVOTEL_ENCRYPTION_KEY` no longer matches (rotation pending re-encrypt) OR the ciphertext is…  |
| `WEBHOOK_AUTH_FAILED`                 | varies | Wave-W1 CPA-005 (P0) — uniform shape for webhook authentication failures on unauthenticated provider webhooks (Meta WhatsApp Flows `/endpoint`, etc.).                                                                                          |
| `WEBHOOK_PROCESSING_FAILED`           | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                 |
| `INVALID_WEBHOOK_URL`                 | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                 |
| `WEBHOOK_DNS_INVALID`                 | 422    | Audit #PRV-001 (2026-05-12) — webhook-endpoint URL DNS-resolves to NXDOMAIN / NODATA / SERVFAIL.                                                                                                                                                |
| `WEBHOOK_ENDPOINT_CAP_REACHED`        | varies | Tenant tried to create more than MAX\_WEBHOOK\_ENDPOINTS\_PER\_TENANT webhook endpoints (default 10).                                                                                                                                           |
| `BULK_REPLAY_IN_PROGRESS`             | 409    | 409 — `POST /webhooks/:id/replay-range` (webhook bulk-replay) refused to start a new bulk-replay because one is already running or queued for the same endpoint.                                                                                |
| `ENDPOINT_GONE`                       | 404    | API-CONTRACT (admin DLQ webhook replay) — `POST /admin/dlq/webhooks/:id/replay` refused to re-enqueue because the target webhook endpoint the DLQ job was destined for has since been deleted or disabled (`endpointPresence` returned \`"gone… |
| `ENDPOINT_LOOKUP_FAILED`              | 503    | API-CONTRACT (admin DLQ webhook replay) — companion to `ENDPOINT_GONE`.                                                                                                                                                                         |
| `STRIPE_CUSTOMER_ORG_MISMATCH`        | varies | Audit #B-004 (2026-05-11) — payment\_intent.succeeded webhook with forged `metadata.orgId` pointing at a victim tenant, paid by an attacker's Stripe customer on the shared platform account.                                                   |
| `BUDGET_REDIS_UNAVAILABLE`            | 503    | Audit #B-040 (2026-05-11) — `reserveBudget` failed CLOSED because Redis was unavailable or the Lua eval threw.                                                                                                                                  |
| `LLM_PLATFORM_CEILING_EXCEEDED`       | 503    | Security fix 2026-05-20 (exploit-llm-budget-no-platform-ceiling): Returned (503) when a new reservation would push the platform-wide aggregate monthly LLM spend above the configured ceiling.                                                  |
| `TENANT_NOT_FOUND`                    | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                 |
| `TENANT_PROVISIONING`                 | 503    | Returned (503) by the auth middleware when an org row exists but its `tenant_schema_ready` flag is still FALSE — meaning the baseline schema creation or the per-tenant migration run has not finished (or failed).                             |
| `TENANT_SCHEMA_INCOMPLETE`            | 503    | Returned (503) when a tenant-schema-scoped query hits SQLSTATE 42P01 (undefined\_table) on a table introduced by a recent feature migration.                                                                                                    |
| `RECIPIENT_OPTED_OUT`                 | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                 |
| `CONTACT_BLOCKED`                     | varies | Contact is blocked at the org level — every outbound send rejected.                                                                                                                                                                             |
| `CONTACT_ERASURE_PENDING`             | varies | Contact has a pending GDPR Article-17 erasure request in its 7-day cooling-off window.                                                                                                                                                          |
| `INVALID_FILE_TYPE`                   | varies | File upload rejected at the FE pre-flight — MIME / extension mismatch.                                                                                                                                                                          |
| `FILE_TOO_LARGE`                      | varies | File upload rejected — size exceeds the configured cap.                                                                                                                                                                                         |
| `MAGIC_BYTE_MISMATCH`                 | varies | File upload rejected — magic-byte signature didn't match the declared MIME.                                                                                                                                                                     |
| `INSUFFICIENT_BALANCE`                | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                 |
| `INSUFFICIENT_CREDITS`                | varies | @deprecated Use INSUFFICIENT\_BALANCE instead                                                                                                                                                                                                   |
| `DEDUCT_IN_FLIGHT`                    | varies | Returned by `deductBalance` / `addBalance` when another caller already holds the same idempotency key in Redis but has not yet posted its final result within the poll window (2 s today).                                                      |
| `RESELLER_MARGIN_RESERVE_FAILED`      | 503    | 503 — the pre-deduct reseller-margin pending-row reservation (`reserveResellerMarginPending`) failed, so the send is aborted BEFORE the child wallet is debited.                                                                                |
| `FORBIDDEN`                           | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                 |
| `INVALID_STATE`                       | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                 |
| `CONVERSATION_TERMINAL`               | 422    | SCAN-CINB-010 + SCAN-CINB-011 — `ConversationsService.resumeAi` and `ConversationsService.handoff` reject calls against conversations in a terminal/non-actionable status (`closed`, `archived`, `snoozed`).                                    |
| `TAKEOVER_NOT_ALLOWED`                | 422    | Supervisor take-over (422) refused on a terminal/closed digital conversation — there is no live conversation to intercept; `details` carries the current `{ status }`.                                                                          |
| `TAKEOVER_ALREADY_ACTIVE`             | 409    | Supervisor take-over (409) rejected because a take-over is already active on the conversation; `details` carries `{ takeover_id, supervisor_id }` so the UI can show who is already in control.                                                 |
| `NO_ACTIVE_TAKEOVER`                  | 409    | Supervisor take-over (409) error returned when a send-reply or release is attempted but no take-over is currently active on the conversation.                                                                                                   |
| `TAKEOVER_FORBIDDEN`                  | 403    | Supervisor take-over (403) denied: the caller neither owns the active take-over nor is an elevated owner/admin recovering it.                                                                                                                   |
| `REAUTH_REQUIRED`                     | varies | audit #511 backend top-10 #2/#7 — fresh re-authentication required for irreversible operations (GDPR delete, 2FA disable, HIPAA toggle).                                                                                                        |
| `ROLLBACK_WINDOW_EXPIRED`             | varies | audit #511 backend top-10 #3 — import rollback past the 24h window.                                                                                                                                                                             |
| `INVITE_EXPIRED`                      | varies | audit #511 backend top-10 #8 — invitation token has expired.                                                                                                                                                                                    |
| `AUTO_TOPUP_MONTHLY_CAP_REACHED`      | varies | Auto-top-up cron tried to recharge but the org's `max_monthly_minor` cap has already been reached this calendar month.                                                                                                                          |
| `AUTO_TOPUP_PAYMENT_FAILED`           | varies | Off-session Stripe PaymentIntent for an auto-top-up failed (card declined, no default payment method, etc.).                                                                                                                                    |
| `SUPERVISOR_ACTION_FAILED`            | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                 |
| `SUPERVISOR_TAKEOVER_FAILED`          | 500    | 500 — `POST /voice/supervisor/takeovers` (initiate a voice supervisor takeover / whisper-coach session) failed unexpectedly.                                                                                                                    |
| `SUPERVISOR_TAKEOVER_LIST_FAILED`     | 500    | 500 — `GET /voice/supervisor/takeovers` (list voice supervisor takeovers) failed unexpectedly.                                                                                                                                                  |
| `SUPERVISOR_TAKEOVER_GET_FAILED`      | 500    | 500 — `GET /voice/supervisor/takeovers/:id` (fetch a single voice supervisor takeover) failed unexpectedly.                                                                                                                                     |
| `SUPERVISOR_TAKEOVER_UPDATE_FAILED`   | 500    | 500 — `PATCH /voice/supervisor/takeovers/:id` (advance state or cancel a voice supervisor takeover) failed unexpectedly.                                                                                                                        |
| `SUPERVISOR_WHISPER_TEXT_FAILED`      | 500    | 500 — `POST /voice/supervisor/calls/:id/whisper-text` (whisper a text coaching line to the live agent) failed unexpectedly.                                                                                                                     |
| `SUPERVISOR_ASSIST_STREAM_ERROR`      | 500    | 500 — `GET /voice/supervisor/calls/:callId/assist/stream` (supervisor AI-assist SSE card stream) failed unexpectedly.                                                                                                                           |
| `DIGITAL_TAKEOVER_START_FAILED`       | 500    | 500 — `POST /conversations/:id/takeover/start` (supervisor seizes reply control on a digital conversation) failed unexpectedly.                                                                                                                 |
| `DIGITAL_TAKEOVER_REPLY_FAILED`       | 500    | 500 — `POST /conversations/:id/takeover/send-reply` (reply under an active digital takeover) failed unexpectedly.                                                                                                                               |
| `DIGITAL_TAKEOVER_END_FAILED`         | 500    | 500 — `POST /conversations/:id/takeover/end` (release a digital takeover back to the agent) failed unexpectedly.                                                                                                                                |
| `DIGITAL_TAKEOVER_GET_FAILED`         | 500    | 500 — `GET /conversations/:id/takeover` (read current digital takeover state) failed unexpectedly.                                                                                                                                              |
| `ONLY_ADMIN`                          | 422    | Audit #SET-003 / #SET-004 — refuses an offboarding operation (SCIM `deleteUser`, settings `removeTeamMember`, danger-zone org-deletion) when the target is the only remaining admin/owner of the organisation.                                  |
| `INSUFFICIENT_SCOPE`                  | 403    | API key was rejected because the declared scope set does not include the scope required by the requested route.                                                                                                                                 |
| `CALLING_REQUIRES_ELIGIBLE_PHONE`     | 422    | WhatsApp Business Calling needs a phone whose country is NOT in Meta's calling-blocked list (US/CA/EG/VN/NG today).                                                                                                                             |
| `FEATURE_DISABLED`                    | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                 |
| `ACCOUNT_LOCKED`                      | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                 |
| `AGENT_EXECUTION_TIMEOUT`             | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                 |
| `PAYLOAD_TOO_LARGE`                   | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                 |
| `LOOKUP_FAILED`                       | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                 |
| `REQUEST_ABORTED`                     | varies | Request cancelled by caller (e.g. campaign pause aborted in-flight provider send).                                                                                                                                                              |
| `POLICY_VIOLATION`                    | varies | Pre-send policy scan blocked the message (TCPA / SHAFT / GDPR).                                                                                                                                                                                 |
| `POLICY_SCAN_MODE_LOOKUP_FAILED`      | 503    | SCAN-MSG-DEEP-002 (2026-05-26) — `resolvePolicyScanMode` could not read `organizations.policy_scan_mode` from Postgres AND the per-org 5-minute Redis cache is cold.                                                                            |
| `BALANCE_OPERATION_FAILED`            | varies | Admin balance adjust operation (deduct/add) failed at the credits layer.                                                                                                                                                                        |
| `BALANCE_CAP_EXCEEDED`                | 422    | SCAN-BILL-R3-013 (2026-05-23) — `addBalance` rejected because the resulting wallet balance would exceed `MAX_BALANCE_CENTS`.                                                                                                                    |
| `BILLING_TENANT_UNRESOLVED`           | 500    | Returned (500) when `resolveBillingTenantId` produced an empty or still-schema-shaped value on a money-touching path (number purchase, deduct, top-up).                                                                                         |
| `PRICING_NOT_CONFIGURED`              | varies | Wave P1-A (2026-05-18) — `resolvePrice()` could not find a rate row OR an org override for the (channel, sub\_type, country, mcc, mnc, prefix) tuple being charged.                                                                             |
| `PRICING_FX_NOT_CONFIGURED`           | varies | Wave P1-A (2026-05-18) — Open Exchange Rates app\_id env var is unset but a currency conversion is required.                                                                                                                                    |
| `PRICING_FX_STALE`                    | varies | Wave P1-A (2026-05-18) — most-recent FX snapshot for the required currency pair is older than the 7-day hard ceiling.                                                                                                                           |
| `PRICING_FX_UPSTREAM_FAILED`          | varies | Wave P1-A (2026-05-18) — Open Exchange Rates returned a non-2xx response while warming a missing rate snapshot.                                                                                                                                 |
| `PRICING_FX_UNEXPECTED_BASE`          | varies | Wave P1-A (2026-05-18) — OXR returned a base other than USD when the free-tier API contract guarantees USD-base.                                                                                                                                |
| `PRICING_FX_UNSUPPORTED_CURRENCY`     | varies | Wave P1-A (2026-05-18) — caller requested a currency the supported set doesn't cover.                                                                                                                                                           |
| `CUSTOM_FIELD_IN_USE`                 | varies | Returned when deleting a custom-field definition would break segments that reference it.                                                                                                                                                        |
| `CONCURRENCY_LIMIT_EXCEEDED`          | varies | Returned when a voice outbound-call request would exceed the per-org concurrency cap (organizations.voice\_max\_concurrent).                                                                                                                    |
| `CONFERENCE_DIAL_ALL_FAILED`          | 502    | Audit #CONF-CALLER-ID — every seed participant on POST /voice/conferences failed to dial via Jambonz.                                                                                                                                           |
| `CONFERENCE_DIAL_PARTIAL`             | varies | Audit #CONF-CALLER-ID — partial-success companion to CONFERENCE\_DIAL\_ALL\_FAILED.                                                                                                                                                             |
| `CONF_INVALID_PARTICIPANT`            | varies | wave\_conf\_core\_2026\_05\_18 — TR-27 — conference create failed because one of the supplied participant numbers did not parse as a valid E.164 phone number.                                                                                  |
| `CONF_CALLER_ID_NOT_OWNED`            | varies | wave\_conf\_core\_2026\_05\_18 — TR-27 — conference create's `from` caller-id is not owned by the calling tenant.                                                                                                                               |
| `CONF_TRUNK_UNREGISTERED`             | 503    | wave\_conf\_core\_2026\_05\_18 — TR-27 — conference create failed because the upstream voice trunk (Devotel softswitch / Jambonz REST) was unregistered or unreachable at dial time.                                                            |
| `CONF_NOT_FOUND_OR_NOT_ACTIVE`        | 404    | Conference row not found OR found but `status != 'active'`.                                                                                                                                                                                     |
| `CONFERENCE_PIN_REQUIRED`             | 401    | DECISION — UCAAS\_003\_018\_CONFERENCE\_PIN\_2026\_05\_28.                                                                                                                                                                                      |
| `CONFERENCE_PIN_MISMATCH`             | 401    | DECISION — UCAAS\_003\_018\_CONFERENCE\_PIN\_2026\_05\_28.                                                                                                                                                                                      |
| `CONFERENCE_STATE_UNRESOLVED`         | 409    | The conference lock was refused because the room has not settled into a live state: no participant is `connected` while one or more legs are still dialing (pending, dialing, or ringing).                                                      |
| `CONF_AI_AGENT_ALREADY_ACTIVE`        | 409    | Conference already has an active AI-agent attached.                                                                                                                                                                                             |
| `CONF_AI_AGENT_NOT_FOUND`             | 404    | Conference AI-agent attachment row not found.                                                                                                                                                                                                   |
| `INVALID_DESTINATION`                 | 422    | SIP softphone outbound destination failed validation.                                                                                                                                                                                           |
| `SIP_TRUNK_UNREGISTERED`              | 503    | SIP trunk dial-time pre-check found `status='unregistered'`.                                                                                                                                                                                    |
| `OUTSIDE_SESSION_WINDOW`              | 422    | Outbound message rejected because the 24h customer-service-window is closed (WhatsApp/Messenger).                                                                                                                                               |
| `VOICE_TRUNK_CPS_CEILING`             | 429    | Customer SIP trunk hit its CPS (calls-per-second) ceiling.                                                                                                                                                                                      |
| `VOICE_TRUNK_CONCURRENT_CAP`          | 503    | Customer SIP trunk hit its concurrent-call cap.                                                                                                                                                                                                 |
| `INTERNAL_COMPLIANCE_ERROR`           | 503    | Compliance scanner threw — fail-closed surface.                                                                                                                                                                                                 |
| `NUMBER_ALREADY_TAKEN`                | 409    | Phone-number purchase race — another tenant already claimed it.                                                                                                                                                                                 |
| `INVALID_REQUEST`                     | 422    | Generic onboarding-wizard validation failure (typed as a Zod error already, this is the API code).                                                                                                                                              |
| `DELIVERY_FAILED`                     | 503    | Verify channel send returned a provider failure (upstream/softswitch rejected the submit).                                                                                                                                                      |
| `ALL_CHANNELS_FAILED`                 | 503    | Verify fan-out exhausted all configured channels without one succeeding.                                                                                                                                                                        |
| `VERIFY_FRAUD_BLOCKED`                | 403    | 403 — Verification refused by Fraud Guard: the recipient destination is blocked by the tenant's anti-fraud policy (geo / high-risk operator / composite risk score).                                                                            |
| `VERIFY_RND_REASSIGNED`               | 422    | 422 — Verification refused by the FCC Reassigned Numbers Database (RND) pre-send guard: the destination phone number (sms / mms / voice / flashcall, US +1) has a permanent-disconnect record in the RND feed and may have been reassigned to…  |
| `VERIFY_SEND_FAILED`                  | varies | Per-recipient failure code in a bulk-verify response row (not an HTTP status).                                                                                                                                                                  |
| `CONF_PROVIDER_ERROR`                 | 502    | wave\_conf\_core\_2026\_05\_18 — TR-27 — conference create's Jambonz REST call returned a non-2xx that wasn't structurally a VALIDATION/AUTH error.                                                                                             |
| `CONF_INSUFFICIENT_CREDIT`            | 402    | wave\_conf\_core\_2026\_05\_18 — TR-27 — conference create denied at the billing-hold step (caller has no remaining credit / hit a spend cap).                                                                                                  |
| `NUMBER_NO_LONGER_AVAILABLE`          | 409    | Returned (409) when a phone number a tenant tried to purchase has been claimed by someone else between the inventory list-fetch and the purchase request.                                                                                       |
| `NUMBER_PROVISIONING_FAILED`          | 502    | Returned (502) when a number was successfully purchased upstream and billed but a downstream platform-side step (e.g. mirroring into `public.platform_numbers` so inbound traffic can resolve the owning tenant) failed.                        |
| `INVALID_RING_GROUP_CYCLE`            | 422    | Returned (422) when a ring-group create/update would introduce a cycle reachable from the group itself (A → B → A or A → B → C → A).                                                                                                            |
| `COMPLIANCE_PROFILE_NOT_APPROVED`     | 422    | Returned (422) when a feature surface (number purchase, sender-ID registration, brand registration, etc.) tries to attach a compliance profile whose status is not 'approved'.                                                                  |
| `COMPLIANCE_PROFILE_REQUIRED`         | 422    | Returned (422) when a number-purchase request targets a regulated country (UK / DE / FR / etc.) AND the tenant has no approved compliance profile that covers it.                                                                               |
| `PLACEHOLDER_REQUIRES_PROFILE`        | 422    | Returned (422) when a tenant tries to buy a DIDWW DID-group PLACEHOLDER row (`did_group:<uuid>`) WITHOUT an approved compliance profile for the row's country.                                                                                  |
| `COMPLIANCE_PROFILE_INCOMPLETE`       | 422    | Returned (422) when a tenant tries to submit a compliance profile that is missing required documents or data fields per the compliance-requirements registry's RequirementSet for that use\_case + country.                                     |
| `COMPLIANCE_PROFILE_IN_USE`           | 409    | Returned (409) when a tenant tries to delete a compliance profile, or detach an underlying document, that's still referenced by an active downstream entity (purchased phone number, registered sender ID, brand, campaign, etc.).              |
| `COMPLIANCE_PROFILE_LOCKED`           | 409    | Returned (409) when the tenant tries to mutate a compliance profile (data, documents, fields) that has already moved past `draft` — once submitted to providers we lock the payload to keep our state in sync with what each carrier holds.     |
| `COMPLIANCE_USE_CASE_NOT_SUPPORTED`   | 422    | Returned (422) when a tenant tries to submit a compliance profile whose use-case fans out only to NOT\_IMPLEMENTED provider shells (TCR / Meta WA / Google RCS at the time of writing).                                                         |
| `BRAND_NOT_APPROVED`                  | varies | Tenant tried to submit an RCS bot under a brand that hasn't been approved yet.                                                                                                                                                                  |
| `SIM_SWAP_DETECTED`                   | 403    | Returned (403) by /verify/start when a SIM-swap event is detected inside the block window (24h default) on the recipient MSISDN.                                                                                                                |
| `MESSAGING_TR_URL_STRIP_VIOLATION`    | 422    | Türkiye BTK Decision 2025/DK-YED/412 (effective 1 Apr 2026) blocks A2P SMS containing URLs from senders not registered in Türkiye — the carrier strips the entire payload at delivery so the recipient sees nothing and the operator burns sp…  |
| `RECORDING_CONSENT_REQUIRED`          | varies | Two-party recording-consent gate (UAE Penal Code Art.                                                                                                                                                                                           |
| `RECORDING_CONSENT_INVALID`           | 422    | Recording-consent receipt failed DB-backed validation (SCAN-RVV-008).                                                                                                                                                                           |
| `MESSAGING_IN_DLT_TEMPLATE_REQUIRED`  | varies | India TRAI DLT (Distributed Ledger Technology) registration requires an approved `dlt_template_id` for every A2P SMS routed to IN destinations.                                                                                                 |
| `MESSAGING_IN_DLT_CONTENT_MISMATCH`   | 422    | 422 — India TRAI DLT content-template enforcement: an A2P SMS carries an approved `dlt_template_id` but its body or sender header does not match the registered template, so Orbit fails the send closed at the platform edge.                  |
| `MESSAGING_BR_SENDER_NOT_REGISTERED`  | varies | Brazil Anatel sender-ID registration is required for any operator sending A2P SMS to BR destinations.                                                                                                                                           |
| `MESSAGING_SA_SENDER_NOT_REGISTERED`  | varies | Saudi Arabia CITC sender-name registration is required for any operator sending A2P SMS to KSA (SA) destinations.                                                                                                                               |
| `MESSAGING_AE_SENDER_NOT_REGISTERED`  | varies | United Arab Emirates TDRA sender-name registration is required for any operator sending A2P SMS to UAE (AE) destinations.                                                                                                                       |
| `MESSAGING_MX_NOM184_CONSENT_MISSING` | varies | Mexico NOM-184-SCFI requires explicit, time-stamped consent for every promotional A2P SMS to a MX subscriber.                                                                                                                                   |
| `CONSENT_RECEIPT_INVALID`             | varies | India DPDP Phase II Consent-Manager receipt verification failed: either the receipt id is unknown to the platform, the signature does not match the registered manager's public key, or the receipt has been tampered with.                     |
| `MESSAGING_TCPA_KNOWN_LITIGATOR`      | 403    | Recipient phone is on the platform's known-litigator list (TCPA professional plaintiff).                                                                                                                                                        |
| `MESSAGING_CONSENT_REQUIRED`          | varies | General pre-send affirmative-opt-in (consent) gate.                                                                                                                                                                                             |
| `TFV_REQUIRED`                        | varies | US toll-free numbers must complete carrier-side Toll-Free Verification (TFV) before they can send A2P SMS to US carriers without aggressive throttling / outright blocking.                                                                     |
| `TEN_DLC_NOT_REGISTERED`              | varies | Audit #COMP-002 — US 10DLC (10-digit long code) send rejected because the org has no approved TCR (The Campaign Registry) brand+campaign registration for the sender.                                                                           |
| `IDEMPOTENCY_KEY_REQUIRED`            | varies | Audit #CB-010 — `Idempotency-Key` header is REQUIRED on money-moving mutations (top-up checkout, future similar endpoints) but the caller omitted it entirely.                                                                                  |
| `INVALID_IDEMPOTENCY_KEY`             | varies | API idempotency-key shape validation failures (length / charset).                                                                                                                                                                               |
| `IDEMPOTENCY_KEY_REUSED`              | varies | Same Idempotency-Key replayed with a DIFFERENT request body.                                                                                                                                                                                    |
| `PAYMENT_IN_FLIGHT`                   | 409    | TF-BILL-02 (2026-05-18) — tenant tried to cancel a crypto top-up intent that has progressed past `waiting`/`confirming`.                                                                                                                        |
| `EMPTY_AUDIENCE_NOT_ALLOWED`          | 422    | TF-SEG-04 (2026-05-18) — operator tried to create a campaign whose explicit audience selection (segment\_id / list\_id / explicit empty csv array) resolves to 0 recipients.                                                                    |
| `BATCH_PRE_INSERT_FAILED`             | varies | Audit #BATCH-SMS-PERSIST-FAILED-1 — `MessagesBatchService` failed to bulk-pre-insert the recipients' `pending` rows (Postgres unavailable / connection refused / unique-id collision).                                                          |
| `INTEGRATION_DISCONNECTED`            | 412    | Audit #INTEGRATION-WIRING-4 — campaign audience source references a CRM (HubSpot / Salesforce / Pipedrive) the tenant hasn't connected via Nango.                                                                                               |
| `AUDIENCE_RESOLVE_FAILED`             | 502    | Audit #INTEGRATION-WIRING-4 — the resolver failed mid-iterate on a CRM-backed audience (Nango timeout, rate-limit, auth expired).                                                                                                               |
| `NANGO_DESTINATION_FAILED`            | 502    | DECISION — CDP\_NANGO\_DESTINATIONS\_2026\_05\_28 — outbound CDP activation through Nango Cloud's `triggerAction` failed (HubSpot, Salesforce, Braze, Iterable, Customer.io, Klaviyo).                                                          |

## Audit #WAVE-O-FOUNDATION — Orby

| Code                       | HTTP   | Description                                                                                                                                                                                                                                   |
| -------------------------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ORBY_TOOL_FORBIDDEN`      | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                               |
| `ORBY_TOOL_NOT_AUTHORIZED` | 403    | Audit #SCAN-AI-V3-010 (AGT-026 follow-up) — execute-time gate.                                                                                                                                                                                |
| `ORBY_TOOL_CLAIM_MISSING`  | 401    | Audit #SCAN-AI-V3-010 — the session token decoded successfully but carries no `tools` claim (or a non-array claim).                                                                                                                           |
| `ORBY_SESSION_MALFORMED`   | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                               |
| `ORBY_SESSION_SIG_INVALID` | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                               |
| `ORBY_SESSION_EXPIRED`     | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                               |
| `ORBY_SESSION_REVOKED`     | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                               |
| `ORBY_SESSION_REQUIRED`    | 403    | Orby is operator-facing only; a request authenticated with an API key rather than a signed-in dashboard session is rejected.                                                                                                                  |
| `ORBY_RATE_LIMITED`        | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                               |
| `ORBY_THREAD_NOT_OWNED`    | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                               |
| `ORBY_ITERATION_LIMIT`     | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                               |
| `ORBY_COST_CAP_EXCEEDED`   | varies | Reserved Orby cost-cap error code.                                                                                                                                                                                                            |
| `ORBY_LLM_FAILED`          | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                               |
| `ORBY_TURN_FAILED`         | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                               |
| `ORBY_KB_NOT_INDEXED_YET`  | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                               |
| `ORBY_KB_REINDEX_FAILED`   | varies | Reserved Orby knowledge-base error code.                                                                                                                                                                                                      |
| `KB_VECTOR_DELETE_FAILED`  | 502    | AIAAS-KB-VECDB-CONSISTENCY (2026-06-02) — a KB document delete could not remove the document's vectors from the Qdrant search index, so the `kb_documents` row was deliberately RETAINED (it is the only handle on the orphaned vectors that… |

## Audit #AGT-001 — confirmation-gate redemption

| Code                            | HTTP | Description                                                                                         |
| ------------------------------- | ---- | --------------------------------------------------------------------------------------------------- |
| `PENDING_ACTION_NOT_APPROVABLE` | 409  | Pending agent action is not in `pending` state (already approved / cancelled).                      |
| `PENDING_ACTION_RACE`           | 409  | Pending agent action lost the approve/reject race against a concurrent operator.                    |
| `PENDING_ACTION_EXPIRED`        | 409  | Pending agent action was past its 5-min approval window (#UX-006).                                  |
| `PENDING_ACTION_PERSIST_FAILED` | 500  | The runtime could not persist a `pending_agent_actions` row, so the tool was refused (fail-closed). |
| `TOOL_EXECUTION_FAILED`         | 500  | Approved tool's executor threw a non-DevotelError exception.                                        |

## Audit #AGT-007 — custom-tool dispatch body cap

| Code                             | HTTP | Description                                                   |
| -------------------------------- | ---- | ------------------------------------------------------------- |
| `CUSTOM_TOOL_RESPONSE_TOO_LARGE` | 502  | Custom-tool executor response body exceeded the 1 MB ceiling. |

## Audit #AGT-002 — accurate cost cap

| Code                | HTTP | Description                                                                             |
| ------------------- | ---- | --------------------------------------------------------------------------------------- |
| `COST_CAP_EXCEEDED` | 402  | Per-conversation LLM cost cap exceeded (accurate computation via Anthropic rate table). |

## Audit #WAVE-O-NEW-ENDPOINTS

| Code                                         | HTTP   | Description                                                                                                                                                                                                                                       |
| -------------------------------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `IVR_FLOW_GRAPH_INVALID`                     | 422    | IVR flow graph failed structural validation (no entry, orphan edges, etc).                                                                                                                                                                        |
| `CALL_TRANSCRIPT_UNAVAILABLE`                | 422    | `POST /voice/calls/:id/summary` — no usable transcript on the call.                                                                                                                                                                               |
| `LLM_PROVIDER_UNCONFIGURED`                  | 503    | No LLM provider key configured on the platform.                                                                                                                                                                                                   |
| `CALL_SUMMARY_LLM_MALFORMED`                 | 502    | LLM reply was malformed / unparseable after retries.                                                                                                                                                                                              |
| `VIDEO_TRANSCRIPT_UNAVAILABLE`               | 422    | UCaaS P1 (2026-05-30) — `POST /video/sessions/:id/summary` — no usable transcript on the meeting (no captions captured, transcript too short, etc.).                                                                                              |
| `VIDEO_SUMMARY_LLM_MALFORMED`                | 502    | UCaaS P1 (2026-05-30) — `POST /video/sessions/:id/summary` — LLM reply was malformed / unparseable after retries.                                                                                                                                 |
| `VIDEO_SESSION_SUMMARY_FAILED`               | varies | UCaaS P1 (2026-05-30) — `POST /video/sessions/:id/summary` — unexpected route-level failure (DB / tenant client / sanitised envelope).                                                                                                            |
| `PUSH_CATEGORY_IDENTIFIER_CONFLICT`          | 409    | Push category identifier collision with an existing tenant row.                                                                                                                                                                                   |
| `BROADCAST_TOO_LARGE`                        | 422    | `POST /push` broadcast (`user_ids: ["*"]`) whose deliverable audience — enabled device tokens minus push/all suppression-list opt-outs — exceeds the `MAX_BROADCAST_RECIPIENTS` cap.                                                              |
| `SCHEDULED_PUSH_NOT_CANCELLABLE`             | 409    | 409 — `DELETE /push/scheduled/:id` refused to cancel a scheduled push that is no longer in `scheduled` state.                                                                                                                                     |
| `SQUAD_DAILY_CAP_REACHED`                    | 429    | Agent squad's today-so-far LLM cost meets/exceeds its configured daily cap.                                                                                                                                                                       |
| `CONVERSATION_COST_CAP_REACHED`              | 429    | Per-conversation LLM cost meets/exceeds the agent's configured cap.                                                                                                                                                                               |
| `AGENT_DAILY_SPEND_CAP_REACHED`              | 429    | SCAN-BILL-FRESH-001 / invariant #64 — tenant's today-so-far agent LLM spend meets/exceeds the configured daily cap, thrown from the gateway-level `callClaude` / `streamClaude` / `callClaudeStructured` chokepoint.                              |
| `SAFETY_CLASSIFIER_REFUSAL`                  | 403    | Audit #VOICE-FRAUD-9 — Anthropic's server-side Constitutional Classifiers refused the completion (`stop_reason:"refusal"`) AND `DEVOTEL_ANTHROPIC_CONSTITUTIONAL_CLASSIFIERS_ENABLED` is on, so the LLM gateway BLOCKS the refused content ra…    |
| `VOICE_BIOMETRICS_TIMEOUT`                   | 503    | Voice biometrics sidecar did not respond within the 10-second timeout.                                                                                                                                                                            |
| `VOICE_BIOMETRICS_UNAVAILABLE`               | 503    | Voice biometrics sidecar is unreachable (network error).                                                                                                                                                                                          |
| `VOICE_BIOMETRICS_AUTH_FAILED`               | 500    | HMAC authentication with voice biometrics sidecar failed.                                                                                                                                                                                         |
| `VOICE_BIOMETRICS_ERROR`                     | 503    | Voice biometrics sidecar returned an unexpected error.                                                                                                                                                                                            |
| `CONFIGURATION_ERROR`                        | 500    | DEVOTEL\_VOICE\_BIOMETRICS\_INTERNAL\_SECRET env var missing.                                                                                                                                                                                     |
| `INVALID_AUDIO`                              | 400    | Audio payload is invalid (not WAV, empty, or corrupt).                                                                                                                                                                                            |
| `AUDIO_TOO_LARGE`                            | 400    | Audio clip exceeds the 30-second / 2MB maximum.                                                                                                                                                                                                   |
| `SPOOF_DETECTED`                             | 422    | Voice enrollment rejected — anti-spoof score is below threshold.                                                                                                                                                                                  |
| `DEEPFAKE_DETECTED`                          | 422    | Voice enrollment rejected — Resemble Detect flagged the audio as a synthetic / cloned voice (deepfake score at or above threshold).                                                                                                               |
| `DUPLICATE_VOICEPRINT`                       | 409    | Identical voiceprint already enrolled for this contact.                                                                                                                                                                                           |
| `IVR_INTENT_CREATE_ERROR`                    | 500    | IVR intent create failed (non-constraint DB error).                                                                                                                                                                                               |
| `IVR_CLASSIFY_LLM_ERROR`                     | 503    | Conversational IVR NLU classifier — LLM call failed.                                                                                                                                                                                              |
| `IVR_SLOT_EXTRACT_LLM_ERROR`                 | 503    | Conversational IVR slot-filling / entity extraction — LLM call failed.                                                                                                                                                                            |
| `HIPAA_BAA_REQUIRED`                         | varies | HIPAA BAA enforcement gate (SCAN-CSPAAS-004) — tenant is opted into HIPAA mode (`settings.hipaa_required = true`) but does not have an executed, in-term Business Associate Agreement on file.                                                    |
| `HIPAA_BAA_GATE_DB_FAIL`                     | 500    | HIPAA BAA enforcement gate (SCAN-CSPAAS-004) — DB read failed while verifying BAA status.                                                                                                                                                         |
| `ESCALATION_EMAIL_RECIPIENTS_FORBIDDEN`      | 403    | Returned by PUT /settings/general when the operator attempts to persist `settings.escalation.email_recipients` containing one or more entries whose domain is not present in the org-member domain allowlist.                                     |
| `ESCALATION_EMAIL_RECIPIENTS_INVALID`        | varies | Returned by PUT /settings/general when the operator submits `settings.escalation.email_recipients` as a non-array or with non-string entries.                                                                                                     |
| `ESCALATION_EMAIL_RECIPIENTS_TOO_MANY`       | varies | Returned by PUT /settings/general when the operator submits a `settings.escalation.email_recipients` array of length > 20.                                                                                                                        |
| `ESCALATION_CHANNEL_FORBIDDEN`               | 403    | Returned by POST /agents and PUT /agents/:id when the operator sets an AI-agent escalation forward with delivery medium `email` (`config.escalation_channel_type === "email"`) whose `escalation_channel` address is on a domain that does NO…    |
| `ORG_COMPLIANCE_EMERGENCY_STOP`              | varies | CCaaS gap #51 — Org-wide compliance emergency stop (panic button).                                                                                                                                                                                |
| `CDP_SOURCE_QUERY_MULTI_STATEMENT_FORBIDDEN` | 400    | DECISION — CDPAAS\_REVERSE\_ETL\_SQL\_INJECTION\_AND\_MIGRATION\_FIX\_2026\_05\_28.                                                                                                                                                               |
| `AGENT_CHANNEL_CAP_EXCEEDED`                 | 422    | CCaaS-PARITY (2026-05-30) — raised by the per-agent per-channel concurrency-cap routing gate (`apps/api/src/lib/agent-channel-cap.ts`) when an attempt to assign a conversation onto an agent would exceed the configured \`agent\_channel\_caps… |
| `AGENT_INVOCATION_RATE_LIMIT_EXCEEDED`       | 429    | AIaaS per-agent invocation throttle (2026-06-29) — a single AI agent exceeded its operator-configured per-minute invocation rate (`config.invocation_rate_limit_per_min`).                                                                        |
| `AGENT_INVOCATION_QUOTA_EXCEEDED`            | 429    | AIaaS per-agent invocation throttle (2026-06-29) — a single AI agent exhausted its operator-configured daily invocation quota (`config.invocation_quota_per_day`).                                                                                |
| `AGENT_RATE_LIMIT_EXCEEDED`                  | 429    | AIaaS per-agent configured rate-limit gate (2026-06-30) — a single AI agent exceeded one of its operator-configured invocation ceilings on the chat / stream entrypoint.                                                                          |
| `INTERNAL`                                   | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `BAD_GATEWAY`                                | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `UPSTREAM_ERROR`                             | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `RATE_LIMITED`                               | 429    | Global HTTP 429 rate limit from the platform-wide request limiter, carrying a `retry_after` value in seconds and a matching `Retry-After` header.                                                                                                 |
| `UNAUTHENTICATED`                            | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `UNPROCESSABLE_ENTITY`                       | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `INVARIANT_VIOLATION`                        | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `SESSION_REVOKED`                            | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `LIGHT_SEAT_RESTRICTED`                      | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `INVALID_TOKEN`                              | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `INVALID_CODE`                               | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `CHALLENGE_INVALID`                          | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `ALREADY_VERIFIED`                           | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `VERIFICATION_REJECTED`                      | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `INVALID_FILTER`                             | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `INVALID_STATUS`                             | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `INVALID_PRIORITY`                           | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `INVALID_STATE_TRANSITION`                   | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `INVALID_TRANSITION`                         | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `INVALID_LAUNCH_STATE`                       | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `INVALID_PHONE`                              | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `INVALID_CALLER_ID`                          | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `INVALID_DESTINATION_URL`                    | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `INSUFFICIENT_FUNDS`                         | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `MAX_PRICE_EXCEEDED`                         | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `COUNTRY_NOT_ALLOWED`                        | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `CHANNEL_COUNTRY_BLOCKED`                    | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `CHANNEL_FAILED`                             | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `BINDING_REQUIRED`                           | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `BINDING_MISMATCH`                           | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `AGENT_NOT_FOUND`                            | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `AGENT_ARCHIVED`                             | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `AGENT_REQUIRED`                             | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `AGENT_REFERENCED_BY_CHILD_ROWS`             | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `AGENT_REFERENCED_BY_SQUAD`                  | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `NO_AGENT_AVAILABLE`                         | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `UNKNOWN_SKILL`                              | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `SKILL_CATALOG_ORG_MISSING`                  | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `SKILL_SLUG_ALREADY_EXISTS`                  | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `TOOL_IMPL_NOT_REGISTERED`                   | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `INVALID_HANDOFF_TARGETS`                    | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `INVALID_KNOWLEDGE_BASE_IDS`                 | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `LEGACY_KB_DOC_NOT_RECHUNKABLE`              | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `POLICY_SCANNER_UNAVAILABLE`                 | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `CUSTOM_CODE_FORBIDDEN`                      | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `QUEUE_NOT_FOUND`                            | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `QUEUE_DEPTH_CAP_REACHED`                    | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `QUEUE_ENTRY_NOT_QUEUED`                     | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `OVERFLOW_QUEUE_NOT_FOUND`                   | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `OVERFLOW_QUEUE_CHAIN_CYCLE`                 | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `OVERFLOW_QUEUE_SELF_CHAIN`                  | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `SKIP_INELIGIBLE`                            | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `NOT_IN_WRAPUP`                              | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `DISPOSITION_REQUIRED`                       | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `DISPOSITION_CODE_NOT_FOUND`                 | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `DISPOSITION_TAG_REQUIRED`                   | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `DISPOSITION_TAG_NOT_FOUND`                  | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `AUX_CODE_ALREADY_EXISTS`                    | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `AUX_CODE_UPDATE_EMPTY`                      | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `TEMPLATE_NOT_FOUND`                         | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `TEMPLATE_NAME_CONFLICT`                     | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `TEMPLATE_LIMIT_EXCEEDED`                    | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `SPEECH_CATEGORY_NOT_FOUND`                  | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `SPEECH_CATEGORY_SLUG_CONFLICT`              | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `RECORDING_CONSENT_ACKNOWLEDGEMENT_REQUIRED` | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `EMERGENCY_DESTINATION_REQUIRED`             | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `VOICE_OVERLOAD_CHAT_VETOED`                 | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `CAMPAIGN_NOT_DRAFT`                         | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `CAMPAIGN_NOT_PENDING_APPROVAL`              | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `CONVERSATION_LINK_EXISTS`                   | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `BLOCKED_NUMBER_ALREADY_EXISTS`              | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `OPT_OUT_LIST_LABEL_CONFLICT`                | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `SEND_WINDOW_LOOKUP_FAILED`                  | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `MESSAGING_SERVICE_NOT_FOUND`                | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `MESSAGING_SERVICE_EXTERNAL_ID_CONFLICT`     | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `MESSAGING_SERVICE_RESOLUTION_FAILED`        | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `MESSENGER_TAG_REQUIRED`                     | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `MESSENGER_OUTSIDE_24H_WINDOW`               | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `CARRIER_PORT_OUT_FAILED`                    | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `PORT_OUT_NOT_SUPPORTED`                     | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `PORT_OUT_PIN_MISMATCH`                      | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `MEF_INTEGRATION_PENDING`                    | varies | DEPRECATED — no longer emitted; country-rule sync now fails open, returning HTTP 200 with any sync issues reported in the response's `errors[]` array instead of throwing this former HTTP 501 code.                                              |
| `VERIFY_LINE_TYPE_BLOCKED`                   | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `VERIFY_EMAIL_UNDELIVERABLE`                 | 422    | 422 — an email OTP (`channel: email` \| `magic_link`) was requested for an address whose domain PROVABLY cannot receive mail: the domain publishes no MX record (NXDOMAIN / ENODATA).                                                             |
| `QR_RENDER_FAILED`                           | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `VIDEO_ROOM_LOCKED`                          | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `VIDEO_PARTICIPANT_BANNED`                   | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `VIDEO_MUTE_ALL_FAILED`                      | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `VIDEO_BROADCAST_FAILED`                     | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `VIDEO_BREAKOUT_CREATE_FAILED`               | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `VIDEO_BREAKOUT_MOVE_FAILED`                 | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `VIDEO_WAITING_ROOM_FAILED`                  | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `VIDEO_WAITING_ROOM_ADMIT_FAILED`            | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `VIDEO_PARTICIPANT_TIER_UPDATE_FAILED`       | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `VIDEO_INGRESS_CREATE_FAILED`                | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `VIDEO_RTMP_EGRESS_START_FAILED`             | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |
| `VIDEO_RECORDING_BACKEND_UNAVAILABLE`        | varies | Platform-defined error code. See source comment in `packages/shared/src/errors.ts` for context.                                                                                                                                                   |

## Video / Rooms (server-side fallback codes)

| Code                                       | HTTP | Description                                                                                                                                                     |
| ------------------------------------------ | ---- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `VIDEO_ROOM_CREATION_FAILED`               | 500  | 500 — an unexpected server error prevented the request to create the video room; the operation did not complete, so retry the request.                          |
| `VIDEO_ROOM_LIMITS_FAILED`                 | 500  | 500 — an unexpected server error prevented the request to load your video room limits; the operation did not complete, so retry the request.                    |
| `VIDEO_ROOM_LIST_FAILED`                   | 500  | 500 — an unexpected server error prevented the request to load your video rooms; the operation did not complete, so retry the request.                          |
| `VIDEO_ROOM_FETCH_FAILED`                  | 500  | 500 — an unexpected server error prevented the request to load this video room; the operation did not complete, so retry the request.                           |
| `VIDEO_ROOM_JOIN_FAILED`                   | 500  | 500 — an unexpected server error prevented the request to generate a join token for this room; the operation did not complete, so retry the request.            |
| `VIDEO_ROOM_END_FAILED`                    | 500  | 500 — an unexpected server error prevented the request to end this video room; the operation did not complete, so retry the request.                            |
| `VIDEO_RECORDING_START_FAILED`             | 500  | 500 — an unexpected server error prevented the request to start the recording; the operation did not complete, so retry the request.                            |
| `VIDEO_RECORDING_STOP_FAILED`              | 500  | 500 — an unexpected server error prevented the request to stop the recording; the operation did not complete, so retry the request.                             |
| `VIDEO_RTMP_EGRESS_STOP_FAILED`            | 500  | 500 — an unexpected server error prevented the request to stop the live stream; the operation did not complete, so retry the request.                           |
| `VIDEO_LIVESTREAM_PLAYBACK_FAILED`         | 500  | 500 — an unexpected server error prevented the request to load the live stream playback URL; the operation did not complete, so retry the request.              |
| `VIDEO_INGRESS_DELETE_FAILED`              | 500  | 500 — an unexpected server error prevented the request to remove the ingress; the operation did not complete, so retry the request.                             |
| `VIDEO_INGRESS_LIST_FAILED`                | 500  | 500 — an unexpected server error prevented the request to load active ingresses; the operation did not complete, so retry the request.                          |
| `VIDEO_INVITE_CREATE_FAILED`               | 500  | 500 — an unexpected server error prevented the request to create a guest invite; the operation did not complete, so retry the request.                          |
| `VIDEO_INVITE_LIST_FAILED`                 | 500  | 500 — an unexpected server error prevented the request to load guest invites for this room; the operation did not complete, so retry the request.               |
| `VIDEO_INVITE_REVOKE_FAILED`               | 500  | 500 — an unexpected server error prevented the request to revoke this guest invite; the operation did not complete, so retry the request.                       |
| `VIDEO_PARTICIPANT_UNMUTE_FAILED`          | 500  | 500 — an unexpected server error prevented the request to unmute this participant; the operation did not complete, so retry the request.                        |
| `VIDEO_PARTICIPANT_BAN_FAILED`             | 500  | 500 — an unexpected server error prevented the request to ban this participant; the operation did not complete, so retry the request.                           |
| `VIDEO_PARTICIPANT_UNBAN_FAILED`           | 500  | 500 — an unexpected server error prevented the request to lift the ban for this participant; the operation did not complete, so retry the request.              |
| `VIDEO_BAN_LIST_FAILED`                    | 500  | 500 — an unexpected server error prevented the request to load the banned participants for this room; the operation did not complete, so retry the request.     |
| `VIDEO_RECORDING_CONSENT_SET_FAILED`       | 500  | 500 — an unexpected server error prevented the request to update this participant's recording consent; the operation did not complete, so retry the request.    |
| `VIDEO_RECORDING_CONSENT_LIST_FAILED`      | 500  | 500 — an unexpected server error prevented the request to load the recording-consent list for this room; the operation did not complete, so retry the request.  |
| `VIDEO_ROOM_LOCK_FAILED`                   | 500  | 500 — an unexpected server error prevented the request to change the room lock state; the operation did not complete, so retry the request.                     |
| `VIDEO_PARTICIPANT_ROLE_UPDATE_FAILED`     | 500  | 500 — an unexpected server error prevented the request to change this participant's role; the operation did not complete, so retry the request.                 |
| `VIDEO_PARTICIPANT_RECEIVE_CONTROL_FAILED` | 500  | 500 — an unexpected server error prevented the request to update this participant's receive settings; the operation did not complete, so retry the request.     |
| `VIDEO_SPOTLIGHT_SET_FAILED`               | 500  | 500 — an unexpected server error prevented the request to spotlight this participant; the operation did not complete, so retry the request.                     |
| `VIDEO_SPOTLIGHT_CLEAR_FAILED`             | 500  | 500 — an unexpected server error prevented the request to clear the spotlight; the operation did not complete, so retry the request.                            |
| `VIDEO_ROOM_SSO_POLICY_FAILED`             | 500  | 500 — an unexpected server error prevented the request to update the room's single sign-on access policy; the operation did not complete, so retry the request. |
| `VIDEO_INVITE_REDEEM_FAILED`               | 500  | 500 — an unexpected server error prevented the request to redeem this guest invite; the operation did not complete, so retry the request.                       |
| `VIDEO_HAND_RAISE_FAILED`                  | 500  | 500 — an unexpected server error prevented the request to raise your hand; the operation did not complete, so retry the request.                                |
| `VIDEO_HAND_LOWER_FAILED`                  | 500  | 500 — an unexpected server error prevented the request to lower your hand; the operation did not complete, so retry the request.                                |
| `VIDEO_HAND_QUEUE_LIST_FAILED`             | 500  | 500 — an unexpected server error prevented the request to load the raised-hand queue; the operation did not complete, so retry the request.                     |
| `VIDEO_HAND_QUEUE_CLEAR_FAILED`            | 500  | 500 — an unexpected server error prevented the request to clear the raised-hand queue; the operation did not complete, so retry the request.                    |
| `VIDEO_REACTION_FAILED`                    | 500  | 500 — an unexpected server error prevented the request to send your reaction; the operation did not complete, so retry the request.                             |
| `VIDEO_POLL_LAUNCH_FAILED`                 | 500  | 500 — an unexpected server error prevented the request to launch the poll; the operation did not complete, so retry the request.                                |
| `VIDEO_POLL_VOTE_FAILED`                   | 500  | 500 — an unexpected server error prevented the request to record your vote; the operation did not complete, so retry the request.                               |
| `VIDEO_POLL_CLOSE_FAILED`                  | 500  | 500 — an unexpected server error prevented the request to close the poll; the operation did not complete, so retry the request.                                 |
| `VIDEO_QA_ASK_FAILED`                      | 500  | 500 — an unexpected server error prevented the request to submit your question; the operation did not complete, so retry the request.                           |
| `VIDEO_QA_ANSWER_FAILED`                   | 500  | 500 — an unexpected server error prevented the request to post the answer to this question; the operation did not complete, so retry the request.               |
| `VIDEO_WHITEBOARD_OPEN_FAILED`             | 500  | 500 — an unexpected server error prevented the request to open the whiteboard; the operation did not complete, so retry the request.                            |
| `VIDEO_WHITEBOARD_DRAW_FAILED`             | 500  | 500 — an unexpected server error prevented the request to sync your drawing to the room; the operation did not complete, so retry the request.                  |
| `VIDEO_WHITEBOARD_CLEAR_FAILED`            | 500  | 500 — an unexpected server error prevented the request to clear the whiteboard; the operation did not complete, so retry the request.                           |
| `VIDEO_WHITEBOARD_CLOSE_FAILED`            | 500  | 500 — an unexpected server error prevented the request to close the whiteboard; the operation did not complete, so retry the request.                           |
| `VIDEO_CHAT_SEND_FAILED`                   | 500  | 500 — an unexpected server error prevented the request to send your message; the operation did not complete, so retry the request.                              |
| `VIDEO_CHAT_DELETE_FAILED`                 | 500  | 500 — an unexpected server error prevented the request to remove that message; the operation did not complete, so retry the request.                            |
| `VIDEO_CHAT_CLEAR_FAILED`                  | 500  | 500 — an unexpected server error prevented the request to clear the chat; the operation did not complete, so retry the request.                                 |
| `VIDEO_CHAT_BLOCKED_BY_POLICY`             | 422  | 422 — the chat message was rejected by the room's proactive content-safety policy (mode=block); it was neither delivered to other participants nor persisted.   |
| `VIDEO_ROOM_CHAT_POLICY_FAILED`            | 502  | 502 — an unexpected server error prevented persisting the room's chat content-safety policy; the change did not take effect, so retry the request.              |
| `VIDEO_DIAL_IN_FAILED`                     | 500  | 500 — an unexpected server error prevented the request to load the dial-in details for this room; the operation did not complete, so retry the request.         |
| `VIDEO_TRANSCRIPT_LIST_FAILED`             | 500  | 500 — an unexpected server error prevented the request to load the transcript for this room; the operation did not complete, so retry the request.              |
| `VIDEO_TRANSCRIPT_DELETE_FAILED`           | 500  | 500 — an unexpected server error prevented the request to delete the transcript for this room; the operation did not complete, so retry the request.            |
| `VIDEO_TRANSCRIPT_EXPORT_FAILED`           | 500  | 500 — an unexpected server error prevented the request to export the caption file for this room; the operation did not complete, so retry the request.          |
| `VIDEO_TRANSCRIPT_CORRECT_FAILED`          | 500  | 500 — an unexpected server error prevented the request to apply that caption correction; the operation did not complete, so retry the request.                  |
| `WEBHOOK_HANDLING_FAILED`                  | 500  | 500 — an unexpected error prevented processing the inbound video webhook; the event was not handled and may be retried by the provider.                         |

## Numbers / Provisioning

| Code                     | HTTP | Description                                                                                                                                                                                                            |
| ------------------------ | ---- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `CARRIER_RATE_LIMITED`   | 429  | 429 — bulk-number-purchase per-item result code: the carrier rate-limited the batch, so the remaining items were skipped without a carrier call; retry the failed rows in a few seconds.                               |
| `LOA_NOT_SIGNED`         | 409  | 409 — hosted-messaging order submit refused because the LOA has not been signed yet (`loa_signed_at` is null); sign the LOA before submitting the order to the hosting carrier.                                        |
| `LOA_URL_INVALID_ORIGIN` | 422  | 422 — number-porting create rejected `loaFileUrl` because it is not a Devotel-issued GCS signed URL (wrong host or path prefix); upload the LoA via `POST /files/upload` and submit the returned `url`.                |
| `TFV_LINT_BLOCKED`       | 422  | 422 — toll-free-verification submit blocked by the pre-submit content lint: one or more sample messages match a disallowed-vertical pattern at `error` severity; fix the issues in `details.lint` before resubmitting. |
| `UNSUPPORTED_MEDIA_TYPE` | 415  | 415 — number-document upload rejected because the request body was not `multipart/form-data`; re-send the document as a multipart file part.                                                                           |

## Compliance (DSAR / RMD / Residency / Traceback)

| Code                           | HTTP | Description                                                                                                                                                                                                                                    |
| ------------------------------ | ---- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `DSAR_CREATE_FAILED`           | 500  | 500 — POST /compliance/dsar failed to persist the new GDPR/CCPA data-subject-access request because the DB insert threw; the operation is retry-safe.                                                                                          |
| `VERIFICATION_NOT_PENDING`     | 409  | 409 — the DSAR identity-verification step was actioned but the request has no pending verification: it may already have been verified, rejected, or filed under a regime that does not require verification.                                   |
| `DSAR_CANCEL_FAILED`           | 500  | 500 — POST /compliance/dsar/:id/cancel failed to withdraw the request because the DB update threw; the operation is retry-safe.                                                                                                                |
| `DSAR_NOT_CANCELLABLE`         | 409  | 409 — the DSAR cannot be withdrawn because it does not exist or has already completed, failed, expired, or been cancelled.                                                                                                                     |
| `DSAR_BUCKET_UNCONFIGURED`     | 500  | 500 — the decrypted Article-15 export download could not run because no DSAR export storage location is configured on this deployment.                                                                                                         |
| `DSAR_DECRYPT_LIST_FAILED`     | 502  | 502 — GET /compliance/dsar/:id/decrypted could not list the export's encrypted files because the storage backend was unreachable; retry-safe.                                                                                                  |
| `DSAR_DECRYPT_NO_ARTIFACTS`    | 404  | 404 — no encrypted export files were found for this DSAR; the export has likely expired and been removed.                                                                                                                                      |
| `DSAR_DECRYPT_DOWNLOAD_FAILED` | 502  | 502 — an individual encrypted export file failed to download while assembling the decrypted bundle; retry-safe.                                                                                                                                |
| `DSAR_DECRYPT_FAILED`          | 500  | 500 — an export file could not be decrypted, because the encryption key has rotated since the export was generated or the stored file is corrupt.                                                                                              |
| `DSAR_DECRYPT_TOO_LARGE`       | 413  | 413 — the combined decrypted bundle is too large to assemble in one response; download the per-file signed URLs individually instead.                                                                                                          |
| `RMD_NOT_FOUND`                | 404  | 404 — no Robocall Mitigation Database (RMD) registration exists for this organization; create one with POST /compliance/rmd first.                                                                                                             |
| `RMD_INVALID_TRANSITION`       | 409  | 409 — the requested RMD lifecycle action (submit / certify / remediate / resolve / withdraw) is not allowed from the registration's current status.                                                                                            |
| `RMD_LOCKED`                   | 409  | 409 — the RMD registration is in a submitted/certified state and cannot be edited in place; use the lifecycle endpoints (submit / certify / remediation / resolve / withdraw) instead.                                                         |
| `RMD_INCOMPLETE`               | 409  | 409 — the RMD registration cannot be submitted yet because required fields are missing; error.details lists the outstanding blockers.                                                                                                          |
| `RESIDENCY_LOCKED`             | 409  | 409 — PUT /compliance/data-residency refused to change the pinned residency region because the current configuration is locked and the transition is not permitted.                                                                            |
| `RESIDENCY_NOT_ENFORCED`       | 409  | 409 — the residency region must be pinned and enforced (PUT /compliance/data-residency with enforced=true) before it can be locked.                                                                                                            |
| `RESIDENCY_REGION_UNAVAILABLE` | 409  | 409 — PUT /compliance/data-residency refused to enforce the requested residency region because that region's storage boundary is not provisioned on the platform (not in the available-regions allowlist); the region may be pinned advisory-… |
| `ARCHIVAL_CHANNEL_NOT_ENABLED` | 409  | 409 — POST /compliance/archival/export refused the run because the requested channel is not enabled in the tenant's archival policy (or archival is not enabled at all); enable it via PUT /compliance/archival first.                         |
| `RESIDENCY_NOT_FOUND`          | 404  | 404 — no data-residency configuration exists for this organization.                                                                                                                                                                            |
| `TRACEBACK_NOT_FOUND`          | 404  | 404 — no ITG (Industry Traceback Group) traceback case with that id exists for this organization.                                                                                                                                              |
| `TRACEBACK_INVALID_TRANSITION` | 409  | 409 — the requested traceback case transition (e.g. acknowledge) is not allowed from the case's current status.                                                                                                                                |

## Campaigns / Journeys

| Code                           | HTTP | Description                                                                                                                                                                                               |
| ------------------------------ | ---- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `AUDIENCE_TOO_LARGE`           | 400  | 400 — campaign send/schedule refused because the resolved audience size exceeds the per-tenant maximum recipient count from `resolveCampaignAudienceLimit`; split the campaign or use a smaller audience. |
| `ALREADY_ENROLLED`             | 409  | 409 — single-contact journey enrollment refused because the contact already has an `active` enrollment row for this journey campaign.                                                                     |
| `CAMPAIGN_NOT_RUNNING`         | 400  | 400 — single-contact enrollment refused because the target campaign is not in the `running` state.                                                                                                        |
| `CAMPAIGN_TYPE_NOT_ENROLLABLE` | 400  | 400 — single-contact enrollment is only supported for `journey`-type campaigns; the target campaign is a different type.                                                                                  |
| `JOURNEY_VALIDATION_FAILED`    | 400  | 400 — SCAN-CMP-013 journey resume re-validation failed: the stored `journey_definition` no longer passes graph validation.                                                                                |
| `JOURNEY_DEFINITION_INVALID`   | 400  | 400 — the campaign steps payload is not a valid journey graph (nodes/edges missing or unparseable).                                                                                                       |
| `JOURNEY_TRIGGER_MISSING`      | 400  | 400 — the journey graph has no `journeyTrigger` node, so no entry point can be resolved for enrollment.                                                                                                   |
| `JOURNEY_TRIGGER_DISCONNECTED` | 400  | 400 — the journey trigger node has no outgoing edge, so there is no first step to enroll a contact into.                                                                                                  |
| `RESUME_FAILED`                | 500  | 500 — the journey executor threw while resuming a paused journey; the scheduler increments `resume_attempts` and backs off / DLQs.                                                                        |

## Contacts / Imports

| Code                         | HTTP | Description                                                                                                                                                                                                       |
| ---------------------------- | ---- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `IMPORT_NOT_CANCELLABLE`     | 409  | 409 — `POST /imports/:jobId/cancel` (service `cancelImport`) refused: the import job exists but is already in a terminal state (`succeeded` / `failed` / `cancelled`), or it lost the concurrent cancel CAS race. |
| `IMPORT_STILL_RUNNING`       | 409  | 409 — `POST /imports/:jobId/rollback` (service `rollbackImport`) refused: the import is still `pending` / `running`, so it cannot be rolled back yet.                                                             |
| `ALREADY_ROLLED_BACK`        | 409  | 409 — `POST /imports/:jobId/rollback` refused: the import job already carries a `rollback_at` stamp, so the contacts it created were already deleted.                                                             |
| `IMPORT_JOB_NOT_FOUND`       | 404  | 404 — `GET /contacts/imports/:id` status poll found no import job with the supplied id in the caller's tenant schema.                                                                                             |
| `IMPORT_QUEUE_UNAVAILABLE`   | 503  | 503 — async contact-import enqueue (`POST /contacts/imports`) could not hand the job to the import queue (queue / Redis offline).                                                                                 |
| `ERASURE_COOLING_OFF_ACTIVE` | 409  | 409 — `POST /contacts/:id/gdpr/erasure-request` refused because a pending or executing Article-17 erasure request already exists for the contact (partial unique index `uq_gdpr_erasure_requests_active`).        |
| `AI_INVALID_RULES`           | 422  | 422 — `POST /contacts/segments/suggest-rules` (AI natural-language segment builder) refused the LLM-proposed filter rules.                                                                                        |

## CDP public ingest (signed-HMAC track API)

| Code                       | HTTP | Description                                                                                                                                                                                                                      |
| -------------------------- | ---- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `CDP_UNAUTHORIZED`         | 401  | 401 — the public, signed-HMAC CDP ingest endpoint (`POST /cdp/v1/{ingest_id}/{track\|identify\|page\|screen\|group\|alias\|batch}`) rejected the request because HMAC signature, timestamp, or replay-nonce verification failed. |
| `CDP_PAYLOAD_TOO_LARGE`    | 413  | 413 — an inbound CDP ingest payload exceeded the inline byte cap (`CDP_INLINE_MAX_BYTES`, 1 MB).                                                                                                                                 |
| `EVENT_PAYLOAD_TOO_LARGE`  | 413  | 413 — the developer event-ingestion surface refused an event whose `properties` JSON exceeds the \~1 MiB inline ceiling (`CDP_INLINE_MAX_BYTES`, 1024×1024 bytes).                                                               |
| `SCHEMA_VALIDATION_FAILED` | 422  | 422 — a CDP ingest event failed strict-mode JSON-schema validation (the tenant runs event-schema enforcement in `strict` mode).                                                                                                  |
| `TRACKING_PLAN_VIOLATION`  | 422  | 422 — a CDP ingest event was rejected by the tenant's tracking plan running with `enforcement=strict`.                                                                                                                           |

## Co-browse (live screen-share)

| Code                   | HTTP | Description                                                                                                                                                                                                                                    |
| ---------------------- | ---- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `COBROWSE_NOT_ACTIVE`  | 404  | 404 — an agent (`POST /cobrowse/:conversationId/join`, see `apps/api/src/routes/cobrowse/cobrowse.controller.ts`) or a visitor (`apps/api/src/routes/widget/index.ts`) asked to join a co-browse room for a conversation that has no live, jo… |
| `COBROWSE_UNAVAILABLE` | 503  | 503 — the co-browse session was joinable, but the co-browse media token could not be minted because the media service is unreachable or not configured on this deployment.                                                                     |
| `USER_ALREADY_IN_ORG`  | 409  | 409 — a Settings → Team invite was declined because the invited email already belongs to an organization; Orbit seats each user in a single organization, so that person can't accept the invite — ask them to use a different email address.  |
| `ALREADY_ORG_MEMBER`   | 409  | 409 — a Settings → Team invite was declined because the invited email is already a member of your own workspace, so no action is needed — manage that person from the members list instead of re-inviting them.                                |

***

## Handling Errors in Code

### Node.js

```javascript theme={null}
import { Orbit, OrbitApiError } from '@devotel/orbit-sdk'

const orbit = new Orbit({ apiKey: process.env.ORBIT_API_KEY })

try {
  await orbit.messages.send({ channel: 'sms', to: 'invalid', body: 'Hi' })
} catch (error) {
  if (error instanceof OrbitApiError) {
    console.error(`[${error.code}] ${error.message}`)
    console.error(`Status: ${error.status}`)
    console.error(`Request ID: ${error.requestId}`)
  }
}
```

<Note>
  The `Devotel` and `DevotelApiError` aliases are exported for
  compatibility with early-access code but `Orbit` / `OrbitApiError`
  are the canonical names in `@devotel/orbit-sdk` v0.2+.
</Note>

<Note>
  A first-party Python SDK is on the roadmap but not yet shipped. Until
  then, decode the JSON response body and read `meta.request_id` /
  `error.code` / `error.message` directly from any HTTP client.
</Note>

<Tip>
  Always include the `request_id` from the error response `meta`
  when contacting Orbit support. This allows us to trace the exact
  request through our infrastructure.
</Tip>
