API versionv1 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, an amount, a capture or refund without a "total", or an Idempotency-Key. 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.
404 The URL fits no request, or the Authorization header holds no key of the form {shopid}:{secret}. 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.
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 Anything else that went wrong: we failed, or a party behind us did, such as the acquirer, or the request did not fit the object, as an unknown transaction, a capture with an old "index", or a declined charge. The message says what. After you synchronize, with a new Idempotency-Key, if the act or charge did not happen and the message does not say why it can't.
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.

In v1, a 500 is the answer to most failures, of ours and of yours, and its message is the only thing that tells them apart. Log it, and don't branch on it: the messages may change. v2 gives each kind of failure a status of its own.

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

Request Its errors
Create payment link Errors
Capture, refund Capture, refund
Create subscriber Errors
Charge subscriber Charge subscriber
Renew subscriber Errors
Seq Errors

Invalid JSON

A body that is not JSON, or an amount or an integer that can't be read, 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 field of the wrong type is not among them: v1 ignores it, as Requests says.

A capture, a refund, or a charge 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. Create payment link reads the object and ignores what follows it.

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: fix it.
  • A 500 from a capture, a refund, or a charge may have done its work before it failed, as when the acquirer acted and our database did not, or may have failed because the transaction changed, or the bank declined the charge. Synchronize, and if the act or charge is not in seq, read the message to decide: send it again with a new key, now or later, or not at all.

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.