Skip to main content

Integration guide

Use this page when you want exact integration steps. The hand-written API pages explain which surfaces exist and how they behave operationally. The GMX API OpenAPI reference is generated and is best used for endpoint schemas and response fields, not for workflow guidance. Use Troubleshooting when reads do not match expected state.

Choose the right integration surface

Start by choosing the narrowest surface that solves your problem.

NeedRecommended surfaceNotes
Live oracle prices, market snapshots, liquidity, and APYOracle API pagesStable public HTTP endpoints on gmxinfra.io
Read app-level HTTP data such as markets, tickers, tokens, pairs, rates, APY, performance, positions, orders, trades, OHLCV, wallet balances, allowances, buyback stats, JIT liquidity, risk-oracle market lists, or staking powerSDK v2, the generated GMX API reference, or direct GMX API HTTP callsSDK v2 provides typed TypeScript helpers for its supported methods; use direct HTTP for routes not yet wrapped or generated
Historical trade and order activitySDK v2, the generated GMX API reference, or GraphQLUse GMX API or SDK v2 for API-backed trade reads; use GraphQL for full indexed history and custom analytics
Submit, edit, cancel, or track ordersSDK v2, SDK v1, or direct contract callsSDK v2 posts signed order intents to the GMX API, which relays express orders via Gelato. SDK v1 and direct contracts remain available for RPC-owned flows
Exchange or aggregator pair listingsIntegration pair feedPublic GET endpoints at https://gmx-integration-cg.vercel.app/api/arbitrum/pairs and https://gmx-integration-cg.vercel.app/api/avalanche/pairs
Delegated, gasless, or one-click order flows on behalf of a userDelegated trading integrationSubaccount and relay pattern using SubaccountGelatoRelayRouter and MultichainSubaccountRouter
GM or GLV token pricesGetting GM and GLV token pricesExplains when to use Chainlink Data Feeds, Reader calls, or API/SDK data for GM/GLV valuation

What is available now

The current hand-written docs and checked-out code support the following split:

SurfaceReadWriteDescription
GMX API OpenAPI ReferenceGenerated schema reference for the GMX API. Covers markets, tokens, positions, orders, trades, rates, APY, performance, JIT liquidity, wallet balances, allowances, staking power, buyback stats, GMX Account, subaccount approval/status, and order transaction prepare/submit/status/edit/cancel/collateral flows. Deployed per chain across two independent peer base URLs: https://{chain}.gmxapi.io/v1 and https://{chain}.gmxapi.ai/v1.
Oracle API (gmxinfra.io)Public market, price, liquidity, APY, and performance reads. Manual docs cover the stable public HTTP endpoints.
GraphQLHistorical indexed activity. Best for history, not write-path confirmation.
SDK v1 (GmxSdk)Full TypeScript integration with reads and writes. Uses RPC, oracle, and Subsquid connections directly.
SDK v2 (GmxApiSdk)TypeScript integration over HTTP against the GMX API. Reads, wallet helpers, subaccount helpers, and order-submission methods are available.
Direct contractsLowest-level integration and custom transaction flows. Highest control and highest implementation burden.

Use the generated GMX API reference for endpoint-level request and response schemas. Use the SDK v2 docs for typed client method names, bigint parsing, signing helpers, and complete TypeScript workflows.

Build a live market overview

Use the Oracle API when you need public market snapshots and fallback URLs. Use /markets for a slower-changing market list, and /markets/info for a near-live market state snapshot.

const endpoints = [
"https://arbitrum-api.gmxinfra.io/markets/info",
"https://arbitrum-api-fallback.gmxinfra.io/markets/info",
"https://arbitrum-api-fallback.gmxinfra2.io/markets/info",
];

async function fetchMarketsInfo() {
let lastError: Error | undefined;

for (const endpoint of endpoints) {
try {
const response = await fetch(endpoint, {
headers: { Accept: "application/json" },
});

if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}

return await response.json();
} catch (error) {
lastError = error as Error;
}
}

throw lastError ?? new Error("All market endpoints failed");
}

const markets = await fetchMarketsInfo();
console.log("Loaded markets:", markets.length);

Use this refresh strategy:

  1. Call /markets when you need the market catalog and can tolerate a 10 second cache window.
  2. Call /markets/info when you need liquidity, open interest, funding, borrowing, token amounts, and the isListed flag. This is also the correct endpoint for near-live funding rates.
  3. Treat /markets/info as a snapshot, not a guarantee of the latest block. The current implementation caches the route for 10 seconds, so build for near-live rather than same-block state.
  4. Use /markets/state when you only need each market's open, closed, or unknown status. This route is cached for 5 seconds.
  5. Use /rates for historical funding and borrowing rate data. This endpoint returns hourly snapshots from the Squid indexer, not realtime values. Use it for rate averages, trends, and historical analysis.

If you use the generated GMX API reference on https://{chain}.gmxapi.io/v1 or https://{chain}.gmxapi.ai/v1, the market reads are split by update frequency:

EndpointUse whenCurrent cache window
GET /marketsYou need the listed market catalog, leverage tiers, and size limits.60 seconds
GET /markets/infoYou need one composite market snapshot with config and near-live values.1 second
GET /markets/configYou need slower-changing market configuration without frequently changing value fields.30 seconds
GET /markets/valuesYou need frequently changing open interest, pool amounts, funding, borrowing, and virtual inventory values.1 second
GET /risk-oracle/marketsYou need the active market list expected by the configured risk oracle.60 seconds

Use the split config and values endpoints when your integration can cache static-like market settings separately from fast-changing market state. Use /markets/info when one coherent response is more important than minimizing payload size.

The market responses include the following configuration and value fields:

ResponseFields
/markets/config and /markets/infomaxCollateralSumLongTokenLong, maxCollateralSumLongTokenShort, maxCollateralSumShortTokenLong, maxCollateralSumShortTokenShort, minFundingIncreaseRatePerSecond, side-specific minimum and maximum funding factors, and virtualIndexTokenId
/markets/values and /markets/infovirtualInventoryForPositionsInTokens

API responses are extensible, so integrations should ignore unknown fields and define local types around the fields they consume. SDK v2 exposes the split reads as fetchMarketsConfig() and fetchMarketsValues(), returning RawMarketConfig[] and RawMarketValues[]. Direct HTTP integrations can call the corresponding endpoints and define local types around the fields they use.

The GMX API also exposes GET /risk-oracle/markets for the active market list expected by the configured risk oracle. Direct HTTP integrations can call it on the same https://{chain}.gmxapi.io/v1 or https://{chain}.gmxapi.ai/v1 base URLs.

Each GET /markets/values row includes updatedAt, expressed as Unix time in milliseconds. This value is the older of the main market-values refresh and the virtualInventoryForPositionsInTokens refresh, so it represents the least-recent component in that row. It is null when either component has no successful refresh timestamp.

The backend retains the last successful values through a total pull failure instead of replacing the snapshot with empty data. The retained timestamp continues to age, so compare updatedAt with your own freshness limit. With the default 5 second pull interval, the backend marks values older than 15 seconds as stale for monitoring but can still serve them. A market-specific failed refresh can leave the prior values in place with updatedAt: null. Disabled markets are excluded from backend staleness accounting.

JIT liquidity history responses can return longLiquidityUsd: null or shortLiquidityUsd: null; integrations should treat those as missing side-specific liquidity values rather than parsing errors.

Use SDK v2 if you are already in TypeScript and want bigint-aware responses. Use the generated GMX API reference if you need raw HTTP schemas.

Install @gmx-io/sdk, then import GmxApiSdk from @gmx-io/sdk/v2. The v2 path is a subpath export, not a separate package.

import { GmxApiSdk } from "@gmx-io/sdk/v2";

const apiSdk = new GmxApiSdk({ chainId: 42161 });

const positions = await apiSdk.fetchPositionsInfo({
address: "0x9f7198eb1b9Ccc0Eb7A07eD228d8FbC12963ea33",
includeRelatedOrders: true,
});

const orders = await apiSdk.fetchOrders({
address: "0x9f7198eb1b9Ccc0Eb7A07eD228d8FbC12963ea33",
});

console.log({
positions,
orders,
});

Both GET /positions and GET /positions/{key} return positionValueInUsd. The API derives it from PositionReader.getPositionInfo, including collateral, claimable funding, base PnL, total price impact, and execution costs. For an account list, the Reader calls for all returned positions use one block number, so the position values share a common on-chain snapshot.

The list and detail routes have a 1 second response cache. A position that closes before the Reader snapshot is omitted from the list or returns 404 from the detail route. Related orders come from the API's order store and are not part of the common-block Reader call.

Direct HTTP returns positionValueInUsd as a decimal string. SDK v2 deserializes it to bigint and exposes it on ApiPositionInfo.

Use this flow when you render account state:

  1. Fetch positions with includeRelatedOrders: true if your page shows open positions and their linked orders together.
  2. Fetch standalone orders only if you also need an account-wide orders view.
  3. After submitting a write through SDK v1 or direct contracts, poll these read endpoints until the expected state appears instead of assuming immediate consistency.

Read historical trade activity

Use SDK v2 or the GMX API for API-backed trade-history reads, and use GraphQL when you need full indexed history or custom analytics. Do not try to reconstruct history from live market snapshots.

import { GmxApiSdk } from "@gmx-io/sdk/v2";

const apiSdk = new GmxApiSdk({ chainId: 42161 });

const trades = await apiSdk.fetchTrades({
address: "0x9f7198eb1b9Ccc0Eb7A07eD228d8FbC12963ea33",
limit: 50,
});

const filteredTrades = await apiSdk.searchTrades({
address: "0x9f7198eb1b9Ccc0Eb7A07eD228d8FbC12963ea33",
fromTimestamp: 1767225600,
limit: 50,
});

For lower-level integrations, the generated GMX API reference documents the raw /trades and /trades/search schemas.

GraphQL remains useful for indexed analytics:

query RecentTrades($account: String!) {
tradeActions(where: { account_eq: $account }, limit: 50, orderBy: timestamp_DESC) {
eventName
account
timestamp
transactionHash
sizeDeltaUsd
collateralDeltaAmount
}
}

The current GraphQL schema exposes transactionHash and top-level timestamp. See GraphQL for schema usage notes and migration context.

For referral analytics, the GraphQL schema also exposes the affiliateStats and traderReferralStats resolvers, plus per-hour stats entities (AffiliateReferralTradeStatsByHour, TraderReferralTradeStatsByHour, AffiliateTraderStatsByHour). Use these instead of stitching tradeActions for affiliate dashboards or trader rebate views — both resolvers accept from/to time windows and return pre-aggregated volume, rebate, discount, and trader-flow figures. TraderReferralTradeStatsByHour.affiliateRewardsUsd, TraderFirstReferral, ReferralTier, and ReferrerTier support referral-code update accounting, while the private referralCodeUpdates resolver is not intended for public integrations. See GraphQL — Referral analytics for the full schema and example queries.

Operational notes

Freshness and caching

  • GET /markets uses a 10 second HTTP cache in the current implementation.
  • GET /markets/info uses a 10 second HTTP cache in the current implementation.
  • GET /markets/state uses a 5 second HTTP cache in the current implementation.
  • The backend currently caches prices, tokensData, and marketsInfo for 1 second, userReferralInfo for 5 seconds, and onchainSettings for 60 seconds.
  • Avoid joining data from unrelated polls when you need one coherent snapshot. Prefer composite endpoints such as /markets/info or fetchPositionsInfo({ includeRelatedOrders: true }).

Retries, timeouts, and fallback URLs

  • The current API server timeout is 60000 ms.
  • SDK v2 uses HttpClientWithFallback with the hosts in its configuration and any additional hosts supplied by your application. In 1.6.4 the packaged fallback list is empty for every chain, so an SDK integration has no peer to fail over to until your application supplies the second host. You still own request retry timing, backoff, and user-facing recovery behavior.
  • Use the Fallback URLs page for Oracle API market and oracle reads.
  • If you receive a timeout, network error, 429, or 5xx, retry with backoff and fail over where you have fallback endpoints.

Surface-specific operational model

  • The Oracle API is deployed per chain on https://{chain}-api.gmxinfra.io primary hosts, uses endpoint-specific cache windows, and documents fallback URLs for some public reads.
  • The GMX API is deployed per chain across two independent peer base URLs (https://{chain}.gmxapi.io/v1 and https://{chain}.gmxapi.ai/v1). Both are equal; there is no primary/secondary. Clients that hit the API directly can use either base URL or rotate across both. The generated reference does not define your retry policy.
  • GraphQL is indexed data. Expect lag relative to live chain state.
  • SDK v1 mixes live RPC, oracle, and indexed reads. Default SDK-created HTTP transports disable retries.
  • SDK v2 is an HTTP client for reads and API-relayed order workflows. Its transport supports peer failover across configured hosts, but the packaged host list is empty in 1.6.4, so your integration must supply the peer hosts and define its own application-level retry policy.
  • Direct contracts give you the most control, but your app owns retry, nonce, gas, and receipt strategy.
  • Delegated trading flows run through SubaccountGelatoRelayRouter or MultichainSubaccountRouter and have their own session lifecycle — your integration owns subaccount authorization, expiry, action-count tracking, and relay-nonce handling. See Delegated trading integration.

Idempotency and race conditions

  • For SDK v2 and API-relayed order workflows, persist the requestId returned by prepare or submit calls and poll order status instead of resubmitting blindly.
  • After a write, do not assume your first follow-up read will reflect final state. Submission, relay processing, keeper execution, and indexing can land at different times.
  • If you need "position plus linked orders" on one screen, prefer a single positions call with includeRelatedOrders: true over stitching data from independent polls.

Next steps

  • Use API Overview to decide between the GMX API, Oracle API, GraphQL, contracts, and the SDK.
  • Use Getting GM and GLV token prices when you need to choose between Chainlink Data Feeds, direct Reader calls, and API or SDK data for GM/GLV valuation.
  • Use the Oracle API for public market, price, and liquidity endpoints.
  • Use the generated GMX API OpenAPI Reference for endpoint-level request and response schemas.
  • Use Troubleshooting if your reads look stale, a query fails validation, or a write does not show up yet.
  • Use SDK v2 when your application needs API-relayed order flows.
  • Use SDK v1 when your application needs direct RPC-backed write flows such as creating or canceling orders.
  • Use Delegated trading integration when you need subaccount-based, gasless, or one-click order flows on behalf of a user.