# List the tokens Olympex lists on Polygon (chain ID 137).
# Needs openssl, curl and OLYMPEX_API_KEY_ID, OLYMPEX_SECRET_KEY, OLYMPEX_PASSPHRASE.
METHOD=GET
ENDPOINT=/tokens
QUERY='chainId=137'
BODY='' # GET has no body: the signature covers the empty string
TS="${OLYMPEX_TIMESTAMP:-$(date +%s)}"
NONCE="${OLYMPEX_NONCE:-$(openssl rand -hex 12)}"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -binary | openssl base64 -A | tr '+/' '-_' | tr -d '=')"
VALUE_INFO="$(printf '%s\n%s\n%s' "$TS" "$NONCE" "$BODY_HASH")"
MESSAGE="$(printf 'OLPX-HMAC-SHA256-V2\n%s\n%s\n%s\n%s\n%s\n%s' "$TS" "$NONCE" "$METHOD" "/api/v1$ENDPOINT" "$QUERY" "$BODY_HASH")"
curl -sS -X "$METHOD" "https://api-rest.olympex.io/api/v1$ENDPOINT${QUERY:+?$QUERY}" \
-H "content-type: application/json" \
-H "x-api-key-id: $OLYMPEX_API_KEY_ID" \
-H "x-value-info: $(printf '%s' "$VALUE_INFO" | openssl base64 -A)" \
-H "x-passphrase: $OLYMPEX_PASSPHRASE" \
-H "x-signature: $(printf '%s' "$MESSAGE" | openssl dgst -sha256 -hmac "$OLYMPEX_SECRET_KEY" -binary | od -An -v -tx1 | tr -d ' \n')"
// npm install viem
import { formatUnits } from "viem";
import { olympexRequest } from "./sign-request.ts"; // /authentication/sign-requests
type Token = { address: string; symbol: string; name: string; decimals: number; icon: string; logoURI?: string };
const { tokens } = await olympexRequest<{ chainId: number; tokens: Token[] }>("GET", "/tokens?chainId=137");
// Casing varies between entries and symbols aren't unique: key by lowercase address.
const byAddress = new Map(tokens.map((token) => [token.address.toLowerCase(), token]));
const usdc = byAddress.get("0x3c499c542cef5e3811e1192ce70d8cc03d5c3359"); // USDC on Polygon
if (usdc) console.log(usdc.symbol, formatUnits(10034668n, usdc.decimals)); // USDC 10.034668
from decimal import Decimal
from sign_request import olympex_request # /authentication/sign-requests
tokens = olympex_request("GET", "/tokens?chainId=137")["tokens"]
# Casing varies between entries and symbols aren't unique: key by lowercase address.
by_address = {token["address"].lower(): token for token in tokens}
usdc = by_address.get("0x3c499c542cef5e3811e1192ce70d8cc03d5c3359") # USDC on Polygon
if usdc:
print(usdc["symbol"], Decimal("10034668").scaleb(-usdc["decimals"])) # USDC 10.034668
{
"success": true,
"data": {
"chainId": 137,
"tokens": [
{
"address": "0x3c499c542cef5e3811e1192ce70d8cc03d5c3359",
"decimals": 6,
"icon": "https://cdn.olympex.io/tokens/images/137/0x3c499c542cef5e3811e1192ce70d8cc03d5c3359.png",
"name": "USD Coin",
"symbol": "USDC"
},
{
"address": "0x7ceb23fd6bc0add59e62ac25578270cff1b9f619",
"decimals": 18,
"icon": "https://cdn.olympex.io/tokens/images/137/0x7ceb23fd6bc0add59e62ac25578270cff1b9f619.png",
"name": "Wrapped Ether",
"symbol": "WETH"
},
{
"address": "0xc2132d05d31c914a87c6611c10748aeb04b58e8f",
"decimals": 6,
"icon": "https://cdn.olympex.io/tokens/images/137/0xc2132d05d31c914a87c6611c10748aeb04b58e8f.png",
"name": "Tether USD",
"symbol": "USDT"
}
]
},
"meta": {
"requestId": "EdjZqgk0IAMEVaA=",
"version": "v1",
"accountType": "integrator",
"apiKeyId": "00000000-0000-4000-8000-000000000000"
}
}
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid query parameters",
"details": [
{
"field": "chainId",
"message": "Invalid input: expected number, received NaN"
}
]
},
"meta": {
"requestId": "EdjZwh0voAMEVlA=",
"version": "v1",
"accountType": "integrator",
"apiKeyId": "00000000-0000-4000-8000-000000000000"
}
}
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Chain 324 is not enabled",
"details": []
},
"meta": {
"requestId": "Edt2TjlIIAMEZkw=",
"version": "v1",
"accountType": "integrator",
"apiKeyId": "00000000-0000-4000-8000-000000000000"
}
}
{
"message": "Forbidden"
}
{
"success": false,
"error": {
"code": "TOKEN_LIST_ERROR",
"message": "Unexpected token list handler error",
"details": [
{
"message": "Unknown error"
}
]
},
"meta": {
"requestId": "EdjZ2hkzIAMEb0A=",
"version": "v1",
"accountType": "integrator",
"apiKeyId": "00000000-0000-4000-8000-000000000000"
}
}
List tokens
List the tokens Olympex lists on a chain, with each token’s address, symbol, decimals and logo.
# List the tokens Olympex lists on Polygon (chain ID 137).
# Needs openssl, curl and OLYMPEX_API_KEY_ID, OLYMPEX_SECRET_KEY, OLYMPEX_PASSPHRASE.
METHOD=GET
ENDPOINT=/tokens
QUERY='chainId=137'
BODY='' # GET has no body: the signature covers the empty string
TS="${OLYMPEX_TIMESTAMP:-$(date +%s)}"
NONCE="${OLYMPEX_NONCE:-$(openssl rand -hex 12)}"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -binary | openssl base64 -A | tr '+/' '-_' | tr -d '=')"
VALUE_INFO="$(printf '%s\n%s\n%s' "$TS" "$NONCE" "$BODY_HASH")"
MESSAGE="$(printf 'OLPX-HMAC-SHA256-V2\n%s\n%s\n%s\n%s\n%s\n%s' "$TS" "$NONCE" "$METHOD" "/api/v1$ENDPOINT" "$QUERY" "$BODY_HASH")"
curl -sS -X "$METHOD" "https://api-rest.olympex.io/api/v1$ENDPOINT${QUERY:+?$QUERY}" \
-H "content-type: application/json" \
-H "x-api-key-id: $OLYMPEX_API_KEY_ID" \
-H "x-value-info: $(printf '%s' "$VALUE_INFO" | openssl base64 -A)" \
-H "x-passphrase: $OLYMPEX_PASSPHRASE" \
-H "x-signature: $(printf '%s' "$MESSAGE" | openssl dgst -sha256 -hmac "$OLYMPEX_SECRET_KEY" -binary | od -An -v -tx1 | tr -d ' \n')"
// npm install viem
import { formatUnits } from "viem";
import { olympexRequest } from "./sign-request.ts"; // /authentication/sign-requests
type Token = { address: string; symbol: string; name: string; decimals: number; icon: string; logoURI?: string };
const { tokens } = await olympexRequest<{ chainId: number; tokens: Token[] }>("GET", "/tokens?chainId=137");
// Casing varies between entries and symbols aren't unique: key by lowercase address.
const byAddress = new Map(tokens.map((token) => [token.address.toLowerCase(), token]));
const usdc = byAddress.get("0x3c499c542cef5e3811e1192ce70d8cc03d5c3359"); // USDC on Polygon
if (usdc) console.log(usdc.symbol, formatUnits(10034668n, usdc.decimals)); // USDC 10.034668
from decimal import Decimal
from sign_request import olympex_request # /authentication/sign-requests
tokens = olympex_request("GET", "/tokens?chainId=137")["tokens"]
# Casing varies between entries and symbols aren't unique: key by lowercase address.
by_address = {token["address"].lower(): token for token in tokens}
usdc = by_address.get("0x3c499c542cef5e3811e1192ce70d8cc03d5c3359") # USDC on Polygon
if usdc:
print(usdc["symbol"], Decimal("10034668").scaleb(-usdc["decimals"])) # USDC 10.034668
{
"success": true,
"data": {
"chainId": 137,
"tokens": [
{
"address": "0x3c499c542cef5e3811e1192ce70d8cc03d5c3359",
"decimals": 6,
"icon": "https://cdn.olympex.io/tokens/images/137/0x3c499c542cef5e3811e1192ce70d8cc03d5c3359.png",
"name": "USD Coin",
"symbol": "USDC"
},
{
"address": "0x7ceb23fd6bc0add59e62ac25578270cff1b9f619",
"decimals": 18,
"icon": "https://cdn.olympex.io/tokens/images/137/0x7ceb23fd6bc0add59e62ac25578270cff1b9f619.png",
"name": "Wrapped Ether",
"symbol": "WETH"
},
{
"address": "0xc2132d05d31c914a87c6611c10748aeb04b58e8f",
"decimals": 6,
"icon": "https://cdn.olympex.io/tokens/images/137/0xc2132d05d31c914a87c6611c10748aeb04b58e8f.png",
"name": "Tether USD",
"symbol": "USDT"
}
]
},
"meta": {
"requestId": "EdjZqgk0IAMEVaA=",
"version": "v1",
"accountType": "integrator",
"apiKeyId": "00000000-0000-4000-8000-000000000000"
}
}
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid query parameters",
"details": [
{
"field": "chainId",
"message": "Invalid input: expected number, received NaN"
}
]
},
"meta": {
"requestId": "EdjZwh0voAMEVlA=",
"version": "v1",
"accountType": "integrator",
"apiKeyId": "00000000-0000-4000-8000-000000000000"
}
}
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Chain 324 is not enabled",
"details": []
},
"meta": {
"requestId": "Edt2TjlIIAMEZkw=",
"version": "v1",
"accountType": "integrator",
"apiKeyId": "00000000-0000-4000-8000-000000000000"
}
}
{
"message": "Forbidden"
}
{
"success": false,
"error": {
"code": "TOKEN_LIST_ERROR",
"message": "Unexpected token list handler error",
"details": [
{
"message": "Unknown error"
}
]
},
"meta": {
"requestId": "EdjZ2hkzIAMEb0A=",
"version": "v1",
"accountType": "integrator",
"apiKeyId": "00000000-0000-4000-8000-000000000000"
}
}
GET /tokens?chainId=137 returns the tokens Olympex lists on one chain: each token’s address, symbol, name, decimals and logo. Use it to fill a token picker and to convert amounts between human-readable units and base units. Take chainId from GET /chains, and cache the result: the list is large and changes rarely.
Choose the chain
chainIdis required and must be a positive integer. Take it fromGET /chains, which returns integers:137becomes?chainId=137.- Send
chainIdas a plain decimal integer:?chainId=137.GET /tokensalso reads some other spellings, such as0x89or137.0, as 137. Don’t rely on them. chainIdis the only query parameter. A missing, empty or non-numericchainId, or any other query parameter, returns400 VALIDATION_ERRORInvalid query parameters.error.detailsreports an unknown parameter underfieldchainId, for example"Unrecognized key: \"foo\"".- A chain that isn’t enabled returns
400 VALIDATION_ERRORwith the messageChain <chainId> is not enabled. - The response echoes the chain as a number in
data.chainId. - The query string is part of the signature: sign
chainId=137as the canonical query, and the empty string as the body, as for everyGET.
Cache the list
The list holds hundreds of tokens per chain. It comes in one response, unsorted, unpaginated and uncompressed, even when you sendAccept-Encoding: gzip, and it changes rarely. There is no ETag or Last-Modified header, so you can’t make a conditional request: refresh the list on a schedule.
- Cache it per chain on your side, for example for 24 hours, instead of calling
GET /tokensfor every page view or quote. - Sort it yourself for display.
- Every enabled chain has a token list. An empty
tokensarray or a500 TOKEN_LIST_ERRORmeans the list couldn’t be read, not that the chain has no tokens: keep using your cached list and retry with backoff.
Match tokens by address
- Identify a token by its address, never by its symbol. Symbols aren’t unique.
- Compare addresses case-insensitively. Address casing varies between entries. Lowercase both sides, and key your cache by the lowercase address.
- The native token is listed as
0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee, the lowercase form of0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE.POST /quotesandPOST /swapaccept it in either casing, so compare it case-insensitively. Limit orders and DCA can’t sell it: use the wrapped token, for example WETH on Ethereum (0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2), WBNB on BNB Chain (0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c) or WPOL on Polygon (0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270). - POL on Polygon. The Polygon list also carries
0x0000000000000000000000000000000000001010, POL’s system contract, with the same symbol. Don’t offer it: it can’t be approved, and quotes can route it at prices unrelated to POL. Use the native pseudo-address for POL. - Symbols are labels, not identifiers. When several listed tokens share a symbol, some carry a numeric suffix such as
STRK_1orUSDP_2, and the number can change when the list is refreshed. A few symbols also differ from the contract’ssymbol()in case or have trailing spaces. Before you display a symbol, trim it and drop a trailing_<number>. Where you need the token’s real symbol, as a limit order’stokenASymbolandtokenBSymboldo, readsymbol()from the token contract. - Logos.
iconis a logo URL, usually oncdn.olympex.io, or an empty string when there is no logo. Some URLs point to third-party hosts that may not serve the image, so show a fallback when a logo is empty or fails to load. Load logos with an<img>element: the CDN sends no CORS headers, so a browserfetchcan’t read them. Some entries also carrylogoURI. - Other fields can appear on an entry. Ignore the ones you don’t use.
Convert amounts with decimals
decimals converts between the two units the API uses. Conventions lists the unit of every amount field.
| Amount | Unit | What to do |
|---|---|---|
params.amount on quotes and swaps, limit order amount, DCA totalAmount | Human-readable | Send it as is. Olympex resolves the decimals. |
Quote and swap outputs such as quote.outAmount | Base units | Divide by 10 to the power of decimals to display it. |
| Token allowances and balances on-chain | Base units | Multiply a human-readable amount by 10 to the power of decimals before you approve it. |
quote.outAmount of "10034668" is 10.034668 USDC, and an allowance of 10 USDC is 10000000 base units. Use integer or decimal arithmetic, never floating point.
# List the tokens Olympex lists on Polygon (chain ID 137).
# Needs openssl, curl and OLYMPEX_API_KEY_ID, OLYMPEX_SECRET_KEY, OLYMPEX_PASSPHRASE.
METHOD=GET
ENDPOINT=/tokens
QUERY='chainId=137'
BODY='' # GET has no body: the signature covers the empty string
TS="${OLYMPEX_TIMESTAMP:-$(date +%s)}"
NONCE="${OLYMPEX_NONCE:-$(openssl rand -hex 12)}"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -binary | openssl base64 -A | tr '+/' '-_' | tr -d '=')"
VALUE_INFO="$(printf '%s\n%s\n%s' "$TS" "$NONCE" "$BODY_HASH")"
MESSAGE="$(printf 'OLPX-HMAC-SHA256-V2\n%s\n%s\n%s\n%s\n%s\n%s' "$TS" "$NONCE" "$METHOD" "/api/v1$ENDPOINT" "$QUERY" "$BODY_HASH")"
curl -sS -X "$METHOD" "https://api-rest.olympex.io/api/v1$ENDPOINT${QUERY:+?$QUERY}" \
-H "content-type: application/json" \
-H "x-api-key-id: $OLYMPEX_API_KEY_ID" \
-H "x-value-info: $(printf '%s' "$VALUE_INFO" | openssl base64 -A)" \
-H "x-passphrase: $OLYMPEX_PASSPHRASE" \
-H "x-signature: $(printf '%s' "$MESSAGE" | openssl dgst -sha256 -hmac "$OLYMPEX_SECRET_KEY" -binary | od -An -v -tx1 | tr -d ' \n')"
// npm install viem
import { formatUnits } from "viem";
import { olympexRequest } from "./sign-request.ts"; // /authentication/sign-requests
type Token = { address: string; symbol: string; name: string; decimals: number; icon: string; logoURI?: string };
const { tokens } = await olympexRequest<{ chainId: number; tokens: Token[] }>("GET", "/tokens?chainId=137");
// Casing varies between entries and symbols aren't unique: key by lowercase address.
const byAddress = new Map(tokens.map((token) => [token.address.toLowerCase(), token]));
const usdc = byAddress.get("0x3c499c542cef5e3811e1192ce70d8cc03d5c3359"); // USDC on Polygon
if (usdc) console.log(usdc.symbol, formatUnits(10034668n, usdc.decimals)); // USDC 10.034668
from decimal import Decimal
from sign_request import olympex_request # /authentication/sign-requests
tokens = olympex_request("GET", "/tokens?chainId=137")["tokens"]
# Casing varies between entries and symbols aren't unique: key by lowercase address.
by_address = {token["address"].lower(): token for token in tokens}
usdc = by_address.get("0x3c499c542cef5e3811e1192ce70d8cc03d5c3359") # USDC on Polygon
if usdc:
print(usdc["symbol"], Decimal("10034668").scaleb(-usdc["decimals"])) # USDC 10.034668
{
"success": true,
"data": {
"chainId": 137,
"tokens": [
{
"address": "0x3c499c542cef5e3811e1192ce70d8cc03d5c3359",
"decimals": 6,
"icon": "https://cdn.olympex.io/tokens/images/137/0x3c499c542cef5e3811e1192ce70d8cc03d5c3359.png",
"name": "USD Coin",
"symbol": "USDC"
},
{
"address": "0x7ceb23fd6bc0add59e62ac25578270cff1b9f619",
"decimals": 18,
"icon": "https://cdn.olympex.io/tokens/images/137/0x7ceb23fd6bc0add59e62ac25578270cff1b9f619.png",
"name": "Wrapped Ether",
"symbol": "WETH"
},
{
"address": "0xc2132d05d31c914a87c6611c10748aeb04b58e8f",
"decimals": 6,
"icon": "https://cdn.olympex.io/tokens/images/137/0xc2132d05d31c914a87c6611c10748aeb04b58e8f.png",
"name": "Tether USD",
"symbol": "USDT"
}
]
},
"meta": {
"requestId": "EdjZqgk0IAMEVaA=",
"version": "v1",
"accountType": "integrator",
"apiKeyId": "00000000-0000-4000-8000-000000000000"
}
}
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid query parameters",
"details": [
{
"field": "chainId",
"message": "Invalid input: expected number, received NaN"
}
]
},
"meta": {
"requestId": "EdjZwh0voAMEVlA=",
"version": "v1",
"accountType": "integrator",
"apiKeyId": "00000000-0000-4000-8000-000000000000"
}
}
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Chain 324 is not enabled",
"details": []
},
"meta": {
"requestId": "Edt2TjlIIAMEZkw=",
"version": "v1",
"accountType": "integrator",
"apiKeyId": "00000000-0000-4000-8000-000000000000"
}
}
{
"message": "Forbidden"
}
{
"success": false,
"error": {
"code": "TOKEN_LIST_ERROR",
"message": "Unexpected token list handler error",
"details": [
{
"message": "Unknown error"
}
]
},
"meta": {
"requestId": "EdjZ2hkzIAMEb0A=",
"version": "v1",
"accountType": "integrator",
"apiKeyId": "00000000-0000-4000-8000-000000000000"
}
}
Authorizations
Your API key ID (UUID). See Sign requests.
Base64 of timestamp + "\n" + nonce + "\n" + bodyHash, where timestamp is Unix seconds, nonce is 24 new hexadecimal characters and bodyHash is the unpadded base64url SHA-256 of the canonical body.
Your account passphrase. Treat it like the secret key.
Lowercase hex HMAC-SHA256 (signature v2), keyed with your secret key string (UTF-8, not decoded), of seven lines joined with \n, with no trailing newline: OLPX-HMAC-SHA256-V2, timestamp, nonce, the uppercase method, path, canonicalQuery and bodyHash. path is the request path including /api/v1, without the query string, for example /api/v1/limit-order/<id>. canonicalQuery is the query parameters decoded (+ is a space), sorted by key and then by value, re-encoded per RFC 3986 and joined with &, or the empty string when there is no query. Headers signed for one request are rejected on any other. See Sign requests.
Query Parameters
Chain ID, for example 137. It must be one of the chains from GET /chains. No other query parameters are allowed.
x >= 1Was this page helpful?
