Orders, fills and portfolio
Build around durable commands and confirmed fills, not HTTP acceptance.
Discover and validate
Before you start: a ready, funded account with trading and portfolio access enabled. Configure the server client.
Display cash balance and available buying power using
getFunding with details: 'trading'. Use
data.availableToTrade.formatted, not the raw cash balance, for buying power.
Use /v1/events, /v1/markets, /v1/markets/{conditionId} and
/v1/books/{tokenId} to select a real market/outcome. Read /v1/order-requirements
and /v1/trading-status; retain tick size, minimum and service restrictions.
Requirements needs tokenId and BUY/SELL side; type defaults to market.
Optional amount, comma-separated amounts (up to six), price and size
must be positive. Limit BUY requirements needs price between zero and one.
Do not hardcode an outcome token, market ID or execution host from an example.
Submit an order
Save the exact order and a unique intent key before the first attempt. The following IDs/keys are illustrative; use real market data, an authorized user, and your persisted intent in production. HTTP tabs omit signing headers.
Market buy: spend cash
const result = await crisp.marketBuy('example:user-123', {
marketId: 'actual-market-id',
tokenId: '12345678901234567890',
spendAmount: '2.00',
}, 'order-buy-intent-001');Market sell: sell shares
const result = await crisp.marketSell('example:user-123', {
marketId: 'actual-market-id',
tokenId: '12345678901234567890',
shares: '10',
}, 'order-sell-intent-001');Limit order: price and shares
const result = await crisp.limitOrder('example:user-123', {
marketId: 'actual-market-id',
tokenId: '12345678901234567890',
side: 'BUY',
price: '0.62',
shares: '10',
}, 'order-limit-intent-001');The token above is illustrative. Common fields: marketId, tokenId, side
(BUY/SELL), type (market/limit), amount, price, size, priceLimit,
orderType, expiresInSeconds, outcomeIndex, tickSize, negRisk.
Use valid combinations and market precision. Keep monetary input as decimal
strings; do not round-trip token base units through JavaScript floating point.
Market BUY amount is a cash budget; configured fees affect executable notional.
Market SELL amount is shares, not dollars. Limit price is cash per share and
size is shares. CRISP validates current fees, exposure and funds at execution.
An optional priceLimit caps/floors market execution; without it the executor
derives a protected limit from a fresh book. This is not a fill guarantee.
Acceptance and recovery
202 returns data.command (id/state/failureCode) and data.order (including
id when known, status and optional fill). Queued/running is pending. Succeeded
means the command succeeded; an accepted limit order can still be open/unfilled.
Failed and ambiguous responses require different treatment.
For pending commands, use the read-only account-scoped
GET /v1/accounts/{externalUserId}/operations/{operationId}. If the response was
lost, recover by operation kind and original intent key through /operations.
See operation recovery. Same-path/key/body POST replay
remains supported for existing integrations. Never create a replacement intent
after an uncertain timeout. Use lifecycle events and resource reads for fills.
Optional POST /orders/prewarm accepts { "tokenIds": ["…"] } (one or two).
The SDK's prepareTrading coalesces warmups and prepares the execution route in
parallel; never block trading on it. High-level SDK order helpers use cached,
server-only cell capabilities automatically and fall back to the standard API
with the same intent when routing is unavailable. See SDK fast execution.
Ordinary /orders remains supported; no integration is forced to use cell routing.
Portfolio and history
const result = await crisp.listPositions('example:user-123');Endpoint suffix after /v1/accounts/{externalUserId} | Purpose |
|---|---|
/orders | Open orders; not complete fill history |
/orders/{orderId}/cancel (POST) | Durable cancel, idempotency required |
/positions | Current position data; closed, limit/offset supported |
/sellable-shares?tokenId=… | Returns tokenId, availableShares and asOf for a ready account |
/trades | Account wallet trade data |
/trade-fills | Canonical fills for your users with fee-distribution metadata |
/orders/{orderId}/trade-fills | One order's individual confirmed fills |
For /trade-fills, from and to ISO timestamps are required (ascending window
up to 366 days). Default limit 50, maximum 100; persist cursor and use hasMore.
For one order's fills, limit defaults to 100, maximum 200. Older history remains
reachable through earlier windows; a window bound is not ledger expiry.
Volume means confirmed USD fill notional, not shares. Do not sum accepted orders
and confirmed fills together or confuse venue fees with referral allocations.
Redeem resolved positions
const result = await crisp.redeemPositions(
'example:user-123',
{
positions: [
{
conditionId: 'actual-condition-id',
size: 7.77,
outcomeIndex: 0,
negRisk: false,
},
],
},
'redeem-intent-unique-001',
);Use live position tuples, not the placeholder. 1–20 distinct condition IDs; eligibility/outcome/size are revalidated before signing. Show a confirmation: close losing positions for zero or claim winning payout. 202 is pending; update portfolio only after confirmation/reconciliation. Allowed in cancel-only mode, blocked when trading is disabled.
Cancel an open order
Use a venue order ID from your account's open orders, not a command ID. A cancellation races fills; refresh the order and fills after completion, rather than assuming all shares were canceled.
const result = await crisp.cancelOrder(
'example:user-123',
'actual-order-id',
'cancel-intent-unique-001',
);Next: follow or recover the command. Exact contracts: placeOrder, cancelOrder, redeemPositions.