Foreline/Products/Line Radar

Product 3 · Line Radar

What the market did, and where your price has drifted

Two streams, deliberately kept apart. A fact-stream of reference main-line changes, typed and timestamped — detected at a median of one minute. And warnings when the gap between your own price and fair is widening, which in an end-to-end day arrived a median of 15.8 minutes before the market caught up.

Fact-stream Gap warnings Published lifecycle Stream and catch-up poll
Request trial See pricing → Facts are facts; warnings are warnings. We label which is which in every payload.
Two streams

A fact-stream and a warning stream

Mixing observations with inferences is how alerting systems lose credibility. These arrive on separate endpoints and are never blended into one score.

1 · Main-line changes — facts

Every time the reference market moves its main line, you get a typed, timestamped event carrying the market, the old line and the new line. Pull the ladder from GET /v1/surface?event_id= when you need it. Nothing here is predicted; it either happened or it did not.

Detection latency · p50 1 min · p95 2 min

2 · Gap warnings — inferences

Your posted price is compared with fair from the surface. When the gap is widening, a warning opens — labelled as an inference, with the gap in percentage points and the band around fair so you can see how solid the reading is.

Median lead in an end-to-end day · 15.8 min
1 / 2 min
detection latency of a main-line change, p50 / p95 — consistent with the 30-second refresh cadence close to kick-off
15.8 min
median lead of a warning over the market, measured across a full end-to-end day rather than on selected cases
8,859
main-line changes captured over 13 consecutive days in the live reconciliation of the surface
What an alert looks like

A gap, a band and an action

Synthetic example. Alerts are prioritised by money at risk (gap × your limit), so the list you work through is ordered by what it costs you, not by how unusual it looks.
  • Direction-free by design. A defensive action does not need a direction — raise margin, trim the limit, or reprice toward fair. We tell you where the risk is; we do not claim to know where the market is going.
  • The band travels with the alert — except on the match result, which has no ladder and therefore no band. A 3 pp gap on a rung with a 1.4 pp band is a different object from the same gap on a rung with a 3 pp band, and the payload says which one you are looking at. On a moneyline alert band_pp, line, main_line, limit and priority are null together: sort and plot code has to handle that rather than assume a number.
Lifecycle

Every alert is resolved, including the ones that fail

An alert is not a notification that disappears into a chat window. It is an object with states, and all of its states are published.

active — the warning is open The gap is present and widening. Readable from GET /v1/alerts.
confirmed — the market moved as the gap implied The alert closes as confirmed, with the timestamps of both the warning and the move, so the lead time is computed from the record and not from memory.
withdrawn — the gap closed without a move The alert closes as withdrawn and stays in the record. Withdrawn alerts are what make a published hit-rate meaningful: we cannot quietly drop the ones that did not work out.

Three more states exist and are published the same way: revised (you re-quoted and the gap changed), corrected (you re-quoted into fair and the warning is retired as answered) and expired — an open alert that nobody re-quoted inside the alert TTL. expired is the most common terminal state in a live journal, not an edge case: it means the conversation stopped, not that the gap was resolved. The full set is in the alert reference.

The lifecycle is committed to the same cryptographic ledger as the prices, so the set of alerts we raised on a given day is fixed on that day.

Delivery

Stream or poll

ChannelCallUse it forRate class
Live streamGET /v1/stream (SSE)Main-line changes as they are detectedstream · connect rate, plus a separate cap on how many streams you hold open at once (stream_concurrent_max on GET /v1/usage)
Catch-up pollGET /v1/line-events?since=Replaying anything missed while you were downevents · 12/min
Open alertsGET /v1/alertsCurrent gap warnings and their statealerts · 60/min
curl -N "https://api.foreline.io/v1/stream" \
  -H "X-Foreline-Key: $FORELINE_KEY"

: foreline sse | data_cadence_s=30

id: 1787080944.7407787
event: line_change
data: {"ts": 1787080944.7407787, "event_id": 1633790365, "market": "spread",
       "old_line": 0.0, "new_line": 0.25}

: ping

A frame carries exactly the row GET /v1/line-events returns — same field names, same types — so one parser serves the stream and the catch-up poll. The field names above are not illustrative: the change is old_line / new_line, the instant is ts as epoch seconds, a JSON number, and event_id is our integer id, never a string. The opening : foreline sse comment and the : ping keepalives are comments, not events — skip any line beginning with :.

Delivery is pull, not push. Hold GET /v1/stream for latency and replay GET /v1/line-events?since= for completeness — together they cover every case a webhook would, and neither needs an endpoint on your side that we can reach. There is no push delivery and no URL to register; if you need one, tell us before you build against it. Values above are illustrative; see the API reference.

Stream & events reference →

Get started

Request a trial of Line Radar

Tell us how you would like alerts delivered and which markets you post. We reply with a trial key.

Email us

We usually reply within one business day. Pricing is quoted per scope — ask and we will send terms.

Request trial