Crypto Payment Gateway Error Codes 2026: We Mapped 9
We sent the same bad API key to nine crypto payment gateways on 4 October 2026. Three HTTP statuses, eight formats, one that matched its own docs.
Key Takeaways
- One error, three HTTP statuses. We sent the same unauthenticated request to nine gateways on 4 October 2026. Five answered 401, two answered 403, one answered 422, and one refused to answer a non-browser client at all.
- Only one gateway returned what its own documentation promises. BlockBee, verbatim. CoinGate returns a reason string that is not in its published table, and NOWPayments returns a code that appears nowhere in its API collection.
- Half give you nothing to branch on. Four of the eight we measured return a machine-readable code; the other four return an English sentence you have to pattern-match.
- OxaPay sends HTTP 403 while its own body says 401. The same 403 also covers a mistyped URL, where the body says 404 — in a field named
resulton one error andstatuson the other. - Two of nine serve HTML to a client expecting JSON. BitPay answers an unknown path with a 6,731-byte app shell, and BTCPay Server answers with zero bytes and no content type.
Table of Contents
- Which crypto payment gateways document their error codes
- One bad API key, nine different answers
- The HTTP status is not the error
- Three gateways change envelope shape mid-API
- Seven of eight contradict their own documentation
- BitPay's 6-digit scheme is the good idea nobody copied
- Mapping nine gateway error-code vocabularies to five buckets
- What this means for your retry logic
- FAQ
Your checkout is returning a failure and the only thing you have is a response body. On the nine crypto payment gateways we track, that body is formatted nine different ways, and three of them will not even tell you which kind of failure it was — a wrong key, a wrong URL and a transient fault can all arrive wearing the same HTTP status. Crypto payment gateway error codes are the part of an integration nobody budgets for, and then a weekend goes into reverse-engineering them.
We spent 4 October 2026 doing exactly that, deliberately. We read every error reference these nine publish, then sent each one an identical malformed request and recorded the status, the headers and the bytes. Every figure below was captured from the live APIs on that date and every documented value was read from a first-party page, not from a comparison article. Here is what nine vocabularies for “your key is wrong” actually look like.
Which crypto payment gateways document their error codes
Five of the nine have a page you can point a new engineer at. The rest make you assemble the vocabulary yourself, out of example responses and endpoint pages,.
The spread in that third column is the story. BitPay publishes 26 codes, BTCPay Server publishes none, and they are both respected products with careful documentation elsewhere. BTCPay's Greenfield specification runs to 552 KB and defines the error object properly — {code, message}, with code described as an error code describing the error — and then never enumerates one value for it. We searched the whole spec for enumerated values on that field and found none.
NOWPayments is the opposite failure. Its API reference is a published Postman collection with 40 example responses, and the error vocabulary exists only inside five of them: NOT_FOUND, INVALID_REQUEST_PARAMS and BAD_REQUEST. There is no index, so the only way to learn the vocabulary is to read every endpoint — and the code you hit first is not among the three, as the next section shows.
Its error formats are documented inline on endpoint pages — the invoice page alone carries 12 distinct message strings, including The network was not found and You are forbidden. We probed eight plausible paths for a consolidated reference on doc.cryptomus.com and every one returned 404; its English sitemap is an empty <urlset>. If a page exists, neither its sitemap nor its URL conventions will find it.
One bad API key, nine different answers
A missing or wrong API key is the first error every integration meets, and the only one measurable across every gateway without an account. So we did: one request per gateway, no credentials, 4 October 2026, recording the wire status and the exact bytes.
Five 401s, two 403s, one 422. Only 401 is the correct status for a missing credential, and a third of the gateways do not use it. That matters, because almost every HTTP client and retry wrapper in common use classifies by status family before it reads a body — and the two 403s will be read as a permissions problem on an otherwise authenticated request, which is the wrong diagnosis.
Plisio's 422 is the most interesting of the three. Its message is genuinely helpful — Please check your secret key is correct and domain is verified tells you about domain verification, a failure mode no other gateway in this set mentions — and it arrives with a numeric code: 101 nested two levels deep at data.code. It is the most actionable auth error we measured and the hardest to parse.
Each probe was a single unauthenticated call to a documented endpoint from our cloud container, which is not a browser. Coinbase Commerce's api.commerce.coinbase.com answered HTTP 503 and an HTML challenge page rather than its API, so its row is marked unmeasurable rather than guessed at. Plisio's API answered us at 14:49 UTC and had stopped answering our egress IP by 14:55; the figures above are from the window when it did, and the likeliest explanation is our own probing, not a Plisio outage.
The HTTP status is not the error
OxaPay is the reason this section exists. Its response to a bad merchant key arrives with 403 on the wire and "status": 401 in the body. Both numbers are in the same response, and they disagree. We reproduced it twice, once with no key header and once with a deliberately wrong one, and got byte-identical bodies both times.
Then we sent OxaPay a mistyped path, and it answered 403 again — this time with "result": 404 in the body. So the wire status is 403 for a credential problem and 403 for a routing problem, the real status lives in the body, and the field holding it is named status on one error and result on the other. You cannot classify an OxaPay failure from its HTTP status, and you cannot classify it from a single body field either.
The practical rule that falls out of all nine measurements: read the body first and the status second, which is the reverse of how most HTTP clients are written. Where the two conflict, the body is the one the gateway's own application layer produced, so it is the one that reflects what the gateway thinks happened.
Three gateways change envelope shape mid-API
An error handler is written once and then trusted. That only works if the shape of an error is stable across a gateway's endpoints, so we tested the cheapest second error available: a path that does not exist.
Cryptomus returns three different envelopes. Its documentation shows {"state":1,"errors":{...}}, an unauthenticated call returns a bare {"message":"Invalid Sign."} with no state field at all, and an unknown path returns a bare {"error":"Not found"}. Three shapes, one API, and a handler written against any one of them fails on the other two. A probe with a bogus merchant header gave a fourth message, Invalid Merchant Uuid., in the second shape.
BitPay and BTCPay Server fail in opposite directions, and both will crash a naive client. BitPay serves a 6,731-byte HTML single-page-app shell at text/html, so JSON.parse throws on a payment error. BTCPay sends zero bytes with no content type, so JSON.parse throws on an empty string. CoinGate avoids both by answering a bad API path with a 301 redirect to its documentation site — which means a mistyped CoinGate URL, in a library that follows redirects, hands you an HTML docs page with a 200.
NOWPayments is the only gateway in the set whose envelope held steady: {status, statusCode, code?, message} on both probes, with statusCode agreeing with the wire both times. For all the complaints above about where it hides its vocabulary, it is the one you can write one handler for.
Seven of eight contradict their own documentation
This is the finding we did not expect and the one that should change how you integrate. Of the eight gateways we could measure, exactly one returned what its documentation says it returns.
BlockBee is that one, and it is exact. Its error-handling guide lists API Key not provided, please use api.cryptapi.io if you don't have an API key under HTTP 401, and that is the string we got back, character for character — including the reference to cryptapi.io, the brand BlockBee operated under before it renamed. A documented string that still names a predecessor product is a sign somebody keeps the page in sync with the code.
The other seven drift in three distinguishable ways, and the distinction matters because the fixes differ:
- Undocumented values. CoinGate's published table maps 401 to
BadCredentials; the live API returnsBadAuthToken. NOWPayments returnsINVALID_API_KEY, which is in neither its collection nor any page we could find. BTCPay returnsunauthenticated, a value its specification permits and never names. In each case an engineer writing aswitchfrom the docs produces a handler with no matching branch. - Wrong status in the docs. Cryptomus documents its errors at HTTP 422 and returns 401. Plisio documents authentication failure as 401
AUTHENTICATION_FAILUREand returns 422 with a numeric code. Neither shows up in testing, because a test with a valid key never exercises it. - A documented scheme the API does not use. BitPay publishes 26 six-digit codes and then answers an unauthorised call with
{"error":"This endpoint does not support the `public` facade"}— no code field at all. The scheme is real and covers invoices and refunds; it is not what you get at the authentication layer.
Before you write the handler, send each gateway the four errors you can trigger without a successful payment: no key, a wrong key, a mistyped path, and a malformed body. Save the raw bytes into your repository as fixtures. Twenty minutes per gateway, it is the only way to find the three drift patterns above, and the fixtures double as regression tests when a vendor reshapes a response.
BitPay's 6-digit scheme is the good idea nobody copied
Worth separating out, because it is the only design in this set that solves the actual problem. BitPay's codes are six digits where the digits carry meaning.
So 010110 is a POST to invoices that failed because the price is below the minimum, and you know all three of those facts before you read the message. The method lives in the code, so a log line locates the call without the request beside it. Across 5 method prefixes, the 26 suffixes give the scheme room for 130 concrete codes.
Nobody else does this. The nearest comparison in the whole search result set is not a merchant gateway at all: Circle's payment network publishes 58-plus numeric codes in 6 tables, with blockchain-specific values a merchant gateway would be useful to have — 290313 INSUFFICIENT_GAS_BALANCE, 290315 GAS_PRICE_TOO_LOW, 290202 QUOTE_EXPIRED. It is the most complete error reference in this niche, and it belongs to a network none of the nine runs on.
Mapping nine gateway error-code vocabularies to five buckets
You do not need to model nine error schemes. You need five decisions — fixable by me, by the caller, by waiting, or by nobody — and a ten-line mapping layer per gateway. Here is the mapping we would write from the measurements above.
The fourth column is the one to read twice: every row has a gateway that breaks the obvious rule, and in four of five it is one that looks correct until you test it. Put the mapping in a small adapter per gateway, not in your business logic — when a vendor changes a string you want one file to edit.
Where a gateway gives you no code at all — BlockBee, Cryptomus, BitPay and OxaPay — match on a substring, not the whole message, and log the full body whenever no branch matches. Message text gets reworded without notice, and an unmatched error that reaches your logs intact is recoverable; one swallowed into a generic failure is not.
What this means for your retry logic
Retry rules written against HTTP status families are wrong on these APIs, and wrong expensively: they retry what cannot succeed and give up on what could.
Do not retry 403 on a crypto gateway. On NOWPayments it means the key is wrong; on OxaPay it means the key is wrong or the path is. Neither improves with backoff, and a retry loop against an auth failure spends your rate-limit budget on a request that can never work — CoinGate allows 200 requests a minute and only two of nine gateways publish a figure at all, so that budget is mostly invisible to you.
Do not treat 422 as permanent. It usually is, which is what makes Plisio's auth 422 dangerous: the fix is to correct the key or verify the domain, which an operator can do, so the right behaviour is to alert rather than to drop the payment. Do not read an empty body as a network failure either — BTCPay returns zero bytes on a 404, and a client that treats that as a dropped connection retries a URL that will never exist.
A gateway that accepts your invoice and then stops delivering callbacks returns no error anywhere, because nothing failed from its side — which is why webhook retry rules and the merchant-side checklist for a payment that never arrives are separate problems from this one, and why testing against a sandbox catches the error vocabulary but not the silence.
Error handling is an integration cost. Price it before you choose.
We track fees, settlement timing, supported chains, invoice windows, webhook retries, rate limits and uptime reporting for every processor in the directory. How legible a gateway's errors are belongs on that list, because it is the column you pay for in engineering hours rather than basis points. NOWPayments is the one whose envelope held steady across both our probes, and the one whose vocabulary is hardest to find.
Compare Crypto Payment Gateways →FAQ
What HTTP status does a crypto payment gateway return for a bad API key?
There is no single answer, which is the problem. On 4 October 2026 we sent an unauthenticated request to nine gateways and got three statuses: 401 from CoinGate, BlockBee, Cryptomus, BitPay and BTCPay Server, 403 from NOWPayments and OxaPay, and 422 from Plisio. Coinbase Commerce answered a non-browser client with a 503 challenge page, so we could not measure it. An integration that branches on status alone misclassifies the commonest failure in crypto payments on three of the nine.
Which crypto payment gateway has the best error documentation?
BitPay on structure, Plisio on coverage. BitPay publishes 26 numeric codes under a scheme where the first two digits encode the HTTP method and the next two the resource, so a code says where the fault happened before you read the message. Plisio publishes a 16-row table mapping every status it uses to a named constant such as RESOURCE_NOT_FOUND and RATE_LIMIT_REACHED.
Does BTCPay Server document its API error codes?
It documents the shape and none of the values. The Greenfield specification defines a ProblemDetails object with a code field typed as a string, and in 552 KB there is not one enumerated value for it. We measured one in the wild: an unauthenticated call returns code unauthenticated at HTTP 401. Validation errors differ again, returning a top-level JSON array of path and message pairs rather than an object.
Why does the same gateway return different error formats?
Because most of these APIs grew endpoint by endpoint and nothing enforced a single envelope. Cryptomus is the clearest case: its documentation shows a state field set to 1 with an errors object, an unauthenticated call returns a bare message field with no state at all, and an unknown path returns a bare error field. Three envelopes, one API. OxaPay does the same with different names, carrying the HTTP status in a status field on one error and a result field on another.
Can I trust the error codes in a gateway's documentation?
Verify them against the live API before shipping a handler that depends on them. Of the eight we could measure, one returned exactly what its documentation says: BlockBee, down to the string that still points callers at its predecessor brand api.cryptapi.io. CoinGate returns the reason BadAuthToken where its table lists BadCredentials, and NOWPayments returns INVALID_API_KEY, which appears nowhere in its published collection.
What should my error handler do with a 403 from a crypto gateway?
Treat it as a permanent failure and alert, rather than retrying. Both gateways that answered 403 mean something retrying cannot fix: on NOWPayments the API key is wrong, and on OxaPay either the key is wrong or the path is. The usual reading of 403 as a permissions problem on an otherwise valid request applies to neither.
Do any crypto payment gateways return a machine-readable error code?
Four of the eight we measured. NOWPayments returns code as a SCREAMING_SNAKE_CASE string, CoinGate returns reason in PascalCase, BTCPay Server returns code as a lowercase slug, and Plisio nests a numeric code at data.code. The other four give a sentence and nothing else, so the only way to branch is to match message text, which breaks the first time a vendor rewords a string. OxaPay is the frustrating case: it has a dedicated error object and it came back empty.
What does “This endpoint does not support the public facade” mean on BitPay?
Your request reached BitPay without a merchant token, so it was evaluated against the public facade, which has no access to that endpoint. BitPay segments its API by facade rather than permission scope: public, merchant and payout. The concept appears nowhere in the 26 numeric error codes, so the error message is the only place most integrators meet it. Add the merchant token and the call works.
Affiliate disclosure: payyd.co earns a commission on sign-ups made through our /go/ links, including the NOWPayments link above. No gateway supplied, reviewed or saw these findings before publication. Method: on 4 October 2026 we read the first-party error references these nine publish — BitPay's error-codes page, CoinGate's common errors, BlockBee's error-handling guide, OxaPay's error reference, the BTCPay Greenfield specification, Cryptomus's invoice endpoint, Plisio's HTTP status-code appendix, NOWPayments' published Postman collection and the official Coinbase Commerce Node SDK — then sent each live API an unauthenticated request and a mistyped path, recording the wire status, content type, byte count and exact body. Circle's CPN error codes are quoted for comparison only; Circle is not one of the nine. Figures are as at 4 October 2026; error vocabularies change without notice.