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.