Skip to main content
The same API also lets a program place orders on Splash prediction markets, read its own orders, positions and transaction history, and read its fee settings and cash balance. Find the markets to trade with the market endpoints; a market’s id is the market_id you order against.

Rate limits

Requests are limited to 10 per second per IP address; see Rate limits for what a 429 looks like, how to retry it and how to stay under the limit.

Base URL

Paths in the reference are relative to the base URL. The market endpoints are open. The order, position, account and balance endpoints must be signed with an API key. API keys are issued by Splash on request, never expire, and stay valid until Splash revokes them, which it does on request.

Placing an order and following it

Orders are asynchronous. Before a buy, check that you have the cash for it. Splash adds a fee to the contracts cost and debits both when the order is submitted; a buy without enough cash is accepted and then cancelled without filling. Read your fee settings and max_trade from GET /account and your cash_available from GET /balance, compute the order’s cost, and send the raw order only when it fits. The order never carries a fee: Splash computes it. The formulas and a calculator are in Fees and order cost.
  1. POST /trading/orders returns 200 with order_status: "pending". That means the order was accepted, not filled: it is queued.
  2. Poll GET /orders?request_id=<your request_id> until the order’s status is executed or cancelled. Poll every 500 ms to 1 second for the first few seconds, then every few seconds; keep polling while it reads pending. See Rate limits.
  3. While the order is queued, or after it was refused, the poll returns a minimal { id, request_id, status, error? } (see PendingOrder). Once the order is recorded it returns the full OrderWithMarket.
Only fill-or-kill is available today: set time_in_force to "FOK", and the order fills completely at your price or better, or is cancelled. IOC is coming; until then it is a 400 with IOC orders are not yet supported.

Order outcomes and retries

Not getting a 200 does not mean the order failed. What each answer to POST /trading/orders tells you, and what to do next: A spent request_id stays spent for 24 hours. Polling it reads cancelled with the refusal’s message in error, and sending it again returns 200 with order_status: "cancelled" and places nothing. Two exceptions to the poll: after a 409 it returns nothing, because the request_id is another account’s; and after a 500, poll before trying again and follow the order if the poll returns one. A body that is not valid JSON, or over 3 MB, is refused by the web framework before anything is read, with a 400 or 413 that may not be JSON. Nothing was recorded, so the same request_id is fine once the body is fixed. A poll of a spent request_id, here after 400 Market is not active:

Idempotency

request_id is required on every order: 1 to 64 characters from A-Z a-z 0-9 _ -. A UUID is ideal.
  • One request_id never places more than one order. Sending your own request_id again returns the order it already names (same order_id) with its current status, and cancelled if the first request was refused. When to reuse it and when to send a new one: Order outcomes and retries.
  • Another account’s request_id is 409 DUPLICATE_REQUEST_ID. Use a fresh random value.

Conventions

  • No null in a response. A value that is unset is omitted. Test for presence.
  • Timestamps are epoch milliseconds on orders and positions.
  • Money is a number in dollars. A price is per contract, between 0 and 1. A price you send is between 0.01 and 0.99.
  • Dollar fields are the source of truth. Fills land on half-cents, so do not recompute a cost as price times quantity; read fill_cost, cost and the other dollar fields.
  • Pagination. Lists take limit (1 to 50, default 50) and offset.
  • Rate limit. At most 10 requests per second per IP address, whichever key they use. See Rate limits.
  • Your data only. Every route acts as the key’s own account. GET /orders, GET /orders/{id}, GET /positions, GET /positions/{id} and GET /transactions refuse a user_id query parameter with a 401; the other routes ignore it.

Errors

An error is { "status": "error", "error": "<CODE>", "message": "<text>" }. error is a string; the codes below are the ones these routes return today, and a code not listed here should be handled by its HTTP status. Every code is also on Enumerations. For POST /trading/orders, whether a request_id can be reused after each error is in Order outcomes and retries. A 429 Too Many Requests is the rate limit, not one of these codes. It records nothing: wait and retry the same request, as in Rate limits.