Market Orders (single-contract trades)
A market order is a single-contract order at the best available price. There are three endpoints: estimate (no commit), submit (asynchronous fill), and a state read. The submit returns immediately with a refId, and you either poll or subscribe to webhooks to find out what happens next.
Auth: user-scoped on all three (sub must equal the acting user's UUID, plus subsig). See Authentication.
For multi-leg orders, see Parlays (2–12 leg trades) instead.
1. The flow
POST /private/v1/market-orders/estimate ─► see expected price + fee + available qty
POST /private/v1/market-orders ─► 202 with refId
GET /private/v1/market-orders/{refId} ─► poll status, fill progress, P/L
Polling is the simplest option. For lower-latency updates without polling, subscribe to MarketOrderEvent webhooks — see Webhooks (push events).
2. The state model
| Field | Values |
|---|---|
status | pending → completed | canceled | failed |
fillStatus | open → partial → filled |
winningStatus | tbd → profit | loss | push (after the event settles) |
Small naming inconsistency to be aware of: in webhook payloads,
fillStatususesrestinginstead ofopenfor the same state. See Webhooks (push events). Treat them as synonyms.
3. POST /private/v1/market-orders/estimate
POST /private/v1/market-orders/estimateA no-commit quote. Use this to show the user what they'd get before they confirm.
Body (EstimateMarketOrderRequest):
{ "contractId": "183c6ffeb2b4b6772a5afb6336293240", "quantity": 25.00 }quantity >= 0allowed here. Use0to see the best available price without specifying a size.
Response (EstimateMarketOrderResponse):
{
"availableQuantity": 50.00,
"expectedAveragePrice": -110,
"expectedAveragePriceAdjusted": -115,
"expectedPayout": 45.45,
"expectedPayoutAdjusted": 43.10,
"expectedFeeAmount": 1.50,
"maxQuantity": 200.00
}Field meanings:
availableQuantity— fillable at the expected average price.maxQuantity— total liquidity across all price levels. Taking the whole thing would mean a worse blended price.- Prices are in American format (
-110,+150). - The
*Adjustedvariants include the ISV fee.
The common failures are 422 with INVALID_CONTRACT (the contract isn't valid or has gone stale) or with an insufficient-liquidity error.
4. POST /private/v1/market-orders
POST /private/v1/market-ordersSubmit the order. Asynchronous — the server returns 202 immediately with a reference ID, and the actual fill happens in the background.
Body (SubmitMarketOrderRequest):
{ "contractId": "183c6ffeb2b4b6772a5afb6336293240", "quantity": 25.00 }quantity > 0required (strict —0is allowed for estimate but not for submit).
Response (202, MarketOrderResponse): same shape as the GET below, with initial status: "pending", fillStatus: "open", filledQuantity: 0.
The refId is not a UUID — it's a string, possibly prefixed with isv_. Treat it as opaque.
Common failure modes:
402 PaymentRequiredError— insufficient balance (relevant on INDIVIDUAL ISVs; SHARED ISVs see this when the pot is constrained).422 INVALID_CONTRACT— unknown or expired contract.422 user_pending_kyc— the user hasn't passed KYC yet.
5. GET /private/v1/market-orders/{refId}
GET /private/v1/market-orders/{refId}Response (MarketOrderResponse):
{
"refId": "isv_xyz",
"contractId": "183c6ffeb2b4b6772a5afb6336293240",
"requestedQuantity": 25.00,
"fee": 0.50,
"quantity": 24.50,
"filledQuantity": 24.50,
"openQuantity": 0,
"expectedAveragePrice": -110,
"currentAveragePrice": -108,
"status": "completed",
"fillStatus": "filled",
"winningStatus": "tbd",
"createdAt": "...",
"updatedAt": "..."
}Read these in pairs:
requestedQuantityis what you asked for;feeis what was taken;quantity = requestedQuantity - feeis what actually went on the order.filledQuantity + openQuantity = quantity.expectedAveragePriceis the floor at submission;currentAveragePriceis the actual achieved price so far.
6. Polling guidance
A few notes to save you time:
- Don't tight-loop. A 1–2 second interval during active fill and longer once
statusstabilizes is plenty. - If you'd rather not poll at all, subscribe to the
/push/market-orderswebhook and let ProphetX push updates. Each event is wrapped in{ id, op, timestamp, data }— see Webhooks (push events). - A terminal
status(completed/canceled/failed) means no further fills.winningStatusmay still flip later when the event settles — that comes through theContractSettlementEventwebhook.
7. Curl
BASE="https://isv-staging-api.betprophet.co/private/v1"
# 1. Estimate
curl -X POST "$BASE/market-orders/estimate" \
-H "Authorization: Bearer $JWT_USER" \
-H "Content-Type: application/json" \
-d '{ "contractId":"abc...", "quantity":25 }'
# 2. Submit
curl -X POST "$BASE/market-orders" \
-H "Authorization: Bearer $JWT_USER" \
-H "Content-Type: application/json" \
-d '{ "contractId":"abc...", "quantity":25 }'
# → 202 { "refId":"isv_xyz", "status":"pending", ... }
# 3. Poll (or wait for the webhook)
curl "$BASE/market-orders/isv_xyz" -H "Authorization: Bearer $JWT_USER"Updated about 9 hours ago
