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.
unauthenticatedAbsent, malformed, unrecognized, revoked, or expired API key.401insufficient_scopeThe key is valid but does not carry the scope this endpoint declares (03-domain-model.md§Authorization lists the twenty-five).403tenant_suspendedThe credential is good; the tenant is notactive-suspendedorclosed, the only other valuesck_tenants_statusallows (§4).403mobile_rollout_disabledA valid native-device authority or browser PKCE request names a workspace that the deployment master or its explicit tenant mobile-pilot decision does not admit.403mobile_rollout_unavailableThe deployment master is enabled, but the narrow database rollout decision could not be read.503forbiddenThe admin surface is not reachable from this address (IP allowlist, evaluated before authentication), and the generic 403 fallback.403not_foundNo route matches the path.404subscription_expansion_not_foundThe requested upgrade quote does not belong to this workspace.404subscription_expansion_conflictThe upgrade needs commercial/source reconciliation, another purchase holds ownership, or the request key names a different target.409subscription_expansion_unavailableBilling is unconfigured or the provider could not verify the upgrade price.503method_not_allowedThe path exists; the method does not.405conflictGeneric conflict fallback for a framework-raised 409.409rate_limitedToken bucket exhausted for this key.429request_failedFallback for any other framework-raised HTTP error, so no response escapes without a code.as raiseddatabase_unavailableThe API started without a database connection.503telephony_unavailableNo live telephony provider is configured in this deployment.503internal_auth_unavailableThe/internalservice credential is not configured, so the voice runtime cannot be authenticated.503admin_auth_unavailableThe staff plane is not configured in this deployment, so/admincannot authenticate anyone.503
9.2 Request shape: validation, filtering, pagination, idempotency
invalid_requestBody or query failed contract validation.422invalid_filterAn unsupported field, operator, or value in a filter query param (§1 Filtering).400invalid_cursorThecursorwas not a verbatimnext_cursorfrom a previous response.400idempotency_key_requiredThe endpoint requiresIdempotency-Keyand none was sent - the two where a duplicate costs money or dials a human twice (§1).400idempotency_key_invalidThe key exceeds the length ceiling.400idempotency_key_reuseThis key was already used for a different request - another endpoint, or a different body.409idempotency_key_in_flightA request with this key is still running (or died between claiming the key and recording its result), so this one must not perform the side effect a second time.409
9.3 Agents, templates, knowledge packs, voice profiles
agent_not_foundNo agent definition of that id belongs to this tenant.404agent_version_not_foundNo published agent version of that id belongs to this tenant.404agent_use_case_immutableA published agent definition cannot changeuse_case.409voicemail_message_uncomposableThe agent carries avoicemail_configthat composes no message (ADR-0023).409voicemail_callback_unavailableThecallback_e164a voicemail message would name is not an active, voice-capable number assigned to this tenant.409template_not_foundNo platform template of that id.404template_not_publishedThe template exists but isdraftordeprecated, so it cannot be instantiated.409eval_gate_failedPublish is blocked: no completed golden-transcript replay run has passed for this agent's exact current draft hash and revision, the queued/running/latest run did not pass, or the definition changed while publish acquired its lock.409conversation_release_qualification_requiredSales, staffing or recruiting publication lacks three complete passing real-model repetitions for the exact current draft, languages, corpus and resolved provider/model/endpoint.409conversation_evidence_missingA conversation action lacks actual caller-turn evidence or cites a turn the trusted runtime did not supply.422action_confirmation_policy_invalidPublication requested an unsupported owner confirmation policy for this workflow.409objective_scoring_invalidPublish (or a release-gate request) is blocked: one or more objectives carry ascoringblock the survey scorer cannot read - unknown scale, mapping keys outside the scale's answer set,ordinalwithout a matchingpointscount, a scored question with noidor no question text, or duplicate objective ids.409compliance_profile_unresolvedPublish is blocked: the agent names no compliance profile and the tenant has no default, so the version would pin nothing.409knowledge_pack_version_unresolvedPublish is blocked: the named knowledge pack has no compiled version to pin (noneready, or the pinned number does not exist).409receptionist_intelligence_version_unresolvedPublish is blocked: this receptionist owns a structured business-intelligence draft but no current immutable intelligence version.409receptionist_intelligence_not_foundThis receptionist has no structured intelligence document yet.404receptionist_intelligence_requires_receptionistThe requested agent is not areceptionistuse case.422receptionist_intelligence_conflictA concurrent writer created or changed the receptionist's intelligence draft.409receptionist_intelligence_compile_failedThe approved structured facts cannot be rendered into the bounded spoken-knowledge bundle.409receptionist_intelligence_source_limitThe receptionist already has the bounded maximum number of immutable source snapshots.422receptionist_intelligence_source_not_foundThe requested immutable receptionist source snapshot does not belong to this receptionist.404receptionist_intelligence_source_review_conflictThe immutable source snapshot already has an approve/reject decision.409receptionist_intelligence_token_budget_exceededThe approved spoken-knowledge bundle exceeds the profile's tokenizer-measured live budget.422receptionist_intelligence_source_reference_unresolvedAn approved FAQ or business policy cites a source snapshot that does not belong to this receptionist.422receptionist_intelligence_source_reference_not_approvedA cited source snapshot is pending or rejected.422receptionist_intelligence_version_conflictA concurrent intelligence publish claimed the next version number.409receptionist_intelligence_version_not_foundThe receptionist owns an intelligence document, but not the requested immutable version number.404receptionist_release_not_supportedThe release-readiness and rollback surface applies only to an inbound receptionist agent; use the normal agent-version controls for every other use case.409receptionist_release_input_changedA release gate's sealed prompt inputs no longer match the receptionist draft, pinned knowledge, or structured-intelligence version.409receptionist_release_qualification_requiredA receptionist publish has no passing exact live-model preflight or carrier-path canary for its sealed inputs.409receptionist_release_not_qualifiedThe selected immutable receptionist version has not been qualified for live calls (or is draining).409rollback_target_not_foundNo earlier published receptionist version with a still-passing release gate is available for restore.409rollback_target_not_priorA restore target must be an earlier immutable receptionist version; the active version is not its own rollback target.409receptionist_rollback_incompatibleThe chosen healthy version would make a current answering-policy location selector, runtime route, or direct-handoff target unsafe.409rollback_target_not_healthyThe selected prior version no longer has a passing release-gate record, so it cannot be restored automatically.409receptionist_regression_requires_receptionistCustomer-authored release regression cases belong only to a receptionist agent; change or create the agent with thereceptionistuse case first.422receptionist_regression_case_not_foundNo regression case of that id belongs to this receptionist.404receptionist_regression_case_version_not_foundThe named regression case has no immutable revision with that version number.404receptionist_regression_case_limitThe receptionist has reached the bounded number of customer-authored regression cases.422receptionist_regression_case_version_limitThe regression case has reached its bounded append-only revision limit.422receptionist_regression_case_name_conflictAnother regression case for this receptionist already uses that name.409receptionist_regression_case_version_conflictThe case changed after the client read it.409receptionist_regression_case_archivedAn archived regression case cannot be edited.409knowledge_pack_not_foundNo knowledge pack of that id belongs to this tenant.404knowledge_pack_version_not_foundThe pack exists; that version number does not.404knowledge_pack_token_cap_exceededThe compiled pack exceeds the hard token cap owned by08-ai-quality.md.409knowledge_pack_version_conflictA concurrent create claimed the same version number.409knowledge_pack_over_budgetThe upload compiles inside the hard cap but over thebudget_tokensceiling the caller asked for.409knowledge_upload_unsupported_formatThe uploaded document is not one of the accepted formats (pdf, docx, csv, md, txt) - by declared format or by extension.415knowledge_upload_too_largeA document (or the request's document set) exceeds the ingest size limits, before any parsing.413knowledge_upload_encryptedThe document is password-protected.422knowledge_upload_corruptThe bytes are not a readable document of the declared format (invalid base64, a broken archive, non-UTF-8 text, a mislabelled file).422knowledge_upload_no_textThe document parsed but carries no extractable text - an image-only scan is the usual cause, and OCR must run before it can become a pack.422knowledge_upload_extractor_unavailableThis document format cannot be read on this deployment (no PDF extraction backend is installed).501knowledge_tokenizer_unavailableNo tokenizer is configured for ingestion in this deployment, so no honest token count can be produced.503voice_profile_not_foundNo voice profile of that id belongs to this tenant.404voice_profile_revokedA revoked profile can neither accept a new consent proof nor be re-approved; create a new profile and collect consent again.409voice_profile_not_approvedAn agent draft tried to pin a cloned voice whose consent review has not approved it.409voice_sample_invalid_audioPOST /v1/voice-profiles/{id}/sample-recording(or consent upload): the file cannot be used - not decodable, wrong container, not 16-bit PCM mono WAV, under 6 s, over 90 s, or below 16 kHz.422voice_upload_too_largeOne voice upload exceeds the per-file cap (20 MB decoded).413voice_upload_storage_unavailableNo voice-artifact storage is configured on this deployment, so sample/consent uploads are refused before any byte is accepted.503stock_voice_not_foundAdmin console: no stock-voice catalog row has that id - neither in the deploy's seed YAML (inference/tts/voices.yaml) nor among admin-created voices (migration 0066's overlay).404stock_voice_reference_missingAdmin console: no reference clip is stored for that voice.404/409voice_audition_unavailableAdmin console: the staff voice bench is not configured in this deployment.503voice_audition_text_requiredAdmin console: an audition was requested with no sentence to speak.422voice_audition_text_too_longAdmin console: the audition text exceeded the 400-character ceiling.422voice_audition_unreachableAdmin console: the voice runtime did not answer the audition request.502voice_audition_failedAdmin console: the voice runtime refused the audition, or produced no audio for it.502stock_voice_roster_emptyAdmin console: the catalog edit would leave no available stock voice, and agents default onto the roster.409stock_voice_not_deletableAdmin console:DELETE /admin/voices/{id}refuses the effective default - elect another default first.409voice_rights_attestation_stalePOST /v1/voice-profiles: the echoed version/SHA-256 of the Voice Rights & Consent Attestation is not the one this deployment serves - the document changed between render and signature.409voice_consent_proof_requiredApproval was attempted with no stored signed release from the voice owner (§4 review queue).409voice_cloning_withdrawnSelf-serve voice cloning is withdrawn (owner decision, 2026-08-18).410
9.4 Contacts, lists, and imports
contact_not_foundNo contact of that id belongs to this tenant (soft-deleted rows are gone for this purpose).404contact_already_existsA live contact with that E.164 already exists for this tenant; numbers are unique per tenant among non-deleted rows.409contact_owner_not_foundThe requestedowner_user_idis not a user in this tenant.404contact_phone_reconsent_requiredPATCH /v1/contacts/{id}refused a changedphone_e164.409consent_captured_in_futurePOST /v1/contactsreceived a consent capture timestamp after the server's current time.422contact_list_not_foundNo contact list of that id belongs to this tenant.404contact_list_in_useDELETE /v1/contact-lists/{id}refused: a campaign still targets this list.409contact_note_not_foundNo note of that id belongs to that contact in this tenant.404contact_call_not_foundThe optionalcall_idfor a note does not name a call for that contact in this tenant.404import_job_not_foundNo import job of that id belongs to this tenant.404import_too_largeThe uploaded CSV exceeds the per-import size limit.413import_mapping_invalidThe column mapping does not fit the uploaded file.422contact_timezone_unresolvedDialability cannot be answered because the contact has no resolved timezone, and quiet hours are evaluated in the callee's local time.409jurisdiction_unresolvedNo policy set governs this number at all, so there is nothing to enforce and no window can be computed.409jurisdiction_residual_gateA policy set governs this number and names its own hole. Raised byGET /v1/contacts/{id}/dialabilityand byPOST /v1/callswhen the resolved policy carries aresidual_gatenothing has cleared - a requirement the record cannot evaluate: a state registration, permit, bond or message filing (operating_authority); a live-human-first or natural-voice condition (call_architecture); or a fact about the callee we do not hold (evidence).409
9.5 Campaigns, scrubbing, consent, and DNC
campaign_not_foundNo campaign of that id belongs to this tenant.404production_key_requiredCampaign creation, editing, launch, pause, resume, and cancellation, plus a BYO caller-ID/routing mutation, require a post-promotionvcp_live_key.403compliance_profile_not_foundThe campaign named a compliance profile that does not belong to this tenant.404scrub_run_not_foundNo scrub run of that id belongs to this tenant.404telephony_account_requiredNotelephony_account_idwas supplied and the tenant has no default account to fall back to.422scrub_requiredLaunch refused: the campaign has no scrub run covering its target, or the run has not finished.409scrub_expiredLaunch refused: the scrub run has gone stale past itsexpires_at.409scrub_unacknowledgedLaunch refused: the scrub report exists and is fresh but nobody has acknowledged it (§2 Step 4).409agent_not_publishedLaunch, ad-hoc call, or test call refused: the agent has no published version to pin.409call_question_conflictPOST /v1/callsrefused: a per-call question reuses an id the pinned version's objectives already carry.409call_questions_unsupportedPOST /v1/callsrefused: the request carriesquestionsbut the pinned version does not grantrecord_survey_answer, so the answers would have no tool to record them - a silent no-op refused at launch rather than debugged after the call.409draft_session_staleAbrowser_draftvoice-session token was redeemed after the draft changed: the token seals the exact draft content hash minted against, redemption recomputes it, and a mismatch refuses rather than running text the operator did not authorize.409callback_in_pastA requested callback time is at or before now, so there is no future instant to schedule.409callback_too_far_aheadA requested callback time is beyond the booking horizon.409callback_confirmation_conflictThis call already has a durably confirmed callback.409callback_exact_time_unavailableCalling rules would move or dispose the caller-confirmed callback time.409telephony_account_unverifiedLaunch, ad-hoc call, or test call refused: the campaign'sTelephonyAccounthas not passed verification.409outbound_caller_id_requiredAn ad-hoc live call's verified default BYO account has no active, tenant-assigned, carrier-confirmed voice number.409spend_cap_exceededLaunch refused: the tenant has spent its cap for the current period.409spend_state_unknownLaunch refused: the tenant has a spend cap and the period's ledger holds chargeable usage on a meter that reaches an invoice but that itsPlancarries nooverage_ratesentry for, so period-to-date spend cannot be established.409payment_past_dueA new campaign launch or ad-hoc live call is refused once a payment has been outstanding since day 7 of the delinquency ladder (11-billing.md§Dunning).409managed_production_not_availableA campaign launch or ad-hoc live call resolved to amanaged(platform-owned)TelephonyAccount.409campaign_not_launchableThe campaign's current status refuses a launch.409campaign_not_pausableOnly arunningcampaign can be paused.409campaign_not_resumableOnly apausedcampaign can be resumed.409campaign_not_cancellableThe campaign has already finished.409campaign_not_editableThe campaign has finished; its configuration is now history.409voicemail_drop_policy_invalidThe campaign's storedvoicemail_dropdocument cannot be read as a policy, so launch cannot tell whether this program leaves messages.409voicemail_callback_not_in_serviceThe campaign elects a voicemail drop, but the callback number the composed message names is not an active voice number on this campaign's own telephony account with a receiving agent configured.409agent_pin_immutableThe campaign has already launched.409campaign_target_immutableA campaign's target cannot be changed: the scrub run authorizing the launch covers one contact list.409scrub_run_already_acknowledgedThe run has already been acknowledged; acknowledgment records an actor and a moment and is not repeatable.409scrub_run_incompleteAcknowledgment refused: the run has not finished.409scrub_run_expiredAcknowledgment refused: the run has gone stale.409scrub_totals_mismatchThe acknowledged totals do not match the run's.409dnc_scope_not_writableOnlyinternal-scope DNC entries are tenant-writable; the federal and state datasets are platform reference data refreshed by ingestion.403dnc_expiry_not_supportedAn internal DNC entry may not carryexpires_at.422consent_record_not_foundThe revocation names a consent record that does not belong to this tenant.404consent_contact_mismatchThe revocation names a different contact than the record it revokes.409consent_not_revocableThe consent record is notactive, so there is nothing to revoke.409disclosure_text_requiredA PEWC consent record requires the verbatim disclosure text shown to the consumer; PEWC without it is not PEWC.422contact_not_dialableThe number is suppressed and this request would contact it anyway.409
9.6 Calls, analytics, billing, and exports
call_not_foundNo call of that id belongs to this tenant.404receptionist_purchase_conflictA reviewed connection price or subscription source changed, a request key belongs to another purchase, or unfinished work requires reconciliation.409receptionist_purchase_unavailableNew connection purchasing is disabled or billing could not verify the purchase.503receptionist_payment_method_requiredThe verified uncovered connection amount is positive and the customer has no default payment method.402receptionist_purchase_not_foundNo saved receptionist connection purchase of that ID belongs to this tenant.404receptionist_purchase_pendingSigned Stripe event recovery could not finish the original connection purchase.503inbound_voicemail_not_foundNo inbound voicemail receipt of that id belongs to this tenant.404transcript_unavailableThe call exists but has no transcript - it never reached conversation, or post-processing has not finalized.404recording_unavailableNo safely playable recording exists for this call - the consent basis in force did not permit one, its retention window has closed, or its retained artifact is temporarily unavailable.404recording_url_signing_unavailableThe recording exists and is retained, but object-storage URL signing is not wired in this deployment, so the302cannot be issued.501analytics_window_unboundedstartandendare both required.400analytics_window_invalidendmust be strictly afterstart; the window is half-open[start, end).400analytics_window_too_wideThe window exceeds the per-report ceiling (the partition ceiling, §2).400analytics_grouping_too_granularThe requestedgroup_bywould return more buckets than one report may emit.400usage_window_too_wideTheoccurred_atwindow on the usage ledger exceeds the per-page ceiling.400subscription_not_foundThis tenant has no subscription.404subscription_inactiveThe subscription is not in a state that permits the request: on campaign launch, the mirrored Stripe subscription isunpaidorcanceled, so new launches refuse immediately (past_dueis different - it follows the documented seven-day dunning grace beforepayment_past_dueblocks launches; existing conversations are never terminated by this gate); onPUT /v1/subscription/extra-sessionsandPUT /v1/subscription/receptionist-connections, any status outsideactive/trialingrefuses the add-on change until billing is resolved.409wallet_not_foundThis tenant has no wallet, so it has no budget to read or set.404subscription_existsPOST /v1/subscriptionon a tenant that already has one (uq_subscriptions_tenant_id).409subscription_provisioning_pendingA priorPOST /v1/subscriptionhas a durable operation but its first Stripe outcome is unknown.409subscription_provisioning_reconciliation_requiredDurable local and Stripe evidence is incomplete or contradictory, so the operation is frozen for billing review.409plan_not_purchasableThe published plan exists but carries nostripe_price_id, so nothing can bill through it.409plan_metered_prices_unwiredThe plan's base-fee Price is wired but its metered Prices are not, so a subscription opened on it would invoice the base fee and never rate a single forwarded charge.409plan_catalog_unavailableThe published plan catalog is not provisioned in this deployment (migration 0028 seeds it; 0055 reshapes it to the ADR-0022 card), so no subscription can resolve a plan.503extra_sessions_not_purchasableExtra concurrent sessions have no Stripe price in this deployment:VOCAPABLE_STRIPE_EXTRA_SESSION_PRICE_IDis unset, so the $200/mo add-on cannot bill.409extra_sessions_not_applicableThe plan includes no concurrent outbound sessions, so the $200/mo add-on has nothing to extend: raised byPOST /v1/subscriptionandPUT /v1/subscription/extra-sessionsfor a positive target on a plan whoseconcurrency_limitis 0 - thereceptionistclass today.409extra_sessions_update_unconfirmedThe capacity operation is saved, but its provider outcome is not fully confirmed.502extra_sessions_update_failedThe current provider subscription could not be safely verified before dispatch, or Stripe definitively refused the original session change.502receptionist_not_purchasableThe AI receptionist's two licensed Prices are not both wired in this deployment:VOCAPABLE_STRIPE_RECEPTIONIST_BASE_PRICE_ID(the first connection) orVOCAPABLE_STRIPE_RECEPTIONIST_CONNECTION_PRICE_ID(each additional one) is unset, so inbound answering connections cannot bill.409receptionist_connections_update_unconfirmedStripe did not answer the subscription-item update, so whether the connection change applied is unknown.502receptionist_connections_update_failedStripe definitively refused the connection change.502receptionist_connections_charge_declinedThe prepaid first month of the connections being added could not be collected, definitely: the tenant has no saved payment method on the Stripe customer, the instrument refused, or the PaymentIntent came back in a terminal non-success state.402receptionist_connections_charge_authentication_requiredThe prepaid first month could not be collected because the card's issuer demands Strong Customer Authentication (3-D Secure and its equivalents): the instrument was not refused and there is nothing to replace, and no off-session request can perform the challenge.402receptionist_connections_charge_unconfirmedThe prepaid month's payment may or may not have been taken: Stripe did not answer, answered a success the adapter cannot parse, answered about a charge whose customer/amount/currency this request does not recognize, or reported the PaymentIntent asprocessing- a delayed instrument such as an ACH debit that has not settled.502receptionist_connections_racedAnother writer movedsubscriptions.receptionist_connectionswhile this request was deciding, so the compare-and-set inset_receptionist_connectionsrefused and nothing local changed.409commercial_status_collection_method_unsafeRaised byPATCH /admin/tenants/{id}/commercial-status(actiontenant.commercial_status.set) on a transition tocompedwhile the tenant's Stripe subscription is stillcharge_automaticallyand/or its Stripe customer still carries a default payment method.409collection_method_update_failedPUT /admin/tenants/{id}/collection-methodsaved the authorized change, but fresh Stripe reads do not yet prove completion.502collection_method_change_conflictAnother capacity purchase, upgrade, or collection-method change owns this subscription; the request key names a different target; or the saved source no longer matches.409credit_note_payment_pendingRaised byPOST /admin/invoices/{id}/credit-note(actionbilling.credit_note.issue) when Stripe refuses credit-note creation because apayment_intentis pending on the open invoice.409credit_note_already_issuedThe same route against an invoice that already carries a credit note in thecredit_notesmirror.409credit_note_not_compedThe same route against an invoice whose tenant'scommercial_statusis notcomped(nor aninternal/trialarrangement that credits).422credit_note_issue_unconfirmedThe same route when Stripe did not answer the credit-note creation - a transient or timeout class, not a definite refusal.502prepaid_deposit_unsignedRaised byPOST /admin/tenants/{id}/prepaid-deposit(actionbilling.prepaid.deposit.record) when the deposit'sorder_acceptance_idnames noagreement_acceptancesrow belonging to this tenant - a deposit that would cite paper this counterparty never signed.422invoice_not_prepaidRaised byPOST /admin/invoices/{id}/settle-out-of-band(actionbilling.invoice.settle_out_of_band) against an invoice whose tenant's in-forcesubscription_terms.deal_shapeis notprepaid.422deferred_balance_insufficientThe same route when the tenant's remaining deferred-revenue balance (sum(deposits) - sum(settlements)) does not cover the invoice'samount_remainingin full.409settle_out_of_band_unconfirmedThe same route when Stripe did not answer the invoice re-read or thepay_invoice_out_of_bandcall - a transient or timeout class, not a definite refusal.502subscription_terms_overlapRaised byPOST /admin/tenants/{id}/subscription-terms(actionbilling.subscription.terms.write) when the requestedvalid_from- or a back-dated correction - lands inside a validity range that already exists for this tenant.409subscription_terms_unsignedThe same route with acustom,comped, orprepaidterms row carrying noorder_acceptance_id(ADR-0035 d1 putprepaidin the acceptance-required branch - a prepayment is a negotiated commitment with a counterparty).422subscription_terms_below_floorThe same route with aminute_rate_minorbelow the $0.05/min publishable floor (CANON 124) on a row carrying neither an explicit owner approval reference (thefloor_approval_refcolumn) nor apricing_memo_ref.422related_party_consent_missingAsubscription_termsrow carryingrelated_party = truewas written, signed or activated with no recorded reference to an executed Conflict Disclosure and Consent Letter.409design_partner_conversion_notice_missingAn operator tried to end a Comped Period - stop the Design Partner Credit and convert the tenant to the Conversion Price - and either no §6.4 sixty-day notice is recorded for that tenant or the recorded send date is fewer than sixty days before the requested Conversion Date.409invoice_write_off_not_permittedbilling.invoice.write_offinvoked against an invoice whose tenant'scommercial_statusiscompedorinternal.409invoice_not_open_for_out_of_band_paymentbilling.invoice.mark_paid_out_of_bandinvoked against an invoice that is notopen- draft, void, uncollectible, or already paid.409promotional_grant_no_metered_itemsbilling.promotional_credit.grantrequested for a subscription carrying no metered items for the grant to apply to.409portal_subscription_update_unavailablePOST /v1/billing/customer-portalwithflow="subscription_update"now directs all plan and connection changes to Vocapable Billing for quote review and confirmed purchase.409subscription_unmanagedPUT /v1/subscription/extra-sessionsorPUT /v1/subscription/receptionist-connectionson a subscription that carries no Stripe reference (a dev-seeded or externally provisioned row), so there is no subscription item to change.409stripe_customer_missingThe tenant has no Stripe customer to subscribe or to credit.409stripe_subscription_missingThe tenant has a local subscription but it has no Stripe subscription id (for example, a dev-seeded or externally provisioned row).409subscription_cancellation_review_requiredHosted cancellation requires an identified Stripe subscription and effectivemtmterms.409billing_portal_unavailableStripe Billing Portal is unavailable.502 / 503stripe_subscription_failedStripe definitively refused the subscription.502stripe_subscription_incompleteStripe answered with a subscription carrying no item billing period, which the pinned API version places on the items.502stripe_credit_failedStripe refused the $49 sandbox credit (ADR-0008).502stripe_read_failedRaised onPOST /stripe/webhookonly, and its audience is Stripe rather than a customer: an inbound invoice or subscription event could not be re-read from Stripe because Stripe did not answer.503export_job_not_foundNo export job of that id belongs to this tenant.404invalid_export_columnsOne or more requested columns are not exportable for that resource;errors[]names each.422export_too_largeThe extraction would exceed the per-job row cap.422api_key_not_foundNo API key of that id belongs to this tenant.404key_mode_escalationPOST /v1/api-keyswithmode: "live"from a test key.403unknown_scopePOST /v1/api-keysnaming a scope outside the catalog (03-domain-model.md§Authorization).422voice_session_unavailablePOST /v1/agents/{id}/voice-session: no browser voice-runtime endpoint is configured in this deployment (VOCAPABLE_VOICE_RUNTIME_BROWSER_URL), so there is no socket to connect to.503voice_profile_missingPromoted from §9.9 (2026-08-11): the pinned agent version carries no voice, so there is nothing to speak with.409disclosure_opener_missingPromoted from §9.9 (2026-08-11): the pinned agent version carries no AI-disclosure opener.409llm_chain_unresolvablePromoted from §9.9 (2026-08-11): no link in the agent's LLM routing chain is reachable from this deployment, so the session would connect to a pipeline with no model.503runtime_plane_unavailablePromoted from §9.9 (2026-08-11): the session-token keyring and LLM provider catalog are not wired, so no session token can be minted or redeemed.503sandbox_session_in_progressPOST /v1/agents/{id}/voice-session: this account already holds its allowed number of open in-browser sessions.409sandbox_session_limit_reachedThe per-account in-browser session budget for the current window is spent.429sandbox_ip_limit_reachedThe same budget, counted per source address rather than per account - the ceiling that stops one network minting sessions through many accounts.429sandbox_capacity_unavailableNo sandbox capacity right now.503sandbox_admission_unavailableThe conversation-slot registry this deployment started with cannot hold lane reservations, so sandbox sessions have neither a per-account concurrency ceiling nor a platform one.503agent_chat_unavailablePOST /v1/agents/{id}/chat: no configured LLM provider can serve a chat turn - the provider catalog (VOCAPABLE_LLM_PROVIDERS_JSON) is absent, or it resolves none of the draft's route and carries no reachable default.503assisted_setup_unavailablePOST /v1/agents/{id}/setup-chat:VOCAPABLE_ASSISTED_SETUP_PROVIDERis unset, so the interviewer has no model to run on.503chat_daily_limit_reachedThe workspace's daily chat-turn budget is spent.429chat_ip_limit_reachedThe hourly per-address chat budget is spent - the ceiling that stops one network chatting through many keys.429chat_turn_limit_reachedThe posted conversation exceeds the draft'sguardrails.max_turns(or the platform default).409chat_guardrails_unenforceableThe draft'sblocklist_patternscannot be compiled into the Layer-2 screen (an invalid or oversized regex), so a chat turn cannot be screened the way a call would be.422chat_upstream_failedEvery link in the resolved chain refused before streaming began.502human_rep_not_foundNo human-rep destination of that id belongs to this tenant.404rep_group_not_foundNo human-rep group of that id belongs to this tenant.404rep_destination_in_useThe tenant already configured that E.164 handoff destination.409rep_group_name_in_useThe tenant already configured a group with that name.409rep_user_not_foundThe optional linked portal user is not active in this tenant.422human_rep_not_availableThe rep is inactive or has transfers disabled, so it cannot publish a manual availability advertisement.409handoff_targets_unconfiguredPublish refused because the draft grantstransfer_to_humanbut has no immutable direct-rep target snapshot.409handoff_targets_unavailablePublish refused because at least one rep in the draft's frozen direct-rep target list is no longer active or transfer-enabled.409funding_amount_out_of_rangePOST /v1/billing/prepaid/funding-intentsnamed an amount below or above this deployment's declared manual-funding range.422prepaid_calling_requires_active_subscriptionManual prepaid credit is available only after this tenant has an active or trialing production subscription.409funding_idempotency_conflictThe supplied manual-funding idempotency key already names a different amount or currency.409funding_intent_expiredThe hosted Checkout page for this local manual-funding intent expired.409checkout_failedStripe refused creation of the hosted manual-funding Checkout Session.502checkout_response_invalidStripe answered Checkout creation without a usable hosted URL or with a customer that does not match the tenant's local Stripe customer.502funding_intent_conflictA Stripe Checkout Session could not be durably attached to its local manual-funding intent.409auto_fund_unavailableAutomatic prepaid funding is feature-disabled, Stripe is not wired, or the deployment lacks a safe hosted return origin.503auto_fund_amount_out_of_rangeThe requested automatic amount or calendar-month cap falls outside the authoritative bounds returned byGET /v1/billing/prepaid/auto-fund; no SetupIntent page or PaymentIntent was opened.422auto_fund_requires_active_subscriptionAutomatic prepaid funding is available only to an active or trialing production subscription.409auto_fund_idempotency_conflictThe supplied setup idempotency key already records different customer-approved threshold, amount, cap, or consent terms.409auto_fund_setup_pendingThe previous setup operation cannot safely be reused or attached.409auto_fund_setup_failedStripe refused or returned an unusable hosted SetupIntent Checkout page.502
9.7 Telephony accounts, phone numbers, and pools
telephony_account_not_foundNo telephony account of that id belongs to this tenant.404credentials_not_acceptedcredentialswere supplied on amanagedelection.422telephony_credentials_missingVerification was requested on an account with nothing stored to verify.409telephony_verification_unsupportedThe account's carrier has a registered adapter that can place calls but cannot answer the two onboarding reads - prove a credential pair, prove a number is the account's.503telephony_account_not_activeThe named telephony account exists and is notactive- it was suspended or removed from service - so no call may resolve a carrier through it.409telephony_credentials_rejectedThe carrier refused the stored credentials.400telephony_credentials_unavailableThe token vault that holds this account's carrier credentials is not configured in this deployment, so they cannot be read.503telephony_provider_unsupportedThe account names a carrier this build registers no adapter for.503telephony_provider_not_conformantThe account names a carrier whose adapter exists but whose conformance gate is not green on the current build - offline Tiers 0–4 red in CI, or the Tier 5 live observation older than a quarter (22-carrier-integration.md§1.1).503telephony_capability_unsupportedA tenant elected a lane the resolved carrier's adapter declares it cannot perform - principally the ADR-0023 voicemail-drop lane on an adapter declaringamdbelow themessage_endrung.409telephony_verification_unavailableNo verification transport is wired in this deployment, so a carrier account cannot be proven.503telephony_number_lookup_unavailableThe carrier's number-inventory lookup is not reachable from this deployment, so ownership of the caller ID cannot be confirmed.503telephony_number_not_ownedThe caller ID is not in the carrier account's own inventory.409telephony_vault_unavailableThe token vault is not configured, so carrier credentials can neither be stored nor read on/v1/telephony-accounts.503telephony_resolver_unavailableNo carrier resolution plane is composed in this deployment, so a telephony account cannot be turned into a live provider.503inbound_voice_webhook_not_readyThis account is not a verified BYO Twilio account with vaulted credentials, so no inbound-Voice webhook URL is published for it.409inbound_voice_callbacks_unavailableThe signed inbound-Voice callback plane is not fully composed: it needs the credential vault, stable public base URL, session-token signing plane, LLM catalog, and Media Streams URL before a customer can copy a webhook URL.503inbound_voicemail_callbacks_unavailableThe number cannot be switched to inbound voicemail because this deployment lacks its signed callback/import plane: credential vault, stable public origin, private recording store, and enabled importer.503phone_number_not_foundNo phone number of that id (or E.164) is visible to this tenant.404phone_number_existsThat E.164 is already on the platform.409phone_number_not_assignableThe number cannot be put into service: it is already in service, or it is being released and must rest first.409phone_number_not_assignedThe operation needs a number in service under this tenant: releasing one that is not in service, or adding platform inventory to a pool.409inbound_voice_number_not_eligibleA non-null inbound route requires an active, assigned, carrier-confirmed voice number on this tenant's verified BYO Twilio account.409inbound_voice_agent_not_readyThe selected receiving agent does not belong to this tenant or has no published immutable version.409inbound_voicemail_policy_not_eligibleThe selected published receiving agent does not carry the one-party recording policy required for inbound voicemail.409answering_policy_not_foundThe number is visible to this tenant but carries no answering policy.404answering_policy_agent_not_readyPUT /v1/phone-numbers/{number_id}/answering-policynames an agent in anaistep that does not belong to this tenant or has no published immutable version.409answering_policy_location_not_readyAnaistep names a stable location reference that the agent's current immutable receptionist-intelligence version cannot resolve.409answering_policy_rep_not_readyPUT /v1/phone-numbers/{number_id}/answering-policynames a rep in aring_humansstep that is not an active, transfer-enabled rep of this tenant.409receptionist_location_unavailableCarrier ingress found that a policy-sealed location selector no longer compiles against the exact intelligence version the selected agent pins.409number_pool_not_foundNo number pool of that id belongs to this tenant.404number_pool_member_existsThat number is already a member of this pool.409verified_number_not_foundNo verified-number registration of that id belongs to this tenant.404verified_number_existsThe number already has a live (pendingorverified) registration for this tenant.409verified_number_not_pendingThe check named a registration with no code awaiting confirmation - it is alreadyverified, orexpired/revokedand must start over.409verified_number_code_invalidThe presented code does not match.409verified_number_code_expiredThe one-time code's window has closed; the registration is nowexpired.409verified_number_attempts_exhaustedToo many wrong codes; the registration is nowexpired.409verified_number_delivery_unavailableNo messaging provider is composed in this deployment to deliver the one-time code to the number, so registration refuses rather than minting a code nobody can receive.503test_call_destination_not_verifiedThe test call'stois not a currentlyverifiedVerifiedNumber of this tenant -pendingis a registration, not proof, andexpired/revokedno longer count.409test_call_cap_exceededThe per-tenant daily Platform Test Call volume cap is spent (CANON 120): counted per UTC day over campaign-less non-mock attempts.409
9.8 Messaging, calendar, and webhooks
message_template_not_foundNo message template of that id belongs to this tenant.404message_template_existsA template of that name and locale already exists.409message_template_not_activeThe template exists but is notactive, so it cannot be rendered into a send.409message_template_body_invalidThe template body carries a malformed placeholder.422template_variables_invalidThe supplied variables do not match the template's declared set.422phone_number_not_sms_capableThe sending number does not carry thesmscapability.409sms_delivery_failedThe carrier refused this specific message and retrying changes nothing - an unreachable landline, a handset that replied STOP, a number that cannot receive SMS.502sms_delivery_unavailableThe message could not be sent: the platform's vaulted messaging credential is missing or incomplete, or a carrier fault interrupted the send.503a2p_registration_missingA2P 10DLC registration is incomplete on the sending number'sTelephonyAccount.409webhook_endpoint_not_configuredThis tenant has no webhook endpoint yet (PUT /v1/webhook-endpointcreates it).404webhook_target_not_foundNo custom-webhook target of that id belongs to this tenant.404webhook_target_existsA target with thatwebhook_idis already registered.409webhook_target_name_reservedThewebhook_idnames a platform tool.422webhook_target_schema_invalidThe target's argument schema uses a construct the shared validator (vocapable_contracts.toolschema) does not enforce, or renders over the per-target prompt budget.422webhook_target_url_invalidThe target URL is outside the delivery policy: not absolute https (plain http is allowed only forlocalhost/127.0.0.1outside production), carries userinfo, or - in production - is a private, link-local, loopback, or otherwise non-global IP literal.422calendar_integration_unavailableDirect Google Calendar OAuth is not configured in this deployment.503calendar_not_connectedThe tenant has no active calendar connection, or its stored grant is gone from the vault.409calendar_reconnect_requiredGoogle no longer accepts the stored grant or required calendar access.409calendar_slot_unavailableThe slot changed after availability was checked.409booking_outside_bookable_hoursPOST /v1/calendar/eventsnamed a time the tenant's bookable-hours policy does not admit - outside its open weekday windows, inside its minimum lead time, or past its booking horizon (migration 0079).409calendar_provider_unavailableGoogle timed out, rate-limited the request, or returned a 5xx.503calendar_provider_errorGoogle refused or malformed this calendar request.502invalid_oauth_stateThe OAuth callback'sstatedid not verify - forged, expired, or minted for a different provider family.400oauth_consent_deniedThe customer's admin declined consent at the provider.400appointment_conflictThat external calendar event is already recorded against a different call, so recording it again would double-book one booking across two calls.409
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.
idempotency_key_requiredA mutating tool call arrived without an idempotency key.400voice_profile_missingThe pinned agent version carries no voice.409disclosure_opener_missingThe pinned agent version carries no AI-disclosure opener.409llm_chain_unresolvableNo link in the agent's LLM routing chain is reachable from this deployment.503runtime_plane_unavailableThe runtime plane is not configured in this deployment.503session_token_refusedThe call-session token is not redeemable.401realtime_token_refusedA private realtime gateway capability is forged, expired, malformed, wrong-audience, or already spent.401call_context_not_foundNo launched call context matches this token.404live_call_session_conflictThe token redeemed, but its pre-minted call identity could not be bound one-to-one to tenant-owned live-session state.409slot_registry_unavailableThe three-level concurrency semaphore is not configured in this deployment, so no call can be admitted against it.503slot_lease_unrecognizedThe presented lease id was not minted by this control plane.422slot_lease_unencodableThe registry admitted the call but returned no portable lease token, so the runtime would have nothing to release with.503fleet_node_not_enrolledA node heartbeat named a node with no enrolled fleet record, or one whose advertised slot ceiling is invalid.404fleet_cell_unavailableNo fresh, healthy, non-draining voice cell has spare capacity and the required immutable model/voice artifacts, so no placement could be leased.503fleet_placement_unavailableFleet routing is enabled but no placement coordinator (and, for inbound, no receptionist lane/entitlement source) is composed on this replica, so a session cannot be placed atomically.503fleet_cell_lease_inactiveA placement-lease renewal named a lease that was already released or expired, so it cannot be renewed.409inbound_voice_session_unavailableA signed inbound Voice webhook could not obtain a durable receipt after collision-safe retries, so no Media Streams token was returned.503inbound_voicemail_session_unavailableA signed, lawfully eligible inbound voicemail callback could not obtain a durable receipt after collision-safe retries, so no recording TwiML was returned.503call_contact_requiredThe requested tool needs the call's contact, and the call has neither one nor a signed inbound caller receipt from which the deterministic DNC path can resolve its ANI.422call_contact_mismatchAn in-call opt-out named a contact that disagrees with the durable signed inbound receipt.422tool_not_server_sideThat tool is not executed by the control plane.400tool_dispatch_unavailableNo backing operation is wired for that tool in this deployment.501tool_arguments_invalidTool arguments do not match the backing operation's schema.422conversation_evidence_invalidCaller-turn evidence supplied with a message fails validation.422idempotency_key_reusedThe same idempotency key was presented with different arguments.409tool_call_in_flightAn identical tool call is still running; the retry is racing the original.409action_confirmation_policy_unsupportedThis runtime does not advertise support for the published version's immutable confirmation policy.409action_confirmation_requiredA strict action lacks valid runtime confirmation bound to the exact choice and complete caller sources, or uses an unsupported alternate tool.422action_confirmation_reusedThis caller confirmation already recorded different durable facts.409teardown_invalidThe call-teardown payload is not internally consistent.422teardown_confirmation_binding_invalidThe teardown's agent version or draft definition and contact do not match the owner-pinned live call, or a strict call lacks that binding.422telephony_callback_refusedThe request is not a verifiable callback for this telephony account.403telephony_callbacks_unavailableThe telephony callback plane is not configured in this deployment.503handoff_callbacks_unavailableThe direct-rep handoff callback plane is not configured in this deployment.503realtime_gateway_unavailableThe separately deployed live-listening gateway/capability signer is not configured.503live_listen_unavailableThe call has no currently lawful listener source: it must be an active phone leg with a confirmed monitoring disclosure and an unexpired realtime-source lease.409realtime_disclosure_refusedA runtime tried to mark live-monitoring consent with text other than the immutable required all-party disclosure.409inbound_sms_callbacks_unavailableThe signed inbound-SMS callback plane has no credential vault or public base URL in this deployment, so the platform neither publishes a webhook URL nor tries to verify an incoming carrier request against a guessed origin.503inbound_sms_webhook_not_readyThe requested account is not a verified BYO Twilio account with vaulted credentials.409call_status_unrecognizedThe callback reports a call status this platform does not model.422amd_verdict_unrecognizedThe callback reports an AMD verdict this platform does not model - refused for the same reason.422amd_message_end_unsupportedThe asynchronous AMD callback carries a message-end verdict.422answer_callback_unavailableThis replica cannot serve the voicemail-drop answer webhook: the webhook mints the call's own session token and points it at the Media Streams endpoint, and neither the session keyring nor the stream URL is wired on this process.503telephony_minutes_untimeableThe completion callback carries no usable event timestamp, sotelephony_minutescannot be derived from it.422admin_reason_requiredA mutating/admincall arrived with noreason, or one shorter than 8 characters.422admin_action_forbiddenThe staff principal is authenticated and allowlisted, but none of its live roles holds the action this route declares (19-admin-action-catalog.md§6).403admin_step_up_requiredThe action requires a fresh proof of presence and the current one is absent, stale, or bound to a different session.403admin_second_approver_requiredThe action is under dual control and carries no approval from a second, different staff user.403admin_second_factor_requiredThe staff session authenticated but has not proved a second factor (ADR-0024, amending ADR-0017 decision 6).403admin_second_factor_refusedA second-factor verification did not succeed.403admin_second_factor_unavailableThis deployment cannot run the factor that was asked for: no email provider for the standard code, no account-security pepper, or (for authenticator enrolment only) no encryption keyring.503admin_totp_already_enrolledAuthenticator enrolment was started, or a set of recovery codes requested, for an account that already has a confirmed authenticator.409admin_totp_not_enrolledAn enrolment confirmation or a disenrolment named an authenticator that does not exist (or was never confirmed).409admin_mutation_unmappedA mutating/adminroute declared no action id.500admin_plane_unavailableThe cross-tenant admin database role is not configured in this deployment, so/adminreads spanning tenants cannot run (adr/0016-admin-database-role.md).503impersonation_read_onlyA non-GETrequest arrived under a read-only impersonation session.403webhook_delivery_not_redrivablewebhook.delivery.redrivewas asked for a delivery that is notexhausted.409
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.
checkout_unavailableThis deployment has no Stripe configuration, so the sandbox fee cannot be collected.503onboarding_incompletePOST /v1/onboarding/activatewas called before the compliance screening admitted the applicant or before the plan step was saved.409validation_failedPATCH /v1/onboardingnamed astepand supplied no answers object of that name.422onboarding_not_foundThe signed-in account has no signup application.404tenant_not_provisionedPOST /v1/onboarding/api-keywas called by a signed-in human whose account carries no tenant yet - the fee is unpaid, or Stripe'scheckout.session.completedhas not landed.409api_key_already_issuedPOST /v1/onboarding/api-keyhas already handed this tenant its first key, and that secret is shown exactly once.409console_access_refusedPOST /v1/auth/console-keywas called by a session whose membership or whose workspace is not active.403production_key_owner_requiredPOST /v1/onboarding/production-api-keyis not being called by the active owner of an active workspace.403production_request_owner_requiredGET /v1/onboarding/production-readiness,POST /v1/onboarding/production-readiness/request, orPOST /v1/onboarding/production-activationis not being called by the active owner of an active workspace.403production_not_readyThe owner tried to activate or request review before every persisted preflight requirement was complete.409production_already_liveThe owner requested review after the onboarding application was alreadylive.409production_application_movedPOST /v1/onboarding/production-activationbegan a clean-pass self-serve activation, but the onboarding application leftpaidbetween the readiness read and the guarded transition (a concurrent activation or staff promotion).409production_no_compliance_profileSelf-serve activation reached the scrub-waiver write but the tenant carries nocompliance_profilesrow to attest against (a corrupted tenant - provisioning writes exactly one and nothing deletes it).409production_not_activatedThe active owner has a provisioned workspace but production activation has not durably put that same onboarding application inliveat theproductionstep.409production_api_key_already_issuedThis tenant's one-time post-activation live-key handoff already succeeded.409webhook_signature_invalidPOST /stripe/webhookcould not verify theStripe-Signatureheader against the configured signing secret - unsigned, wrongly signed, or outside the 300-second replay tolerance.400workload_class_below_floorThe plan selected atPATCH /v1/onboardingsits below the class the compliance screen established for this applicant.422onboarding_closedThe compliance screening for this signup application returnedblockedorneeds_review, and the application is closed.409agreements_requiredThe tenant has not accepted the CURRENT version of every document needed by the surface.403agreement_version_mismatchThe acceptance names a version or content SHA-256 that is not whatGET /v1/agreementscurrently serves.409agreement_draft_unacceptableThe named document still carries theDRAFT - FOR COUNSEL REVIEWbanner and this is production: no tenant may accept a draft (CANON 121).503device_authorization_owner_requiredPOST /v1/onboarding/device-authorizations/approvelacks an email-verified active owner session for an active workspace.403device_authorization_unavailableDevice bootstrap cannot safely construct the configured browser approval URL, or its narrow pairing store could not create a usable request.503device_authorization_invalidThe submitted human code is malformed, absent, expired, consumed, or bound to a different owner/workspace.400device_authorization_grant_refusedThe device code or route-limited grant is malformed, unknown, expired, unapproved, or already spent.400device_first_key_unavailableDevice bootstrap can claim only the never-delivered provisioningDefaultkey.409
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.
invalid_credentialsSign-in did not succeed.401google_signin_unavailablePOST /v1/auth/googlein a deployment with noVOCAPABLE_GOOGLE_SIGNIN_CLIENT_IDconfigured.503google_credential_invalidThe Google ID token did not verify - expired, wrong audience, bad signature, and unknown issuer are one indistinguishable refusal on purpose; the reason goes to the security log.401google_email_unverifiedThe Google account's own email is unverified, so it cannot key a Vocapable account.403email_verification_requiredThe account exists and authenticated, but has not proved its email address, which onboarding requires before it can be started or paid for.403verification_link_invalidThe email-verification token is unknown, already consumed, or past its window.400password_reset_link_invalidThe password-reset token is unknown, already consumed, or past its window.400csrf_token_refusedAn unsafe request carrying the session cookie presented noX-CSRF-Token, or one that is not this session's synchronizer.403csrf_origin_refusedAn unsafe request carrying the session cookie declared anOrigin/Refererthat is not a configured portal origin.403dashboard_auth_unavailableThis deployment cannot verify browser sessions - no account-security secret, or no session verifier composed.503auth_email_unavailableNo email provider, template set, or portal base URL is configured, so a verification or reset link cannot be minted or delivered.503auth_rate_limiter_unavailableThe limiter that bounds sign-in, verification, and reset attempts is not composed, so those endpoints refuse rather than run unbounded.503
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.
account_deletion_unavailableThe session's platform account is missing or notactive, so no account request can be resolved for it.409account_deletion_email_confirmation_requiredPOST /v1/account-deletion/requestswas called on an account that signs in without a password, so a password cannot be the proof.409account_deletion_password_confirmation_requiredPOST /v1/account-deletion/email-confirmationswas called on an account that has a password, so the email link is not its proof.409account_deletion_reauthentication_failedThe password supplied to confirm the request did not verify.403account_deletion_request_settledThis account-deletion request already reached a terminal outcome, so it cannot be re-confirmed.409account_deletion_confirmation_invalidThe one-time email confirmation token is unknown, already spent, or expired (or its account is no longer active).400account_deletion_email_unavailableThe confirmation email cannot be minted or sent - no portal base URL, no email provider, or the send failed.503
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.
answering_policy_closed_steps_requiredA mobile schedule edit gave a number's answering policy business hours or holiday dates, but the policy carries no closed-step route to answer with when closed.422answering_policy_version_conflictThe answering policy changed after this mobile schedule edit was based on it (optimistic-concurrency mismatch on the policy version).409appointment_not_foundNo appointment of that id belongs to this tenant.404cellular_handoff_unavailableEmergency forwarding remains unavailable until the cellular-handoff feature and a verified destination are in place.409emergency_forward_destination_invalidThe named human rep is not an active, transfer-enabled destination in this tenant, so it cannot be an emergency forward target.422emergency_override_expiry_invalidThe emergency-override expiry must be in the future and no more than 24 hours from now.422emergency_override_version_conflictThe emergency override changed before it could be cleared - the confirmation was for an earlier route.409handoff_booking_in_progressA calendar booking for this handoff is already running.409handoff_booking_not_foundNo handoff booking is available for this handoff and mobile role.404handoff_request_not_foundNo transfer (handoff) request of that id is available to this tenant or mobile role.404idempotency_key_conflictThe mobileIdempotency-Keywas already used for a different task action.409mobile_auth_rate_limiter_unavailableThe limiter that bounds mobile sign-in is not composed, so mobile auth refuses rather than run unbounded.503mobile_auth_unavailableMobile sign-in is not configured in this deployment - no mobile access-token signer, or no safe claimed-HTTPS/iOS-compatibility return URI.503mobile_availability_window_invalidThe availability duration must be in the future and no more than 12 hours from now.422mobile_billing_budget_unavailableThis workspace has no safely editable billable wallet, or its existing guardrail uses a legacy period the app must not relabel.409mobile_billing_budget_version_conflictThe spend guardrail changed after the app loaded it.409mobile_call_ai_agent_unavailableThe agent named for a mobile AI call is not active or has no current published version.409mobile_call_ai_contact_search_too_shortThe Mobile Call AI contact search needs at least two characters; a phone number or email address is not a searchable label.422mobile_call_ai_transport_invalidMobile Call AI could not start on the verified business carrier route.503mobile_capability_forbiddenThe signed-in mobile role does not carry the mobile capability this operation declares.403mobile_feature_disabledThe requested mobile feature is not enabled for this workspace's staged rollout.403mobile_handoff_booking_unavailableThis handoff cannot book a calendar event now: it needs an active carrier-confirmed handoff, a linked live contact, and a connected calendar.409mobile_invitation_delivery_failedThe team-invitation email could not be sent; no invitation was issued.503mobile_invitation_delivery_unavailableTeam-invitation delivery is unavailable - this deployment has no safe portal URL and transactional email sender.503mobile_invitation_expiry_invalidThe invitation expiry must be in the future and no more than 30 days away.422mobile_member_not_foundNo editable team member of that id belongs to this workspace.404mobile_metrics_window_invalidThe receptionist-metricsendmust be strictly afterstart; the window is half-open [start, end).400mobile_metrics_window_too_wideThe requested receptionist-metrics window exceeds the maximum analytics span.400mobile_metrics_window_unboundedReceptionist metrics require a bounded window: provide bothstartandend.400mobile_redirect_uri_refusedThe mobile return URI is not the exact claimed HTTPS or fixed iOS compatibility URI registered for this deployment.400mobile_rep_link_invalidThe selected transfer representative is not an existing rep owned by this workspace and unlinked elsewhere.422mobile_rep_link_requiredThis mobile membership is not linked to a transfer rep.403mobile_self_membership_change_refusedAn admin cannot suspend, revoke, or change their own role from the mobile app.409mobile_step_up_callback_refusedThe mobile step-up return address is not registered.400mobile_step_up_email_confirmation_invalidThe step-up email confirmation link is invalid or expired.400mobile_step_up_email_proof_requiredThis account has no password, so the sensitive change must be confirmed from its verified email.409mobile_step_up_email_unavailableThe step-up email confirmation cannot be minted or sent in this deployment.503mobile_step_up_grant_refusedThe browser step-up confirmation can no longer be used.403mobile_step_up_native_context_refusedThis mobile session can no longer start a confirmation.401mobile_step_up_password_proof_requiredThis account has a password, so the sensitive change must be confirmed by re-entering it - not the email option.409mobile_step_up_payload_invalidThe protected step-up command is malformed.422mobile_step_up_portal_unavailableBrowser step-up confirmation is not configured in this deployment.503mobile_step_up_reauthentication_failedThe step-up password could not be confirmed.403mobile_step_up_request_unavailableThis mobile step-up confirmation is no longer available.404mobile_step_up_requiredA fresh browser step-up confirmation is required for this sensitive change.403mobile_token_refusedThe mobile authorization (native token exchange) is not valid.400mobile_transfer_destination_conflictThat transfer-destination phone number is already assigned to another representative.409mobile_transfer_destination_delivery_failedThe transfer-destination verification code could not be sent; no change is pending.503mobile_transfer_destination_delivery_unavailableTransfer-destination verification delivery is unavailable - this deployment has no platform SMS sender.503mobile_transfer_destination_not_pendingThis transfer-destination verification is not pending.409mobile_transfer_destination_rep_link_requiredLink the active team member to a human transfer representative before setting a transfer destination for it.409mobile_transfer_destination_unavailableAvailability cannot be enabled: no active transfer destination is linked to this team member.409mobile_transfer_destination_verification_not_foundNo transfer-destination verification exists for this team member.404mobile_transfer_destination_verification_replacedThis verification code was superseded by a newer one.409mobile_unauthenticatedThe mobile session is invalid or expired.401mobile_workspace_selection_refusedThe chosen workspace is not one of the active workspaces available to the signed-in account.403mobile_workspace_unavailableNo active mobile workspace is available to this account.409operations_task_assignee_invalidThe chosen assignee is not an active member of this workspace.422operations_task_not_foundNo operations task of that id is available to this mobile role.404operations_task_state_conflictThat task action is no longer available in the task's current state.409operations_task_version_conflictThe task changed before this update (optimistic-concurrency version mismatch).409mobile_change_feed_cursor_invalidThe change-feed position (cursor) is malformed or no longer valid.400mobile_coach_telemetry_role_invalidThe Coach telemetry role does not match the role currently granted to this mobile workspace session.422mobile_notification_test_unavailableThis device is not ready for a test notification - it has no registered push token or is not fully enrolled.409mobile_receptionist_not_publishedThe receptionist has not been published yet, so it cannot be test-called from the Studio.409mobile_receptionist_studio_number_not_foundNo active receptionist line with that identifier belongs to this workspace.404mobile_receptionist_studio_intelligence_agent_invalidThe line-owned target is not a receptionist belonging to this workspace.422mobile_receptionist_studio_intelligence_agent_unavailableThis line has no unambiguous, line-owned receptionist intelligence target, or the requested target is not part of this line's policy.409mobile_receptionist_studio_status_expiry_invalidThe temporary-status expiry must be in the future and no more than seven days from now.422mobile_receptionist_studio_version_conflictThe Receptionist Studio record changed elsewhere (optimistic-concurrency version mismatch).409
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.
caller_request_not_foundNo caller request of that id belongs to this tenant.404qualification_not_foundNo sales or recruiting qualification response of that id belongs to this tenant.404qualification_review_conflictCaller answers or the team review changed.409qualification_review_unavailableThe source answers or pinned company question set cannot be verified.409contact_correction_not_foundNo proposed caller identity correction of that id belongs to this tenant.404contact_correction_conflictThe contact changed, a newer caller statement superseded the proposal, or it already has a final decision.409contact_correction_unavailableThe live contact, allowed identity field, or source evidence cannot support a correction review.409caller_request_version_conflictThe request changed since it was read (optimistic-concurrency version mismatch).409caller_request_invalid_transitionThe requested move is not one the state machine allows: acknowledge applies toopenrequests only, andresolvedis terminal for every edit, assignment included (no reopen in v1 - ADR-0037 records the deferral).409caller_request_assignee_not_foundThe namedassignee_user_idis not a user of this tenant.404
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.