WEBHOOK RELAY
Pinnacle drop alerts in Discord or Slack.
A relay is one process that holds the Pinnacle odds API drop stream open and posts each alert to a chat webhook. This page gives the loop, the message shape, the retry rule for the webhook and the cooldown that keeps a busy market from flooding a channel. It runs on a plan with SSE alerts; the free key is REST only.
The three parts of a relay
The stream side is a GET to /odds-drop for live markets or
/odds-drop-prematch for prematch ones, with your key in the
x-portal-apikey header and min_drop set on the
query string. The connection stays open and every data: line
carries a JSON list of alerts. A bare object instead of a list is a control
message such as the connected greeting; skip those.
The chat side is a POST to the webhook URL your workspace gave you. Discord
reads a JSON body with a content field; Slack incoming webhooks
read a text field. Both answer in well under a second and both
limit how fast one webhook may post.
In between sits a formatter and a cooldown check. The whole relay is about forty lines in any language with an HTTP client:
open GET /odds-drop?min_drop=5 (key in header)
for each line of the stream:
skip lines that do not start with "data:"
msg = parse JSON after "data:"
skip msg when it is an object (control message)
for alert in msg:
skip when alert.sport not in SPORTS
skip when cooldown(alert) is still running
enqueue post(webhook, text(alert))
Keep the POST off the reading loop. If the relay waits for every webhook answer before reading the next line, one slow answer delays every alert behind it. A small in-memory queue with a worker that drains it is enough, and if the queue fills, drop the oldest entry: an alert about a price from three minutes ago is no longer news.
What to put in the message
Each alert names the match and the selection: home,
away, league, sport, the market in
sect, the side in outcome, and the two prices,
from_price and to_price. The stream sends prices,
not a percentage, so the relay works the drop out itself:
(from − to) ÷ from × 100. It also carries nvp, the fair price
with the margin removed, which is the number a reader compares against the
price still on offer elsewhere.
Cairns Dolphins v Sunshine Coast Phoenix
Basketball · Moneyline · Away
2.86 → 2.70 (−5.59%)
fair 3.04 · Australia NBL1 Women
Four short lines read well on a phone and in a channel list. Print the
fair price as n/a when nvp is null rather than
turning a missing value into a zero. Leave the timestamp to the chat
client; every message already carries one.
Retries on the webhook side
Webhooks fail in three ways and each wants a different reaction. A 429
means the channel is being posted to faster than the platform allows; it
comes with a Retry-After header, so wait that long and send
the same message again. A 5xx or a timeout is transient; retry with a
doubling delay, capped at 30 seconds and at three attempts. A 400 means the
body itself was rejected, and no retry will fix it: log the payload shape
and move on.
A burst of alerts during a big slate is when the 429 arrives. Two settings absorb most of it: post one message per event instead of one per outcome, and hold a cooldown per selection so a price that keeps falling does not post every few seconds. The dedupe and cooldown rules cover the keys to use.
When the stream ends
Connections drop. When the stream closes, reconnect after a short pause that grows on repeated failures, and check the plan when the first control message reports an error. Alerts that fell while you were disconnected are not replayed, so a gap stays a gap; the selections that matter alert again the next time they cross your threshold. The SSE setup page covers the frame format and the reconnect loop in detail.
Live and prematch drops arrive on separate streams. One relay process can hold both connections and post to two channels, which keeps a slow prematch drift out of the channel that watches in-play moves. If a phone rather than a channel is the target, the Telegram bot on pnclDATA is the same loop with a different POST at the end.
Questions before you build it
Does the relay need a paid plan?
Yes. The drop stream comes with the SSE alerts plan at $99 a month and with the two combined REST and SSE plans at $149 and $229. The free key is REST only and cannot open the stream.
Can one relay serve several channels?
Yes. Filter on sport or league after parsing and route each alert to the webhook for that group. The stream has no sport parameter of its own, so the filter lives in the relay.
Why did the same match post twice?
A price that keeps falling can cross the threshold more than once, and each crossing is a new alert. Skip repeats by the alert id and hold a cooldown per event and outcome.
Stream fields and plan prices follow the vendor's published documentation, checked on 26 September 2026. Published .