API reference
Simulations
Copy as Markdown
Create a simulation
POST /v1/simulations
Simulate one match for exactly draws / 1,000 credits per live delivery, including cached results.
Authentication: Bearer API key with simulations.run; active Plus or Pro plan required.
Parameters
Send an optional Idempotency-Key header (1–255 characters) and keep the same key and exact JSON body for retries.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
| — | — | — | None. |
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
| — | — | — | None. |
Body parameters
| Name | Type | Required | Description |
|---|---|---|---|
fixture_id | integer or string | Conditional | Use a returned fixture ID instead of home, away, and date. |
home | string | Conditional | Home team name; required with away when you omit fixture_id; maximum length: 200. |
away | string | Conditional | Away team name; required with home when you omit fixture_id; maximum length: 200. |
draws | integer | No | Number of simulated matches: full simulated playthroughs of the fixture; range: 100–1,000,000; default: 1,000. |
date | string | No | Fixture date in YYYY-MM-DD format; omit it to select the next match. |
wait_seconds | integer | No | Maximum time to wait for a result before returning a job; range: 0–25; default: 25. |
lineups | object | No | Optional home and away source choices: auto (default), predicted, announced, or custom; see Choosing lineups. |
Example request
curl --request POST 'https://api.opono.com/v1/simulations' \
--header "Authorization: Bearer $OPONO_API_KEY" \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: match-example-1' \
--data '{"fixture_id":19609874,"draws":1000}'Response
| Field | Type | Description |
|---|---|---|
object | string | simulation for delivery; simulation_job for pending or terminal jobs. |
id | string | Delivered simulation ID. |
fixture_id | integer | Resolved fixture ID. |
state | string | provisional, inputs_final, or lineups_announced. |
data_version | string | Opaque input version; compare it only for equality. |
created_at | string | Simulation creation time in ISO 8601 UTC. |
livemode | boolean | False for synthetic test output. |
price.draws | integer | Number of simulated matches for this simulation. |
price.credits | string | Exact credit price with three decimal places. |
credits_charged | number | Credits settled for this request; zero in test mode. |
scope | string | shared or private; private results belong only to your organisation. |
inputs.lineups | object | Resolved home and away sources; custom sides include normalized XI, bench and formation. Announced sides show only source. |
inputs.squad_version | string | Squad version used to validate your lineups. |
warnings | array | Non-blocking low_start_probability, goalkeeper_unverified, or official_lineups_announced warnings. |
receipt | object | Request ID, idempotency key, price, charged credits, and remaining credits. |
receipt.inputs_hash | string or null | The run's input fingerprint; null on older receipts. |
simulation | object | The opono.simulation.v1 document; see the fields below. |
simulation.fixture | object | Fixture ID, kick-off, competition, and both team labels. |
simulation.basis | object | Input state, as_of timestamp, data_version, lineups, number of simulated matches (draws), and seed. |
simulation.basis.lineups | string | predicted, announced, or custom; this enum can gain values. |
simulation.basis.lineup_sources | object | Optional home and away sources: predicted, announced, or custom; absent on older results. |
simulation.result | object | Home win, draw, and away win probabilities from 0 to 1. |
simulation.goals | object | Expected goals, score grid, and goal distributions. |
simulation.markets | object | Scorelines, totals, and both-teams-to-score probabilities. |
simulation.half_time | object | Half-time and joint half-time/full-time probabilities. |
simulation.timeline | object | 110 steps with minute_label, team event series, and score-state probabilities. |
simulation.goal_events | object | First-goal, first-scorer, and comeback probabilities when present. |
simulation.players | array | Per-player probabilities, expected minutes, and box-score statistics. |
simulation.lineups | object | Starting elevens and benches used for each side when present. |
simulation.samples | array | 20 illustrative match paths when present. |
simulation.uncertainty | object | Number of simulated matches, Monte Carlo estimates, and model-accuracy status. |
simulation.model | object | Public model name, version, and qualification status. |
simulation.timing | object | Simulation duration when present. |
Example response
200 test response (excerpt); see OpenAPI for the full schema.
{
"object": "simulation",
"fixture_id": 19609874,
"state": "provisional",
"data_version": "2026-10-13:predicted:b167bda637016662e2585f872b25dea30f954c9a56bd5a345ff965b1663eee10",
"livemode": false,
"credits_charged": 0,
"simulation": {
"schema": "opono.simulation.v1",
"basis": {
"as_of": "2026-10-12T18:30:00Z",
"data_version": "2026-10-13:predicted:b167bda637016662e2585f872b25dea30f954c9a56bd5a345ff965b1663eee10"
},
"result": {
"home": 0.47,
"draw": 0.26,
"away": 0.27,
"calibrated": true
},
"goals": {
"expected": {
"home": 1.69,
"away": 1.27
}
},
"model": {
"public_name": "Opono Robin",
"status": "unqualified"
}
},
"price": {
"draws": 1000,
"credits": "0.000"
}
}202 response.
{
"object": "simulation_job",
"job_id": "job_example",
"fixture_id": 19609874,
"reservation_id": "reservationexample",
"result_url": "/v1/simulations/jobs/job_example?reservation_id=reservationexample",
"status": "queued",
"price": {
"draws": 1000,
"credits": "1.000"
},
"credits_reserved": 1,
"retry_after_seconds": 10
}Errors
| Status | Code | Meaning |
|---|---|---|
| 400 | parameter_invalid | A parameter has an invalid value. |
| 401 | invalid_api_key | The credential cannot authenticate. |
| 401 | key_revoked | The API key has been revoked. |
| 401 | key_expired | The API key has expired. |
| 403 | scope_missing | The key lacks the required scope. |
| 403 | tier_restricted | The organisation plan does not include this operation. |
| 403 | org_suspended | Your account is suspended. |
| 403 | ip_not_allowed | The caller is outside the key's IP allowlist. |
| 429 | rate_limited | A request or authentication rate limit was exceeded. |
| 503 | dependency_unavailable | Request admission is unavailable. |
| 503 | maintenance | The API is paused for maintenance. |
| 402 | balance_too_low | Your available balance cannot cover the request. |
| 404 | fixture_not_found | No matching simulation fixture exists. |
| 409 | fixture_ambiguous | The fixture lookup identifies multiple candidates. |
| 503 | fixture_lookup_incomplete | The fixture lookup could not prove a unique match. |
| 409 | idempotency_conflict | An idempotency key conflicts with a prior request. |
| 429 | concurrency_limited | The organisation has no available concurrent slot. |
| 429 | loop_guard | A repeated-call burst was refused. |
| 400 | fixture_not_covered | The requested fixture is not available for simulation. |
| 503 | refreshing | The request can't be checked right now. |
| 503 | settlement_unknown | Delivery settlement could not be confirmed. |
| 400 | lineup_invalid | The custom XI, bench, goalkeeper selection, or formation is invalid; recovery.reason identifies the rule. |
| 400 | player_not_in_squad | A custom player ID is outside this side's squad; check recovery.unknown_id against the free squads list. |
| 409 | lineups_not_announced | Announced team sheets are unavailable; wait for publication or use auto. |
| 429 | lineup_cooldown | Custom-lineup requests are temporarily locked; wait for Retry-After and recovery.retry_at. |
Quote a simulation
POST /v1/simulations/quote
Get the exact price without running a simulation or reserving credits. Non-auto sources also validate lineups against current fixture inputs; that validation holds while squad_version and data_version remain unchanged.
Authentication: Bearer API key with simulations.run; active Plus or Pro plan required.
Parameters
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
| — | — | — | None. |
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
| — | — | — | None. |
Body parameters
| Name | Type | Required | Description |
|---|---|---|---|
fixture_id | integer or string | Conditional | Use a returned fixture ID instead of home, away, and date. |
home | string | Conditional | Home team name; required with away when you omit fixture_id; maximum length: 200. |
away | string | Conditional | Away team name; required with home when you omit fixture_id; maximum length: 200. |
draws | integer | No | Number of simulated matches: full simulated playthroughs of the fixture; range: 100–1,000,000; default: 1,000. |
date | string | No | Fixture date in YYYY-MM-DD format; omit it to select the next match. |
wait_seconds | integer | No | Maximum time to wait for a result before returning a job; range: 0–25; default: 25. |
lineups | object | No | Optional home and away source choices: auto (default), predicted, announced, or custom; see Choosing lineups. |
Example request
curl --request POST 'https://api.opono.com/v1/simulations/quote' \
--header "Authorization: Bearer $OPONO_API_KEY" \
--header 'Content-Type: application/json' \
--data '{"fixture_id":19609874,"draws":1000}'Response
| Field | Type | Description |
|---|---|---|
object | string | simulation_quote. |
price.draws | integer | Requested number of simulated matches. |
price.credits | string | Exact credit price; zero in test mode. |
credits | number | Numeric credit price. |
credits_charged | number | Always zero. |
rate_card | string | Price revision. |
livemode | boolean | False for a test key. |
scope / inputs / warnings | string / object / array | Proposed run scope, normalized lineup inputs and non-blocking warnings when present. |
Example response
200 response.
{
"object": "simulation_quote",
"price": {
"draws": 1000,
"credits": "1.000"
},
"credits": 1,
"credits_charged": 0,
"rate_card": "draws-2026-10-13",
"livemode": true
}Errors
| Status | Code | Meaning |
|---|---|---|
| 400 | parameter_invalid | A parameter has an invalid value. |
| 401 | invalid_api_key | The credential cannot authenticate. |
| 401 | key_revoked | The API key has been revoked. |
| 401 | key_expired | The API key has expired. |
| 403 | scope_missing | The key lacks the required scope. |
| 403 | tier_restricted | The organisation plan does not include this operation. |
| 403 | org_suspended | Your account is suspended. |
| 403 | ip_not_allowed | The caller is outside the key's IP allowlist. |
| 429 | rate_limited | A request or authentication rate limit was exceeded. |
| 503 | dependency_unavailable | Request admission is unavailable. |
| 503 | maintenance | The API is paused for maintenance. |
| 400 | lineup_invalid | The custom XI, bench, goalkeeper selection, or formation is invalid; recovery.reason identifies the rule. |
| 400 | player_not_in_squad | A custom player ID is outside this side's squad; check recovery.unknown_id against the free squads list. |
| 409 | lineups_not_announced | Announced team sheets are unavailable; wait for publication or use auto. |
| 429 | lineup_cooldown | Custom-lineup requests are temporarily locked; wait for Retry-After and recovery.retry_at. |
| 404 | fixture_not_found | No matching simulation fixture exists. |
| 400 | fixture_not_covered | The requested fixture is not available for simulation. |
| 503 | refreshing | The request can't be checked right now. |
Create a batch
POST /v1/simulations/batch
Reserve credits for up to 1,000 matches before queuing them; each delivered item costs draws / 1,000 credits.
Authentication: Bearer API key with simulations.run; active Plus or Pro plan required.
Parameters
Send an optional Idempotency-Key header (1–255 characters) and keep the same key and exact JSON body for retries.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
| — | — | — | None. |
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
| — | — | — | None. |
Body parameters
| Name | Type | Required | Description |
|---|---|---|---|
fixtures | array | Yes | Distinct match selectors; each uses fixture_id or home and away with an optional date; items: 1–1,000. |
fixtures[].fixture_id | integer or string | Conditional | Fixture ID; omit team names and date when you use it. |
fixtures[].home | string | Conditional | Home team name; required without fixture_id; maximum length: 200. |
fixtures[].away | string | Conditional | Away team name; required without fixture_id; maximum length: 200. |
fixtures[].date | string | No | Optional fixture date in YYYY-MM-DD format. |
fixtures[].lineups | object | No | Optional per-side lineup choices for this item; all items are validated before reserving credits. |
draws | integer | No | Number of simulated matches: full simulated playthroughs of the fixture; range: 100–1,000,000; default: 1,000. |
Example request
curl --request POST 'https://api.opono.com/v1/simulations/batch' \
--header "Authorization: Bearer $OPONO_API_KEY" \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: match-example-1' \
--data '{"fixtures":[{"fixture_id":19609874}],"draws":1000}'Response
| Field | Type | Description |
|---|---|---|
object | string | simulation_batch. |
batch_id | string | Your batch ID. |
items | array | Per-fixture jobs and reservations. |
items[].fixture | integer | Fixture ID. |
items[].job_id | string | Job ID for this fixture. |
items[].status | string | Current item status. |
items[].credits_reserved | number | Credits held for this item. |
items[].reservation_id | string | Request-bound reservation when present on submission. |
items[].result_url | string | Follow this path to deliver and settle the item. |
items[].error | object | Error code and message when an item is unavailable. |
items[].credits_charged | number | Settled credits when present on a status response. |
items[].freshness | object | Freshness state and check times when present on a status response. |
items[].scope / inputs / warnings | string / object / array | Each item's run scope, normalized inputs and lineup warnings when present. |
validUntil | number or null | Earliest item freshness deadline in Unix milliseconds when present. |
credits_reserved_total | number | Total credits reserved for this batch when present. |
Example response
202 response; the JSON body must fit within 2 MiB.
{
"object": "simulation_batch",
"batch_id": "batch_example",
"items": [
{
"fixture": 19609874,
"job_id": "job_example",
"status": "queued",
"credits_reserved": 1,
"reservation_id": "reservationexample",
"result_url": "/v1/simulations/jobs/job_example?reservation_id=reservationexample"
}
],
"credits_reserved_total": 1
}Errors
| Status | Code | Meaning |
|---|---|---|
| 400 | parameter_invalid | A parameter has an invalid value. |
| 401 | invalid_api_key | The credential cannot authenticate. |
| 401 | key_revoked | The API key has been revoked. |
| 401 | key_expired | The API key has expired. |
| 403 | scope_missing | The key lacks the required scope. |
| 403 | tier_restricted | The organisation plan does not include this operation. |
| 403 | org_suspended | Your account is suspended. |
| 403 | ip_not_allowed | The caller is outside the key's IP allowlist. |
| 429 | rate_limited | A request or authentication rate limit was exceeded. |
| 503 | dependency_unavailable | Request admission is unavailable. |
| 503 | maintenance | The API is paused for maintenance. |
| 402 | balance_too_low | Your available balance cannot cover the request. |
| 404 | fixture_not_found | No matching simulation fixture exists. |
| 409 | fixture_ambiguous | The fixture lookup identifies multiple candidates. |
| 503 | fixture_lookup_incomplete | The fixture lookup could not prove a unique match. |
| 409 | idempotency_conflict | An idempotency key conflicts with a prior request. |
| 429 | concurrency_limited | The organisation has no available concurrent slot. |
| 429 | loop_guard | A repeated-call burst was refused. |
| 400 | fixture_not_covered | The requested fixture is not available for simulation. |
| 503 | refreshing | The request can't be checked right now. |
| 503 | settlement_unknown | Delivery settlement could not be confirmed. |
| 400 | lineup_invalid | The custom XI, bench, goalkeeper selection, or formation is invalid; recovery.reason identifies the rule. |
| 400 | player_not_in_squad | A custom player ID is outside this side's squad; check recovery.unknown_id against the free squads list. |
| 409 | lineups_not_announced | Announced team sheets are unavailable; wait for publication or use auto. |
| 429 | lineup_cooldown | Custom-lineup requests are temporarily locked; wait for Retry-After and recovery.retry_at. |