API versionv2 next

API v2 is not live yet: it launches in early 2027, and until then these pages are its spec. Switch to v1 (live)

Errors

A request that fails is answered with a status other than 200, and a message of one line. The status says what kind of failure it is, and whether to try again; the message says what exactly.

The response

HTTP/1.1 400 invalid json in items[0].total: missing currency
Content-Type: text/plain

invalid json in items[0].total: missing currency

The message is the body, in UTF-8, ended by a newline, and over HTTP/1.1 it is also the status line's reason phrase. Read it from the body, as HTTP/2 has no reason phrase. Log it whole: it names the field and the fault, and it is what we ask for when you write to support.

An error is never JSON. Check the status before you parse the body.

Status codes

Status Meaning Retry
400 The request is wrong: its JSON, a field's value, or the HTTP itself. The message says what. No. Fix the request.
401 The API key is missing or wrong, or may not make this request. See Authentication. No.
402 A charge of a subscriber was declined: its message starts with transient or permanent. See Declines. transient: later, with a new key. permanent: no.
404 The URL fits no request, or names an object that does not exist. No.
405 The URL is right, but not the method, such as a GET to create a link. No.
408 The request's body did not arrive within 30 seconds of its headers. Yes, with the same Idempotency-Key.
409 The request conflicts with the object's state. The message says which, and is one of index mismatch, transaction in use, transaction is locked, transaction has acts, and link is paid. After you read the object again with seq, with a new Idempotency-Key.
410 The object can't be used as asked until it changes, such as a deleted subscriber, which can't be charged until it is renewed. No.
413 The body is over 32 KiB, or the request line and headers over 4 KiB. No.
414 The URL's path has more than 8 segments. No.
500 We failed, or a party behind us did, such as the acquirer. The message says what, and the request's page whether anything was done. After you synchronize, with a new Idempotency-Key.
502, 503, 504 We could not be reached, as while we deploy. If it lasts, our status page says whether we are down. Yes, with the same Idempotency-Key.

A request's own page lists the errors that only it gives:

Request Its errors
Create payment link Errors
Delete payment link Errors
Capture, refund, void Capture, refund, void
Create subscriber Errors
Charge subscriber Declines and other errors
Renew subscriber Errors
Delete subscriber Errors
Seq Errors

Invalid JSON

A body that is not a JSON object, or a field that is not as its table says, is answered with:

400 invalid json in {where}: {why}

{where} is the path of the field at fault: keys joined by dots, with array indexes in brackets, as in items[1].total or billing.address[2]. It is json root object when the fault is in the object as a whole, and json data when there is no object at all. {why} is one of these, or another that says as plainly what is wrong:

{why} Meaning
no json present The body is empty.
unexpected end of object The body ends inside the object, as when it is cut off.
invalid amount An amount is not a number and a currency. See Amounts.
missing currency An amount has no currency.
mismatching currencies DKK and EUR The items' totals are in more than one currency.
missing total in item An item has no "total".
number is not a pure integer An integer field has a fraction or an exponent.
illegal control character \x0A in string A string contains a raw control character, here a newline, which JSON requires to be escaped.
invalid utf in string A string is not valid UTF-8.

A request whose body has more after the object than white space fails with 400 invalid json: garbage at offset {n}, where {n} is the byte where the trouble starts.

Retrying

A request that got no answer, because the connection broke or timed out, or got a 408, 502, 503, or 504, may or may not have run. Send it again, unchanged and with the same Idempotency-Key, so that we answer with the first request's result if it ran. See Idempotency.

A request that got an error from us, 4xx or 500, has run, and its answer is stored under its key. Sending it again with the same key gets the same error, for 24 hours. So:

  • A 4xx, but 408, fails the same way until you change the request or the object changes: fix the request, or for a 409, read the object again first. A 402 transient is the one to send again unchanged, the next day, with a new key.
  • A 500 from an act or a charge may have done its work before it failed, as when the acquirer acted and our database did not. Synchronize, and if the act or charge is not in seq, send it again with a new key.

Between tries, wait, longer each time: from 1 second, doubling, to a minute. The implementation note on retries works through the cases, such as a capture whose answer never came.