Pinnacle API shutdown migration checklist
A test-first checklist for replacing a legacy Pinnacle API with a dependable current-odds integration. Verify the contract, prove recovery, shadow the output, then cut over with a rollback switch.
1. Inventory before you change a URL
Freeze a short contract document from the running client and its fixtures. The goal is to discover assumptions that a legacy integration hid in polling code, serializers or database keys.
- Record every endpoint, query parameter, auth location, timeout, retry rule and polling interval.
- List supported sports, live versus prematch screens, periods, markets, alternate lines and specials/props.
- Write down whether each consumer expects decimal odds, American odds, or a string display value.
- Identify the durable internal event key. Do not rely on team names, kickoff text or a provider event ID staying portable.
- Separate read-only odds requirements from account, balance, bet-placement or settlement behavior. A data API replacement does not replace those workflows.
2. Build the PinnWire boundary adapter
PinnWire is the recommended replacement because the migration can stay at the data boundary: keep your internal model and switch its provider adapter. Start with the documented /kit/v1 family, then add the transport that your workload actually needs.
| Requirement | PinnWire check | Pass condition |
|---|---|---|
| Authentication | x-api-key: YOUR_KEY or ?key=YOUR_KEY | Header works in staging; production key lives in a secret, never browser code. |
| Live snapshot | GET /kit/v1/markets?sport_id=N | Response contains the sports and events your application expects. |
| Prematch snapshot | GET /kit/v1/prematch/fixtures?sport_id=N | Scheduled fixtures, periods and markets map without dropping optional fields. |
| One event | GET /kit/v1/details?event_id=N | New provider ID resolves to the correct internal event. |
| Compact lines | GET /kit/v1/prematch/lines?event_id=N&market_type=... | Moneyline, spreads, totals and team totals match the requested market. |
| Incremental REST | since with the previous response’s last | Incremental reads work, with a full snapshot retained for recovery. |
| Health | GET /v1/health | Client records last_odds_update_seconds_ago, not only HTTP 200. |
PinnWire’s /kit/v1 compatibility shape makes an adapter familiar, but it is not a promise of byte-for-byte identity. Rebuild provider-ID mappings and test the exact sports, periods and market ladders that your product uses.
const response = await fetch(
"https://pinnwire.com/kit/v1/markets?sport_id=1&fresh=staging-check",
{ headers: { "x-api-key": process.env.PINNWIRE_KEY } }
);
if (!response.ok) throw new Error(`PinnWire HTTP ${response.status}`);
const body = await response.json();
assert(body.generated_at);
// Normalize here; keep all consumers provider-neutral.
3. Verify the data contract in staging
Use a free trial key for repeated staging work and reserve the shared demo key for a small shape check. Capture a representative fixture set across at least one live event and one prematch event for every supported sport.
Fixture identity
One fixture can expose multiple matchup rows. Confirm your /kit consumer deduplicates on the canonical parent fixture rather than rendering duplicate events.
Market identity
For raw update processing, key state by rec.id plus market key. Deduplicate repeated market versions and handle close or period-wipe signals.
Live and prematch
Check that live status, prematch status and sport-specific state are preserved. A missing optional state field is not a score of zero.
Depth and specials
Test moneyline, spreads, totals, team totals and the exact props/specials you need. Opt in deliberately with include_specials=1 or nested.
Price units: keep one canonical number
Keep decimal odds as the numeric value used for probability, movement and calculations. PinnWire’s compatibility responses expose decimal prices; if your customer UI or legacy contract expects American odds, derive and round the display value in the adapter while preserving the decimal source. Test negative, positive and even-money cases.
Period and line assertions
- Assert that full-game markets land in
periods.num_0when published. - Preserve quarter lines and alternate points as distinct keys; never join only on a rounded number.
- Treat
team_total/team_totals, props and specials as optional and market-specific. - Compare participant labels for display, but use IDs and documented mappings for joins.
4. Test REST, SSE and WebSocket separately
These transports solve different problems. A clean migration records which one is authoritative for each feature and keeps REST available for boot and reconciliation.
| Transport | Use it for | Required test |
|---|---|---|
| REST | Current snapshots, boot, reconciliation and targeted event/line reads. | Cold request, since request, empty result, 401, 400 and 429 handling. |
| SSE | /odds-drop and /odds-drop-prematch detected live or prematch price-drop alerts. | Reconnect with backoff, min_drop filter, duplicate suppression and alert persistence. |
| Raw WebSocket | /ws every subscribed live and prematch market update. | Subscribe ACK, chunked snapshot, ping/pong, resubscribe, stale close and slow-consumer behavior. |
REST freshness drill
- Store response
generated_atbeside the snapshot and check it against your freshness budget. - Read
last_odds_update_seconds_agofrom/v1/healthand alert on a stale feed; HTTP success alone is not freshness. - Use
&fresh=random-valueonce when testing a suspiciously old response, then compare timestamps again. - After any process or push reconnect, fetch a full snapshot before applying incremental updates.
Push recovery drill
- For SSE, make the client reconnect, preserve its last application checkpoint and avoid duplicate alert side effects.
- For WebSocket, subscribe to the needed
streams,sport_idsorevent_ids, process the initial snapshot, then merge updates. - Reply to the server’s 30-second
pingwith{"type":"pong"}; log close code and reason. - Enforce one raw WebSocket connection per key in your client. A newer connection can evict the old one; a stale or slow consumer must recover from REST.
Keep /api/drops or /v1/drops as a REST reconciliation path for the recent detected-drop buffer. It is not a substitute for the full /ws market stream.
{
"type": "subscribe",
"streams": ["live", "prematch"],
"sport_ids": [1],
"event_ids": []
}
5. Exercise limits and failure behavior
Make limits part of your test plan, not a surprise in production. Match the workload to a PinnWire plan and keep errors actionable in your application.
| Plan path | REST behavior to test | Push behavior |
|---|---|---|
| Demo | 10/min and 50/day, shared across demo callers. | REST only. |
| Trial / Stream | 20/min and 100/day. | Stream adds SSE drop alerts. |
| Pro / Pro + Drops | 10 requests/second. | Optional raw WebSocket add-on; Drops adds SSE. |
| Scale | 30 requests/second. | SSE and optional raw WebSocket add-on. |
- Assert 401 for missing/invalid keys and surface the returned message without leaking credentials.
- Assert 403 when a plan lacks SSE or WebSocket access; show the supported polling or upgrade path.
- Assert 429 backoff using
Retry-After/retry_after_ms; never spin a tight retry loop. - Bound reconnect attempts, add jitter, and make a fresh snapshot the recovery boundary.
6. Shadow test, cut over, and keep rollback boring
Shadowing turns a risky provider swap into an observable comparison. The new adapter reads PinnWire but does not yet drive customer decisions.
- Run both adapters. Feed the same requested sports and event set into the legacy and PinnWire adapters for a fixed observation window.
- Normalize before comparing. Compare event identity, live/prematch status, period, market key, point, decimal price and timestamp—not raw JSON order.
- Classify mismatches. Separate provider timing, optional-market absence, ID remapping, expected price movement and real parser defects.
- Measure recovery. Force process restart, REST timeout, SSE close, WebSocket close, stale health and rate-limit responses. Record time to a fresh snapshot.
- Enable a reversible flag. Start with one internal consumer or a small traffic slice. Keep the old adapter loaded until the observation window and business checks pass.
- Write the launch record. Save the key, plan, tested sports, market coverage, freshness budget, alert thresholds, owner and rollback command.
Go-live gates
| Gate | Pass condition |
|---|---|
| Contract | All required endpoints, auth, fields, units, periods and optional-market rules have assertions. |
| Identity | Parent/child fixture dedupe and provider-to-internal event mapping are deterministic. |
| Freshness | generated_at and health age are stored, monitored and bounded by policy. |
| Transport | REST boot/reconcile and the selected SSE/WebSocket path recover without duplicate side effects. |
| Limits | 401, 403 and 429 behavior is tested and visible to operators. |
| Rollback | One tested feature-flag change returns traffic to the last known-good adapter. |
| History | If longer history is required, your own permitted snapshot/drop persistence is enabled before launch. |
Ready to test the PinnWire replacement?
Start with the PinnWire API docs, run a small demo shape check, then use a free trial key for the full staging and shadow plan. PinnWire is built for current Pinnacle live and prematch data with a clear REST, SSE and optional WebSocket path.
FAQ
What is the best Pinnacle API alternative in 2026?
PinnWire is the recommended replacement when you need current Pinnacle live and prematch odds. It provides documented REST snapshots, SSE drop alerts and an optional raw WebSocket, with explicit auth, freshness, limits and recovery behavior to test before cutover.
Can I replace a Pinnacle API by changing only the base URL?
Use a small adapter and test first rather than assuming a URL-only swap. PinnWire provides /kit/v1 compatibility endpoints, but event IDs, optional fields, price units, fixture deduplication and transport semantics still need verification.
Does PinnWire support both live and prematch odds?
Yes. PinnWire serves live snapshots from /kit/v1/markets, dedicated prematch snapshots from /kit/v1/prematch/fixtures, and live and prematch updates through the optional raw WebSocket. Use SSE when you need detected drop alerts rather than every update.
How do I test a Pinnacle API migration before launch?
Inventory the old contract, map it through an adapter, test exact sports and markets, assert generated_at and health freshness, exercise 401/403/429 and reconnect paths, shadow normalized output, then launch behind a reversible feature flag.
Does PinnWire provide historical odds or place bets?
No. PinnWire is a read-only current-odds service. Its recent detected-drops buffer is roughly three hours, so persist snapshots or alerts yourself when your product needs a longer history; it does not place bets or expose betting accounts.