API concepts
How the Doxa public market data API works. Authentication, rate limits, errors, pagination, ids and price units.
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.
Base URL
Section titled “Base URL”https://doxa.proEvery endpoint is a GET request under /api/, for example https://doxa.pro/api/events.
Authentication
Section titled “Authentication”None. The public endpoints need no account, key or token. Send a plain HTTPS request.
curl "https://doxa.pro/api/events?limit=5"Rate limits
Section titled “Rate limits”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
Section titled “Errors”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.
Pagination
Section titled “Pagination”List endpoints page with limit and offset.
GET /api/eventsreturnseventsplustotal,offset,limitandhasMore. Ask for the next page withoffsetincreased bylimitwhilehasMoreistrue.totalmay be an estimate.GET /api/marketsreturnsmarketsplus apaginationobject withtotal,limit,offset,hasMoreandnextCursor. For long walks, passpaginate=keyseton the first request, then pass each page’snextCursorback asafter_id. A cursor stays stable while new markets are added.nextCursorisnullon 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:512345kalshi: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.
Prices and amounts
Section titled “Prices and amounts”- Market prices (
yesPrice,noPrice) are decimal strings from0to1."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].sizeis the number of shares at that price andcumulativeis 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.
Versioning and stability
Section titled “Versioning and stability”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.
Caching
Section titled “Caching”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.