Skip to content

API concepts

How the Doxa public market data API works. Authentication, rate limits, errors, pagination, ids and price units.

View as Markdown

Doxa has a small public API for reading market data: events, markets, order books and search. It is read-only and in beta. This page covers what applies to every endpoint. The API reference lists each endpoint with its parameters, example requests and example responses.

https://doxa.pro

Every endpoint is a GET request under /api/, for example https://doxa.pro/api/events.

None. The public endpoints need no account, key or token. Send a plain HTTPS request.

Terminal window
curl "https://doxa.pro/api/events?limit=5"

Requests without a signed-in session are limited per IP address. The limit is currently 300 requests per 60 seconds. It may change.

Responses carry RateLimit and RateLimit-Policy headers that show your remaining budget. When you go over the limit, the API answers 429 Too Many Requests:

{ "message": "Too many requests, please try again later" }

Wait for the number of seconds in the Retry-After header before you try again. Do not retry in a tight loop.

Errors use the usual HTTP status codes. The body is JSON with a human-readable message.

Status Meaning
400 A query parameter is invalid. Event and market lists add an errors object keyed by parameter name. Search adds a details object.
404 The event, market or order book was not found.
429 Rate limit reached. See above.
451 The service is not available in your region. See the Terms.
500 Something went wrong on our side.
503 Temporarily unavailable. When a Retry-After header is present, wait that many seconds and retry.

Example 400:

{
"message": "Invalid query parameters",
"errors": { "limit": ["Too big: expected number to be <=100"] }
}

Treat message as text for people. Do not parse it, because the wording can change.

List endpoints page with limit and offset.

  • GET /api/events returns events plus total, offset, limit and hasMore. Ask for the next page with offset increased by limit while hasMore is true. total may be an estimate.
  • GET /api/markets returns markets plus a pagination object with total, limit, offset, hasMore and nextCursor. For long walks, pass paginate=keyset on the first request, then pass each page’s nextCursor back as after_id. A cursor stays stable while new markets are added. nextCursor is null on the last page and in plain offset mode.

The allowed range for limit differs per endpoint. The reference lists it for each one.

Ids are opaque strings prefixed with the venue, in the form <venue>:<venue id>. For example:

  • polymarket:512345
  • kalshi:KXBTC-26DEC31-T100000

Use an id exactly as the API returned it. Do not build ids yourself or parse the part after the colon. A market’s id is what GET /api/orderbook/{marketId} expects. A market’s eventKey identifies the event it belongs to.

  • Market prices (yesPrice, noPrice) are decimal strings from 0 to 1. "0.410000" means 41¢, about a 41% chance.
  • Order book levels use cents from 0 to 100. Each level is an array [price, size, cumulative]. size is the number of shares at that price and cumulative is the running total from the best price.
  • Dollar amounts such as liquidity and volume are decimal strings in US dollars.
  • Times are ISO 8601 strings in UTC.

Read prices and amounts as decimals. Do not convert them to floating point if you need exact values.

The API is in beta. The current version is 0.1.0-beta.

  • Endpoints, parameters and fields can change while the API is in beta.
  • Only the fields in the reference are documented. A response can contain other fields. Those are unstable and can change or disappear without notice, so do not depend on them.
  • Ignore fields you do not recognise. That way your code keeps working when fields are added.

Market data changes quickly. Event and market lists can be cached for up to 30 seconds (Cache-Control: public, max-age=30). Order books are never cached (Cache-Control: no-store). Poll no faster than you need, and stay within the rate limit.