Skip to content
ZeroKYC Pay

Errors

The uniform error envelope and all eight error codes: when each fires and how to handle it.

Every failure — validation, auth, throttling, internal — returns the same JSON envelope. There are exactly eight error codes; nothing else will ever appear in error.code, so you can switch on it safely.

The error envelope

{
  "error": {
    "code": "rate_limited",
    "message": "rate limit exceeded (invoices: 30/min); retry later",
    "doc_url": "https://zerokyc-payments.com/docs/errors#rate_limited"
  }
}
  • code — one of the eight machine-readable codes below.
  • message — human-readable, safe to log and show in your own dashboards. For validation failures it carries the first failed check, e.g. ttl_minutes must be between 10 and 4320.
  • doc_url — deep link to the matching section on this page.

Codes at a glance

CodeHTTPFires when
invalid_request400Request body or query fails validation
unauthorized401Missing, malformed or unknown API key
account_suspended402Billing suspension — creating invoices is blocked
forbidden403Key revoked or account archived
not_found404Object does not exist (or belongs to another merchant/mode)
idempotency_conflict409Same Idempotency-Key reused with a different body
rate_limited429Per-key rate limit exceeded
internal_error500Unexpected server-side failure — retry with backoff

invalid_request

HTTP 400. Body validation, out-of-range values, or an operation the invoice's state does not allow (e.g. canceling an already confirmed invoice). Fix the request; retrying unchanged will fail the same way.

unauthorized

HTTP 401. The Authorization: Bearer … header is missing, malformed, or the key is unknown. Check the prefix: pk_live_… / pk_test_…. Note that 401 also covers sandbox/live mismatches only implicitly — a valid pk_test_… key simply will not see live invoices (they resolve as not_found).

account_suspended

HTTP 402. Your subscription is in suspension (unpaid platform invoice past its grace period). Creating new invoices returns this code until the platform invoice is settled; existing invoices, checkout pages and webhooks keep working. Details: Direct checkout — billing.

forbidden

HTTP 403. The API key has been revoked in the console, or the account was archived after a long suspension. Rotate to a live key in API keys.

not_found

HTTP 404. The object id does not exist, belongs to another merchant, or lives in the other mode: pk_test_… keys see only sandbox invoices and pk_live_… only live ones. Treat a unexpected 404 on a known invoice as a mode mismatch first.

idempotency_conflict

HTTP 409. You reused an Idempotency-Key with a different request body within the 24-hour window. Either send the identical body, or use a new key. Full semantics: Rate limits & idempotency.

rate_limited

HTTP 429. The per-key limit is exceeded for this scope. The response carries Retry-After: <seconds> plus the standard X-RateLimit-* headers — respect them instead of hammering:

HTTP/1.1 429 Too Many Requests
Retry-After: 37
X-RateLimit-Limit: 30
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1694007937

internal_error

HTTP 500. Unexpected failure on our side. Safe to retry the same request after a short backoff — if you sent an Idempotency-Key, the retry cannot create a duplicate. If it persists, check GET /v1/ping and contact support.