Error Codes
All errors return a consistent JSON structure with a machine-readablecode field for programmatic handling and a human-readable message field for debugging.
Error Types
| Type | Description |
|---|---|
invalid_request_error | The request was malformed or missing required parameters. |
authentication_error | Invalid, expired, or missing API key. |
authorization_error | Valid API key but insufficient permissions for the requested resource. |
not_found_error | The requested resource does not exist. |
conflict_error | The request conflicts with existing state (e.g., duplicate idempotency key, cancelling a confirmed intent). |
rate_limit_error | Too many requests. Back off and retry. |
api_error | An internal error on our side. Retry with exponential backoff. |
Payment Intent Errors
| Code | HTTP Status | Description | Resolution |
|---|---|---|---|
amount_out_of_range | 400 | Amount is below 10,000. | Adjust the amount to within the allowed range. |
invalid_currency | 400 | Currency is not usd. | Set currency to "usd". |
invalid_merchant | 400 | Merchant ID is malformed. | Check the merchant ID format (mer_*). |
merchant_not_found | 404 | Merchant does not exist or is not accessible to this API key. | Verify the merchant ID and API key permissions. |
merchant_not_active | 422 | Merchant account is suspended or deactivated. | Contact support or check merchant status in the dashboard. |
intent_not_cancellable | 409 | Payment intent is not in awaiting_payment status. | Only intents with status awaiting_payment can be cancelled. |
idempotency_key_conflict | 409 | The idempotency key was used with different parameters. | Use a unique idempotency key for each distinct request. |
ttl_out_of_range | 400 | TTL is below 60 or above 3600 seconds. | Set TTL between 60 and 3600. |
Authentication Errors
| Code | HTTP Status | Description | Resolution |
|---|---|---|---|
missing_api_key | 401 | No Authorization header provided. | Include Authorization: Bearer sk_* in request headers. |
invalid_api_key | 401 | API key is malformed or does not exist. | Check that the key is correct and hasn’t been revoked. |
revoked_api_key | 401 | API key has been revoked. | Generate a new API key from the dashboard. |
environment_mismatch | 403 | Using a test key against production resources or vice versa. | Use sk_test_* for sandbox and sk_live_* for production. |
Webhook Errors
| Code | HTTP Status | Description | Resolution |
|---|---|---|---|
invalid_webhook_url | 400 | Webhook URL is not a valid HTTPS URL. | Provide a valid HTTPS URL. |
webhook_unreachable | 422 | Could not reach the webhook URL during registration. | Ensure your endpoint is publicly accessible and returns 200. |
Rate Limit Errors
| Code | HTTP Status | Description | Resolution |
|---|---|---|---|
rate_limit_exceeded | 429 | Too many requests in the current window. | Wait and retry. Check X-RateLimit-Reset header for when the window resets. |
Handling Errors
Best Practices
- Always check
error.codefor programmatic handling, noterror.message(messages may change). - Retry on
429and500with exponential backoff. Use theX-RateLimit-Resetheader for rate limits. - Never retry on
400,401,403,404— these indicate issues with your request, not transient failures. - Log the full error response for debugging. Include the
error.type,error.code, anderror.paramfields.

