ResoMarket/Docs/Trading API

Trading API v1

HTTP and WebSocket protocol for automated trading and market making across ADI Mainnet and Polygon. USDC / pUSD · EIP-712 · HMAC.

Protocol v1Wallet-nativeADI Mainnet · Chain 36900Polygon · Chain 137USDC / pUSDEIP-712 + HMAC
Download JavaScript API demov0.1.2 · SHA-256 1920806fdb8c... · Node 20crypto: Previewsports: Previewbtc-3m: Preview

Preview means the API and offline demo are available, but the current release ZIP has not completed per-product runtime and real-funds closed-loop acceptance. Validate with a controlled wallet and the minimum amount before production funding.

Orders require an owner-wallet signature. Only a signed-in session with a managed owner signer may have one order server-signed; L2 credentials cannot sign orders or withdraw funds.

WebSocket recovery

Code example
{"op":"SUBSCRIBE","channel":"MARKET","stream":"BOOK", "marketId":"BTC-3M-...","outcome":"UP","afterSequence":"42"}{"op":"SUBSCRIBE","channel":"MARKET","stream":"LIFECYCLE", "marketId":"BTC-3M-...","afterSequence":"7"}{"op":"SUBSCRIBE","channel":"USER","afterSequence":"101"}

Without afterSequence, the server sends a first snapshot. With it, retained events replay from the next sequence. A gap, future cursor, retention loss, or backpressure returns RESYNC_REQUIRED; reload the REST snapshot before reconnecting. BOOK deltas bind previousBookHash to the new bookHash.

Heartbeat

POST /heartbeats renews every 5 seconds with a 15-second TTL. On an unknown renew result, HEARTBEAT_EXPIRED, or HEARTBEAT_CANCEL_IN_PROGRESS, stop order submission immediately. Poll until DISARMED, confirm account snapshot openOrders is empty, then re-arm with a new timestamp, nonce, and HMAC. Any remaining order or recovery timeout must fail closed. WebSocket ping/pong does not renew it.

Code example
// Stop submitting orders as soon as renew is unknown or returns// HEARTBEAT_EXPIRED / HEARTBEAT_CANCEL_IN_PROGRESS.for (;;) {  const heartbeat = await resoGet("/api/trading/heartbeats");  if (heartbeat.status === "ARMED" && heartbeat.expiresAtMs > heartbeat.serverTimeMs) break;  if (heartbeat.status === "EXPIRED" || heartbeat.status === "CANCELING") {    await delay(heartbeat.heartbeatIntervalMs);    continue;  }  if (heartbeat.status !== "DISARMED") throw new Error("heartbeat recovery unconfirmed");  const snapshot = await resoGet("/api/trading/account/snapshot");  if (snapshot.openOrders.length !== 0) throw new Error("open orders remain");  await resoPost("/api/trading/heartbeats"); // New timestamp, nonce and HMAC.  break;}

Errors and safe retries

Trading V2 /api/trading/* errors use {error:{code,message,requestId,retryable,retryAfterMs}}. Existing product and Funding routes use the OpenAPI-documented {error:"CODE_OR_MESSAGE"}; do not parse them as the same envelope. Honor Retry-After. Never retry authentication, signature, nonce, parameter, or balance failures unchanged.

HTTPMeaningRetry unchanged
400 / 422Request, signature, or balance errorNo
401 / 403Authentication or permission errorNo
409State or idempotency conflict; query firstSame key and bytes only
413Request body exceeds 256 KiB; reduce itNo
423Feature safely pausedNo
429Rate limitedHonor Retry-After
500 / 503Server or Provider unavailable; query unknown creates firstSame key and bytes only

Manual Provider orders return a stable category in order.failureCode with HTTP 422: ADI_SIGNATURE_REQUIRED, ADI_SUBMIT_FAILED, LIVE_SUBMIT_FAILED, LIVE_API_KEY_MISMATCH, LIVE_CREDENTIAL_REFRESH_FAILED, LIVE_DEPOSIT_WALLET_REQUIRED, LIVE_MIN_ORDER_SIZE, LIVE_INSUFFICIENT_BALANCE, LIVE_ALLOWANCE_REQUIRED, or GEOBLOCKED_REGION. Clients must tolerate future values and treat unknown values like LIVE_SUBMIT_FAILED.

On an unknown create result, query account/orders first and retry only with the identical idempotency key and exact signed payload. A changed payload requires a new key and signature. Limits: 15 batch orders, 100 cancel IDs, 32 market scopes, 256KiB HTTP JSON, and 16KiB WebSocket client messages.