Trading

Place an order directly

POST
/execution/orders

Authorization

appIdbearerAuth
headerx-app-id<token>

Your application ID. Required on app-tier and user-tier routes. Omitted on routes that authenticate with x-app-api-key only.

headerAuthorizationBearer <JWT>

JWT access token from POST /auth/verify. Required with x-app-id on user routes. On the smart-route quote it is optional and turns a preview into an executable quote.

Request Body

application/json
  1. body
venue*string

The venue to trade on. Singular by design — this endpoint never splits an order.

Value in"kalshi""polymarket""limitless""predict""pred""tiprun""myriad""hyperliquid""novig""prophetx""betdex""lighter"
venueMarketOutcomeId*string

The outcome to trade. May be the outcome on another venue: it is resolved through matched-outcome links to the equivalent outcome on venue. Passing the id that already lives on venue is the unambiguous form.

Length1 <= length
side*string

Trade direction. sell closes an existing position on venue.

Value in"buy""sell"
maxSpend?number

Buy only. Maximum all-in USD spend, inclusive of app fee.

Range0 <= value
sellShares?number

Sell only. Number of contracts to sell.

Range0 <= value
externalId*string

Idempotency key. Your own id for this trade — required, and unique within your app: two different users of the same app cannot share one. A repeat is rejected with 409 rather than trading twice, so it is safe to retry a request that timed out using the same value. A request rejected before its order was queued leaves the value free to reuse.

Length1 <= length <= 36
slipCapBps?number

Slippage cap in basis points. Defaults to 500 (5%) when omitted. On sells set this explicitly: sellShares bounds the shares sold, not the proceeds.

Range0 <= value
allowedSourceChainIds?array<>

Restrict funding to these source chains. Omitted, the order may be funded from any chain the user holds, bridging in when the venue's own chain is short. Listing only the venue's chain (56 for predict.fun, 137 for Polymarket) makes the order fail with insufficient funding instead of bridging. Balances are still read on-chain: this narrows which of them may be spent, it never adds capacity.

Items1 <= items
chainBalances?

Per-chain USD funding budgets, e.g. {"56": 50}. Caps refreshed wallet balances; never adds capacity. A chain-only budget is shared across its token buckets. Omitted chains cannot fund the order; an empty map allows no on-chain funding. Combines with allowedSourceChainIds: excluded chains cannot fund the order.

appFeeBips?number

Per-trade app fee in basis points of routed notional, 0..10000. Replaces the app's configured rate for this order only. Honoured only when the request carries x-app-api-key; otherwise 400 app_fee_override_requires_api_key. Buy only.

Multiple Of1
Range0 <= value <= 10000
appFeeBipsByVenue?

Per-venue app fee in basis points, e.g. {"polymarket":20,"hyperliquid":10}. Keys are venue names; a rate applies to the legs filled on that venue and overrides appFeeBips there. The scalar appFeeBips still applies to venues the map omits. Honoured only when the request carries x-app-api-key; otherwise 400 app_fee_override_requires_api_key. Buy only.

referrerFeeBipsByVenue?

Per-venue referral fee in basis points, e.g. {"polymarket":20,"hyperliquid":10}. Keys are venue names; a rate applies to the legs filled on that venue and overrides referrerFeeBips there, which still applies to venues the map omits. referrerFeeBips is optional when this is sent; 0 = no referral on that venue, but at least one venue must end up with a positive rate. Needs referrer. Same rules as referrerFeeBips: x-app-api-key required, buy only.

referrer?string

Referral: the EVM address that receives the referral fee. Requires referrerFeeBips or referrerFeeBipsByVenue. Honoured only when the request carries x-app-api-key; a JWT-only request that sends it is rejected with 400 referral_requires_api_key. Buy only.

Length42 <= length <= 42
referrerFeeBips?number

Referral fee in basis points of the routed notional, 1..10000. sufwan-local-test takes no share of it. With referralPayer "user" it is reserved from maxSpend next to the app fee; with "app" the user pays nothing.

Multiple Of1
Range1 <= value <= 10000
referralPayer?string

Who funds the referral. Default "user".

Value in"user""app"
referralPayerAddress?string

Required when referralPayer is "app": the wallet that settles the payout. After the fill, a pendingSignatures entry appears with signerAddress set to this address and purpose "referral_payout"; answer it on POST /execution/fill/:quoteId/signatures. Read its type: on an EVM chain it is a transaction to broadcast (post the hash), on HyperCore an eip712 to sign (post the signature).

Length42 <= length <= 42
referralPayoutChainId?number

Optional, and only with referralPayer "app": the chain the referrer is paid on. Must carry USDC. On an EVM chain the payout is an ERC-20 transfer the partner's wallet broadcasts, needing USDC plus native gas there; on HyperCore (1337) it is a user-signed sendAsset from the partner's HyperCore spot balance — a signature, nothing to broadcast — and the referrer receives spot USDC on Hyperliquid. A first payout to a referrer with no Hyperliquid account costs the partner an extra 1 USDC that Hyperliquid charges to create it; later payouts to the same referrer cost nothing. Solana does not support app-paid payouts and is refused. Defaults to the trade's fee chain, or Polygon when that chain is not EVM. Sending it with a user-paid referral is rejected with 400 referral_invalid.

Multiple Of1
Range1 <= value
referralActivationSponsorAddress?string

Optional, and only with a user-paid referral (referralPayer "user" or absent): a wallet that pays Hyperliquid's one-time 1 USDC account-activation fee when the referrer has never received anything on HyperCore. Honoured on self-custody Hyperliquid buys only; ignored otherwise. Before the fill a pendingSignatures entry appears with signerAddress set to this address, purpose "hl_activation_sponsor" and optional: true — an eip712 sendAsset of 0.000001 USDC to the referrer. Sign it and post the signature on POST /execution/fill/:quoteId/signatures. After the fill it is posted just before the referral transfer, only if the referrer still has no HyperCore account. This wallet's HyperCore spot balance must hold at least 1.000001 USDC. Declining it is safe: the trade proceeds and the referral is attempted as usual. Must differ from referrer; rejected with referralPayer "app". The request reaches your signer through the user's client: sign only the exact transfer described here (see Fees → Securing the paying wallet's signer).

Length42 <= length <= 42
skipQuote?boolean

Skip the smart-route solver and send one order straight to venue. predict, hyperliquid, kalshi, novig and prophetx only; any other venue returns 400. Requires a read_write x-app-api-key (401 without a key, 403 with a read key). No bridging: the funds must already sit on the venue's own chain, and allowedSourceChainIds / chainBalances are ignored. A buy the stored balance cannot fund returns 400 quote_insufficient_balance before acceptance. Referral fields apply to buys as on a routed order; on a sell they return 400. You own the price and minimum checks — an order the venue refuses fails after acceptance and uses up its externalId. Kalshi and connected ProphetX/Novig API buys use fixed-price admission automatically; the venue decides available cash when accepting the order.

skipBalance?boolean

With skipQuote, skip the balance check and fund hold on a buy: nothing checks the balance and an underfunded order fails at the venue. Sells still check and hold the position. Without skipQuote, skip only the quote-time balance refresh: the route uses the last stored balances, and the fund hold and balance check still run, so a stale balance can fail the order after acceptance but never overspend. Requires a read_write x-app-api-key.

price?number

With skipQuote or a native API buy, the price limit, e.g. 0.52. Optional: omitted, the best available price at submission is used (best ask for a buy, best bid for a sell), and an empty side returns 400. A hyperliquid buy is sized as the whole contracts that fit maxSpend at this price plus slippage. Ignored on clearinghouse prophetx, which prices the order itself within slipCapBps.

Range0 <= value <= 1

Response Body

200

application/json
  1. response
orderId*string

The single order this call created.

externalId*string

Echoed back so a webhook or socket event can be tied to this response.

venue*string

The venue the order was placed on.

Value in"kalshi""polymarket""limitless""predict""pred""tiprun""myriad""hyperliquid""novig""prophetx""betdex""lighter"
status*"pending"

Always pending: the order is accepted and queued for execution, not yet filled. Poll GET /execution/orders or listen for order events for the terminal state.

Value in"pending"
quoteId*string

Server-minted quote backing this order. Useful for support, not required.

quotedPriceRaw*string

Quoted price, decimal string (e.g. "0.53"). null if the order row does not carry a quoted price — the order is still live; re-fetch it from GET /execution/orders rather than treating this as zero.

quotedCostRaw*string

Quoted cost, 6-decimal atomic USDC. null under the same conditions as quotedPriceRaw.

quotedSharesRaw*string

Quoted shares, 6-decimal atomic. null under the same conditions as quotedPriceRaw.

Example Request
curl -X POST 'https://api.t.sufwankhalid.com/execution/orders' \  -H 'Content-Type: application/json' \  -d '{  "venue": "polymarket",  "venueMarketOutcomeId": "cmf3q8z2m00a4mw0lr5t1k7yc",  "side": "buy",  "maxSpend": 25,  "externalId": "trade-2f9c61d4",  "slipCapBps": 200}'
Example Response
{  "orderId": "cmf3r1a2b00c4mw0lq8y7e3uj",  "externalId": "trade-2f9c61d4",  "venue": "polymarket",  "status": "pending",  "quoteId": "k2r8v5n1x7c4m9t3b6q0w2za",  "quotedPriceRaw": "0.52",  "quotedCostRaw": "25000000",  "quotedSharesRaw": "48076923"}