API Reference
Base URL
https://juhus.ee/api/v1All requests route through the apps/web proxy. There is no separate subdomain for the API.
Money and prices
All EUR amounts are in integer cents. 500 = €5.00, 12345 = €123.45. There are no decimal fields.
- Prices are integers 1–99 and represent the implied probability percentage of the YES outcome (e.g. price
62= 62% probability). - Volumes (
yesVolume,noVolume) are in EUR-cents, representing the total value of contracts traded on each side. - Balances are in EUR-cents.
Each fill charges a taker fee in EUR-cents. See Fees.
Authentication
Public read-only endpoints require no credentials. Authenticated endpoints require a Bearer token:
Authorization: Bearer jk_...API keys are created at Account → API Keys in the web app. See Authentication for details.
The minted JWT used by the browser is an internal mechanism: it is not exposed through this API. External integrations always use jk_* API keys.
Rate limits
| Bucket | Applies to | Limit |
|---|---|---|
v1 | All public endpoints | 60 req / 60 s per IP |
v1-auth | Authenticated REST (per IP) | 120 req / 60 s per IP |
v1-user | Authenticated REST (per user/API key) | 120 req / 60 s per user |
sse:market | GET /markets/:id/stream | 120 connections / 60 s per IP |
sse:user | GET /user/stream | 30 / 60 s per user (120 / 60 s per IP) |
When a limit is exceeded the server responds with 429 Too Many Requests and a Retry-After header (seconds).
Error format
All error responses share this shape:
{
"error": "Human-readable message",
"code": "MACHINE_READABLE_CODE"
}The code field is present only on errors that callers should handle programmatically (e.g. INSUFFICIENT_BALANCE, INSUFFICIENT_LIQUIDITY). Generic errors omit it.
Common status codes
| Code | Meaning |
|---|---|
200 | Success |
201 | Created (new order placed) |
400 | Bad request: invalid parameters |
401 | Unauthorized: missing or invalid token |
404 | Not found |
405 | Method not allowed |
429 | Rate limit exceeded |
500 | Internal server error |
503 | Transient conflict, safe to retry |
Pagination
Endpoints that return lists accept page (default 1) and limit (default 20, max 50) query parameters and return a meta object:
{
"data": [...],
"meta": {
"total": 143,
"page": 1,
"limit": 20,
"hasMore": true
}
}SSE conventions
Server-Sent Events streams use Content-Type: text/event-stream. Each frame is:
data: <JSON payload>\n\nKeep-alive frames are sent every 25 seconds:
: ping\n\nDisconnect and reconnect on any network error. The market stream sends a full snapshot on reconnect; the user stream sends a { "type": "connected" } frame.
Sell-order inversion
Sell orders are stored internally with the side inverted (a YES sell is stored as a NO buy at price 100 - P) but the API always returns orders in the user-facing representation: side and price match what you submitted. See Orders for details.