Skip to main content
Every failed request returns one of two bodies: the Olympex error envelope, or a short gateway body with only a message. This guide shows how to tell them apart, which failures a retry can fix, and a retry wrapper that signs every attempt again, because the API rejects a nonce it has already seen. It also shows how to check whether an order you tried to create exists before you send the create again.
The examples wrap olympexRequest from sign-request.ts and olympex_request from sign_request.py. Get them from Sign requests.

Prerequisites

  • The signing helper for your language, and API credentials in your server’s environment. TypeScript examples run on Node.js 22.18 or later, in an ES module project (npm pkg set type=module); Python examples need 3.8 or later with requests.
  • A structured logger. The examples write JSON lines to the console or use Python’s logging.
  • The list of error codes on Errors and retries.

Steps

1

Tell the two error shapes apart

Olympex returns errors in its envelope, with a stable error.code and a meta.requestId. For validation errors, each item in error.details names a field and a message:
400 VALIDATION_ERROR
For errors raised while handling the request, details items carry only a message, and the list can be empty:
500 SWAP_ERROR
The API gateway answers some requests before they reach Olympex. Its body has only a message, with no meta.requestId; the request ID is in the apigw-requestid response header instead:
403 Gateway
The helpers turn both shapes into one error type, OlympexApiError, with the HTTP status, the code, the details and the request ID (requestId in TypeScript, request_id in Python). For a gateway body, code is HTTP_<status>, for example HTTP_403, and the request ID is empty: the helpers read it from the body only, not from the apigw-requestid header. For gateway 401 and 403 responses, log that header from your HTTP client, or reproduce the call with curl -i to see it.Every 404 is an Olympex envelope with NOT_FOUND. On an {id} path, the order, strategy or DCA order ID doesn’t exist or belongs to another API key. For an unknown path or method, the message names them, for example "No route for GET /api/v1/quote".Branch on error.code and the HTTP status, never on error.message: messages are for people and can change. Olympex can add codes, so handle a code you don’t recognize by its HTTP status.
2

Decide what to retry

A retry helps only when the failure is transient, and it’s safe only when repeating the request can’t create something twice:
  • Safe to repeat: every GET, PATCH and DELETE, and POST /quotes, POST /swap, POST /support-chain and POST /tx-status, which only read or build data. POST /swap returns calldata and never broadcasts it; after a retry, use the calldata from the last response you received. A DELETE /limit-order/{id} repeated after the first one succeeded returns 409 CONFLICT, because the order is no longer pending: read the order to confirm it is cancelled.
  • Never retried automatically: POST /limit-order, POST /dca-order/strategies and POST /accounts. Each creates a new resource every time it succeeds, and Olympex ignores any id you send. A timeout or a 5xx doesn’t tell you whether the first call succeeded, and a duplicate order or strategy is a second live one that draws on the same token allowance. List your orders or strategies and match on your own fields before you send the create again, as the reconcile step below shows. No endpoint lists accounts, so after a POST /accounts that failed this way, decide by hand whether to create another.
A gateway 401 or 403 is returned before the request reaches Olympex, so nothing was created: signing again once is safe on every endpoint, creates included.
3

Retry with backoff, and sign every attempt

olympexRequest and olympex_request sign the body each time you call them, with a new timestamp and nonce, so a retry is a new call, never a resend of the same headers. Wait longer after each failure, and add random jitter so many clients don’t retry in step.
Use it wherever you’d call the helper directly:
The wrapper follows the table above. It signs a gateway 401 or 403 again once on any request. It retries 5xx responses, 422 NO_ROUTE and network failures with backoff, except on POST /limit-order, POST /dca-order/strategies and POST /accounts: for those it logs "retry": false and throws, so you can reconcile.Size attempts for the caller. Each attempt can take up to the gateway timeout of about 30 seconds, so a user waiting on a quote needs fewer attempts than a background job. Keep your client timeout above 30 seconds; the helpers use 35.
4

Reconcile a create that failed

When POST /limit-order fails with a timeout, a network error or a 5xx, the order may exist anyway. Look for it with GET /limit-order before you create it again. Filter by maker and chain, and match on fields you chose: expired is a good key, because your code generates it for each order.
If it finds the order, use it. If not, send the create again. Spell the filters exactly and send each once: the list ignores unknown query parameters, so a misspelt filter returns every order, and a repeated parameter matches nothing. For POST /dca-order/strategies, list GET /dca-order/strategies with ?accountTo=, newest first, and match on the tokens, totalAmount, frequency, iterations and a createdAt after you sent the request.
5

Switch liquidity source on SWAP_ERROR or NO_ROUTE

When POST /swap fails for one source, the quote’s aggregatorOrder lists the others that quoted the same pair, best first (Aggregation and routing). Give each source one retry, then move on:
A fallback source can return less than the quote’s winner. Show the user the outAmount and minOutAmount from the POST /swap response you use. Cross-chain swaps have no fallback list: on a persistent CROSS_CHAIN_SWAP_ERROR or NO_ROUTE, request a new cross-chain quote.A 200 doesn’t guarantee that the calldata executes: a source can build calldata that reverts, and no error code tells you. Run eth_estimateGas on every transaction before you send it. If it reverts once the balance and allowance are in place, move to the next source the same way, or request a new quote for a cross-chain swap. Execute a swap shows the loop.
6

Log the request ID and show a safe message

Log every failure as structured data: endpoint, HTTP status, error.code, meta.requestId, attempt number and your own correlation ID. Gateway errors have no meta.requestId: their ID is in the apigw-requestid response header, which the helpers don’t read, so log the UTC time and path too, and the header if your HTTP client exposes it. Support needs the request ID to find a request.Never log the x-passphrase or x-signature headers, the secret key or the passphrase. Many HTTP clients and APM agents record headers by default: redact them.Show users a message that matches what they can do, and keep codes and request IDs in your logs:

Verify

Send chainId as a string to POST /support-chain, where it must be an integer. The wrapper makes one attempt, logs "retry": false and throws:
The API answers with:
Then check the other paths:
  • A GET to an unknown path such as /quote returns 404 NOT_FOUND after one attempt, with the message "No route for GET /api/v1/quote".
  • GET /limit-order/{id} with a random UUID returns 404 NOT_FOUND after one attempt.
  • With your connection down, a GET /chains is retried with growing delays, then throws. A POST /limit-order fails after one attempt, and the log line shows "retry": false.
  • Your logs show the request ID for envelope errors and contain no passphrase or signature.

Common pitfalls

Resending the same signed headers. The API rejects a nonce it has seen in the last 5 minutes, and a timestamp more than 300 seconds from server time. Replaying a captured request fails with 403. Sign every attempt again.
Retrying a create. POST /limit-order and POST /dca-order/strategies create a live order or strategy on every success, and a timeout doesn’t tell you whether the first call succeeded. A blind retry can leave two of them drawing on the same allowance. Reconcile first.
Retrying a broadcast. A wallet transaction can reach the chain even when sending it fails. Check whether the first transaction arrived (look up its hash or the account’s nonce) before you build and send another swap.
Retrying 4xx responses. A 400, 404 or 409 fails the same way every time, and so does an Olympex UNAUTHORIZED or FORBIDDEN: fix the cause instead. A gateway 401 or 403 that repeats after one freshly signed attempt is a credential, clock or signing problem: stop and alert instead of retrying. Retrying hides the bug and turns one alert into a flood of failed requests.
Timing out before the gateway. A client timeout under 30 seconds abandons requests the gateway would still answer, then retries them. Keep yours above 30 seconds.

What’s next

Errors and retries

Every error code and gateway response.

Track a swap to finality

Polling POST /tx-status through unknown states.

Limits

Signing windows, timeouts and volume.

Going to production

The pre-launch checklist.