Errors
The error format of the merchant API, the error codes, and when to retry a request.
The merchant API returns errors as JSON with an HTTP status code. The format is the format of the common hosted-gateway API, so existing error handling works.
Format
{
"status": false,
"statusCode": 400,
"code": "INVALID_REQUEST_PARAMS",
"message": "`price_amount` must be greater than 0."
}
| Field | Description |
|---|---|
status |
Always false for an error |
statusCode |
The HTTP status code |
code |
A stable code. Use it in your code |
message |
A text for people. It can change. Do not parse it |
Codes
| HTTP | code |
Cause |
|---|---|---|
| 400 | INVALID_REQUEST_PARAMS |
A field is missing or not valid, the body is not valid JSON, the ticker is not enabled for the project, the amount is below the minimum, or the two-factor code is wrong. The message tells which |
| 401 | AUTH_REQUIRED |
The API key is missing or wrong, the payout token is missing, wrong or expired, or the email or password for POST /v1/auth is wrong |
| 403 | FORBIDDEN |
The user of the payout token is not a member of the key's project, is not a project admin, or has no two-factor authentication on a mainnet install |
| 404 | NOT_FOUND |
The path does not exist, or the payment, invoice or payout does not exist or belongs to another project |
| 405 | METHOD_NOT_ALLOWED |
The path exists, but not with this HTTP method |
| 409 | CONFLICT |
The request conflicts with an existing object, for example a unique_external_id that is used with other fields |
| 429 | TOO_MANY_REQUESTS |
Too many requests or too many wrong codes. Wait and retry |
| 500 | INTERNAL_ERROR |
An error on the server. The message is Internal error. The server log has the details |
| 503 | UNAVAILABLE |
A service that the request needs is not available: the exchange rates, a free deposit address or a node of the network |
Treat code as an open set. Later versions can add values. Handle an unknown code by its HTTP status.
Rate limits
| Limit | Value |
|---|---|
| Merchant API, per client IP address | 600 requests per minute |
| Checkout pages, per client IP address | 300 requests per minute |
POST /v1/auth, per IP address and per email address |
10 attempts per minute |
Wrong two-factor codes in POST /v1/payout/{batch_id}/verify, per user |
5, then the user is locked for 15 minutes |
A request above a limit gets 429. Turmite sends no Retry-After header with a 429.
When to retry
| Response | Action |
|---|---|
2xx |
Done |
400, 401, 403, 404, 405, 409 |
Do not retry. Fix the request or the configuration |
429 |
Retry after a delay, for example 10 s |
503 with Retry-After: 30 |
Retry after 30 s. There was no free deposit address, or the network has no connected node |
500, 502, 503, 504 |
Retry with backoff, for example after 1 s, 5 s and 30 s |
| Timeout or connection error | Read the state before you retry. See below |
Timeouts on POST requests
A timeout does not tell you if Turmite created the object.
POST /v1/payment: sendidempotency_keywith the request. Send the same request again after a timeout. Turmite returns the first payment.POST /v1/invoice: you can create a second invoice for the same order. The customer pays one of them. The unpaid one expires. Use the newestinvoice_url.POST /v1/payout: give each withdrawal aunique_external_id. Send the same request again. Turmite returns the existing payout. Do not create a payout without one. See Payouts.
Log errors safely
- Log
statusCode,codeandmessage. - Do not log the
x-api-keyheader, the payout token or the request body ofPOST /v1/auth.
Errors on your webhook endpoint
Turmite treats every response other than 2xx from your endpoint as a failure and retries. See Webhooks.
Return 401 when the signature is wrong. Return 2xx for an event that you already processed. A 5xx response causes a retry.