Skip to main content

Overview

This guide walks through a complete Node.js/TypeScript integration with the Limitless Exchange API: authentication, market data, EIP-712 order signing with viem, order submission, and WebSocket subscriptions for real-time data.
Never expose your private key. Use environment variables and never commit secrets to version control. For production, consider a dedicated key management solution.

Prerequisites

Install the required dependencies:
If using Node 18+, you can omit cross-fetch and use the built-in fetch.

Environment variables

Create a .env file (and add it to .gitignore):
OWNER_ID is your Limitless profile ID (numeric). Obtain it from your account settings or from an authenticated API response. It is required for order submission.
Preflight: check your trading wallet mode before placing orders. If you ever accepted the app’s one-time “choose your trading wallet” prompt, your profile is in smart-wallet mode. Every self-signed order will then fail with Signer does not match - you should use embedded address for smart wallet. Check GET /profiles/me first. If tradeWalletOption is "smartWallet", switch with PUT /profiles and body {"tradeWalletOption": "eoa"} (HMAC-signed like any other request). See Trading wallet mode.

1. Authentication

Authenticated REST requests (e.g. submitting orders) are signed with HMAC-SHA256 using your scoped API token. Each request carries three headers — lmts-api-key, lmts-timestamp, and lmts-signature — computed over a canonical message of timestamp, HTTP method, request path (with query string), and body. Public market data (browsing markets, orderbooks) needs no authentication. See Authentication for the full reference.
Generating lmts-signature by hand on the command line is awkward — for shell usage, run the signRequest helper above (or your SDK) to produce the three headers. See Authentication for ready-to-use signing snippets.

2. Fetching market data and caching venue info

Fetch market details via GET /markets/:slug. The response includes venue (exchange, adapter) and tokens (the YES and NO token IDs) for CLOB markets.
1

Fetch market by slug

Call GET /markets/{slug} to retrieve market data including venue addresses.
2

Extract venue and token IDs

Use venue.exchange as the EIP-712 verifyingContract. Use tokens.yes for YES and tokens.no for NO.
3

Cache the venue

Venue data is static per market. Fetch once and reuse for all orders on that market.

3. Creating signed orders with viem (EIP-712)

Build the order payload and sign it with viem’s signTypedData. The domain uses venue.exchange as verifyingContract.

EIP-712 domain and types

Signing logic

USDC uses 6 decimals. Use parseUnits(value, 6) for amounts. Prices are in dollars; multiply price * shares before scaling.
Fee-bearing markets validate the signed fee. If the market’s metadata.fee flag is set, the signed feeRateBps must exactly equal your profile’s fee band — rank.feeRateBps on GET /profiles/me. Any other value (including 0) is rejected with feeRateBps[...] is out of user's band. On markets without a fee flag, sign 0. Set FEE_RATE_BPS accordingly.

4. Submitting orders

Submit the signed order to POST /orders with order, orderType, marketSlug, and ownerId.

5. WebSocket subscription for real-time data

Connect to wss://ws.limitless.exchange with namespace /markets using socket.io-client. Emit subscribe_market_prices with marketAddresses and/or marketSlugs.
Subscriptions replace previous ones. To subscribe to both AMM (by address) and CLOB (by slug), send both marketAddresses and marketSlugs in a single subscribe_market_prices call.

Complete end-to-end example

Reference summary

Next steps

EIP-712 signing

Deep dive into order structure and signing.

Venue system

Token approvals and venue addresses.

WebSocket events

Full event reference for real-time data.

API reference

Complete endpoint documentation.