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 ofauthentication_error,invalid_request_error,card_error,rate_limit_error,api_error.code— a stable machine-readable string (list below). Branch oncode, not onmessage.message— human-readable, may change.param— present when the error is about one request field.- Bank verification errors add
attempts_remainingandterminal.
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
| Status | Meaning |
|---|---|
| 200 / 201 | Success. Creates return 201. |
| 400 | Invalid request, or a declined charge (card_error / charge_failed). |
| 401 | Missing, malformed, revoked, expired or wrong-mode API key. |
| 402 | A bank account that is not verified or is disabled (card_error). |
| 403 | Key is valid but not allowed: wrong key type, IP not allowed, suspended key, merchant not onboarded, processing disabled, plan limit. |
| 404 | Resource not found or not yours. |
| 409 | Idempotency key reused for another operation/account, saved card needs re-entry, no active business. |
| 422 | Idempotency key reused with a different body; wrong microdeposit code. |
| 429 | Rate limited. |
| 500 | Unexpected error; retry with the same Idempotency-Key. |
| 502 | The 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.