OnLink

Errors

One error envelope for every refusal, the codes you branch on, and what is worth retrying.

Every partner-plane failure returns the same JSON shape.

{
  "statusCode": 409,
  "message": "QUOTE_EXPIRED_OR_CONSUMED",
  "error": "Conflict",
  "requestId": "req-1756512000000-a1b2c3d"
}

Two fields are appended when they apply:

  • errorCode — present on some refusals, absent on most.
  • retryAfterSeconds — present on a 429, mirrored into the standard Retry-After header.

Branch on message, not on errorCode

The stable short codes arrive in message. errorCode is only set on some refusals, so a client that switches on it silently falls through to a default branch for most of the catalogue. Validation failures are the one exception to the short-code shape: they read Validation failed on: <fields>.

requestId is on every error body and is also returned as the X-Request-Id header. It is the only handle that resolves to your request in our logs — log it on every non-2xx response and quote it when you contact us.

Status codes

StatusMeaningRetry?
202Accepted. The order exists; it has not settled.
400The request body failed validation.No. Fix the request.
401Authentication failed. Uniform, with no reason given.No. See below.
404No such route, or no such order for your partner account.No.
409A conflict with existing state — a spent quote, a reused reference, a hash already attached.Only after changing something.
422The order breaches one of your caps.No. Split it or wait for the window.
429Rate limited.Yes, after Retry-After seconds.

401 is deliberately uninformative

A bad signature, an expired timestamp, a replayed nonce and an unknown key all return the same body:

{
  "statusCode": 401,
  "message": "An error occurred",
  "error": "unauthorized",
  "requestId": "req-1756512061412-9f4e2b7"
}

Distinguishing them would tell an attacker which half of a guess was right. Debug against the worked example on the authentication page instead.

429 carries its own backoff

{
  "statusCode": 429,
  "message": "Too Many Requests",
  "error": "Too Many Requests",
  "requestId": "req-1756512184903-7c1d5a0",
  "retryAfterSeconds": 12
}

Honour retryAfterSeconds, or the Retry-After header that mirrors it. A tight retry loop stays refused. The limit is 120 requests per minute per partner across all your credentials — see Caps and limits.

The code catalogue

These are the values that arrive in message. Branch on them.

Quotes

CodeStatusMeaningWhat to do
QUOTE_EXPIRED_OR_CONSUMED409The quote has expired or was already used to create an order.Take a fresh quote. Do not retry this one.
QUOTE_SIDE_MISMATCH409A buy quote was presented to the sell route, or the reverse.Quote the side you are creating.

Orders

CodeStatusMeaningWhat to do
ORDER_EXCEEDS_PER_ORDER_CAP422The order is larger than your per-order ceiling.Split it.
ORDER_EXCEEDS_DAILY_CAP422The order would breach your rolling 24-hour ceiling.Wait for the window to roll, or talk to us.
ORDER_NOT_BUY_SIDE409A buy-only action was taken against a sell order.Check the orderId.
ORDER_NOT_SELL_SIDE409A sell-only action was taken against a buy order.Check the orderId.
ORDER_NOT_AWAITING_USDT409A transaction hash was attached to an order that is no longer awaiting a deposit.Read the order; it has already moved on.
EXPECTED_AMOUNT_MISMATCH409The amount presented does not match what the order expects.Do not adjust and retry — read the order first.
PARTNER_SUSPENDED409Your partner account cannot create orders.Contact us. Retrying will not clear it.

Deposits and payouts

CodeStatusMeaningWhat to do
TX_HASH_ALREADY_ATTACHED409This order already has a transaction hash.One hash per order. Read the order.
TX_HASH_ALREADY_USED409That hash is already attributed to another order.One deposit funds one order. Send a separate deposit.
WALLET_NOT_DELIVERABLE409The withdrawal address cannot receive — usually not confirmed.Confirm the address, then retry.
PAYOUT_ACCOUNT_NOT_PAYABLE409The payout account cannot receive the KES.Use another registered account, or contact us.

Ignore codes you do not recognise

We may add codes. Treat an unknown message on a 4xx as a non-retryable refusal, log it with its requestId, and surface it rather than retrying — the safe default when you do not know why something was refused.

What is worth retrying

  • 429 — yes, after the interval it gives you.
  • 5xx and network timeouts — yes, with backoff, and reuse the same partnerReference. That is what makes a retry safe: the same reference returns the existing order rather than creating a second.
  • Everything else — no. A 4xx means the request will be refused the same way until something changes.

On this page