Skip to main content
A limit order sells a set amount of one token for another when the market reaches your price. You create it with one call to POST /limit-order. Olympex then watches the price and executes the swap from the maker’s wallet, under the maker’s pair signature and token allowance. Nothing moves when you create the order, and you follow it by polling its status.

The model

An order sells amount of inTokenAddress for outTokenAddress, on one chain, for one maker: accountTo, inTokenAddress and outTokenAddress must be valid EVM addresses: 0x and 40 hexadecimal digits, in lowercase or EIP-55 checksummed form. A mixed-case address with a wrong checksum returns 400 VALIDATION_ERROR with "Must be a valid EVM address". Send only the fields in the table above. Fields that Olympex sets as it executes an order, such as status, txHash and reasonFail, return 400 VALIDATION_ERROR, and every new order starts pending. Responses return amount, price and priceTrigger as JSON numbers. Olympex stores them as double-precision numbers, which keep 15 to 17 significant digits: an amount of "0.123456789123456789" is stored and returned as 0.12345678912345678. Send at most 15 significant digits, so the stored value equals the one you sent.

Price direction

priceTrigger is the price of the token you sell, expressed in the token you buy. The order executes when the market price of inTokenAddress, in outTokenAddress, reaches priceTrigger or better. For an order that sells "0.5" WETH for USDC with a priceTrigger of "4200", the trigger is 4,200 USDC per WETH. At that price, 0.5 WETH is worth 2,100 USDC.
Check the orientation before you send an order. A trigger written as WETH per USDC (1/4200, about 0.000238) is read as USDC per WETH, which is a different price.

Reference price

Olympex needs a reference price for the pair. When you create an order, it reuses a recent lookup for the same chain and token addresses, written exactly the same way, or looks up a market for the two symbols, or identifies the tokens by address. When all of these fail, the call returns 400 and no order is created. In this example, the two addresses aren’t token contracts:
  • Send each token’s real symbol in tokenASymbol (the token you sell) and tokenBSymbol (the token you buy). Olympex doesn’t check them against the token contracts. Read symbol() from each token contract, or take the symbol from GET /tokens by address, trimmed and without a trailing _<number>: the list tells duplicate symbols apart with suffixes such as STRK_1, so send STRK.
  • Responses can return a normalized symbol: WETH becomes ETH, WBNB becomes BNB and WPOL becomes POL. The addresses are returned as you sent them.
  • Check the symbols in the response. Olympex accepts a real but wrong symbol, such as WBTC on a WETH order, and then prices the order from that token’s market. Cancel an order whose symbols match neither your tokens’ symbols nor their normalized forms.
  • The same error can occur when Olympex can’t reach its price data at that moment. If you’re sure of the pair and the symbols, retry later with backoff before you rule the pair out.

Lifecycle

Treat any status not in this table as not final. deletedAt is an empty string until the order is cancelled. Poll GET /limit-order/{id} to follow an order’s status.

Expiry

expired must be a Unix timestamp in milliseconds, as a 13-digit string, in the future and at most 365 days ahead. POST requires it and PATCH can change it. Any other value, such as a time in seconds, an ISO 8601 date or a past time, returns 400 VALIDATION_ERROR. No documented status marks an expired order. Don’t rely on expired to stop an order: when you no longer want it, cancel it with DELETE and lower the allowance.

Update a pending order

PATCH /limit-order/{id} changes an order while it is pending. Send only the fields you change: priceTrigger and price, amount, expired, slippage or gasPrice. A PATCH with only priceTrigger leaves price unchanged, so send both. If you change amount, set the allowance to match. To change the tokens, the chain or the maker, cancel the order and create a new one. On an order that isn’t pending, the call fails with 409 CONFLICT and changes nothing.

Cancel a pending order

DELETE /limit-order/{id} cancels an order while it is pending: status becomes cancelled and deletedAt is set. The order stays readable and stays in the list. On an order that isn’t pending, including one that is already cancelled or completed, the call fails with 409 CONFLICT and changes nothing. After a timeout, read the order before you send the call again. Cancelling doesn’t touch the maker’s token allowance. Lower it to what the remaining orders need, or set it to 0 to stop every order that sells the token: see Stop everything.

List your orders

GET /limit-order takes the optional filters status, chainId and accountTo, combined with AND.
  • It ignores any other query parameter, so a misspelt filter returns every order. Send each parameter once: a repeated parameter matches nothing.
  • The list returns only orders created with your API key, including cancelled ones. An order ID from another API key returns 404 NOT_FOUND.
  • It is unsorted and unpaginated: sort by createdAt yourself.
  • accountTo is stored exactly as you sent it, and ?accountTo= matches case-sensitively. Send the EIP-55 checksummed form everywhere.

Creating an order is not safe to repeat

Each successful POST /limit-order creates a new order, and Olympex ignores any id you send. If a create call times out, the order may still exist. Don’t retry it blindly: list your orders for the maker and chain, and look for one that matches your pair, amount, priceTrigger and creation time before you send the call again. Handle errors and retries covers the pattern.

Funds and fees

  • Nothing moves at creation. The tokens stay in the maker’s wallet, and nothing is reserved. The wallet must still hold amount and the allowance when the order executes, or it can’t execute.
  • At execution, Olympex pulls amount of inTokenAddress from accountTo through the Olympex order contract, swaps it, and sends all the output to accountTo.
  • Gas is reimbursed in the token sold. Olympex pays the execution gas and is reimbursed from accountTo in inTokenAddress, as a second transfer. The maker needs no native token for the execution, only for its own approvals.
  • The reimbursement is the real gas cost. It is the execution transaction’s gas used times its actual gas price, converted to inTokenAddress. The order’s gasPrice isn’t a cap: neither the API nor the order contract enforces it.
  • So the allowance must cover amount plus the gas cost in inTokenAddress. Estimate that cost with a single-chain POST /quotes and "includeGasInfo": true: dataFeeTransaction.transactionFeeInToken is the estimate, and valueToApprove is amount plus it. Size the allowance from that estimate plus a generous buffer, not from gasPrice: the estimate leaves out the Olympex contracts, and gas prices move before the order executes. See Gas and fees.
Gas and fees compares the costs of swaps, limit orders and DCA.

What can’t be sold

Check these before you create an order. The create call can accept an order for one of them, and that order can’t execute.

What this means for your integration

  • Express priceTrigger in units of the token you buy per 1 token you sell, and send amount as a human-readable string.
  • Sign the pair once, and keep the allowance at amount plus the gas estimate and a buffer, summed over every open order that sells the token.
  • Send the tokens’ real symbols and check the ones the create call returns. Poll GET /limit-order/{id}, and treat unknown statuses as not final.
  • Never retry a create call blindly: list your orders and match first.

Order signatures and allowances

The pair signature, the allowance and the order contract.

Place a limit order

The step-by-step guide.

Create a limit order reference

Every field of POST /limit-order.

DCA strategies

Spread a purchase over time instead.