error.code on failures and a meta.requestId on every response. Some failures happen earlier, at the API gateway, and come back with a smaller body and no meta.requestId. Their ID is in the apigw-requestid response header instead. Your client needs to handle both, retry only the failures a second attempt can fix, and sign every attempt again.
The response envelope
200, including creates (POST /limit-order, POST /dca-order/strategies) and cancels (DELETE /limit-order/{id}).
New error codes can be added. Treat a code you don’t recognize according to its HTTP status.
Error codes
Gateway responses
The API gateway sits in front of Olympex. It authenticates signed requests, enforces a timeout of about 30 seconds and answers some requests itself. Its responses carry onlymessage: no success, error or meta, so no meta.requestId. They carry an ID in the apigw-requestid response header, which browsers can’t read on cross-origin calls. The OpenAPI spec names their body GatewayError.
To tell the two kinds of response apart, check the body for
success. Every Olympex response has it and no gateway response does. Three statuses can come from either:
401. The gateway’s{"message":"Unauthorized"}means a signing header is missing. Olympex’sUNAUTHORIZEDis a problem on the Olympex side.403. The gateway’s{"message":"Forbidden"}means authentication failed. Olympex’sFORBIDDENmeans the body doesn’t match the signed hash.500. From Olympex, with an error code; from the gateway, with onlymessage.
404 comes from Olympex, with the code NOT_FOUND. For an unknown path or method, its message names them, for example "No route for GET /api/v1/quote".
Sign requests maps each signing mistake to the 401, 403 or 400 it produces.
Which errors to retry
Requests that create a resource
GET, PATCH and DELETE requests are safe to repeat. So are POST /quotes, POST /swap, POST /support-chain and POST /tx-status, which change nothing: POST /swap only returns calldata and never broadcasts. A repeated DELETE /limit-order/{id} whose first attempt went through returns 409 CONFLICT, because the order is already cancelled: read the order with GET /limit-order/{id} instead of treating the 409 as a failure.
Three endpoints create a new resource on every successful call. Olympex ignores any id you send, so you can’t use one to make a repeated call recognizable:
After a timeout, a network error or a
5xx, you can’t tell whether a create succeeded. Don’t retry it blindly: list what exists and match on your own fields first.
- Limit order. Call
GET /limit-order?accountTo=<maker>and look for an order with the same chain, tokens,amountandpriceTrigger. - DCA strategy. Call
GET /dca-order/strategies?accountTo=<maker>, which lists strategies newest first, and look for one with the same tokens,totalAmount,iterationsandfrequency. - API account. No endpoint lists accounts. If you never received the response, you never saw its secret key, so create another account.
?accountTo= matches case-sensitively. Send the maker address in the same EIP-55 checksummed form you used to create the order.
Back off with jitter
Retry with exponential backoff and full jitter: before each retry, wait a random time between zero and a ceiling that doubles after every failure, up to a cap, and stop after a few attempts. Jitter spreads retries out, so many clients that failed together don’t retry together. Route every call through one helper instead of retrying at each call site. Handle errors and retries builds one on the reference implementations:olympexRequestWithRetry in TypeScript and olympex_request_with_retry in Python. Both take (method, path, body), like the reference helpers, and never retry the three creates automatically. Their defaults (4 attempts, a 1-second base delay, a 20-second cap) are starting points: tune them to your latency budget.
Sign every attempt again
The server rejects a nonce it has already seen in the last 5 minutes, and any timestamp more than 300 seconds from server time. Resending the headers of an earlier attempt fails with403 if that attempt reached Olympex, even if it ended in a 500 or a timeout. After a client timeout you can’t tell whether it did, so sign again.
Call your signer for every attempt, so each one gets a new timestamp and a new nonce. olympexRequest and olympex_request sign on every call, so a retry helper that calls them for each attempt already does this. Never cache, queue or reuse signed headers: each set authenticates one request, once.
Keep the request ID
meta.requestId identifies a request. Log it for every response, next to your own correlation ID. When a failure persists, send it to partners@olympex.io: it is the fastest way for Olympex to find your request. The error types in the reference implementations carry it as requestId (TypeScript) and request_id (Python).
Gateway responses have no meta.requestId. Log their apigw-requestid response header instead, with the UTC time, the endpoint, the status and your API key ID. The reference helpers read the request ID from the body only, so for a gateway 401 or 403 their error has no requestId or request_id: read the header where your code receives the HTTP response, for example in your copy of the helper, and log it there. Browsers can’t read that header on cross-origin calls, so log it on your server. From a terminal, add -i (or -D -) to a curl command to print the response headers, including apigw-requestid. Never log or send the secret key, the passphrase or the signed headers.
Polling transaction status
A
500 TX_STATUS_ERROR from POST /tx-status right after you broadcast, or for a transfer the provider marks failed, means the status is unknown. It doesn’t tell you whether the transfer succeeded or failed.meta.requestId. Track a swap to finality has the full polling loop.
GET /transactions/{hash} returns TX_STATUS_ERROR when the chain’s RPC fails: retry it with backoff too. A hash the chain doesn’t know yet isn’t an error there: the response is a 200 with the status not_found, so you can poll it right after you broadcast.
What this means for your integration
- Branch on
success,error.codeand the HTTP status, never onerror.message. - Retry a gateway
429,500-class responses,422 NO_ROUTEand network errors with exponential backoff and jitter, except the three creates: list and match before you create again. - Sign again once after a gateway
401or403, then stop and check your signer, credentials and clock. - Never retry
400,404or409, and fix the cause before you resend afterUNAUTHORIZEDorFORBIDDEN. - Sign every attempt again, with a new timestamp and nonce.
- Log
meta.requestId, or theapigw-requestidheader for gateway responses, for every failure and include it when you contact support.
Related
Handle errors and retries
A step-by-step guide to a production error-handling layer.
Sign requests
The signing algorithm and the troubleshooting table.
Limits
The timestamp window, nonce reuse and the gateway timeout.
Track a swap to finality
Poll a cross-chain transfer until it completes.
