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

  1. 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.
  2. In Settings, mint an API key. The secret is shown once and looks like hk_live_…. Up to five active keys; revoke any time.
  3. Send picks to POST https://hindsight-production-e3c9.up.railway.app/picks with 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.

fieldmeaning
sportA 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_numberThe league's team codes and the ET date; game_number defaults to 1 (doubleheaders are 2).
eventFree 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.

marketselectionline
moneylinehome · away (or a team name)none
spreadhome · awayhome side's number, e.g. -1.5 for a home favourite
totalover · underthe total, e.g. 8.5
team_totalhome_over · home_under · away_over · away_underthat team's total
f5_moneylinehome · awaynone (first five innings, MLB)
f5_totalover · underthe 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"
        }
      ]
    }
  ]
}
reasonwhat it means
invalidUnknown market, a selection that does not fit it, or a missing line.
unknown_algorithmNo API-fed algorithm of yours by that id or name (or the name is ambiguous; use the id).
unmappedNo scheduled event matches; for a tracked league only our schedule counts.
ambiguousMore than one event matches; candidates are listed. Add the date or game number.
already_startedThe event's scheduled start has passed on our clock.
duplicateThe same (algorithm, event, market, selection, line) already exists; its id is returned.
rate_limitedPast 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

Limits

limitvalue
Requests per minute, per key60
Picks per day, per key2,000
Picks per batch200
Active keys per user5
API-fed algorithms per user10

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.

Pick API — Hindsight