Direct Link: Sandbox Notes and FAQ

Things Direct Link partners have asked that don't fit neatly into the step-by-step guide. If your question isn't here, ask in your shared Slack channel — and if the answer is generally useful, it'll end up on this page.


Sandbox vs production

  • Sandbox is a real order book with no house quotes. Liquidity exists only where another tester has posted it. Main lines on major games usually have some; player props often show no selections at all, and that's expected, not broken. Test fill logic against lines that visibly have quantity on them in get_multiple_markets.
  • sport_event_is_not_booked (400) on submit_order means the event isn't open for trading in that environment yet. In sandbox this is common for events that haven't been set up; it's not something your integration can fix — pick another event or ask us to book it.
  • Hosts differ, CORS allowlist is shared. See Environments, Hosts, and Tokens. One allowlist request covers both environments.
  • Token lifetimes are shorter in sandbox. The participant accessToken lasts 15 minutes in sandbox vs 60 in production. If your Step 1 → Step 2 flow has any delay in it, you'll notice it here first.
  • Test funds. Sandbox accounts can be topped up by ProphetX on request; ask in your channel.
  • In-play delay is 0s in both environments (the former 2-second delay was removed in October 2026). It never applied to pre-match orders.
  • Feature timing. New capabilities land in sandbox first, typically a few days to a week before production. If a step in the guide works in sandbox but not production, that's the first thing to check.

Orders

Can I get an all-or-none fill? Not today. fillOrKill fills what's available and cancels the remainder; a partial fill stands. Size your order at or below the visible quantity at your price if you need a full fill, and see Order lifecycle §3 for how a partial is represented.

Why does submit_order always say unmatched? Because the response is returned before matching runs. See Order lifecycle §1–2.

I got 404 data_not_found from get_order right after a 200 from submit_order. The order exists; the reporting store hasn't caught up yet. Keep polling with backoff (cap ~15–20s), and don't rely on get_order alone for time-critical decisions. See Order lifecycle §2.

If the price is just a floor, why does it have to be on the ladder? The same price field is where a non-fillOrKill order would rest on the book, and the engine keeps every price on the ladder grid, so the check is global rather than fillOrKill-specific. Cache the ladder (it doesn't change) and snap your slippage tolerance down to a rung.

What's quantity — dollars or contracts? USD. Minimum $1.

Does aggregator_id get assigned, or do I pick it? You pick it (self-declared). Keep it identical on every order and tell us the value so attribution reports line up. See the IDs cheat sheet.


Authentication and keys

GET /partner/auth/keys returned {"data": []}. GET lists existing keys; POST creates one. An empty list on a fresh account is correct — send a POST. See Step 2.

Do I send access_key / secret_key on each request? No. They're exchanged once at POST /partner/auth/login for a Bearer access_token (10-minute lifetime; refresh at /partner/auth/refresh). Every Trading API call, including get_balance, uses the Bearer token. There's no separate key-based auth scheme.

Can I register a public key for request signing (Kalshi-style)? Not currently. Keys are opaque access_key / secret_key pairs.

Can I create read-only keys for a history-sync-only integration? Not yet — it's on the roadmap. Today every key can trade.

Does my user need the "API Integration" tab enabled? No longer. Any KYC-approved, non-suspended account can generate keys (Universal API Access). The only failure modes are KYC not complete, a suspended/self-excluded account, or the per-account key cap.

The user hit a phone verification step during login. That's standard 2FA, and SMS is currently the only method. The code goes to the phone number already on the account; handle it as in Step 1.


Reading user data

How do I sync a user's bet history? With the user's own trading token: get_order_history (paginated, filterable), get_order_matched_detail, get_trades. See Order lifecycle §7. Don't scrape the web app's grouped history endpoints — their grouping ids aren't stable.

Can my backend get real-time position/fill events for all my linked users? Not under the Direct Link model: the user's token (and therefore their private WebSocket channel) lives only on their device. Options are (a) the client listens on the user's orders channel and reports back to you, or (b) the client forwards get_order_history results to you. Server-side webhooks for linked users aren't available today.

Can I check balance before placing an order? Yes — GET /v4/mm/get_balance with the user's Bearer token. balance is available cash; unmatched_order_balance is what's tied up in resting orders. Funds are deducted on fill, not on placement.


Parlays and deep links

Direct Link covers single orders on the Trading API. Parlays are a separate RFQ product: if you deep-link a user into the ProphetX parlay slip, the price they see is a live quote from market makers, not something computed from the legs.

Why does the parlay price in the slip preview differ from the price at execution? Three separate reasons, all by design:

  1. The fee is built into the quoted price rather than shown as a separate item, and it's only applied once the user is logged in. A logged-out preview shows the raw market-maker price, so it will look slightly better than the executable price.
  2. Quotes are sized. If the quantity exceeds the best offer's size, the fill blends into the next offers, so a bigger quantity gets a slightly worse blended price than the headline.
  3. Quotes refresh and expire; the slip shows the current best at confirmation time, not the one from a few seconds ago.

The fee rate isn't a flat percentage — it depends on the parlay's price (longer-shot prices carry a somewhat higher rate) and is applied per market-maker offer. If you're reproducing displayed prices from the public quote endpoint, expect a difference on the order of 1–5% of implied probability for logged-in users, varying with price, and talk to us before hard-coding any adjustment.


Did this page help you?