Pick API
Submit your system's picks before the event. We stamp the market price the moment the batch arrives, freeze each pick, grade it after the event, and build the verified record on your algorithm's page. Free, private by default.
Setup
- Sign in and open My algorithms. Choose Connect your system: a name, the league, a paragraph, and whether picks are revealed before start. Note the algorithm id on its page.
- In Settings, mint an API key. The secret is shown once and looks like
hk_live_…. Up to five active keys; revoke any time. - Send picks to
POST https://hindsight-production-e3c9.up.railway.app/pickswith the key as a bearer token. That is the whole integration.
Submit picks
One request, up to 200 picks. Each item names your algorithm (id or name), the league, the event, the market, and the selection. Nothing about price or time is in the body: we stamp both at receipt. Every item gets its own result, keyed by index; one bad item never sinks the rest.
curl -X POST https://hindsight-production-e3c9.up.railway.app/picks \
-H "Authorization: Bearer hk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"picks": [
{
"algorithm": 123,
"sport": "MLB",
"game_date": "2026-09-08",
"home": "BOS",
"away": "NYY",
"market": "moneyline",
"selection": "home"
},
{
"algorithm": 123,
"sport": "MLB",
"event": "Yankees at Red Sox 9/8",
"market": "total",
"selection": "over",
"line": 8.5
},
{
"algorithm": "My CS2 model",
"sport": "CS2",
"event": "NaVi vs Vitality, IEM Cologne",
"market": "moneyline",
"selection": "Vitality"
}
]
}'Identifying the event
Either the structured fields or free text, never both.
| field | meaning |
|---|---|
| sport | A registered league — the codes the league picker shows when you connect a system (MLB, NFL and the esports/college leagues as they land). |
| game_date, home, away, game_number | The league's team codes and the ET date; game_number defaults to 1 (doubleheaders are 2). |
| event | Free text: team names or codes, an optional date, an optional tournament. Resolved against our schedule for tracked leagues and against public sources otherwise; an ambiguous mention is rejected with the candidates. |
Markets and selections
The line is always the home side's number. A side selection may be a team mention instead of home/away.
| market | selection | line |
|---|---|---|
| moneyline | home · away (or a team name) | none |
| spread | home · away | home side's number, e.g. -1.5 for a home favourite |
| total | over · under | the total, e.g. 8.5 |
| team_total | home_over · home_under · away_over · away_under | that team's total |
| f5_moneyline | home · away | none (first five innings, MLB) |
| f5_total | over · under | the first-five total |
The receipt
For the batch above. An accepted pick carries its id, the receipt time, the stamped price for your side and the other side (or priced: false when no capture covers the market yet), and the event it resolved to.
{
"results": [
{
"index": 0,
"status": "accepted",
"pick_id": 9812,
"submitted_at": "2026-09-08T14:02:11.418Z",
"priced": true,
"stamped_price": -135,
"stamped_opposite_price": 115,
"stamped_provider": "DraftKings",
"stamped_at": "2026-09-08T13:00:04.902Z",
"event": {
"id": 4410,
"event_key": "MLB:2026-09-08:NYY@BOS:1",
"sport": "MLB",
"home_name": "Boston Red Sox",
"away_name": "New York Yankees",
"home_code": "BOS",
"away_code": "NYY",
"scheduled_start_at": "2026-09-08T23:10:00Z",
"tier": "deterministic"
}
},
{
"index": 1,
"status": "accepted",
"pick_id": 9813,
"submitted_at": "2026-09-08T14:02:11.418Z",
"priced": false,
"stamped_price": null,
"stamped_opposite_price": null,
"stamped_provider": null,
"stamped_at": null,
"event": {
"id": 4410,
"event_key": "MLB:2026-09-08:NYY@BOS:1",
"sport": "MLB",
"tier": "deterministic"
}
},
{
"index": 2,
"status": "rejected",
"reason": "ambiguous",
"detail": "2 CS2 events match ('NaVi', 'Vitality'); add the date",
"candidates": [
{
"id": null,
"event_key": "CS2:2026-09-09:Natus_Vincere@Team_Vitality:1",
"tier": "evidence"
},
{
"id": null,
"event_key": "CS2:2026-09-11:Natus_Vincere@Team_Vitality:1",
"tier": "evidence"
}
]
}
]
}| reason | what it means |
|---|---|
| invalid | Unknown market, a selection that does not fit it, or a missing line. |
| unknown_algorithm | No API-fed algorithm of yours by that id or name (or the name is ambiguous; use the id). |
| unmapped | No scheduled event matches; for a tracked league only our schedule counts. |
| ambiguous | More than one event matches; candidates are listed. Add the date or game number. |
| already_started | The event's scheduled start has passed on our clock. |
| duplicate | The same (algorithm, event, market, selection, line) already exists; its id is returned. |
| rate_limited | Past the daily cap for this key; Retry-After says when it resets. |
Withdraw before start
A pick can be voided by its owner before the event starts, never after and never once settled. Within 15 minutes of receipt the void is a correction: it leaves the record and readers never see it. After that it is a withdrawal: the pick stays in the history with its time, counts nowhere as a result, and the record shows how often the system withdraws. A change of mind is a withdrawal plus a new pick. Nothing is ever edited or deleted; resubmitting a voided pick is a duplicate.
curl -X DELETE https://hindsight-production-e3c9.up.railway.app/picks/9812 \ -H "Authorization: Bearer hk_live_YOUR_KEY"
Read back
Your own picks with settlement state, for reconciliation, and the resolvable schedule so you can look up a doubleheader before submitting.
# your own picks, with settlement state curl "https://hindsight-production-e3c9.up.railway.app/picks?algorithm=123&from=2026-09-01" \ -H "Authorization: Bearer hk_live_YOUR_KEY" # the resolvable schedule for a date (no key needed) curl "https://hindsight-production-e3c9.up.railway.app/events?sport=MLB&date=2026-09-08"
What happens after
- Stamped at receipt. The price is the newest one our own capture holds for that market, with the book and the capture time on the pick. A league without a price feed carries an accuracy-only record and says so.
- Sealed until start unless you turn on reveal before start. Followers of a sealed system get “posted N picks”; the picks appear as each event starts.
- Closed and settled. The last price before start is recorded for closing-line value. Tracked leagues settle from our results; other leagues settle when two independent public sources agree, with the evidence attached to the event. A disagreement waits for a person and the pick shows “pending review”.
- On the record. Accuracy, flat-stake units, dog/chalk splits and CLV, with sample-size bands, the tier mark and priced-vs-unpriced counts, on your algorithm's page and in the directory.
Limits
| limit | value |
|---|---|
| Requests per minute, per key | 60 |
| Picks per day, per key | 2,000 |
| Picks per batch | 200 |
| Active keys per user | 5 |
| API-fed algorithms per user | 10 |
Over a limit the response is 429 with a Retry-After header. A key on a web route, or a web session on an API route, is a 401.