Errors
What an EPD error response looks like, what each code means, and how to react.
What this is and who needs it
When something goes wrong, EPD returns a JSON body in a consistent shape with a code your code can switch on. Reading this page once will save you a lot of guessing later.
Error response shape
{
"error": {
"type": "invalid_request_error",
"code": "validation_error",
"message": "One or more fields are invalid.",
"request_id": "req_a1b2c3d4e5f67890abcdef0123456789",
"param": "amount",
"field_errors": [
{ "field": "amount", "code": "invalid_value", "message": "amount must be a positive integer" },
{ "field": "currency", "code": "required_field", "message": "currency is required" }
]
}
}
| Field | Description |
|---|---|
type | Coarse category — see the table below. |
code | Specific machine-readable code. Stable across versions; switch on this in code. |
message | Human-readable explanation. May change between versions; do not parse it. |
request_id | Trace id. Include in any support ticket — it lets us find your call instantly. |
param | The single field most responsible for the error (when applicable). |
field_errors | Per-field breakdown for validation errors. Surface these directly in your UI when possible. |
Error types
type | Status | What it means |
|---|---|---|
invalid_request_error | 400 | Malformed request, missing field, invalid value, business rule broken. |
authentication_error | 401 | Missing, malformed, expired, or revoked key. |
authorization_error | 403 | Key valid but not allowed to perform this action. |
idempotency_error | 409 / 422 | Idempotency key reused incorrectly or in flight. |
rate_limit_error | 429 | Too many requests for the current window. |
processing_error | 4xx / 5xx | Card declined, gateway error, internal failure. |
webhook_error | varies | Webhook delivery, signature, or endpoint configuration error. |
Codes you will hit most often
Validation
validation_error— top-level catch-all; checkfield_errors[]for details.required_field— a field was omitted.invalid_value— a field had the wrong type, range, or shape.invalid_format— string did not match the required format (e.g. email).contains_html— a free-text field contained HTML and was rejected for safety.
Resource state
resource_not_found— the id does not exist (or you do not have access to it).resource_already_exists— unique constraint clash.resource_in_use— cannot delete because something still references it.email_already_exists,phone_already_exists,sku_already_exists— narrow variants ofresource_already_exists.invalid_state_transition— e.g. canceling an already-canceled subscription.customer_has_active_subscriptions,product_in_active_plans,subscription_not_modifiable,already_canceled.
Authentication & authorization
missing_api_key,invalid_api_key,invalid_api_key_format,expired_api_key,revoked_api_key.insufficient_permissions— restricted key lacks the right scope.ip_not_allowed— request came from an IP off the allowlist.environment_mismatch— sandbox-only data with a live key, or vice versa.invalid_api_version,api_version_sunset— bad or retiredepd-versionheader.
Idempotency
missing_idempotency_key— endpoint required one and you sent none.invalid_idempotency_key— empty, too long, or wrong characters.idempotency_key_in_use— same key still in flight; retry after a short delay.idempotency_key_conflict— same key, different payload. Use a fresh key.
Rate limiting
rate_limit_exceeded— per-category limit hit.global_rate_limit_exceeded— global per-merchant limit hit.
Processing & payments
payment_failed— generic payment failure; check the underlying message.card_declined— issuer declined.insufficient_funds— card had no funds.expired_card— card past its expiry.invalid_vault_id—billing_iddoes not exist in EPD Gateway, or wrong environment.gateway_error— temporary downstream failure; safe to retry with the same idempotency key.gateway_delete_failed— could not remove a card from the gateway vault.replacement_required— the customer’s card needs to be re-collected.internal_error— unexpected EPD failure. Safe to retry.service_unavailable— EPD or a dependency is temporarily down.not_implemented— endpoint exists but is not yet enabled (e.g. subscription pause).merchant_not_configured— your account is missing required setup; contact support.
Webhooks
webhook_delivery_failed,webhook_endpoint_invalid,webhook_signature_failed.
How to react
On 4xx — fix and re-send
These mean your request was wrong. Surface the message (or the field-level field_errors) to the user; do not blindly retry.
On 429 — back off
Honor the Retry-After header. Add jitter. Avoid thundering-herd retries from many workers at once.
On 5xx — retry with the same idempotency key
EPD treats these as transient. Use exponential backoff (e.g. 1s, 2s, 4s, 8s, capped). Reusing the same X-EPD-Idempotency-Key makes the retry safe.
Always log request_id. With it, EPD support can find your exact call in seconds; without it, debugging is much slower.