Skip to main content
The Programmatic API enables partners to build integrations that create and manage user accounts, place orders on behalf of users, and operate with fine-grained access control — all through HMAC-authenticated API tokens with scoped permissions.
Building a bot or trading for yourself? You do not need to apply for the Programmatic API. Derive a scoped API token with the trading scope from the Authentication page and start trading immediately. The Programmatic API and the application below are for platforms and partners that need to create and manage sub-accounts on behalf of their users.
HMAC credentials contain a secret key and must only be used in backend or BFF environments. Never expose them in browser-side code.
Recommended setup for production integrations:
  • Store the real HMAC credentials on your backend. The tokenId and secret should never leave your server infrastructure.
  • Use the SDK server-side to sign partner-authenticated requests. All trading, account creation, and delegated signing calls should be made from your backend.
  • Expose only your own app-specific endpoints to the frontend. Your frontend talks to your backend API — your backend talks to the Limitless API.
  • Keep public market reads in the browser. Unauthenticated endpoints like market data and orderbooks can be called directly from the frontend.

Overview

The programmatic API introduces three capabilities:
CapabilityDescription
Scoped API tokensHMAC-SHA256 authenticated tokens with granular scopes (trading, account_creation, delegated_signing)
Partner sub-accountsCreate and manage user profiles linked to your partner account
Delegated signingSubmit orders without end users managing private keys — the server signs via a managed wallet

Partner lifecycle

1

Bootstrap your partner account

Create a standard Limitless account by logging in with your wallet at limitless.exchange. This gives you a profileId and wallet address.
2

Get partner capabilities enabled

Apply for programmatic API access. The team will review your application and enable token management and allowed scopes on your account.

Apply for Programmatic API Access

Fill out the partner application form to get started. You’ll need your Limitless wallet address from Step 1.
3

Derive a scoped API token

Authenticate with your Privy identity token and call POST /auth/api-tokens/derive to create a scoped token. The response includes a tokenId and secret — store the secret securely, it is only returned once.
import { Client, HMACCredentials } from '@limitless-exchange/sdk';

const client = new Client({
  baseURL: 'https://api.limitless.exchange',
});

const derived = await client.apiTokens.deriveToken(identityToken, {
  label: 'my-trading-bot',
  scopes: ['trading', 'account_creation', 'delegated_signing'],
});

const scopedClient = new Client({
  baseURL: 'https://api.limitless.exchange',
  hmacCredentials: {
    tokenId: derived.tokenId,
    secret: derived.secret,
  },
});
4

Create sub-accounts

Use the scoped token to create sub-accounts for your end users. Choose server wallet mode for Web2 integrations (delegated signing) or EOA mode for Web3 users who manage their own keys.
const account = await scopedClient.partnerAccounts.createAccount({
  displayName: 'user-alice',
  createServerWallet: true,
});
// account.profileId, account.account
5

Trade on behalf of sub-accounts

With the delegated_signing scope and server wallet accounts, submit unsigned orders — the server signs them automatically. GTC (resting limit), FAK (fill-and-kill limit), and FOK (fill-or-kill market) order types are supported.GTC order — stays on the orderbook until filled or cancelled:
import { OrderType, Side } from '@limitless-exchange/sdk';

const gtcOrder = await scopedClient.delegatedOrders.createOrder({
  marketSlug: 'btc-100k',
  orderType: OrderType.GTC,
  onBehalfOf: account.profileId,
  args: {
    tokenId: market.tokens.yes,
    side: Side.BUY,
    price: 0.55,
    size: 10,
    postOnly: true, // Optional for GTC only
  },
});
FAK order — matches immediately up to available size and cancels any remainder:
const fakOrder = await scopedClient.delegatedOrders.createOrder({
  marketSlug: 'btc-100k',
  orderType: OrderType.FAK,
  onBehalfOf: account.profileId,
  args: {
    tokenId: market.tokens.yes,
    side: Side.BUY,
    price: 0.45,
    size: 10,
  },
});
FOK order — executes immediately at market price or is cancelled entirely:
const fokOrder = await scopedClient.delegatedOrders.createOrder({
  marketSlug: 'btc-100k',
  orderType: OrderType.FOK,
  onBehalfOf: account.profileId,
  args: {
    tokenId: market.tokens.yes,
    side: Side.BUY,
    makerAmount: 10, // spend 10 USDC
  },
});

Scopes

ScopeDescriptionSelf-service
tradingPlace and cancel orders. Default scope. Required base for delegated_signing.Yes
account_creationCreate sub-account profiles linked to the partner.Yes
delegated_signingServer signs orders on behalf of sub-accounts via managed wallets. Must be paired with trading.Yes
withdrawalTransfer ERC20 balances from managed server-wallet sub-accounts to the partner’s own addresses.Yes
adminAccess admin-protected endpoints.No (admin-provisioned only)

Scope requirements by operation

OperationRequired scopes
Place or cancel orders (POST /orders)trading
Create sub-accounts (POST /profiles/partner-accounts)account_creation
Create sub-accounts with server wallets (createServerWallet: true)account_creation + delegated_signing
Submit unsigned orders (server signs)trading + delegated_signing
Redeem resolved positions (POST /portfolio/redeem)trading
Withdraw funds (POST /portfolio/withdraw)withdrawal

Sub-account modes

Server wallet (Web2 partners)

Set createServerWallet: true when creating a sub-account. The server provisions a managed Privy wallet and links it to the profile. The partner submits unsigned orders and the server signs them via the managed wallet. Token approvals are provisioned automatically.
Server wallet mode requires both account_creation and delegated_signing scopes on your API token.

Lifecycle after a trade

For server wallet sub-accounts, it helps to treat trading, market resolution, and redemption as separate stages:
  1. Order execution - Place and cancel orders through POST /orders or the SDK DelegatedOrderService.
  2. Portfolio resolution state - Portfolio endpoints such as GET /portfolio/positions and GET /portfolio/{account}/positions may later show status: RESOLVED and winningOutcomeIndex once the winning side is known.
  3. On-chain payout settlement - Winning positions become redeemable only after the underlying conditional token payout has been reported on-chain.
status: RESOLVED and winningOutcomeIndex in the portfolio response do not by themselves guarantee that the underlying conditional token position is already redeemable on-chain. Resolution in the API can appear before the CTF condition has been settled on-chain.
If your integration checks settlement directly on-chain, wait until the payout vector has been posted before attempting redemption. For CTF-based positions, a condition is not yet settled if payoutDenominator(conditionId) is still 0.

Redemption and withdrawal support

Server wallet partner flows now include direct endpoints for payout settlement and treasury movement: As of SDK v1.0.6, all three SDKs provide helper methods for server wallet claim (redeem) and withdrawal. See the SDK getting-started pages for details.

EOA (Web3 partners)

Omit createServerWallet or set it to false. The partner proves wallet ownership using x-account, x-signing-message, and x-signature on POST /profiles/partner-accounts. The end user keeps their private key in their own wallet and signs each order (EIP-712) themselves — Limitless never holds their key. Scopes: trading and account_creation are sufficient for EOA partner flows. You do not need delegated_signing unless you also use server wallet sub-accounts.

End-to-end flow

  1. Register the user’s wallet (once per address)POST /profiles/partner-accounts with EOA headers. The response returns profileId and the wallet account. If a profile already exists for that address, the API returns 409 Conflict — your app should reuse the stored profileId instead of re-registering.
  2. Persist the mapping in your backend — save at least walletAddress → profileId (and your own user id if you have one). You are not storing a Limitless “session object”; you are storing your app’s record so you know which profileId to pass on orders. See What to persist below.
  3. User signs each order — build the order per EIP-712 signing and have the user sign in the browser (e.g. wagmi/viem/ethers). maker and signer must be the user’s EOA address.
  4. Submit the order from your backend (HMAC)POST /orders with HMAC auth, onBehalfOf set to the user’s profileId, and ownerId set to that same profileId when you send a signed order body. The order’s maker / signer must match the sub-account wallet. (If you use delegated signing with an unsigned order, the server sets ownerId for you — that path is for server-wallet sub-accounts, not pure EOA signing.)

Common EOA auth error

If POST /orders returns Signer does not match authenticated profile account, check all three fields point to the same user account:
  • ownerId = user’s profileId
  • onBehalfOf = same user’s profileId
  • order.maker and order.signer = that user’s wallet address
Using the partner profile ID in ownerId while signing with a user wallet causes this error.

Architecture (browser + backend)

Typical layout for a Next.js (or any SPA) app:
  • Browser: connect wallet (e.g. wagmi + RainbowKit); sign the ownership proof for step 1; sign EIP-712 orders for step 3. Never put partner HMAC secrets in client bundles.
  • Backend (Next.js Route Handlers, server actions, or a separate API): holds the scoped token tokenId / secret; signs every request to api.limitless.exchange with HMAC; forwards POST /orders after the client submits the signed order payload (or proxies market data as needed).
There is no official Next.js sample app in the public GitHub org today; use the TypeScript SDK on the server with the pattern above. Generic Node examples in Quickstart: Node.js illustrate HMAC and orders — swap in partner hmacCredentials and partnerAccounts.createAccount for EOA registration.

What to persist for EOA partners

Store in your DBWhy
User’s wallet address and Limitless profileIdNeeded for onBehalfOf / ownerId on every POST /orders for that user.
Optional: feeRateBps / profile metadataYou can refetch from the API if needed.
Do not rely on storingNotes
The user’s private keyNot required and not recommended; the wallet stays in the user’s client.
A Limitless “login session” to avoid order signingEOA mode requires an EIP-712 signature per order (or a new signing policy you implement). You can avoid repeated registration by persisting profileId.
Partner HMAC secret in the browserForbidden — keep only on the server.
There is no partner endpoint to list or lookup previously created sub-accounts by wallet address. GET /profiles/{account} returns only the authenticated account’s own profile. Treat walletAddress -> profileId persistence as required integration state.
Wallet UX: Standard wallet connectors remember the user’s connection across visits, so users don’t necessarily “reconnect from scratch” every time — but each order still needs a signature unless you move to server wallet + delegated signing.

Delegated order types

Delegated orders support three execution strategies:

GTC (Good-Til-Cancelled)

Limit orders that rest on the orderbook at a specified price until they are filled or explicitly cancelled. Use price and size to specify the order.
ParameterDescription
pricePrice between 0 and 1
sizeNumber of contracts
postOnlyOptional. When true, the order is rejected if it would immediately match against existing orders. Guarantees maker-only execution. Default false.

FAK (Fill-And-Kill)

Limit orders that use price and size like GTC but only match immediately available liquidity. Any unmatched remainder is cancelled.
ParameterDescription
pricePrice between 0 and 1
sizeNumber of contracts

FOK (Fill-Or-Kill)

Market orders that execute immediately at the best available price or are cancelled entirely — no partial fills. Instead of price and size, FOK orders use makerAmount.
ParameterDescription
makerAmountBUY: USDC amount to spend (e.g., 50 = spend $50 USDC). SELL: number of shares to sell (e.g., 18.64 = sell 18.64 shares).
import { OrderType, Side } from '@limitless-exchange/sdk';

// FAK BUY — fill immediately up to 10 shares at 0.45, cancel remainder
const response = await scopedClient.delegatedOrders.createOrder({
  marketSlug: 'btc-100k',
  orderType: OrderType.FAK,
  onBehalfOf: account.profileId,
  args: {
    tokenId: market.tokens.yes,
    side: Side.BUY,
    price: 0.45,
    size: 10,
  },
});

if (response.makerMatches?.length) {
  console.log(`Matched immediately with ${response.makerMatches.length} fill(s)`);
} else {
  console.log('No immediate fill. Remainder was cancelled.');
}

Reading sub-account data

Partners can read portfolio, order, and position data for their sub-accounts using the x-on-behalf-of header. This lets you show users their positions, trade history, and order status without requiring the sub-account to authenticate directly.

How it works

Add the x-on-behalf-of header with the sub-account’s profileId to any supported read endpoint. The response is exactly what the sub-account would see if they called the endpoint themselves.
GET /portfolio/positions HTTP/1.1
Host: api.limitless.exchange
lmts-api-key: <your-token-id>
lmts-signature: <hmac-signature>
lmts-timestamp: <unix-ms>
x-on-behalf-of: 1292711

Requirements

  1. Scope — your API token must include the delegated_signing scope.
  2. Ownership — the target profile must be a sub-account linked to your partner profile.
  3. Auth — use your existing HMAC flow (lmts-api-key, lmts-signature, lmts-timestamp). Nothing new.

Supported endpoints

MethodPathDescription
GET/portfolio/positionsSub-account’s current positions
GET/portfolio/historySub-account’s trade history
GET/markets/:slug/user-ordersSub-account’s orders for a specific market
POST/orders/status/batchBatch order status check
More read endpoints will be enabled over time.

Without the header

If you omit x-on-behalf-of, these endpoints behave exactly as before — you read your own data. The header is purely additive.

Error responses

StatusWhen
200Success — data is for the target sub-account
400Invalid header value or endpoint does not support delegation
403Token lacks delegated_signing scope, or target profile is not your sub-account
Error messages on 403 are intentionally generic — the API does not confirm or deny the existence of specific profile IDs.

HMAC authentication

All day-to-day programmatic API calls use HMAC-SHA256 request signing. See the Authentication page for the signing protocol, canonical message format, and code examples.

API endpoints

EndpointAuthDescription
GET /auth/api-tokens/capabilitiesPrivyCheck partner capability configuration
POST /auth/api-tokens/derivePrivyCreate a scoped API token
GET /auth/api-tokensAnyList active tokens
DELETE /auth/api-tokens/{tokenId}AnyRevoke a token
POST /profiles/partner-accountsHMACCreate a sub-account
POST /ordersHMACPlace orders (with optional delegated signing)
GET /portfolio/positionsHMACRead positions (supports x-on-behalf-of for sub-accounts)
GET /portfolio/historyHMACRead trade history (supports x-on-behalf-of for sub-accounts)
GET /markets/:slug/user-ordersHMACRead user orders for a market (supports x-on-behalf-of for sub-accounts)
POST /orders/status/batchHMACBatch order status (supports x-on-behalf-of for sub-accounts)
POST /portfolio/redeemAny (apiToken, Privy, session)Redeem resolved positions from a server wallet
POST /portfolio/withdrawAny (apiToken, Privy, session)Withdraw ERC20 funds from a server wallet

SDK support

All three official SDKs provide built-in support for the programmatic API:
As of SDK v1.0.6, all three SDKs include helper methods for server wallet claim (POST /portfolio/redeem) and withdrawal (POST /portfolio/withdraw).

TypeScript

Client with hmacCredentials, ApiTokenService, PartnerAccountService, DelegatedOrderService

Python

Client with hmac_credentials, api_tokens, partner_accounts, delegated_orders

Go

Client with WithHMACCredentials, ApiTokens, PartnerAccounts, DelegatedOrders