PinnFeed
Real-time Pinnacle odds API with a hosted MCP server: use live and prematch Pinnacle odds, no-vig fair odds and closing lines in ChatGPT and Claude. WebSocket from €99/mo, free REST plan.
Hosted MCP Server
npx add-mcp 'https://pinnfeed.io/mcp'Installs into Claude Code, Codex, Cursor and more
Documentation
Built for the bot, not the browser.
Everything you would otherwise write yourself (reconnection, merge rules, odds conversion, margin removal, kickoff detection) is done once on our side and delivered as clean JSON.
Push · no pollingSubscribe once, receive deltas.
A snapshot arrives first, then only the prices that moved. No polling loop and no wasted quota: a quiet market costs you nothing.
Filters · server-sideAsk for exactly the slice you trade.
Filter by sport, league, event, market type and live or prematch. You only receive, and only pay bandwidth for, what you asked for.
Fair odds · closing linesThe sharp number, already de-vigged.
Every market carries its margin and a fair decimal price per outcome. At kickoff the last prematch price is archived as the closing line.
Schema · stable idsA clean, documented schema.
Events and markets with stable ids, decimal and American odds, lines, periods, max stake and cut-off time. No raw feed archaeology.
AI · hosted MCPYour assistant can read the board.
A hosted MCP server at /mcp gives Claude, Cursor, Copilot and ChatGPT live odds, drops and closing lines with your key. How it works.
Self-serve · keysKeys for every project.
Create, rename and revoke keys, see usage per key, upgrade or cancel from the dashboard. Keys are stored hashed.
Fig. 2 — A working client Connect, subscribe to live soccer, print every move. Plain WebSocket and JSON: Python, Node or anything else.
# pip install websockets
import asyncio, json, os, websockets
async def main():
url = "wss://pinnfeed.io/v1/stream"
async with websockets.connect(url, additional_headers={"x-api-key": os.environ["PINNFEED_KEY"]}) as ws:
await ws.send(json.dumps({"type": "subscribe", "sports": ["soccer"], "live": True}))
async for raw in ws:
msg = json.loads(raw)
if msg["type"] == "ping": await ws.send('{"type":"pong"}')
elif msg["type"] == "delta":
for c in msg["changes"]:
if c["kind"] == "market" and c["op"] == "upsert":
m = c["market"]; print(m["key"], [(o["name"], o["decimal"], o["fair"]) for o in m["outcomes"]])
asyncio.run(main())
// npm install ws
import WebSocket from 'ws';
const ws = new WebSocket('wss://pinnfeed.io/v1/stream', {
headers: { 'x-api-key': process.env.PINNFEED_KEY }, perMessageDeflate: true,
});
ws.on('open', () => ws.send(JSON.stringify({ type: 'subscribe', sports: ['tennis', 'basketball'] })));
ws.on('message', (buf) => {
const msg = JSON.parse(buf);
if (msg.type === 'ping') return ws.send('{"type":"pong"}');
if (msg.type === 'delta') for (const c of msg.changes) console.log(c.kind, c.op, c.market?.key ?? c.event?.home);
});
# REST snapshot: every live soccer event with main markets
curl -H "x-api-key: $PINNFEED_KEY" \
"https://pinnfeed.io/v1/odds?sport=soccer&live=true&main=true"
# Closing lines for yesterday (Builder and above)
curl -H "x-api-key: $PINNFEED_KEY" \
"https://pinnfeed.io/v1/closing?date=2026-11-08&sport=tennis"
Snapshot, then only what changed.
Send one subscribe message and you are streaming. Each delta carries the full market with decimal, American and fair prices, so your book never needs a second request.
Fig. 3 — One delta frame A live moneyline moves. Margin, max stake and the no-vig fair price ride along with every outcome.
{
"type": "delta", "seq": 48213, "ts": 1762679412093,
"changes": [{
"kind": "market", "op": "upsert",
"market": {
"id": "1640278226:s;0;m", "eventId": 1640278226,
"type": "moneyline", "period": 0, "main": true, "live": true,
"margin": 0.0357, "maxStake": 1500,
"outcomes": [
{ "name": "home", "american": -128, "decimal": 1.781, "fair": 1.845, "fairProb": 0.5421 },
{ "name": "draw", "american": 262, "decimal": 3.62, "fair": 3.750, "fairProb": 0.2667 },
{ "name": "away", "american": 405, "decimal": 5.05, "fair": 5.230, "fairProb": 0.1912 }
]
}
}]
}
- Snapshot, then deltas. A chunked snapshot on subscribe, then only the markets that changed, batched per upstream update.
- Removals are explicit. Suspended or settled markets arrive as
op: "remove", so your book never shows stale prices. - REST mirrors the socket. The same objects come from
GET /v1/oddsfor cron jobs and backfills.
Push beats polling. Here is the arithmetic.
A polling client sees a price change only on its next request: on average half an interval late, at worst a full interval, plus the round-trip. A WebSocket has no interval. This is arithmetic, not a benchmark, so you can check it yourself.
| WebSocket push | REST, poll every 5 s | REST, poll every 30 s | REST, poll every 60 s | |
|---|---|---|---|---|
| When you see a change | Pushed as it arrives | On the next poll | On the next poll | On the next poll |
| Average extra delay | None | 2.5 s | 15 s | 30 s |
| Worst-case extra delay | None | 5 s | 30 s | 60 s |
| Requests per hour, one endpoint | 1 connection | 720 | 120 | 60 |
| Unchanged markets | Not resent | Resent every poll | Resent every poll | Resent every poll |
Network transit and processing apply to both and are not shown. Our own Free REST tier is delayed 30 s on purpose; Hobby REST and every WebSocket plan are real time. How the WebSocket works.
The rate card.
Start free on delayed data. Every paid plan opens with 3 days free: card on file, charged on day four unless you cancel. Builder is the WebSocket plan. EUR · monthly price shown; quarterly and annual available. VAT included where applicable.
| Plan | Price | What the key carries | |
|---|---|---|---|
| ### FreeEvaluate the data. REST only, 30-second delay. | € 0 | REST snapshots (30 s delay) · 2 sports of your choice · Main markets · 1,000 requests/day · No card | Get key |
| ### HobbyReal-time REST snapshots for side projects and personal bots. No WebSocket. | € 29 /mo € 78 /quarter €26/mo · save 10% € 290 /yr €24.17/mo · 2 months free 3 days free | Real-time REST (no delay) · 3 sports · Main markets + no-vig fair odds · 2 req/s REST · No WebSocket | Start 3 days free Then €29/mo · card required · charged after day 3 unless you cancel |
| The WebSocket plan · recommended ### BuilderThe real-time Pinnacle WebSocket: every sport and market, pushed as it moves. | € 99 /mo € 267 /quarter €89/mo · save 10% € 990 /yr €82.50/mo · 2 months free 3 days free | Real-time WebSocket push (3 connections) · All 13 sports · All markets, alt lines, props & futures · 10 req/s REST · Closing-odds history | Start 3 days free Then €99/mo · card required · charged after day 3 unless you cancel |
| ### ProHigh throughput, raw Pinnacle frames, priority support. | € 199 /mo € 537 /quarter €179/mo · save 10% € 1,990 /yr €165.83/mo · 2 months free 3 days free | 10 WebSocket connections · Everything in Builder · Raw Pinnacle frames option · 30 req/s REST · Priority support | Start 3 days free Then €199/mo · card required · charged after day 3 unless you cancel |
| ### EnterpriseClosing-line archive exports, SLA and commercial licence. | Custom | Custom connection & rate limits · Bulk closing-odds exports (CSV/Parquet) · SLA & commercial licence | Talk to us |
Pay by card through Stripe, or prepay 1, 3 or 12 months in USDC, USDT, SOL or BTC. Cancel in one click from your dashboard. Compare every limit.
Questions developers ask.
Something missing? Email support@pinnfeed.io.
Is there still a public Pinnacle API?
Pinnacle closed its public API to most users in July 2025. PinnFeed is an independent service that streams Pinnacle prices to developers over a normalized WebSocket and REST API. You do not need a Pinnacle account.
Why a WebSocket instead of polling a REST API?
A polling client only sees a price change on its next request, so on average it is half a polling interval late, plus the request round-trip. A WebSocket removes the interval: PinnFeed pushes each change as soon as it reaches our server, filtered to what you subscribed to, as delta-only updates with no-vig fair odds. Builder (€99/mo) is the WebSocket plan.
What is a no-vig (fair) price?
Pinnacle prices include a margin. We remove it with the multiplicative method and return the fair probability and fair decimal price for every outcome, so you can compare any bookmaker against the sharpest line without extra maths.
Which sports and markets are covered?
Thirteen sports: soccer, tennis, basketball, ice hockey, American football, baseball, rugby, MMA, boxing, volleyball and handball, esports, golf and cricket. Moneyline (1X2), spreads/handicaps including quarter lines, totals, team totals, every period, plus props and futures on Builder and above.
Is there a free plan?
Yes. The Free plan gives REST access to two sports with a 30-second delay and 1,000 requests a day, with no card. Hobby (€29/mo) makes REST real-time; Builder (€99/mo) adds the real-time WebSocket.
Can I cancel any time?
Yes. Every paid API plan starts with 3 days free (card required, charged on day four unless you cancel) and is monthly through Stripe; cancel or switch plans from the dashboard in one click. Crypto plans are prepaid for 1, 3 or 12 months and never auto-renew.
Start streaming in five minutes.
Free key, no card. Not a developer? Pinnacle Terminal gives you live screens and drop alerts without code.
Prefer to inspect the contract first? OpenAPI spec · Postman collection.