Authentication

Authenticate API requests with your merchant API key.

All merchant API endpoints require an API key passed in the x-api-key request header. Unauthenticated endpoints do not require the header: GET /v1/status, GET /v1/currencies, GET /v1/estimate, GET /v1/min-amount, the buyer-facing GET /v1/invoices/:id/status, and GET /v1/x402/discovery.

The x-api-key header

curl -X POST "$PAYZUM_BASE/v1/payment" \
  -H "x-api-key: $PAYZUM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ ... }'

The header name is case-insensitive. Issued keys are randomly generated 32-byte hex strings — 64 hex characters. The gateway's format validation rejects any value shorter than 32 characters with 401 API_KEY_MALFORMED; a real key always passes because it is 64 characters long.

How keys are stored

payzum stores only the SHA-256 hash of your API key alongside the last 4 characters (the "preview") for identification in the dashboard. The plaintext key is shown once at creation and cannot be retrieved afterwards.

Store your API key in a secrets manager or environment variable immediately after copying it from the dashboard. If you lose the plaintext key you must rotate it — the old key will stop working as soon as rotation completes.

Key lifecycle

Issuance

A key is generated automatically when you create a merchant via the dashboard (Merchants → New merchant). The reveal page shows the plaintext key once. Copy it before leaving the page.

Rotation

To rotate your key, navigate to Merchants → [your merchant] → API key and click Rotate key. A fresh key is generated immediately. The old key is invalidated immediately — rotation takes effect on the next request. Allow a few seconds for the change to propagate fully across all active connections.

Rotation is the only recovery path if a key is lost or compromised.

Test vs production keys

Credentials are per environment. Production (merchant.payzum.com) and sandbox/staging (staging.payzum.com) are separate stacks with separate databases. There are no test_/live_ key prefixes — a key only works on the host where it was created.

To get sandbox credentials, register a merchant on the staging dashboard the same way you would in production. See Sandbox / staging environment for details.

Never point a production integration at staging (or vice versa) — the key will simply return 401 API_KEY_NOT_FOUND on the other host.

Revocation (account suspension)

There is no standalone "revoke" action. To permanently block a key, suspend the merchant account via the admin panel. A suspended merchant returns 403 MERCHANT_SUSPENDED on every authenticated request. Existing open invoices continue to receive payments and webhooks, but no new invoices can be created.

Authentication errors

| HTTP | Error code | Cause | |------|------------|-------| | 401 | API_KEY_MISSING | The x-api-key header was not sent. | | 401 | API_KEY_MALFORMED | The key fails format validation (the gateway rejects values shorter than 32 characters; issued keys are 64-char hex). | | 401 | API_KEY_NOT_FOUND | The key format is valid but no merchant matches the hash. | | 403 | MERCHANT_SUSPENDED | The merchant account has been suspended. |

Error responses follow the shape { "statusCode": 401, "code": "API_KEY_MISSING", "message": "..." }.

Rate limiting

After a successful auth check, a per-merchant rate limit is enforced. The limit is 60 requests per 60 seconds. When exceeded, the server responds with:

HTTP/1.1 429 Too Many Requests
Retry-After: 60

Back off for at least the number of seconds in the Retry-After header before retrying. The rate limit counter is keyed to the merchant, not the calling IP, so all requests sharing the same API key share the same quota.