TxLINE / TxODDS feedback — from FairLine's real integration experience
What genuinely worked: the data itself. Real event-by-event feed for an actual World Cup Final — goals, cards, corners, VAR outcomes, all at real granularity — plus real de-margined consensus pricing via TXLineStablePriceDemargined. Free-tier access to a real high-profile fixture was genuinely valuable for a hackathon build. The 60s batch delay is clearly what it is, no complaint.
What cost us real hours, in order of pain
- The field is
StatusId(numeric), notStatusSoccerId— we built against a name that doesn't exist in the real payload, silently fell back to a different field, and shipped a live "pre-match" label for an hour of real match time before catching it. The numeric enum (1=NS, 2=H1, 3=HT, 4=H2, 6=awaiting-ET, 7=ET1, 9=ET2, 100=finalised — we reverse-engineered these one real transition at a time; 5, 8, 10 are still unknown to us) isn't documented anywhere we found. Even a bare list would have saved hours. GameStatestays"scheduled"for the entire match, including well into extra time. It reads like a live-status field; it isn't. Actively misleading if you don't already know to ignore it.Clock.Seconds/Clock.Runningare PascalCase on/scores/snapshot, silentlyundefinedif you check lowercase — no error, just wrong defaults everywhere downstream./scores/snapshot/{id}only returns a small rolling window (~35-40 recent events), not full history. A real event — including a goal — can roll out of that window between polls, silently reverting your "current state" to something stale./scores/updates/{id}has the complete history but is SSE-formatted text (data: {...}lines), not JSON — a plain.json()parse fails, which looks exactly like a broken/404 endpoint rather than a framing mismatch. Cost us a live P1 during the actual final.- Score totals are only attached to some events (goals/cards/corners/finalisation) — most events (shots, possession, clock ticks) carry
Clock/StatusIdbut noScoreat all. "Take the latest event" works for phase/clock and silently drops real goals for score. Not obvious until you've been burned by it. - Goal confirm/VAR lifecycle is real and under-documented: a goal event can carry
Confirmed:false, get VAR-reviewed (var/var_endwithData.Outcome: "Stands"or"Overturned"), and later showaction_discarded— which does NOT always mean the goal was wrong, sometimes it's just superseding a provisional record. We tracked three distinct goalIds across one real match and needed cross-lane reconciliation with another team's independent box score to fully resolve which record was canonical. - We saw a VAR review say
var_end: {"Outcome":"Stands"}for a goal, and then the very nextSeq— the immediately adjacent record —action_discardedthe same goalIdanyway. Taking "Stands" as final the moment you see it is a real trap: the record right after can reverse it. We only caught this because a second independent source (another team's box-score cross-check) forced us to re-examine the adjacency; nothing about the "Stands" record itself hinted a discard was one Seq away. Action:"game_finalised"withStatusIdANDPeriodboth=100is the one reliable "match is truly over" signal — genuinely useful once we found it, but easy to miss; it deserves top billing in the docs, not a buried detail.
One line we mean genuinely, not cheekily: an official SDK would have saved real hours here — several of the above are exactly the conventions a client library should encode once instead of every integrator rediscovering independently. We'd point at 0xPulsePlay/txline-kit (demo) as the shape of what that looks like.