Pinnacle line movement API
Answer: PinnFeed gives you three pieces of line movement: the live price stream (delta frames on the Builder WebSocket), recent drops (GET /v1/drops) and the closing price (GET /v1/closing, Builder). There is no tick-by-tick history endpoint, so to chart a full line you record the deltas yourself from the moment you subscribe. The script below writes every price change to SQLite and plots one outcome.
Record deltas (Python, Builder)#
# pip install websockets
import asyncio, json, os, sqlite3, time, websockets
db = sqlite3.connect("moves.db")
db.execute("create table if not exists moves(ts real, market_id text, event_id int, type text, line real, outcome text, decimal real)")
async def main():
url = "wss://pinnfeed.io/v1/stream"
async with websockets.connect(url, additional_headers={"x-api-key": os.environ["PINNFEED_KEY"]}, max_size=None) as ws:
await ws.send(json.dumps({"type": "subscribe", "sports": ["soccer"], "markets": ["moneyline", "total"], "main": True}))
async for raw in ws:
msg = json.loads(raw)
if msg["type"] == "ping":
await ws.send(json.dumps({"type": "pong"}))
elif msg["type"] == "delta":
for ch in msg["changes"]:
if ch["kind"] == "market" and ch["op"] == "upsert":
m = ch["market"]
for o in m["outcomes"]:
db.execute("insert into moves values(?,?,?,?,?,?,?)",
(time.time(), m["id"], m["eventId"], m["type"], m.get("line"), o["name"], o["decimal"]))
db.commit()
asyncio.run(main())
On websockets older than 14, the argument is extra_headers instead of additional_headers.
Chart one outcome#
import sqlite3, pandas as pd, matplotlib.pyplot as plt
df = pd.read_sql("select * from moves where market_id = ? and outcome = 'home'", sqlite3.connect("moves.db"), params=["<market id>"])
df["ts"] = pd.to_datetime(df["ts"], unit="s")
df.plot(x="ts", y="decimal", drawstyle="steps-post", title="Pinnacle home price")
plt.show()
Without the WebSocket#
Poll GET /v1/drops?sport=soccer&minutes=10&min_pct=5 for recent shortenings (dropping odds API) and read the close with GET /v1/closing/{eventId} (closing line API). Steam logic: steam detection in Python.
Plans#
Line recording needs the WebSocket: Builder (€99/mo), which also includes closing-line history. /v1/drops works on Free (30-second delay) and Hobby (€29/mo). Paid plans: 3-day trial; a card is required and it is charged after day 3 unless you cancel.
Educational content for adults (18+). Line movement is a statistical signal, not a tip.
Related: Pinnacle lines API, Sharp money signals via Pinnacle maxStake.
Questions people ask#
Can I download past line movement?#
Not tick by tick. You get closing prices on Builder and recent drops via /v1/drops. Bulk archive exports are an Enterprise item.
Does the snapshot count as a move?#
No. The snapshot is the starting state. Store it as your first row if you want the opening point of your recording.
How much data is this?#
It depends on how many sports and markets you subscribe to. Filter with main: true and a short market list to start.