Skip to content

Errors

Errors return a JSON body with a stable numeric code and a human readable msg.

{"code": -1022, "msg": "signature mismatch"}

Every error belongs to one of four ranges, and the range tells the client what to do.

POST /order answers 202 once the order is on its way. Any other status means nothing was placed, and since the clientOrderId is spent either way, a retry needs a new one. A 202 can still carry an error object holding -5004, which means the submission was sent but not confirmed, so the order stands and GET /order says what became of it.

An order that reaches the chain and then fails records the reason on itself, so -2024, -2023 and -1000 can appear on GET /order after a 202. A client that places orders should read order.error.code there as well as the HTTP status.

{"orderId": "0x...", "status": "REJECTED", "error": {"code": -2024, "msg": "transaction reverted"}}

Request errors, -1xxx

The request itself is wrong, so it has to be fixed before it is sent again. A retry of the same request fails the same way.

Code Meaning
-1000 Internal error.
-1021 Timestamp outside the recv window. Synchronize against GET /time.
-1022 Invalid key, signature, or authentication headers.
-1023 Session missing or invalid on a key management endpoint.
-1099 Unknown API version.
-1102 Missing or malformed field. The message names the field.
-1121 Unknown contractId.

Rate limits, -1003

Too many requests were sent. Unlike the rest of -1xxx, this one is retryable.

Status Meaning
429 This wallet's quota is spent, or this IP address has sent too much.
503 The API is shedding load, which is not a quota problem.

Wait Retry-After seconds, then retry. If the header is absent, back off and retry.

X-RateLimit-Limit and X-RateLimit-Remaining come back on every response from a limited endpoint, so a client can watch the remaining count fall and ease off before it hits zero.

What the limits are and what drains them is in Rate limits.

{"code": -1003, "msg": "rate limit exceeded, slow down and retry"}

State conflicts, -2xxx

The request is well formed but conflicts with the current state of the account or the market. The message states what stands in the way.

Code Meaning
-2019 Betting on this market is closed. Sent with HTTP 503 rather than a 4xx, so branch on the code and not on the status, since retrying will not open the market.
-2022 rfqId does not match a live quote, request a new one with POST /order/rfq.
-2023 The broker refused to sign the order.
-2024 The transaction reverted on chain.
-2025 Unknown order. No order matches the orderId or clientOrderId on GET /order.
-2026 The request is understood but this API cannot serve it yet.
-2027 The rfqId was already used by an order, a quote executes once. Look up the order named in the message with GET /order to see what became of it. It may have failed, and the quote is spent either way, so request a new quote to trade again rather than retrying this one.
-2028 This clientOrderId is already being placed, retry the same request in a moment.
-2029 Nothing is held for that outcome to be sold.
-2030 The opposite outcome is held. Close that bet before betting this one.
-2031 The rfqId expired before it was used, request a new quote with POST /order/rfq.

Signing, -4xxx

Code Meaning
-4002 On an order, this key can no longer sign for the wallet because the grant was removed, so create a new API key and retrying will not help.

Upstream failures, -5xxx

Something behind the API was unavailable. The same request may succeed later.

Code Meaning
-5001 Chain state or position history could not be read.
-5002 The broker service was unavailable.
-5003 The signer was unavailable. If it keeps failing, check for a -4002 on the order, which means the grant is gone rather than the service being down.
-5004 The chain was congested and the transaction could not be placed.

Handling errors in code

try {
  await signedPost("/order", body);
} catch (err) {
  const { code, msg } = err.response.data;
  console.error("rejected:", code, msg);
}
try:
    signedPost("/order", body)
except requests.HTTPError as err:
    e = err.response.json()
    print("rejected:", e["code"], e["msg"])
// call() surfaces API errors as ordinary Go errors carrying code and msg.
if err := signedPost("/order", body, &order); err != nil {
    fmt.Println("rejected:", err)
}

Versioning

Clients may pin a major version with the X-Api-Version header. The current version is 0 and is echoed on every response. An unknown version returns -1099.

Limits

Signed request bodies are read up to 1 MB and anything beyond that is truncated rather than rejected, so an oversized body surfaces as a signature mismatch (-1022) or a JSON parse error. The recommended X-Recv-Window is 5000. Request rates are limited, and Rate limits describes how.