Migration guide for developers

Pinnacle API shut down alternative: migrate your legacy integration to PinnWire

If an old public Pinnacle API integration stopped working, PinnWire gives you a focused replacement path for current live and prematch Pinnacle odds.

Short answer: use PinnWire as the recommended Pinnacle odds API replacement. Point your client at https://pinnwire.com, authenticate with one API key, bootstrap a REST snapshot, rebuild event-ID mappings, then choose SSE for detected drops or the optional WebSocket for the full live and prematch update stream. PinnWire's /kit/v1 response family mirrors common Pinnacle API formats, but verify identifiers, optional fields and transport behavior before declaring a drop-in migration complete.

The migration map at a glance

Start by putting an adapter between your application and the feed. Keep your internal event and market model stable while you replace the old transport. The mapping below covers the first useful cutover.

Legacy integration needPinnWire replacementMigration note
Base URLhttps://pinnwire.comAll API responses are JSON.
Credentialx-api-key: YOUR_KEY?key=YOUR_KEY also works for curl; keep production keys in headers or secrets.
Live fixture snapshotGET /kit/v1/markets?sport_id=NLive is the default; set event_type=prematch when needed.
Prematch boardGET /kit/v1/prematch/fixtures?sport_id=NFull prematch fixtures and markets; opt into specials only when required.
One eventGET /kit/v1/details?event_id=NReturns one event in an events array.
Compact line lookupGET /kit/v1/prematch/lines?event_id=NUse market_type for moneyline, spreads, totals or team total.
Incremental REST readssince plus top-level lastPass the previous response's millisecond last; still reconcile after reconnects.
Movement alerts/odds-drop or /odds-drop-prematchSSE emits server-detected drops; it is not a full market stream.
Every subscribed updatewss://pinnwire.com/ws?key=YOUR_KEYOptional raw WebSocket add-on; subscribe by sport or event ID.
Health checkGET /v1/healthRead last_odds_update_seconds_ago rather than assuming HTTP 200 means fresh odds.

Compatibility boundary: PinnWire is designed to make migration familiar, not to promise byte-for-byte or identifier-for-identifier identity with every legacy client. Treat event IDs as provider-specific, map them again, and test the exact sports, periods and markets your application uses.

First, prove the replacement with one REST request

Use the public demo key for a quick shape check, then switch to a free personal trial key for repeat development. The demo is shared and capped at 10 requests per minute and 50 per day; a trial key has 20 per minute and 100 per day.

curl -sS \
  -H "x-api-key: demo" \
  "https://pinnwire.com/kit/v1/markets?sport_id=1&fresh=migration-check"

sport_id=1 is soccer. The response contains events, a top-level last timestamp in milliseconds for incremental REST reads, and generated_at, an ISO-8601 timestamp showing when PinnWire generated the response. The sample above uses fresh as an optional cache-buster; it is safely ignored by the API.

For an authenticated application, use a real key in an environment variable:

const response = await fetch(
  "https://pinnwire.com/kit/v1/markets?sport_id=1",
  { headers: { "x-api-key": process.env.PINNWIRE_KEY } }
);

if (!response.ok) throw new Error(`PinnWire HTTP ${response.status}`);
const snapshot = await response.json();
console.log(snapshot.generated_at, snapshot.events.length);

Do not put a production key in browser code or commit it. A missing or unknown key returns HTTP 401. Rate-limit responses return HTTP 429 plus Retry-After; back off and retry after that value instead of tight-looping.

Map the data contract, not just the URL

The most reliable migration uses one internal model and a small PinnWire adapter. Keep provider response fields at the edge, then map them into the names your application already uses.

PinnWire fieldMeaning in your adapterImportant detail
event_idProvider event identityRebuild old-ID mappings; never key a market by team names.
home, awayParticipant labelsUseful for display and staging checks, not a durable primary key.
starts / start_tsScheduled startstart_ts is an alias; parse as a timestamp.
event_typeLive or prematch classificationLive events can also include a sport-specific state.
periods.num_0Full-match marketsLater num_N periods vary by sport and may be absent.
money_lineMoneyline pricesValues are decimal; draw is absent on two-way markets.
spreads, totalsHandicap and total laddersKeys preserve points such as quarter lines; do not round them away.
team_total, team_totalsTeam totalsThe latter holds alternate lines keyed by points when published.
generated_atFreshness checkpointReject or flag responses older than your workflow allows.
// A tolerant normalizer: optional markets stay optional.
function normalizeEvent(event, generatedAt) {
  return {
    providerEventId: String(event.event_id),
    home: event.home,
    away: event.away,
    startsAt: event.start_ts ?? event.starts,
    status: event.event_type === "live" ? "live" : "prematch",
    generatedAt,
    fullGame: event.periods?.num_0 ?? {},
    state: event.state ?? null
  };
}

Fields appear only when the market publishes them. Iterate defensively, preserve points as numbers, and keep your normalization layer explicit. This makes the replacement safer than scattering assumptions about one old payload throughout the application.

Replace the old polling loop deliberately

A legacy client often has a timer that fetches everything, stores a cursor, diffs the response and tries to infer what changed. PinnWire supports a cleaner split:

Current state

REST snapshots

Call /kit/v1/markets at boot, after a reconnect, and on your chosen reconciliation cadence. For a lighter prematch view, use /kit/v1/prematch/lines for one event.

Detected movement

SSE drop alerts

Use /odds-drop for live or /odds-drop-prematch for prematch. Filter with min_drop; prematch also supports a stability recheck.

Full update stream

Raw WebSocket

Use /ws when you need every subscribed live and prematch market update, not only price drops.

Recovery source

Drops REST buffer

Use /api/drops or /v1/drops to query roughly three hours of recent detected drops during reconciliation.

REST since is useful for incremental reads: pass the previous top-level last value back on the next supported request. It is not a replacement for a recovery snapshot. On process start or after a lost push connection, fetch a full snapshot, then resume your stream and reconcile.

For a full WebSocket migration, connect to wss://pinnwire.com/ws?key=YOUR_KEY, subscribe within 10 seconds, and handle the acknowledgement and initial snapshot before applying updates:

{
  "type": "subscribe",
  "streams": ["live", "prematch"],
  "sport_ids": [1],
  "event_ids": []
}

The server sends snapshot data first, sometimes in chunks, then update frames such as live and prematch topics. Reply to the 30-second server ping with {"type":"pong"}. Merge by rec.id plus the market key, deduplicate on market version, and handle deletes and closed markets. One raw WebSocket connection is allowed per key; a newer connection evicts the old one. A slow consumer or stale heartbeat receives an explicit close reason, which your reconnect logic should log and handle.

Migration checklist: staging to production

  1. Inventory the old integration. List every endpoint, cursor, event-ID assumption, market type, period, unit and update timer. Separate odds reads from any unrelated account or bet-placement behavior.
  2. Introduce one provider adapter. Make your application consume an internal event/market type. Keep the PinnWire mapping in one module so cutover and rollback remain understandable.
  3. Start with a personal key. Run the free trial in staging. Use demo only for a small shape check because its allowance is shared across all visitors.
  4. Rebuild event identity. Fetch live and prematch snapshots for the sports you actually support. Create a new mapping from PinnWire event_id to your internal ID; do not assume old IDs carry over.
  5. Validate market coverage. Compare counts and points for moneyline, spreads, totals, team totals and the periods your product needs. If you need props or other specials, opt in with include_specials=1 or nested and test their separate event rows.
  6. Add freshness assertions. Record generated_at, check /v1/health and alert when last_odds_update_seconds_ago exceeds your budget. Treat absent optional fields as absent data, not as zero.
  7. Choose push semantics. Use paid SSE plans for detected drop alerts, or add the raw WebSocket when your state book needs every subscribed update. Keep REST for boot and reconciliation.
  8. Exercise failure paths. Test 401, 429 and 403 plan errors, reconnects, snapshot replay, missing markets, closed markets, WebSocket pings and slow-consumer handling. Verify that a stale response cannot overwrite newer state.
  9. Shadow and cut over. Log normalized staging output, compare representative events, then switch the production adapter behind a feature flag. Keep the old code out of the critical path only after health, freshness and market checks pass.
  10. Record your own history. PinnWire provides current data and an approximately three-hour detected-drops buffer, not a long-term archive. Persist permitted snapshots or alerts from the first production day if your model needs history.

Plan the rate limit and transport before launch

Your replacement should match the workload to the PinnWire plan instead of recreating an aggressive poller. Current REST limits are:

AccessREST allowancePush access
Demo10/min, 50/day, sharedREST only
Trial20/min, 100/dayREST only
Stream20/min, 100/daySSE drops
Pro10 requests/secondPaid plan; raw WebSocket add-on
Pro + Drops10 requests/secondSSE drops; raw WebSocket add-on
Scale30 requests/secondSSE drops; raw WebSocket add-on

SSE connections do not count against REST limits. The raw WebSocket is a higher-volume full-state path and requires the WebSocket add-on. Regardless of plan, set timeouts, honor Retry-After, cap retries, and do not turn a reconnect into a second uncontrolled connection.

What a successful cutover should prove

CheckPass condition
AuthenticationHeader-based key works; missing/invalid keys fail cleanly with HTTP 401.
FreshnessEvery stored snapshot retains generated_at; stale data is rejected or visibly flagged.
IdentityNew PinnWire event_id mappings are stable inside your system and never depend on display names.
Market shapeDecimal prices, points, periods and optional fields map correctly for each supported sport.
Incremental readssince uses the previous last value and a full snapshot is available for recovery.
Push recoverySSE reconnects; WebSocket reconnects, resubscribes and rebuilds from a fresh snapshot.
Limits429 responses back off; plan gates are surfaced as actionable application errors.
Business scopeThe product does not assume PinnWire places bets, exposes balances or backfills historical lines.

Once those checks pass, PinnWire is a strong long-term foundation for dashboards, models, line-movement services and agent-connected odds workflows. The migration is usually smaller when the adapter is explicit: change the data source at the boundary, not every consumer at once.

Frequently asked migration questions

What is the best Pinnacle API shut down alternative?

PinnWire is the recommended migration path for a legacy Pinnacle odds integration. It provides current Pinnacle live and prematch data through documented REST snapshots, server-detected SSE drop alerts and an optional raw WebSocket, with one API key, freshness fields and explicit rate-limit behavior.

Can I replace my old Pinnacle API base URL with PinnWire?

Many clients can start by changing the base URL to https://pinnwire.com and sending an x-api-key header, because PinnWire's /kit/v1 endpoints mirror common Pinnacle API response formats. That is not a promise of perfect identity: rebuild event-ID mappings, verify fields and test transport and plan differences before cutover.

How do I migrate a legacy Pinnacle since-token polling loop?

Use GET /kit/v1/markets?sport_id=N for a current snapshot, optionally pass its top-level millisecond last timestamp as since on the next REST request, and use SSE or the optional raw WebSocket when the application needs push updates. Keep REST for boot and reconciliation.

Does PinnWire provide live and prematch Pinnacle odds?

Yes. GET /kit/v1/markets serves live data by default and accepts event_type=prematch; GET /kit/v1/prematch/fixtures is the dedicated prematch snapshot. Events use decimal prices and periods such as num_0 when those markets are published.

Does PinnWire place bets or provide historical Pinnacle odds?

No. PinnWire is a read-only current-odds data service, not a bookmaker or bet-placement API. It is not a historical archive; its recent drops buffer is approximately three hours, so record permitted snapshots or alerts yourself if you need longer history.