Errors

Every /v1 endpoint answers a failed request with a JSON body and a 4xx or 5xx status. There are two body shapes; the first is what you will meet in practice.

1. The API error object (all /v1 routes)

json

{
  "error": {
    "type": "invalid_request_error",
    "code": "missing_required_param",
    "message": "amount is required and must be a positive integer (in cents).",
    "param": "amount"
  }
}
  • type — one of authentication_error, invalid_request_error, card_error, rate_limit_error, api_error.
  • code — a stable machine-readable string (list below). Branch on code, not on message.
  • message — human-readable, may change.
  • param — present when the error is about one request field.
  • Bank verification errors add attempts_remaining and terminal.

An idempotent replay returns the original success body, not an error.

2. The wrapper shape (rare)

A few failures happen before a route's own handler runs, in the shared tenant wrapper, and use a flat body:

json

{ "success": false, "error": "Human-readable message", "code": "tenant_ownership_denied", "type": "permission_error" }

You will see it for 403 tenant_ownership_denied (the key's business is not yours), 409 no_active_merchant (no active business for the key), 400 mode_merchant_mismatch, and for an unhandled 500 internal_error on routes built on that wrapper (customers, webhooks, invoices, products, subscriptions, payment-method verification). Older pages showed the Processing Guard error in this flat shape; on the /v1 routes it is actually delivered as the API error object with code: "processing_disabled".

Two more shapes exist at the edges: the platform's per-IP flood limiter answers 429 { "error": "Too many requests. Please slow down." } with X-RateLimit-* and Retry-After headers (see Rate Limits), and the legacy /api/tokenize/* endpoints answer { "error": { "type", "message" } } without a code.

Write your client to treat body.error as either an object (read .code) or a string.

HTTP statuses

StatusMeaning
200 / 201Success. Creates return 201.
400Invalid request, or a declined charge (card_error / charge_failed).
401Missing, malformed, revoked, expired or wrong-mode API key.
402A bank account that is not verified or is disabled (card_error).
403Key is valid but not allowed: wrong key type, IP not allowed, suspended key, merchant not onboarded, processing disabled, plan limit.
404Resource not found or not yours.
409Idempotency key reused for another operation/account, saved card needs re-entry, no active business.
422Idempotency key reused with a different body; wrong microdeposit code.
429Rate limited.
500Unexpected error; retry with the same Idempotency-Key.
502The card vault was unreachable (vault_error).

Error codes

Authentication (401 unless noted) — missing_api_key, invalid_api_key, key_inactive, key_revoked, key_expired, key_suspended (403), key_auto_suspended (403), wrong_key_type (403: a publishable key on a secret-key route or vice versa), test_mode_mismatch, test_mode_not_available, invalid_api_key_prefix, ip_not_allowed (403), insufficient_scope (403), unauthorized, auth_service_error (500).

Request validation (400) — missing_required_param, invalid_param, invalid_type, invalid_source, invalid_status_transition.

Rate limits (429) — rate_limit_exceeded, operation_rate_limit.

Idempotency — idempotency_key_conflict (409), idempotency_key_mismatch (422).

Account / business (403 unless noted) — merchant_not_onboarded, merchant_not_found, processing_disabled, tier_limit_exceeded, tier_feature_disabled, ach_disabled, tenant_ownership_denied, no_active_merchant (409), mode_merchant_mismatch (400), account_not_found (404).

Charges — charge_failed (400, declined), card_declined (400), resource_missing (404, unknown source / charge / payment method), resource_not_found (404), payment_method_requires_reentry (409), charge_not_capturable (400), capture_failed (400), amount_too_large (400), bank_account_unverified (402), bank_account_verification_failed (402), bank_account_disabled (402).

Payment methods — pci_vault_required (400, raw card data sent), bank_account_error (400), not_a_bank_account (400), vault_error (502), and on /verify (422) the processor's reason in lower case: incorrect_microdeposit_verification_code, microdeposit_verification_attempts_exceeded, microdeposit_verification_expired, microdeposit_returned, total_microdeposit_attempts_exceeded_account_locked, invalid_bank_account_routing_number, invalid_field.

Refunds (400) — charge_not_refundable, charge_already_refunded, refund_failed, refund_unsupported.

Checkout, payouts, subscriptions, invoices, products — missing_line_items, too_many_line_items, validation_error, payment_failed, not_found, payout_failed, payout_list_failed (500), subscription_creation_failed, subscription_pause_failed, subscription_resume_failed, subscription_cancel_failed, pause_failed, resume_failed, cancel_failed, creation_failed, update_failed, send_failed, price_creation_failed, product_creation_failed (500), email_delivery_failed (500).

Server — internal_error (500).

Processor names never appear in messages; a decline reads as Processing error: … or the card-holder-facing reason.