Error codes
Every error the API raises itself has the same JSON shape and a stable machine-readable code. Switch on code, not on message: messages are for people and may be reworded.
{ "error": { "code": "idempotency_conflict", "message": "…" } }- A
429carries aRetry-Afterheader (seconds). - Objects that belong to another account return
404 not_found, never403, so an ID cannot be probed. - Malformed request bodies (a missing field, a wrong type) are rejected by the framework's own validation with
422and adetailarray instead of theerrorobject.
How this page is generated
This page is generated, not written by hand. uv run python -m scripts.gen_errors_doc parses the API source (services/api/app) without running it: it collects every DomainError subclass in app/core/errors.py and elsewhere with its HTTP status and default code, the MANAGEMENT_ERROR_CODES table, and every call that raises one of those classes with an explicit literal code. The meaning column is the API's own message from one place the code is raised (… marks a value filled in at run time); generic codes get a short description instead.
The table covers every API surface, including the dashboard and platform administration. Merchant integrations using an API key mostly see unauthorized, api_key_expired, forbidden, merchant_suspended, not_found, invalid, conflict, idempotency_conflict, order_conflict, rate_limited, pricing_unavailable and platform_paused.
3 raise sites compute their code at run time (a variable rather than a literal); a static scan cannot name those, so they are not listed separately.
All codes
| Code | HTTP status | Meaning | Raised in |
|---|---|---|---|
account_disabled | 401, 409 | This account is disabled | admin, auth, content, operations |
addressing_unavailable | 503 | No receive key configured for … | addresses |
admin_mfa_required | 403 | Enable and verify MFA to use platform administration | admin |
admin_session_expired | 401 | Your administrator session was idle for too long; sign in again | admin |
already_acknowledged | 409 | This amount was already acknowledged. | admin, exceptions |
already_disabled | 409 | This wallet is already disabled. | settlement |
already_frozen | 409 | These funds are already frozen; acknowledging would change nothing. | admin |
already_live | 409 | Live mode is already enabled | compliance |
already_member | 409 | Already a member | auth |
already_recovered | 409 | Case is already recovered | payments |
already_reviewed | 409 | Refund is already … | refunds |
already_staff | 409 | This person is already platform staff | admin |
already_submitted | 409 | Application already submitted and awaiting review | compliance |
amount_mismatch | 422 | This payment link has a fixed amount | invoices |
amount_out_of_range | 422 | Amount must be between … and … USD | invoices |
amount_required | 422 | Enter an amount for this payment | invoices |
api_key_expired | 401 | This API key has expired | auth |
api_key_inactive | 409 | Only an active key can be rotated | dashboard |
approval_required | 409 | … needs a second approver: submit it through POST /admin/commands | admin |
approval_stale | 409 | This approval expired before execution | admin |
artifact_expired | 404 | This export has expired and can no longer be downloaded | dashboard, operations |
artifact_unavailable | 404 | This job has no downloadable artifact | operations |
asset_not_allowed | 422 | This asset is not accepted by this payment link | invoices |
asset_not_available | 422 | Assets not available in …: … | billing, checkout, invoices |
asset_rail_decimals_mismatch | 409 | This native asset declares … decimals but its … rail uses …; correct the row with app.correct_native_decimals, then verify it again | admin |
asset_verification_failed | 409 | On-chain verification did not match this asset's configuration | admin |
asset_verification_unavailable | 422 | Verification was unavailable; activating anyway requires force and a reason | admin |
attestation_required | 422 | Accept the attestation before submitting | compliance |
audience_empty | 409 | No eligible recipient matches this audience | content |
audience_too_large | 409 | More than … recipients | content |
below_minimum | 422 | Amount below minimum for … | checkout |
billing_credit_review | 409 | Your purchase credit covers this price; support must review the upgrade | billing |
billing_live_not_enabled | 503 | Live plan purchases are not enabled yet | billing |
billing_purchase_pending | 409 | Finish the existing plan payment or contact support for its review | billing |
billing_review | 409 | A previous plan payment requires verified recovery | billing |
billing_test_only | 403 | Test payments cannot upgrade a live organization | billing |
billing_treasury_unavailable | 503 | The treasury must not be a deposit address | billing |
billing_unavailable | 503 | Platform billing store configuration is invalid | billing |
binance_ipn_amount | 409 | IPN amount does not match the order | binance |
binance_ipn_malformed | 422 | malformed IPN | binance |
binance_ipn_signature | 403 | invalid IPN signature | binance |
binance_pay_error | 503 | Binance Pay refused the order: … | binance |
binance_pay_unavailable | 403 | Binance Pay is not enabled for this store | binance |
campaign_missing | 409 | The campaign no longer exists | content |
campaign_not_cancellable | 409 | A … campaign can no longer be cancelled | content |
campaign_not_scheduled | 409 | The campaign is …, not scheduled | content |
campaign_not_sendable | 409 | A … campaign cannot be sent | content |
campaign_stale | 409 | The campaign changed after the send was queued | content |
change_request_not_found | 404 | Change request not found | admin |
channel_unsupported | 422 | Campaigns are email only in this release; unsupported: … | content |
client_address_unavailable | 503 | Client address unavailable; try again | auth |
command_result_unsafe | 500 | The command result could not be recorded safely; the change was rolled back. | admin |
concurrent_decision | 409 | Another decision on this item was recorded at the same moment. Reload and check. | admin |
config_block_page_kind | 422 | A '…' block belongs on the '…' configuration page | content |
config_page_sections | 422 | A '…' page carries exactly one '…' block | content |
configuration_required | 409, 422, 503 | … jobs are not available | admin, content, dashboard, operations |
conflict | 409 | The request conflicts with the current state of the object. | core/errors |
connection_disabled | 409 | This connection is disabled | operations |
connection_exists | 409 | An enabled connection already exists for this scope | operations |
content_page_missing | 409 | The scheduled page no longer exists | content |
content_review_missing | 409 | Legal content needs a recorded review of this exact revision before publication | content |
content_schedule_stale | 409 | The pinned revision is no longer this page's scheduled revision | content |
country_not_supported | 422 | Zenq Pay does not currently offer live payments in that country | compliance |
credentials_not_allowed | 422 | Credentials must not be sent in command parameters; reference a candidate revision instead | admin |
csrf_rejected | 403 | A cookie-session request came from an origin that is not allowed. | core |
destination_changed | 409 | This payout is bound to a wallet that is no longer valid (…). It cannot be released to that wallet. | settlement |
destination_confirmation_required | 409, 422 | An authenticated attesting actor is required | refunds |
destination_is_sender | 422 | The destination is the address that paid this invoice. Refunds are never returned to an identified paying sender, even when the address is said to be confirmed. | refunds |
destination_not_pending | 409 | Only a pending (enabled, not yet effective) payout-wallet change can be blocked | admin |
destination_unverified | 422 | Confirm the destination address with the customer before requesting a refund; the sending address is never assumed to be a valid destination (§14) | refunds |
direct_route_required | 409 | announcement.send is applied through POST /admin/announcements/{id}/send; the command facade executes it only from an approved change request | content |
email_taken | 409 | An account with this email already exists | auth |
email_unavailable | 503 | Email delivery is not configured on this server | core |
email_unverified | 403, 409, 422 | Verify your email address before accepting | admin, auth, billing, content, dashboard, operations |
environment_invalid | 422 | environment must be live or test | exceptions |
evidence_changed | 409 | The amount changed since you reviewed it (now … …). Reload the page and decide again. | admin, exceptions |
evidence_configuration_mismatch | 409 | This evidence describes a configuration this asset no longer has: … | admin |
evidence_expired | 409 | This verification evidence has expired; verify the asset again | admin |
evidence_missing | 409 | No verification evidence with that id exists for this asset; verify it first | admin |
evidence_required | 409 | Activation now requires recorded verification evidence. POST /admin/assets/…/verify, then submit the asset.activate command through POST /admin/commands with that evidence_id. | admin |
expected_version_not_applicable | 422 | … has no versioned target; omit expected_version | admin |
expected_version_required | 428 | expected_version is required for this command | admin, operations |
export_too_large | 422 | export exceeds the row limit; narrow the filters | operations |
facade_required | 409 | Resolving an alert now requires an audited reason. Submit the alert.resolve command through POST /admin/commands. | admin, compliance, notifications, status |
field_not_editable | 422 | Not editable by an administrator: … | dashboard |
forbidden | 403 | Authenticated, but this action is not allowed for this account or role. | auth, support |
forbidden_webhook_destination | 422 | Webhook URL host is not allowed | webhooks |
gas_reconciliation_required | 409 | Gas funding requires on-chain reconciliation | settlement |
idempotency_conflict | 409 | Could not reserve the Idempotency-Key | billing, invoices, operations |
idempotency_key_invalid | 422 | Idempotency-Key is too long | operations |
idempotency_key_required | 422, 428 | Express invoices require Idempotency-Key | invoices, operations |
incomplete | 422 | Complete these fields first: … | compliance |
insufficient_approvers | 409 | Enabling two-person approval for … needs … active staff who can approve it; … exist. | admin |
insufficient_scope | 403 | This API key does not have the … scope | auth |
internal_error | 500 | A server-side check failed and the change was rolled back. | core/errors |
invalid | 400, 409, 422 | The request was understood but a value is not acceptable. | content, core |
invalid_action | 422 | Unknown action | admin, exceptions |
invalid_address | 422 | Treasury must not be the platform gas wallet | admin, core |
invalid_amount | 422 | … must be a decimal string | dashboard, invoices, refunds |
invalid_amount_mode | 422 | amount_mode must be 'fixed' or 'customer' | invoices |
invalid_asset | 422 | That asset is not available for this invoice | dashboard |
invalid_assignee | 422 | The assignee must be active platform staff with support permission | support |
invalid_audience | 422 | Unknown sign-in audience | auth |
invalid_body | 422 | Message body must be text | support |
invalid_category | 422 | Category must be text | compliance, support |
invalid_channel | 422 | Unknown channel for … | notifications |
invalid_columns | 422 | Duplicate column '…' | dashboard |
invalid_country | 422 | Country must be an ISO 3166-1 alpha-2 code (e.g. AE) | compliance |
invalid_credentials | 401 | Password is incorrect | auth |
invalid_cursor | 422 | Invalid cursor; restart from the first page | admin, core, dashboard, operations, platform, webhooks |
invalid_decision | 422 | decision must be one of … | compliance |
invalid_email | 422 | Invalid email: … | admin, auth, notifications |
invalid_environment | 422 | environment must be live or test | admin |
invalid_event | 422 | Unknown events: … | notifications |
invalid_event_type | 422 | Unknown event types: … | webhooks |
invalid_filter | 422 | Filter '…' … | admin, dashboard, platform |
invalid_follow_up | 422 | Only a closed ticket is continued by a follow-up | support |
invalid_group | 422 | group must be day or month | admin |
invalid_idempotency_key | 422 | A 1–128 character Idempotency-Key is required | billing, invoices |
invalid_limit | 422 | limit must be between 1 and … | admin, platform |
invalid_link_amounts | 422 | min_usd must not exceed max_usd | invoices |
invalid_mfa_code | 401 | Invalid code | admin, auth |
invalid_month | 422 | month must be YYYY-MM | admin |
invalid_name | 422 | name must be a string | auth, dashboard |
invalid_network | 422 | Unknown network | admin |
invalid_parameters | 422 | Provide either a plan to set or restore_purchased, not both or neither | admin |
invalid_passkey | 401, 422 | Passkey verification failed | auth |
invalid_plan | 422 | Choose Pro or Elite | admin, billing |
invalid_plan_prices | 422 | Elite must cost more than Pro | admin |
invalid_policy | 422 | settlement_review_above must not be below settlement_min_amount | admin |
invalid_precision | 422 | Amount exceeds the asset decimal precision | checkout |
invalid_priority | 422 | Unknown priority: … | support |
invalid_range | 422 | from must be before to | admin, dashboard, webhooks |
invalid_reauth_action | 409 | Unknown reauthorization action | auth |
invalid_reauth_params | 422 | invoice_id must be a UUID | auth |
invalid_reference | 422 | The referenced invoice does not belong to the referenced store | support |
invalid_report | 422 | Unknown report. Choose one of … | admin |
invalid_resource | 422 | Unsupported saved-view resource; use one of … | admin, dashboard |
invalid_role | 422 | Invalid role | admin, auth |
invalid_scopes | 422 | Unknown or empty scopes: … | dashboard |
invalid_screening_date | 422 | The screening date cannot be in the future | compliance |
invalid_screening_list | 422 | Unknown screening list: … | compliance |
invalid_screening_result | 422 | result must be one of … | compliance |
invalid_slack_url | 422 | Slack URL must be at most … characters | notifications, operations |
invalid_sort | 422 | Unsupported sort | dashboard |
invalid_status | 422 | Unknown incident status | admin, support |
invalid_subject | 422 | Subject must be 1-… characters | support |
invalid_title | 422 | title must not be blank | invoices |
invalid_token | 401, 422 | Invalid metrics token | auth, ops |
invalid_transition | 409 | a … job cannot become … | admin, content, operations, support |
invalid_visibility | 422 | Unknown message visibility: … | support |
invalid_volume_band | 422 | Unknown volume band | compliance |
invalid_webhook_url | 422 | Webhook URL must use https | webhooks |
invite_expired | 422 | This invitation has expired | admin |
invite_not_found | 404 | Invitation not found | admin |
invite_pending | 409 | An invitation for this email is already pending | admin |
invite_pending_limit | 409 | Too many invitations are waiting to be accepted; wait for them to be accepted or expire before inviting more people | auth |
invite_rate_limited | 429 | Too many invitations were sent today; try again tomorrow | auth |
invite_revoked | 422 | This invitation was revoked | admin |
invite_used | 409 | This invitation was already accepted | admin |
inviter_revoked | 403 | The person who invited you no longer has authority to add staff | admin |
invoice_expired | 422 | Invoice has expired | binance |
invoice_not_pending | 409, 422 | Invoice is … | binance, checkout, dashboard |
invoice_simulated | 422 | This test payment was simulated: no funds exist to refund | refunds |
ip_not_allowed | 403 | Platform administration is not available from this network address | admin |
job_not_retryable | 409 | This job cannot be retried safely | operations |
last_approver | 409 | … needs … approvers; this change would leave …. Relax the approval policy first. | admin |
last_owner | 409 | The platform needs at least one active owner | admin, organizations |
legal_review_required | 409 | Legal content needs a recorded review of this exact revision before publication | content |
live_not_enabled | 403 | Live mode is not enabled for this merchant (§6 step 8) | dashboard, invoices |
media_busy | 429 | Too many uploads are being processed. Try again shortly. | content |
media_referenced | 409 | This asset is used by … and cannot be deleted | content |
media_rejected | 422 | An uploaded file is not an accepted image. | content |
merchant_daily_volume_limit | 422 | This account's daily live volume limit (… USD) would be exceeded; try again tomorrow (UTC) or contact support | invoices |
merchant_invoice_limit | 422 | Live invoices for this account are limited to … USD each | invoices |
merchant_limit_open_amount | 422 | Open-amount live invoices are not available while this account has invoice limits; set a fixed amount | invoices |
merchant_message_required | 422 | A merchant-facing merchant_message of 10-500 characters is required; the internal reason is never sent to the merchant | refunds |
merchant_monthly_volume_limit | 422 | This account's monthly live volume limit (… USD) would be exceeded; contact support | invoices |
merchant_suspended | 403 | This organization is suspended | billing, invoices |
message_not_plain_text | 422 | The message must be plain text (no HTML tags or entities) | compliance |
message_too_short | 422 | Write at least 10 characters for the merchant | compliance |
mfa_already_enabled | 409 | Two-factor authentication is already enabled | auth |
mfa_enabled | 409 | MFA is already enabled | auth |
mfa_not_enabled | 409 | Enable two-factor authentication first | auth |
mfa_required | 401, 403, 409 | Second factor required | admin, auth, compliance, dashboard, settlement |
mfa_required_for_live | 403 | This organization processes live payments: turn on two-factor authentication for your account to continue | auth |
module_disabled | 403 | This part of the product is turned off for the account or deployment. | core |
module_unknown | 422 | Unknown module: … | platform |
network_not_found | 404 | Network not found | auth, settlement |
no_asset | 422 | No active test asset to simulate with | dashboard |
no_fields | 422 | Provide a status or body to change | admin |
no_organization | 403 | You are not a member of any organization | auth |
no_passkeys | 409 | No passkey is registered on this account | auth |
not_admin | 403 | Platform administrator access required | admin, content |
not_authenticated | 401 | Not signed in | auth |
not_cancellable | 409 | Only pending invoices can be cancelled (this one is …) | exceptions |
not_editable | 409 | Application is …; it cannot be edited | compliance |
not_failed | 409 | Transfer is … | settlement |
not_found | 404 | The object does not exist, or it belongs to another account (never 403). | admin, auth, billing, binance, checkout, compliance, content, dashboard, exceptions, invoices, notifications, operations, ops, refunds, settlement, support, webhooks |
not_frozen | 409 | These funds are not frozen; there is no hold to release. | admin |
not_in_review | 409 | Transfer is … | settlement |
not_reviewable | 409 | Invoice is … | exceptions |
not_submitted | 409 | Application is …, not submitted | compliance |
nothing_left_to_accept | 409 | Everything received on this invoice was refunded. There is nothing left to accept as paid; close the invoice instead. | exceptions |
nothing_to_refund | 409 | No confirmed funds on this invoice to refund | refunds |
operation_unknown | 422 | Unknown operation: … | admin |
option_change_limit | 429 | This checkout has changed payment method too many times; create a new invoice | checkout |
order_conflict | 409 | An Express invoice already exists for this order | invoices |
organization_suspended | 403 | This organization is suspended; API changes are blocked | auth |
owner_required | 403 | Only an owner can remove an owner | auth |
page_archived | 409 | This page is archived | content |
parameters_invalid | 422 | … must be an id | admin, audit, compliance, content, dashboard, operations, platform |
passkey_challenge_invalid | 422 | This passkey request has expired or was already used; start again | auth |
passkey_exists | 409 | This passkey is already registered | auth |
passkey_limit | 409 | You can register at most … passkeys | auth |
passkeys_disabled | 503 | Passkeys are not available on this server | auth |
password_required | 422 | Choose a password to create your account | auth |
permission_denied | 403 | You cannot manage media | admin, content, operations |
plan_override | 409 | An administrator manages your plan. Contact support before purchasing. | billing |
plan_owned | 409 | You already own this plan or a higher lifetime plan | billing |
platform_paused | 503 | New invoices are temporarily paused by the platform | invoices |
precondition_required | 428 | The request must carry a precondition header (for example If-Match). | core |
pricing_unavailable | 503 | No price quote could be produced; there is no fallback rate. | billing, checkout |
rate_limited | 429 | Too many requests; wait for the Retry-After seconds. | auth, content |
readiness_failed | 409 | Live readiness is not satisfied: … | admin, compliance |
reason_required | 422 | A reason is required | admin, exceptions, payments, platform, refunds |
reauth_intent_mismatch | 403 | This authorization was issued for a different change | auth |
reauth_required | 403 | Re-enter your authentication code to authorize this change | admin, auth |
refund_exceeds_available | 409 | This refund (… base units) exceeds what remains refundable on the payment (… base units after the platform fee, settled payouts and other refunds). Reject it; the merchant may request a smaller amount. | refunds |
refund_in_progress | 409 | A refund on this invoice is still waiting for review or has not completed on chain. Decide or finish it first; then accept what remains as paid. | exceptions |
refund_not_approved | 409 | This request is still waiting for review; reject it with refund.review instead | refunds |
refund_not_cancellable | 409 | Refund is … | refunds |
refund_rail_unsupported | 422 | Refunds on this rail are not supported: the paying sender cannot be compared safely | refunds |
reorg_hold | 409 | Payment is held after a chain reorganization; verified recovery is required | payments |
resend_cooldown | 429 | A verification email was sent moments ago; please wait before asking again | auth |
reserved_config_slug | 422 | '…' is reserved for the '…' configuration page | content |
reserved_slug | 422 | '…' is a reserved application path and cannot become a content slug | content |
reset_not_supported | 409 | … has no inherited value to fall back to | platform |
review_message_required | 422 | A merchant-facing review_message of 10-500 characters is required; the internal reason is never sent to the merchant | refunds |
revision_activated | 409 | This revision is already active | operations |
revision_conflict | 409 | This wallet list changed while you were adding. Reload and try again. | settlement |
revision_mismatch | 409 | That revision is no longer this page's current draft | content |
revision_not_pinned | 409 | Only the published revision or the current draft can be sent as a test | content |
revision_not_published | 409 | A campaign sends the announcement's PUBLISHED revision only | content |
revision_not_verified | 409 | Only a verified revision can be activated | operations |
revision_superseded | 409 | That revision has been superseded | content |
revision_withdrawn | 409 | The pinned revision is no longer the published announcement | content |
role_not_found | 404 | Unknown platform role | admin |
sample_value_invalid | 422 | At most … sample values | content |
saved_view_exists | 409 | You already have a view with this name for this resource here | admin, dashboard |
saved_view_stale | 409 | This saved view no longer matches the supported filters (…). Edit or delete it. | dashboard |
schedule_elapsed | 409 | The approved send time has passed; submit a new request | content |
scheduled_at_invalid | 422 | scheduled_at must include a timezone | content |
scope_invalid | 422 | … replays a … | admin, audit, content, operations, platform |
scope_not_allowed | 403 | Your role (…) cannot create a key with: … | auth |
screening_lists_incomplete | 422 | Screening must cover OFAC, UN and EU lists; missing: … | compliance |
screening_note_required | 422 | Explain in the note how the possible match was shown to be someone else | compliance |
secret_clear_requires_command | 422 | Clearing a secret is a separate, explicit action | operations |
secret_required | 409 | A … connection needs its secret before activation | operations |
secret_storage_error | 503 | Stored secret could not be authenticated | core |
self_target | 422 | You cannot disable your own account | admin |
sender_identity_unavailable | 409 | The paying sender could not be identified for every confirmed receipt on this invoice, so no destination can be accepted safely | refunds |
setting_locked | 409 | This platform setting is locked and cannot be changed here. | platform |
setting_not_editable | 422 | … declares no validator | platform |
setting_not_platform_scoped | 422 | … is applied through the … command, which names its own target and scope | platform |
setting_unknown | 404, 422 | Unknown setting key | admin, compliance, platform |
simulate_live_forbidden | 403 | Payments can only be simulated on test stores | dashboard |
slug_taken | 409 | A content page already uses the slug '…' | content |
source_already_selected | 409 | This source is already selected for this scope | operations |
source_not_configured | 409 | The selected source is not configured for this scope… | operations |
staff_signin_required | 401 | Sign in on the staff sign-in page to use platform administration | admin |
statement_too_large | 422 | This month has too many postings to display. | admin, dashboard |
store_archived | 403, 409 | An archived store cannot be edited | dashboard, invoices |
store_has_active_obligations | 409 | This store still has active obligations (…). They keep processing; archive once they settle. | dashboard |
target_invalid | 422 | target_id must be a … id | admin, content |
telegram_unavailable | 422, 503 | Telegram notifications are not available | notifications |
template_block_unsupported | 422 | Emails carry no images; remove the hero media | content |
template_placeholder_malformed | 422 | A '{{' or '}}' does not form an approved variable | content |
template_subject_missing | 422 | An email needs a hero block whose headline is the subject | content |
template_variable_in_link | 422 | Template variables may not be used inside a link | content |
template_variable_unknown | 422 | Only approved variables may be used; unknown: … | content |
template_variables_invalid | 409, 422 | The announcement uses content an email cannot carry | content |
ticket_closed | 409 | This ticket is closed and keeps its history. Create a follow-up ticket linked to it to continue the conversation. | support |
too_many_ids | 422 | At most … notification IDs per request | notifications |
unauthorized | 401 | Missing, invalid, or revoked credentials. | auth |
unavailable | 503 | A dependency needed to answer safely is unavailable; retry later. | core/errors |
unsafe_destination | 422 | The zero address cannot receive funds; tokens sent there are destroyed | settlement |
unsupported_address | 422 | This Bitcoin address type is not supported for payouts | core |
unsupported_network | 422 | Payouts are not supported on this network | core |
unsupported_parameter | 422 | Job cancellation is page-scoped; use cancel_pending_publications | content |
version_conflict | 409 | Module policy has changed since it was read | content, core, dashboard, operations, platform |
weak_password | 422 | Password must be at least … characters | auth |
would_lock_you_out | 409 | Your current address (…) is outside this allowlist; saving it would lock you out. Add your own network first. | admin |