The key is the account. How it is sent, and every way a credential can be refused.
| API Key | Label | Last Used | |
|---|---|---|---|
Every operation in this reference authenticates with a secret API key, sent as a header. There is no user, no password and no account identifier: the key's prefix says which account it belongs to and the rest of the key proves it. The key is the account — which is why no request body or query parameter in this API names one, and why a key must never reach code that runs in a payer's browser.
The lifecycle around a key — the prefix's shape, the per-key rate limit, allowed origins, expiry, rotation and revocation — is the Autenticación y Claves API guide. This page is the credential surface of the reference: how to send it, and how it is refused.
Send one of two headers
X-API-KEY: pay_aBcD1234_test_EXAMPLE_KEYAuthorization: Bearer pay_aBcD1234_test_EXAMPLE_KEYEither is accepted and they are equivalent. If both arrive, Authorization is read and X-API-KEY is ignored without a warning — two headers with different values do not produce an error, they produce the result of one of them.
A credential is never accepted in the query string. There is no parameter for it on any operation. A URL is written whole into server logs, into any proxy in between and into browser history, and gets pasted into support tickets without a thought; a header is not. That holds in Sandbox exactly as it does in Production.
A 401 has two body shapes
Authentication runs in middleware, ahead of every controller. That layer answers with error and code — no success, no message — and it runs before body validation, so a request with no key and an invalid body comes back as a 401 rather than a 422.
code | error | When |
|---|---|---|
missing_api_key | API key required | No credential in either accepted header |
invalid_key_format | Invalid API key format | The key's prefix could not be parsed |
invalid_tenant | Invalid tenant | The prefix parses but matches no account |
tenant_init_failed | Tenant initialization failed | The account was found but could not be loaded |
invalid_api_key | Invalid API key | The key did not verify against any active key of the account |
Six of the sixteen operations can also return a 401 from inside the controller, in the ordinary {success, code, message} envelope with code: INVALID_API_KEY — creating, reading and cancelling a payment request, and the same three on card payments. It means something else entirely: the key verified, but its record is incomplete, and the key has to be replaced. The other ten operations cannot produce it. The same six, and only those six, can answer 404 USER_NOT_FOUND for the same underlying reason.
Note that invalid_api_key and INVALID_API_KEY differ only in case, are two different failures, and are both a 401. Do not switch on the status code to decide which body to parse, and do not lowercase a code before comparing it. Test for the key you need: the middleware envelope has error, the ordinary envelope has success and message.
A 403 is either the ability or the origin
{ "error": "Insufficient permissions", "code": "insufficient_scope" }The key does not carry the ability the operation requires. It can only occur on the twelve operations that declare one; the four reference operations declare none, so insufficient_scope is impossible there.
{ "success": false, "error": "Origin not allowed", "code": "ORIGIN_NOT_ALLOWED" }The key has allowed origins configured and this request's Origin is not among them — including a request with no Origin header at all, which is every server-to-server call. It reaches all sixteen operations. Note the shape: it carries success like the ordinary envelope and puts its text under error like the middleware one, so checking only for success will misread it.
A third kind of 403 uses the ordinary envelope and is about the account rather than the credential — a paused account, a product not enabled. Each operation declares its own.
A 429 comes from one of two limiters
One counts by client IP, runs before authentication and answers RATE_LIMIT_EXCEEDED in the ordinary envelope. The other is the key's own limit and answers rate_limit_exceeded in the middleware envelope. The case of the code is the reliable way to tell them apart. retry_after is on both bodies and is the value to back off on; only the IP limiter sets a Retry-After header.
