Errors
The envelope
Every error the API produces itself is JSON in one shape:
{
"success": false,
"error": "payee_name_mismatch",
"message": "The receiving bank says this account is held by Kettlewick Trading Ltd. …",
"details": {"outcome": "close_match", "…": "…"}
}
| Field | Meaning |
|---|---|
success | Always false. |
error | The code. Branch on this — together with the HTTP status. Codes are stable. |
message | For people: a log line, or text to show. It changes; never parse it. |
details | Only on some codes, listed below, where it carries state you are meant to read — the scope you lack, what would clear a payee mismatch. In the sandbox, a 5xx also carries a diagnostic string here; production omits it. |
Successful responses are the resource itself — there is no
{"success": true, "data": …} wrapper.
Four codes always carry a fixed, generic message, in both environments:
internal_error ("An internal error occurred"), database_error ("A
database error occurred"), service_unavailable ("Upstream service is
unavailable") and gateway_timeout ("Upstream service timed out"). The
sandbox puts the specific reason in details; production does not. Every other
code, 5xx ones such as platform_paused included, keeps its own message.
The detail is in our logs under the response's X-Request-Id — quote that id
to support.
Not every error is this envelope
Some failures happen before our code runs, and those are not JSON:
| Status | Body | Cause | Fix |
|---|---|---|---|
400 | Plain text: "Failed to parse the request body as JSON: …" | The body is not valid JSON | Send valid JSON |
415 | Plain text: "Expected request with Content-Type: application/json" | A body without that header | Set Content-Type: application/json |
422 | Plain text: "Failed to deserialize the JSON body into the target type: missing field beneficiary_id …" | A required field is missing, or a field has the wrong type — for example an amount that is not a decimal | The text names the field |
400 | Plain text: "Invalid URL: Cannot parse payout_id …" or "Failed to deserialize query string: …" | A path or query parameter of the wrong type | Check the parameter |
404 | Empty | No such route | Check the method and path |
405 | Empty | The path exists, not with this method | Check the method |
So: read the status first; parse JSON only when the Content-Type is
application/json. Note that a 422 can be either this plain-text rejection
or one of our JSON codes (payee_name_mismatch, plan_limit_exceeded, …).
What to retry
| Response | Retry? |
|---|---|
5xx, 429, a timeout, a dropped connection | Yes — with backoff, and with the same Idempotency-Key. For a payout or a conversion, the retry never sends it twice — and never re-sends one the first attempt recorded: it returns that attempt. Read what comes back (Payouts, FX). |
409 conflict on fx/execute, after a timeout | No — the first attempt was recorded; the message carries its id and status (FX) |
409 idempotency_key_reuse | No — your key generation is wrong |
Any other 4xx | No — fix the request first |
Not every route that takes an Idempotency-Key honours it — in production a
retried POST /v1/banking/beneficiaries can register a duplicate. See
Idempotency for what each route does with the key.
Codes that any route can return
| Status | error | Cause | What to do |
|---|---|---|---|
| 400 | bad_request | A validation failure. message says which. | Fix the request. |
| 401 | unauthorized | Any authentication failure — see below. | Check the key and the environment. |
| 403 | insufficient_scope | A restricted key without the route's scope. details.required_scope, details.granted_scopes. | Create a key with the scope — Authentication. |
| 403 | key_not_admitted | A key type the route does not admit. details.admits lists what is. Also a 401 when the money or dashboard surface refuses the key type at the door. | Use the credential the route admits. |
| 403 | route_not_available_to_api_keys | A route no API key may call. | Use a dashboard session. |
| 403 | permission_denied | A dashboard session whose seat lacks the action's permission (payouts.create, fx.execute, collect.manage, collect.links.create, api_keys.manage). message names it. | Ask an owner or admin — seat permissions. |
| 403 | account_not_verified | An account that is not verified, on every route that moves money or needs the bank relationship. Refused before anything is sent to the bank. details: account_id, kyb_status, next_action (complete_verification, await_review, contact_support), delegated, referral, doc_url. | Complete verification; the same request works once the account is active. |
| 403 | api_not_in_plan | Production only: your plan does not include this use of the API — live keys and webhooks from Starter, moving money (POST /v1/banking/payouts, POST /v1/banking/fx/execute) from Professional. details.upgrade names the plan that does. | See Plan limits and upgrades. |
| 403 | forbidden | A public session token. | See below. |
| 403 | RESOURCE_FORBIDDEN | Another account's resource on a dashboard route — GET /v1/accounts/{id}, GET /v1/accounts?managed_by=, GET /v1/customers/{id}, DELETE /v1/platform-permissions/{id}, POST /v1/accounts?acting_as= — or ?account_id= naming an account that is not yours. Upper case, unlike every other code. | Use your own account's ids. ?account_id= is for CashXChain staff. |
| 404 | not_found | On the money and developer routes: the resource does not exist or is not yours — they do not tell the two apart. | Check the id and the credential. |
| 409 | conflict | The request conflicts with current state. message says how. | Read the state, then decide. |
| 413 | payload_too_large | A request body over 2 MB, sent with an API key. | Send less. |
| 429 | rate_limited | Our rate limit, or our banking partner's. | Wait Retry-After if present, else back off. |
| 500 | internal_error, database_error, internal_panic | Our fault. | Retry with backoff; if it persists, send us the X-Request-Id. |
| 503 | service_unavailable | Our banking partner, or a service we depend on, is unavailable. | Retry with backoff. |
| 503 | verification_status_unavailable | The account's verification status could not be read, so a money request was refused rather than risk moving money for an unverified account. | Retry with backoff; it is temporary. |
| 504 | gateway_timeout | Our banking partner did not answer in time. The operation may or may not have happened. | Never retry with a new key. For a payout, see Payouts. |
Plan limits and upgrades
What your plan includes is enforced in production; the sandbox leaves
every API feature open on every plan, so an integration can be built before
it is paid for. A refusal because of the plan is not a dead end: its
details.upgrade names the cheapest plan that allows the request.
{
"success": false,
"error": "api_not_in_plan",
"message": "moving money through the API is not part of the starter plan",
"details": {
"upgrade": {
"current_plan": "starter",
"plan": "professional",
"reason": "live_api_move_money",
"self_serve": true
}
}
}
| Field | Meaning |
|---|---|
current_plan | Your plan now. |
plan | The cheapest plan that allows the request; null when none sold does (talk to us). |
reason | What was asked for — live_api_read, live_api_move_money, webhooks, currencies, named_accounts, a limit name. |
self_serve | true when the plan can be bought in the dashboard; false for Enterprise. |
current_limit, plan_limit | On limit refusals: the limit now and under plan. |
| Status | error | Cause | What to do |
|---|---|---|---|
| 403 | api_not_in_plan | A live key, a webhook, or a payout / FX execution by API, on a plan without it. Checked on every request, so a plan change applies at once. | Upgrade, or use the sandbox. Do not retry. |
| 403 | currency_limit_reached | Your plan's currency limit is used. | Close an account, or upgrade. |
| 403 | named_account_limit_reached | Your plan's local-account limit is used. | As above. |
| 422 | plan_limit_exceeded | A payout over the plan's single, daily or monthly limit. | Wait for the window, send less, or upgrade. |
Plans and what each includes: Pricing.
Authentication and access
All authentication failures are 401 unauthorized; the message tells them
apart. The full table is in
Authentication.
| Status | error | Cause | What to do |
|---|---|---|---|
| 401 | unauthorized | No Authorization: Bearer header | Send one |
| 401 | unauthorized | Unknown, revoked or other-environment key | Check CXC_BASE and the key belong together |
| 401 | unauthorized | Any key on /v1/sandbox/* | These routes take a dashboard session |
| 401 | unauthorized | pk_ on a non-GET request | Publishable keys are read-only |
| 401 | key_not_admitted | pk_ on /v1/banking/*; any sk_, rk_ or pk_ key on a dashboard route. message names what the route admits | Use a key type the route admits |
| 403 | insufficient_scope | "this key does not carry fx:read, which GET /v1/fx/rates requires" — a restricted key without the scope. details.required_scope, details.granted_scopes | Create a key with the scope |
| 403 | key_not_admitted | Any API key on /v1/api-keys, POST /v1/customers or another people-only route; rk_/pk_ on request logs or usage; pk_ on a route whose scope is not publishable. details.admits | Use a session, or the credential the route needs |
| 403 | permission_denied | A session whose seat lacks the permission: a viewer sending a payout, a member minting a key | Ask an owner or admin |
| 403 | forbidden | "this endpoint is not available to public-API tokens" | Use a key, or a dashboard session |
| 403 | account_not_verified | "This account cannot move money until its business verification is approved. Nothing was sent to the bank." — every money route, with one body | Complete verification — details below |
account_not_verified
The account the request acts for has not been approved by business verification (KYB), or its verification is suspended. Every route that moves money or needs the bank relationship — payouts, FX quotes and execution, beneficiaries, opening or closing accounts, digital-asset transfers — refuses it before anything is sent to the bank. On a call made for a managed account, it is the managed account that is not verified.
{
"success": false,
"error": "account_not_verified",
"message": "This account cannot move money until its business verification is approved. Nothing was sent to the bank.",
"details": {
"account_id": "9f2b7c10-5d6e-4b1a-9c3f-2e8d7a6b5c41",
"kyb_status": "pending",
"next_action": "await_review",
"delegated": false,
"referral": {
"external_id": "corp_1826115186",
"status": "pending",
"check": "GET /v1/banking/kyb/referrals/corp_1826115186"
},
"doc_url": "https://docs.cashxchain.com/docs/api/errors#account_not_verified"
}
}
Do not retry it in a loop: approval is a person's decision and takes days.
Follow details.next_action — complete_verification (no application yet),
await_review (submitted; the bank decides) or contact_support
(suspended). Nothing was recorded, so once GET /v1/accounts/me reports
can_move_money: true you can send the identical request again, with the
same Idempotency-Key.
In the sandbox, send Cxc-Simulate: account_not_verified (or
account_not_verified; kyb_status=suspended) to receive this response on
demand:
curl -X POST https://api.sandbox.cashxchain.com/v1/banking/fx/quote \
-H "Authorization: Bearer $CXC_SECRET_KEY" \
-H "Content-Type: application/json" \
-H "Cxc-Simulate: account_not_verified" \
-d '{}'
Idempotency
| Status | error | Cause | What to do |
|---|---|---|---|
| 400 | bad_request | Idempotency-Key missing, empty, over 255 characters, or not visible ASCII | Send a valid key |
| 409 | idempotency_key_reuse | The key was used for a different request — a different body, or a payout key reused for FX | Use a new key for a new operation; keep the old one for retries of the old one |
Lockdown and holds
CashXChain can pause money movement platform-wide, and can put a single
account on hold. Both stop these writes and nothing else:
POST /v1/banking/payouts, POST /v1/banking/fx/execute,
POST /v1/banking/beneficiaries, PUT /v1/banking/settlement/policies,
POST /v1/banking/accounts/close, Collect refunds, and approving a
digital-asset trusted beneficiary (POST /v1/banking/digital-assets/trusted-beneficiaries;
revoking one is never stopped). Reads and quotes keep working.
| Status | error | Cause | What to do |
|---|---|---|---|
| 503 | platform_paused | Money movement is paused. message is the operator's notice, or "Money movement is temporarily paused. Please try again shortly." | Retry later. GET /v1/platform-status tells you when it lifts. |
| 503 | platform_status_unavailable | We could not confirm the platform is running normally, so we refuse rather than guess | Retry shortly |
| 403 | account_on_hold | "This account is on hold. Contact support." | Contact support; retrying will not help |
| 503 | hold_status_unavailable | We could not check holds | Retry shortly |
None of them carries Retry-After. GET /v1/platform-status needs no
credential:
{"paused": false, "since": "2026-09-30T18:45:45.000Z", "confirmed": true, "enforced": true}
paused: true with confirmed: false means the status could not be read —
treat it as paused.
Delegation
Refusals of the Cxc-Account header: delegation_malformed,
delegation_conflict, delegation_not_supported, delegation_not_permitted,
delegation_no_grant, delegation_scope_denied and
delegation_requires_session. Each carries details; the table with causes
is in Platforms. A managed account that is not
verified is refused like your own, 403 account_not_verified, with
details.delegated: true.
Step-up
Dashboard sessions only — API keys never step up.
| Status | error | Cause | What to do |
|---|---|---|---|
| 401 | two_factor_required | No X-Step-Up-Token | Ask the user to confirm with their second factor |
| 401 | step_up_expired | The token is older than five minutes | Mint a new one |
| 403 | step_up_invalid | Wrong signature, purpose, factor or user | Mint a new one |
| 403 | step_up_not_linked | The token is not bound to a payment | Mint one bound to this payment |
| 403 | step_up_binding_mismatch | Bound to a different amount, currency or recipient | Mint one for this exact payment |
| 403 | step_up_already_used | Tokens are single-use | Mint a new one |
| 500 | step_up_not_configured | Our configuration | Tell us |
Accounts
| Status | error | Cause | What to do |
|---|---|---|---|
| 400 | bad_request | "XYZ is not a currency we can open accounts in" | See offered_currencies in GET /v1/banking/accounts |
| 403 | currency_limit_reached | Your plan's currency limit is used | Close one, or change plan |
| 403 | named_account_limit_reached | Your plan's local-account limit is used | As above |
| 409 | conflict | "you already hold a EUR account" — also the answer to a retried open | Use the account you hold |
| 422 | primary_not_eligible | Only an active EUR, GBP, USD or CAD account can be primary | Pick one of those |
| 422 | primary_account | You cannot close the primary account | Make another account primary first |
| 404 | not_found | "no enabled banking rail knows account …" — an account id that is not yours or does not exist | Take ids from GET /v1/banking/accounts |
| 403 | account_not_verified | Production: your account is not approved yet, so there is nothing at the rail to list | Complete verification |
| 503 | service_unavailable | No rail could list your accounts | Retry |
Beneficiaries and corridors
| Status | error | Cause | What to do |
|---|---|---|---|
| 400 | bad_request | "corridor validation failed for EUR/DE: …"; "scheme "iban" requires field "iban""; "unknown account scheme …"; "beneficiary_type must be …" | Ask GET /v1/banking/corridors and send what it lists |
| 400 | bad_request | A partner query or field — the rail is chosen for you and is no longer named; accept-verification without payment_idempotency_key | Drop the field; send the key |
| 404 | not_found | "no beneficiary …" — not yours, or no such id | Take ids from GET /v1/banking/beneficiaries |
| 404 | username_not_found | A cxc_handle that names nobody | Check the handle |
| 409 | conflict | A cxc_handle payee whose account is not active yet; your own account not yet linked to the rail | Wait for verification |
| 422 | corridor_unsupported | Nobody offers this corridor. details.corridor is {type: "payout", currency, country, rail?}. Returned by GET /v1/banking/corridors, POST /v1/banking/beneficiaries and POST /v1/banking/payouts alike. | Choose another currency or destination — retrying will not change it |
| 422 | payee_name_mismatch | On accept-verification: an invalid destination, which no consent clears. details.resolve_by is beneficiary | Correct the account details and register a new beneficiary |
| 503 | service_unavailable | The rail that offers the corridor is down | Retry with backoff |
Payouts
| Status | error | Cause | What to do |
|---|---|---|---|
| 400 | bad_request | "amount must be positive"; too many decimal places for the currency | Fix the amount |
| 400 | bad_request | "the beneficiary is paid in EUR, not GBP" | Send the beneficiary's currency |
| 400 | bad_request | "account … holds GBP, so it cannot pay EUR without an fx_quote_id" (production) | Lock a rate — Payouts |
| 400 | bad_request | "this quote sells …", "this quote buys …" | The quote must match the source account, the currency and the amount exactly |
| 400 | bad_request | Production: "a payout pays an exact amount: request its quote with fixed_side: buy" — the quote fixed the sell side, so the beneficiary would be paid an amount the payout never stated | Quote with "fixed_side": "buy" and the payout amount |
| 403 | api_not_in_plan | Production, with an API key: moving money by API is not in your plan (Professional and up) | Plan limits and upgrades |
| 400 | bad_request | Production: the reference is over 18 characters, an unknown purpose_of_payment, or the rail rejected the request outright. Nothing was sent. | Read message; fix and send with a new key |
| 400 | insufficient_balance | Sandbox: the account cannot cover the amount plus the fee | Add test funds, then send with a new key |
| 403 | account_not_verified | Your account is not verified; nothing was sent | KYB |
| 403 | permission_denied | A dashboard session whose seat lacks payouts.create | Ask an owner or admin |
| 404 | not_found | "no beneficiary …" or "no enabled banking rail knows account …" | Check the ids |
| 409 | idempotency_key_reuse | See Idempotency | |
| 409 | quote_expired | The fx_quote_id has expired | Get a new quote |
| 409 | quote_unrecorded | We hold no record of that quote | Get a new quote |
| 422 | corridor_unsupported | Nobody pays this currency to this country. Refused before anything is recorded, so the key is not spent. | Choose another corridor — final |
| 422 | payee_name_mismatch | The receiving bank's name check did not pass. details: outcome, account_holder (close match only), check, partner_detail, resolve_by (accept-verification, or beneficiary for an invalid destination), accept_url (null for invalid) | Beneficiaries |
| 422 | plan_limit_exceeded | Over your plan's single, daily or monthly limit (in USD) | Send less, or change plan |
| 422 | no_rate | Sandbox: no rate for the currency pair | Use another pair |
| 503 | limit_unmeasurable | The amount could not be priced in USD to check your limits | Retry shortly |
| 503 | fee_unpriceable | Sandbox: the fee could not be priced | Retry shortly |
| 503 | service_unavailable | Production rail: the account's rail could not take the payout, or the rail failed after we asked it. The message is the same for both. | The payout may be recorded as created, and a retry with the same key returns it as it is — it is never re-sent. Follow Payouts before sending again. |
| 409 | route_changed | Sent with quote_id: the route the payout would take now is not the one quoted. details.quoted_route, details.current_route. Nothing sent | Ask for a new quote |
| 409 | route_quote_used | The quote_id was spent on another payout | Ask for a new quote |
| 422 | route_quote_expired | The quote_id is past its expires_at | Ask for a new quote |
| 422 | route_quote_mismatch | The body is not the one quoted; details.fields names what differs | Send the quoted body, or quote this one |
A payout from a digital-asset account (sandbox) has codes of its own —
travel_rule_incomplete, trusted_beneficiary_required, wallet_not_open,
amount_below_minimum, payout_outcome_unknown and more: see
Digital-asset errors.
FX
| Status | error | Cause | What to do |
|---|---|---|---|
| 400 | bad_request | Quote: fixed_side not sell/buy; same currency twice; a bad amount. Rates: a malformed code, or more than 30 currencies | Fix the request |
| 400 | account_currency_mismatch | Execute: account_id does not hold the quote's sell currency | Use the account in the sell currency |
| 400 | quote_expired | Execute, sandbox: past expires_at | New quote, new key |
| 400 | quote_consumed | Execute, sandbox: already executed | New quote, new key |
| 400 | insufficient_balance, invalid_amount | Execute, sandbox | Top up / fix the quote |
| 400 | bad_request | Execute, production: the rail rejected the request outright; message has its reason. A conversion it accepts and cannot carry out turns failed later instead. | New quote, new key |
| 403 | account_not_verified | Quote or execute: your account is not verified | KYB |
| 403 | permission_denied | Execute, dashboard session: the seat lacks fx.execute | Ask an owner or admin |
| 403 | insufficient_scope | Rates or quote: a restricted key without fx:read | Add the scope |
| 409 | conflict | Execute: the key was used already — the message has the conversion id and its status | Read it; FX |
| 409 | quote_unrecorded | Execute, dashboard session: we hold no record of the quote | New quote |
| 422 | corridor_unsupported | Quote: nobody converts this pair, or an unknown currency code. details.corridor is {type: "fx", sell_currency, buy_currency} | Use another pair — final |
| 422 | market_closed | Outside the pair's market hours | Show message; try later |
| 503 | service_unavailable | The rail that offers the pair is down | Retry with backoff |
KYB
| Status | error | Cause | What to do |
|---|---|---|---|
| 400 | bad_request | A missing or invalid field; a person's persons[i].… field | message names it |
| 404 | not_found | An external_id that is not yours, or that no rail knows | Use the id from your referral |
| 422 | kyb_precheck_blocked | The pre-check blocked the application; message lists the rules | Nothing to retry — the business cannot be onboarded |
| 503 | service_unavailable | No rail accepts referrals | Retry later |
The referral outcomes manual_review (202) and already_referred (200)
are not errors — see KYB.
Statements and settlement
| Status | error | Cause | What to do |
|---|---|---|---|
| 400 | bad_request | Statement: from after to, to in the future, or a period over 366 days | Fix the dates |
| 400 | bad_request | Settlement policy: a malformed currency, equal source and target, a negative min_amount | Fix the policy |
| 503 | service_unavailable | Statement, production: the account's balance could not be read from the rail | Retry |
The banking rail
When our banking partner refuses or fails, its answer reaches you as one of
these. A refusal (4xx) carries the partner's wording in message, its name
replaced by "banking partner"; a failure (5xx) carries only the generic
message.
| Partner outcome | You get |
|---|---|
| Rejected the request | 400 bad_request |
| Not found | 404 not_found — "partner resource not found" |
| Conflict | 409 conflict |
| Rate-limited us | 429 rate_limited |
| Market closed | 422 market_closed |
| Down, or rejected our credentials | 503 service_unavailable |
| Timed out | 504 gateway_timeout — the operation may have happened. For a payout or conversion, a retry with the same key returns the recorded attempt and does not send it again — see Payouts. |
| Unreadable answer | 500 internal_error |
This is why a few codes differ by environment — see Environments.
Developer routes
| Route family | Status | error | Cause |
|---|---|---|---|
| Webhooks | 400 | bad_request | URL not https (production only — the sandbox accepts http), too long, with credentials, a private IP; description over 200 bytes; an unknown event (the message lists the catalogue) |
| Webhooks | 409 | conflict | "this URL is already registered for the account" — also when the existing one is disabled; delete it first |
| Webhooks | 404 | not_found | No such endpoint |
| API keys | 400 | bad_request | Invalid type; restricted with no scopes; an unknown scope; a bad name |
| API keys | 403 | permission_denied | A session without api_keys.manage; a secret key minted by a seat without payouts.create and fx.execute; a scope the creator's seat does not hold |
| API keys | 403 | key_not_admitted | Any API key — keys are managed by people |
| API keys | 404 | not_found | Revoking an unknown or already revoked key |
| Request logs | 404 | not_found | No such log entry, or not yours |
| Contacts | 422 | contact_username_required | A cashxchain_user contact without username |
| Contacts | 422 | too_short, too_long, invalid_characters, edge_separator, repeated_separator, no_alphanumeric, reserved | An invalid username |
| Contacts | 404 | username_not_found | The username names nobody |
| Contacts | 403 | forbidden | Editing an automatic contact (agg: id) |
Sandbox tools
| Status | error | Cause |
|---|---|---|
| 401 | unauthorized | An API key on adopt-corporate — it takes a dashboard session. The faucet and the digital-asset tools (kyb/digital-assets/approve, simulate-deposit, simulate-arrival, simulate-completion) take API keys too |
| 400 | bad_request | Faucet: an amount that is not a whole number from 1 to 100,000, or an Idempotency-Key that is empty, over 255 characters or not visible ASCII |
| 409 | conflict | Faucet: "you hold no active EUR account — open one first" |
| 409 | idempotency_key_reuse | Faucet: the Idempotency-Key sent again with another currency or amount |
| 422 | asset_unsupported | Faucet: a digital asset — use simulate-deposit |
| 429 | rate_limited | More than 30 requests an hour from your account to one sandbox route |
The digital-asset tools' codes are on Digital-asset errors.
Digital assets (sandbox)
Onboarding, digital-asset accounts, wallets, sends, trusted beneficiaries and the route lock: every code is on Digital-asset errors.
The earlier /v1/casp/* routes were removed and answer 404; their codes
(casp_not_configured and the rest) are no longer returned.
Dashboard routes
These routes take a dashboard session or a master key. Their codes, for master-key callers:
| Family | Codes |
|---|---|
| Collect | stripe_not_configured (503), collect_not_onboarded (409), collect_not_active (409), onboarding_incomplete (409), vba_not_ready (409), already_processed (409), cannot_cancel (409), already_fully_refunded (409), invalid_iban (400), no_connect_account (404), payment_not_found (404), expired (410), not_implemented (501). The merchant routes also take sk_ and rk_ keys with collect:read, collect:write or refunds:write; onboarding needs a seat with collect.manage and the other writes collect.links.create (permission_denied otherwise). |
| Billing | billing_provider_error (503), stripe_not_configured (503), price_not_in_catalogue (503), no_subscription (404), subscription_not_active (409), no_plan_chosen (409), plan_assigned (409), plan_not_billable (400), already_on_plan (409), upgrade_is_already_immediate (409), card_setup_incomplete (409), no_card_setup_in_progress (409), invalid_interval (400), promotion_code_invalid (422), promotion_code_wrong_currency (422), promotion_code_minimum (422), promotion_code_no_plan (409), promotion_code_after_start (409), early_bird_is_better (409) |
| Usernames | username_not_found (404), username_not_offered (422), org_username_locked (403), personal_usernames_unavailable (403), the username validation codes above (422), taken (409), recently_released (409) |