Skip to main content
These rules apply to every endpoint in this reference. Endpoint-specific behavior is on each endpoint page, and field-level types are in the OpenAPI specification.

Requests

Methods

A method that a path doesn’t support returns 404 NOT_FOUND, with a message that names the method and path, for example DELETE on a DCA strategy ("No route for DELETE /api/v1/dca-order/strategies/…"): cancel a strategy with PATCH instead. The service’s own GET /openapi.json and GET /docs are public.

Bodies and signing

  • Content-Type: application/json on every request, including GET, DELETE and the public endpoints. Without it, or with another type such as curl’s default application/x-www-form-urlencoded, the gateway base64-encodes a body before Olympex reads it, and the request fails with 403 (Invalid body hash) on a signed endpoint or 400 (Invalid JSON body) on a public one.
  • UTF-8. Encode the body as UTF-8 JSON.
  • Send the bytes you signed. On POST and PATCH, serialize the body once as canonical JSON (keys sorted at every level, no whitespace), hash that string, and send the same string. Sign requests has the algorithm and reference code.
  • Sign the empty string when there is no body. GET and DELETE send no body, and the signature covers the empty string: its bodyHash is 47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU.
  • The signature covers the whole request: the method, the path (including /api/v1), the canonical query and the body hash, with the timestamp and the nonce. Headers signed for one request are rejected on any other. Sign right before you send, and never log or share the headers.
  • Sign every attempt. Each signature carries a nonce, which the server rejects if it has seen it in the last 5 minutes, and a timestamp it accepts within ±300 seconds of its own clock. The nonce makes each set of headers usable once. A retry needs a new signature, and your server clock must stay synchronized.

Response envelope

Every endpoint wraps its result in the same envelope, whatever its method. The exceptions are gateway responses and the service’s own GET /openapi.json and GET /docs, which return the raw spec and an HTML page. Every success is HTTP 200, including creates (POST) and cancels (DELETE).
Branch on success, never on the value of data: POST /support-chain returns "success": true with "data": false for an unsupported chain, and a list with no matches returns "data": [].

Amounts

Amounts you send are human-readable decimals: "10" is 10 USDT, and Olympex resolves the token’s decimals itself. Most amounts you receive from quotes and swaps are integer strings in the token’s base units: the human-readable amount multiplied by 10 to the power of the token’s decimals. Limit order and DCA amounts stay human-readable in both directions.
Don’t convert params.amount, a limit order’s amount or a DCA strategy’s totalAmount to base units. "10" is 10 USDT. "10000000" is ten million USDT, not 10.

Values you send

To turn a gas price in wei from your RPC into the quote and swap hint, round up to whole gwei, for example ((gasPriceWei + 999_999_999n) / 1_000_000_000n).toString() with a bigint. Below 1 gwei this gives "1": the hint is then higher than the chain’s gas price, and your wallet or signer still sets the gas price of the transaction you send. A limit order’s gasPrice is a decimal string, so it can carry a fraction, for example "0.05". Quote, swap and limit-order amounts, prices and slippage are decimal strings: quotes and swaps reject a JSON number in these fields with 400 VALIDATION_ERROR. DCA’s totalAmount, slippage, minPrice and maxPrice must be JSON numbers: a string returns 400. The reference signers canonicalize numbers the way JavaScript does, so fractional values such as a minPrice of 0.00025 sign correctly. If you write your own signer in another language, format numbers exactly as JavaScript’s JSON.stringify does (1.0 becomes 1, 1e21 becomes 1e+21, 0.0000001 becomes 1e-7), and keep integers within ±(253 − 1). See Portability rules.

Values you receive

To display a base-unit amount, divide by 10 to the power of the token’s decimals with integer or decimal arithmetic. Take decimals from GET /tokens, or read decimals() from the token contract. Cross-chain quotes also report decimals for each asset listed in middlewareRoute.
Keep amounts as strings, BigInt or Decimal from end to end. A JavaScript number or a Python float loses precision on 18-decimal tokens.

Addresses

  • Addresses are accepted in lowercase or EIP-55 checksum form, as 0x and 40 hex digits. A mixed-case address whose checksum is wrong returns 400 VALIDATION_ERROR with the detail "Must be a valid EVM address", which catches most typos.
  • The chain’s native token uses this pseudo-address wherever a token address is expected, in either casing:
    GET /tokens lists it in lowercase, 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee, so compare it case-insensitively.
  • Limit orders and DCA strategies can’t sell the native token: inTokenAddress and tokenAddressFrom must be ERC-20 tokens. Use the wrapped token, for example WETH, WBNB or WPOL.
  • Olympex resolves token decimals server-side. You never send them.
  • Responses don’t normalize addresses. GET /tokens returns addresses in varying case. On single-chain quotes, routes[].subRoutes[].from and to are token addresses as the source reports them: case varies, and the native token can appear as 0xeeee… or the zero address. middlewareRoute can use checksummed addresses in the same quote, and can show a native token as the pseudo-address or the zero address, depending on the provider. Compare addresses case-insensitively.
  • Limit orders and DCA strategies store the maker’s accountTo exactly as you send it, and the ?accountTo= list filters match case-sensitively. Always send the EIP-55 checksummed form.
  • feeRecipient can’t be the zero address.

Chain IDs

Chain IDs are standard EVM chain IDs, sent and returned as JSON integers on every endpoint: 137, not "137". A string in a request body returns 400 VALIDATION_ERROR, and so does a non-numeric ?chainId= on GET /tokens or GET /transactions/{hash}. The ?chainId= filter of GET /limit-order isn’t validated: a value that isn’t a number returns an empty array.
400 String sent to /support-chain
GET /chains returns every enabled chain ID. Supported chains lists them by name.

IDs

  • Olympex assigns every ID. Limit order and DCA strategy IDs are UUIDs, for example afc47108-d059-473c-b2e1-5f2ca7951466. DCA order IDs are strings that Olympex creates as a strategy runs. Treat every ID as an opaque string, and pass it in the path: /limit-order/{id}.
  • IDs are scoped to your API key. A limit order or DCA strategy belongs to the API key that created it, and a DCA order belongs to its strategy’s key. Lists return only your key’s resources. An ID that doesn’t exist or belongs to another API key returns 404 NOT_FOUND.
  • Keep the key with the ID. If you use more than one API key, store which key created each order or strategy. meta.apiKeyId in the create response names it.

Booleans and enums

  • Booleans are JSON true and false. The string "true" is rejected.
  • Enum values are case-sensitive. mode is "single-chain" or "cross-chain"; orderBy and gasMultiplier values are uppercase, for example "MAX_OUT_AMOUNT" and "MEDIUM".
  • Limit order, DCA strategy and DCA order statuses are lowercase, for example "pending" and "cancelled". Each endpoint page lists the values.
400 String boolean and lowercase enum

Optional and empty fields

  • An optional response field can be missing or null. Treat both as “not provided”.
  • integratorFeeBreakdown is present on every quote. It reports the Olympex protocol fee, which applies even when you don’t send fees, and your fee: integratorMarginBps equals fees.feeBps, and is 0 when you don’t send fees.
  • dataFeeTransaction appears only when the single-chain quote request sets includeGasInfo: true.
  • /tx-status returns fromTxHash, toTxHash, amounts, token addresses and bridgeHash only when the provider reports them. errorMsg is always null in a 200, because a provider error comes back as 500 TX_STATUS_ERROR. Display detailStatus instead.
  • GET /transactions/{hash} returns blockNumber and gasUsed as null, and confirmations as 0, until the transaction is mined.
  • A limit order’s txHash is an empty string until the order executes, reasonFail is an empty array unless execution failed, and deletedAt is an empty string until you cancel the order.
  • A DCA strategy omits minPrice and maxPrice when you didn’t set them. A DCA order carries amountReceived, executionPrice and transactionHash once it executes, and errorMessage when it fails.
  • Lists that have no entries are empty arrays, for example "market": [] or "data": [].

Casing

Timestamps

The signing timestamp is in seconds and expired is in milliseconds. Don’t reuse one for the other.

Lists

  • No pagination. Each list endpoint returns every match in one response. Use the filters to keep responses small.
  • Unsorted unless stated. Sort limit orders by createdAt yourself when the order matters.
  • Filters combine with AND. accountTo matches case-sensitively.
  • Unknown query parameters. The order and strategy lists ignore unknown query parameters, so a misspelt filter such as ?acountTo= returns the full list. Send each parameter once: a repeated parameter matches nothing. GET /chains ignores query parameters too, while GET /tokens rejects any parameter other than chainId.
  • Cancelled limit orders stay in the list. Filter by ?status= to see one status only, for example pending.
  • Only your API key’s resources. See IDs.

Errors

Errors come from two layers. If the body has a success key, it is an Olympex error envelope. If it has only message, it is a gateway response.

Error envelope

error.code is the stable, machine-readable value to branch on, together with the HTTP status. error.message is a human-readable summary: don’t parse it. error.details takes one of three forms:
422 No route

Error codes

Not found

A request for an ID that doesn’t exist, or that belongs to another API key, returns 404 with the code NOT_FOUND. Olympex doesn’t tell the two cases apart, and a malformed limit order ID returns the same 404, not a 400. The message names the resource: Limit order not found, DCA strategy not found or DCA order not found. Don’t retry it: check the ID and the API key you signed with.
404 Unknown limit order
An unknown path or method also returns 404 NOT_FOUND. Its message names the method and path, for example "No route for GET /api/v1/quote", and its meta has no accountType or apiKeyId.
404 Unknown route

Gateway responses

The API gateway answers some requests itself, before or instead of Olympex. These bodies have no success, error or meta. The spec names this body GatewayError.

Retries

  • GET, PATCH and DELETE are safe to repeat.
  • PATCH and DELETE /limit-order/{id} return 409 CONFLICT once the order isn’t pending, so a repeated DELETE whose first attempt went through returns 409: read the order to confirm it is cancelled. Don’t retry a 409 unchanged.
  • 422 NO_ROUTE from POST /quotes can be temporary: retry with backoff, then change the amount or pair. On POST /swap, a 422 NO_ROUTE or 500 SWAP_ERROR means that source can’t build the route now: build again with the next aggregatorId in the quote’s aggregatorOrder.
  • POST /limit-order, POST /dca-order/strategies and POST /accounts create a new resource on every success. After a timeout, don’t retry them blindly: list your orders or strategies and match on your own fields first.
Errors and retries explains which errors to retry and how to back off.

Request IDs

  • Every Olympex envelope carries meta.requestId. Log it with the HTTP status and error.code for every failed call.
  • Gateway responses have no meta.requestId, but the response carries an apigw-requestid header with an ID. On Olympex responses that header has the same value as meta.requestId. Browsers can’t read the header on cross-origin calls, so read it from a server or a terminal.
  • The reference helpers in Sign requests report no request ID for a gateway response, such as a 401 or 403 with only message. Log the apigw-requestid response header yourself for those. With curl, add -i or -D - to print the response headers.
  • Include the request ID when you contact support. It is the fastest way to find your request.

Timeouts

The gateway stops waiting for a response after about 30 seconds and returns 500 or 503 with only a message. Set your HTTP client timeout slightly above that: the reference clients in Sign requests use 35 seconds. Retry with backoff, and sign each attempt again.

Forward compatibility

  • Ignore unknown response fields. Within v1, responses can gain new fields, and token, order and strategy objects can carry fields you don’t use. Don’t fail validation on a field you don’t recognize.
  • Handle unknown error codes by HTTP status. New error.code values can be added.
  • Pass aggregatorId through. Send /swap the exact value the quote returned instead of hardcoding one.
  • Treat unknown transfer statuses as in progress. /tx-status reports each provider’s own status values. Get cross-chain transfer status lists the success and failure values.
  • Treat unknown order statuses as not final. A limit order, DCA strategy or DCA order status you don’t recognize means the resource can still change: keep polling it.

What’s next

Errors and retries

Which errors to retry, and how to back off.

Sign requests

Canonical JSON, the signature and reference code.

List chains

The enabled chains.

OpenAPI specification

Every schema, and how to generate a typed client.