Errors

Every error is JSON with the same fields. Switch on type, show message to a developer, and keep request_id for support.

{
  "_tag": "ParseError",
  "type": "ParseError",
  "message": "Failed to parse QR code: invalid checksum",
  "docs_url": "https://apidocs.borderli.io/docs/errors/ParseError",
  "request_id": "550e8400-e29b-41d4-a716-446655440000"
}

Some errors add a field: details on validation and conflict errors, reason on ExecutionError, scheme on UnsupportedScheme, retryAfter on RateLimitError and ServiceUnavailable. _tag always equals type.

Error types

typeHTTPWhat to do
ParseError400The QR string could not be decoded. Check the scan. Do not retry as is.
IdempotencyConflict400The key was used with a different body. Use a new key.
AuthError401Fix the x-api-key header.
IdempotencyInProgress409The first request is still running. Send the same request again after a moment.
ConflictError409The transaction is not in a state that allows this. details.reason says why. See Pay-ins.
ValidationError422A field is missing or wrong. details says which.
NotFound404No transaction or delivery with this id exists for your account. Check the id.
UnsupportedScheme422Borderli does not support this QR scheme yet.
AmountRequired422The QR carries no amount. Send amount and retry.
InstructionExpired422The instruction is older than 30 minutes. Resolve the QR again.
FxQuoteExpired422The FX quote has expired. Resolve the QR again.
RateLimitError429Wait retryAfter seconds and retry.
RoutingError502No provider could handle this scheme and country right now. Retry with backoff.
FxError502No FX quote right now. Retry, or leave out wallet_currency.
ExecutionError502The payment rail rejected the request. reason says why. Retry with the same idempotency key.
ServiceUnavailable503Borderli or a dependency is down. Retry after retryAfter seconds with the same idempotency key.

Retrying

Errors that arrive later

An HTTP error means the request was not accepted. A payment that was accepted and then failed on the rail is a different thing: the transaction ends in status: failed with error.reason, and you learn about it by webhook or by polling. See Pay-outs and Webhooks.