Skip to content

Error registry

Every non-2xx response from the API is an RFC 9457application/problem+json body whose type URI points at a page in this registry at https://docs.vocapable.com/errors/{code}. The code is stable and machine-matchable: a changed meaning is a new code, never a re-pointed one. Branch on the code alone and treat the status as redundant confirmation. How to handle problems: see theerror-handling guide.

Two families of 5xx are worth knowing before you retry anything:503 means this deployment is missing a dependency it needsThe request may succeed later or on another environment. 501means the code path is deliberately unbuilt here and retrying will never help until it ships. Neither is ever the caller's fault.

9.1 Transport, authentication, and tenancy

Raised on every surface, ahead of any resource logic.

9.2 Request shape: validation, filtering, pagination, idempotency

9.3 Agents, templates, knowledge packs, voice profiles

9.4 Contacts, lists, and imports

9.5 Campaigns, scrubbing, consent, and DNC

9.6 Calls, analytics, billing, and exports

9.7 Telephony accounts, phone numbers, and pools

9.8 Messaging, calendar, and webhooks

9.9 Non-customer surfacesInternal surface

The /internal audience (the voice runtime's synchronous calls, authenticated by a service credential) and the telephony provider callbacks are excluded from the customer OpenAPI document and are not part of the public contract. They emit the same problem shape, and their codes are registered here so an operator reading a log line has one place to look.

9.10 Agreements

P1: GET /v1/agreements includes an additive nullable markdown field per document. The current registry supplies the exact UTF-8 source bytes identified by content_sha256, allowing the portal to display every document before its acceptance. Older clients can ignore this field. Acceptance still requires the current version and hash; adding the text does not change any legal document. The click-through legal set (CANON 121; source of truth in legal/, versioning rules in legal/README.md). Numbered after §9.9 only because §9.9's number is load-bearing in cross-references - this is a customer surface.

9.11 First-party accounts and browser sessions (ADR-0017)

The portal's own sign-in. ADR-0017 replaced the hosted IdP with first-party accounts, so these are the codes a browser sees before it holds an API key - and the only consumer codes raised against a cookie credential rather than an Authorization header. Numbered after §9.10 because §9.9's and §9.10's numbers are load-bearing in cross-references. Two properties are deliberate and load-bearing. Sign-in refuses with one body for every reason - unknown email, wrong password, and a disabled account are invalid_credentials alike, because a per-reason message is an account-existence oracle on a surface with no credential to rate-limit against. And an action link refuses with one body whether it was never valid, already spent, or expired, for the same reason: the token travels through a mailbox this platform does not control.

9.12 Account deletion

The verified, non-destructive account-deletion request/status path (/v1/account-deletion), one of the three session-cookie customer surfaces (§1) rather than a key-reachable one. A request opens a reviewable record; it does not erase a workspace or its call, billing, and compliance records. Confirmation is a fresh proof of presence - a password on a password account, a one-time emailed link on a passwordless one - so the code split below is which proof is owed and why one was refused.

9.13 Mobile companion app (receptionist)

The native mobile receptionist app's own surface (/v1/mobile/*): a separate audience authenticated by a mobile access token minted through native universal-link / PKCE sign-in, gated per operation by mobile-role capabilities, with sensitive changes held behind a browser step-up. These codes are raised only against that credential and are not part of the API-key contract; families with a /v1 or /internal near-neighbor (idempotency_key_conflict, mobile_capability_forbidden) are distinct codes on this distinct surface. The Owner Command Center adds six feature-gated, live-only reads/writes: GET /v1/mobile/workspace/overview, GET /v1/mobile/workspace/setup, GET /v1/mobile/workspaces, GET /v1/mobile/billing/summary, PUT /v1/mobile/billing/budget, and POST /v1/mobile/billing/portal. Admins receive the safe billing detail and can change only the spend cap or mint the generic Stripe-hosted browser link after a one-use billing_budget_update or billing_portal_launch proof. Managers receive only capacity/usage/renewal/payment-risk state; Reps receive neither Workspace nor billing state. These endpoints never return Stripe/customer/provider identifiers, payment methods, invoice-host links, or a broad portal route. Feature flags are fixed, tenant-scoped release decisions; a disabled surface remains refused even for an otherwise valid mobile session. POST /v1/mobile/receptionist/numbers/{number_id}/studio/intelligence-snapshots is the narrow bridge from Mobile Studio to the same canonical Receptionist Intelligence review queue. It takes an exact saved Studio revision after the normal mobile write, feature, and browser-step-up checks. The server resolves the direct receptionist or the one unambiguous receptionist AI target in the line's answering policy; an explicit agent_id is accepted only when it is an AI target for that exact line. It serializes only the bounded Studio fact vocabulary into a pending immutable source snapshot. It never changes an answering policy, route, intelligence draft, or published version. A mobile retry of the same snapshot returns the existing review item; a customer must still review, cite, compile, and publish it through the web intelligence workspace before any caller can hear it. A multi-receptionist policy is intentionally resolved in the web control center rather than guessed on mobile.

9.14 Caller requests and the inbox (ADR-0037)

GET /v1/inbox also accepts equality filters agent_id and campaign_id, and created_at.lt for an exclusive upper bound. Existing created_at.lte remains inclusive. Metric links pass the received-period start with .gte and end with .lt; the displayed request lifecycle is its current state, even if resolution happened later. All filters apply before each source's keyset page limit. Assistant attribution follows the stored version, or the appointment's actual saved call. Campaign attribution requires the record's own campaign (callbacks) or an owned saved call and campaign. Sharing a contact never supplies attribution. Pending campaign-less callbacks and inbound voicemail therefore remain visible under their assistant without becoming campaign work. Existing line/version filters and the 30-day default lower bound remain compatible.

Source of truth: vocapable-backend/docs/04-api.md §9 (Error-code registry). This index and every code page are regenerated from it on each build; the build fails if the registry and these pages diverge.