Skip to main content
Find the symptom, check each cause in turn, and follow the link for the full rule. If none fits, send us the response’s x-request-id.

401 unauthorized

A key sent to the other environment’s host gets a message that says so. Every other problem with the key itself returns the same 401, so the response never tells someone holding a stolen key whether it’s valid. A valid key without the scope a request needs gets 403 insufficient_scope instead, naming the scope. Check each cause of a 401:
  • The header is Authorization: Bearer followed by the key.
  • The key belongs to this host: sandbox keys work only on the sandbox host, and live keys only on the live host.
  • In live, the request comes from an address registered for the key. If live requests start failing, check whether your servers’ outbound addresses have changed. New addresses need a new key.
  • The key hasn’t expired at the end of a rotation, or been revoked.
When the cause is the address, our log records it: send us the response’s x-request-id. See Keys and security. We check the path and the method before the key, so a request to a path we don’t serve gets 404 not_found, and one with the wrong method gets 405 method_not_allowed, with or without a key. The one exception is /v1/orders/estimate, which accepts POST only: another method there is read as an order id.

A webhook signature doesn’t match

  • You used the body bytes exactly as they arrived. A framework that parses the JSON and writes it out again changes them.
  • You base64 decoded the part of the secret after whsec_ and used those bytes as the key.
  • You signed the webhook-id, the webhook-timestamp and the body, joined by full stops, in that order.
  • You used this environment’s secret. The sandbox and live endpoints have different secrets.
  • You checked every entry in webhook-signature. During a secret rotation there are two.
Run your code against the test vector. If it passes there and fails on real events, the bytes are changing before your check.

An order is uncertain or stays sending

Don’t place it again under a new key: it may already be at the exchange. Wait for its next event, or retrieve it. See Handle an uncertain result.

An allocation is uncertain or stays sending

Don’t send it again under a new key: the broker may already have booked it. Wait for its next event, or retrieve it. See Identical allocations.

An application is uncertain or stays sending

Don’t send it again under a new key: the broker refuses a second application for the same customer. Wait for its next event, or retrieve it. See Applications and allocations.

A 409

A 503

The request didn’t complete. Codes ending in _not_sent were stored as never sent, so send the request again with a new key. For outcome_not_recorded, retrieve the order, application or allocation the error names until it resolves, and don’t send it again under a new key. Every other 503 takes the same request again: with the same key where the request has one, after the Retry-After seconds where the response has that header, and backing off where it doesn’t. When to use a new key lists each code. A 503 exchange_unavailable on a read of balances, positions, trades or contract notes can also mean the broker is busy with other reads. See Reads that ask the broker.

An event didn’t arrive

  • An endpoint is registered in this environment. Events from before registration are only in GET /v1/events.
  • Your endpoint answered 2xx in time. If not, we retry on the schedule, and failures in a row pause your endpoint.
  • There’s no event for sending, and every other state has one.
  • The event is in GET /v1/events, whatever happened to its delivery. Catch up from your stored cursor.
If we stopped retrying events while your endpoint was down, ask us to send them again.

An application stays submitted

The broker decides how long its review takes. For how long we check on it, see Wait for the account to open.

A payment isn’t in your wallet

See Find the credit.

429 or 422 limit_exceeded

You’ve reached a limit. GET /v1/limits shows what’s left. See Limits.