PulsePlayPulsePlayExplorerLive markets · World Cup + friendlies
← back

PulsePlay coverage

Every requirement in soccer_data_requirements.md probed against 3 live fixtures / 2874 updates (17882805, 17932445, 17952170).

13 present🟡 9 partial🔴 6 absent

Market settleability (A–E)

A · Rolling time-windowPARTIAL

Ship goal / corner / card / shot-on-target windows. Reset nuance (own-goal/penalty split) partial; stale-void heuristic until heartbeat confirmed.

B · Set-piece outcomePARTIAL

LOCK is the blocker — no corner/penalty/free-kick *_taken marker. Penalty & corner-outcome via time-window lock (documented risk); FK location gating impossible.

C · Next-eventFULL

Strict Seq ordering ✅. Curate the taxonomy to verbs that exist (exclude foul + standalone offside). Confirmed adds ~1–15s latency.

D · Segment over/underPARTIAL

Corners ✅ and throw-ins ✅ (count events in segment). Fouls ✗ — no foul event.

E · PossessionPARTIAL

Self-integrate the Possession stream (~6s cadence). Basis (time-in-control?) + final-vs-interim unconfirmed → flag for review upstream.

Universal spine (§3 — required on every message)

Data pointFeedNote / evidence
match_id (stable, unique)
FixtureIdFixtureId on every message.
live example
17882805
🟡
match_status incl. suspended/abandoned/postponed
medium
StatusId (+ suspend action)StatusId observed: 1=NS, 2=H1, 3=HT, 4=H2, 5=FT. Only NS/H1/HT/H2/FT live; suspended/abandoned/postponed documented (15/18/19) but unobserved; `suspend` action present.
live example
[
  1,
  2,
  3,
  4,
  5
]
match_clock (second res) + announced added time
Clock{Running,Seconds} + additional_time.Data.MinutesClock.Seconds = elapsed match seconds; additional_time carries announced minutes.
live example
{
  "clock": {
    "Running": false,
    "Seconds": 0
  }
}
timestamp_utc (millisecond, every message)
Ts13-digit epoch ms on every message (944 distinct sub-second remainders → genuine ms precision).
live example
1780325524893
sequence_id (monotonic, per match)
SeqStrictly increasing per fixture but GAPPY (~4 missing — non-fixture frames, not loss; dedup on Seq, can't count-detect drops).
live example
{
  "sampleFixture": 17882805,
  "range": [
    0,
    954
  ]
}
🟡
event_id (unique, dedup)
medium
IdId is a LOGICAL-event id reused across provisional/confirmed/amend (99 ids span ≥2 Seq) — NOT unique per message. Dedup on Seq; use Id for lifecycle correlation.
live example
{
  "reusedIds": 99
}
🟡
heartbeat (fixed, known interval)
high
SSE event: heartbeat / standby / Ts-gapNo top-level heartbeat field; SSE stream emits `event: heartbeat` (cadence unconfirmed). Infer staleness from Ts inter-arrival + disconnected/standby/suspend. Confirm cadence on a tier-12 live match.
live example
{
  "standbyFrames": 15,
  "disconnectedFrames": 4
}
confirmation_status (provisional / confirmed)
ConfirmedPer-event Confirmed bool transitions false→true; settle only on true.
live example
{
  "provisional": {
    "FixtureId": 17882805,
    "GameState": "scheduled",
    "StartTime": 1780600200000,
    "IsTeam": true,
    "FixtureGroupId": 10116166,
    "CompetitionId": 430,
    "CountryId": 466,
    "SportId": 1,
    "Participant1IsHome": true,
    "Participant2Id": 2236,
    "Participant1Id": 1999,
    "CoverageSecondaryData": true,
    "CoverageType": "TV/Stream",
    "Action": "kickoff",
    "Id": 27,
    "Ts": 1780600225527,
    "ConnectionId": 534,
    "Seq": 17,
    "StatusId": 2,
    "Type": "Soccer",
    "Confirmed": false,
    "Clock": {
      "Running": true,
      "Seconds": 0
    },
    "Kickoff": {
      "Team": 1
    },
    "Possession": 1,
    "PossessionType": "SafePossession"
  },
  "confirmed": {
    "FixtureId": 17882805,
    "GameState": "scheduled",
    "StartTime": 1780600200000,
    "IsTeam": true,
    "FixtureGroupId": 10116166,
    "CompetitionId": 430,
    "CountryId": 466,
    "SportId": 1,
    "Participant1IsHome": true,
    "Participant2Id": 2236,
    "Participant1Id": 1999,
    "CoverageSecondaryData": true,
    "CoverageType": "TV/Stream",
    "Action": "connected",
    "Id": 2,
    "Ts": 1780597443946,
    "ConnectionId": 534,
    "Seq": 2,
    "Confirmed": true
  }
}
🟡
revision_flag / retraction
high
action_amend{New,Previous} + action_discardedaction_amend carries a full field diff; action_discarded self-describes nothing → requires an Id-cache to know what was withdrawn. (VAR-disallowed goal surfaces via var_end:Overturned, NOT action_discarded — handle both retraction paths.)
live example
{
  "amend": {
    "Action": "injury",
    "New": {
      "Clock": {
        "Running": true,
        "Seconds": 1013
      },
      "Outcome": "OnPitch",
      "PlayerId": 10248162
    },
    "Previous": {
      "Clock": {
        "Running": true,
        "Seconds": 1013
      },
      "Outcome": "OffPitch",
      "PlayerId": 10248162
    }
  },
  "discardCount": 7
}
review_state (VAR: none/in_review/confirmed/overturned)
var → var_end.Data.Outcomevar (in_review) → var_end.Outcome ∈ {Stands,Overturned}. Both Stands+Overturned observed → confirmed/overturned distinguishable.
live example
{
  "varTypes": [
    "Goal",
    "Penalty"
  ],
  "varEndOutcomes": [
    "Stands",
    "Overturned"
  ]
}
score (home / away)
Score tree + Participant1IsHomePeriod-bucketed Score tree (H1/HT/H2/Total → Goals/YellowCards/RedCards/Corners); resolve home via Participant1IsHome.
live example
{}
team_ref (stable home/away)
Participant (1|2) + Participant1IsHomeParticipant 1/2 on events; Participant1IsHome maps to home/away, constant for the match.
live example
{
  "participant1IsHome": true,
  "p1": 1999,
  "p2": 2236
}

Events (§5 / §7)

Data pointFeedNote / evidence
🟡
Goal + type (open_play / penalty / own_goal)
medium
goal.Data.GoalType (+ penalty_outcome for pens)goal.GoalType observed: {Shot} (only "Shot" seen → no open_play/own_goal split; penalty goals arrive as a separate penalty_outcome).
live example
{
  "goalTypes": [
    "Shot"
  ]
}
Corner awarded + team
corner actioncorner action (+Participant; Score.Corners increments). No corner_taken.
live example
{
  "FixtureId": 17882805,
  "GameState": "scheduled",
  "StartTime": 1780600200000,
  "IsTeam": true,
  "FixtureGroupId": 10116166,
  "CompetitionId": 430,
  "CountryId": 466,
  "SportId": 1,
  "Participant1IsHome": true,
  "Participant2Id": 2236,
  "Participant1Id": 1999,
  "CoverageSecondaryData": true,
  "CoverageType": "TV/Stream",
  "Action": "corner",
  "Id": 261,
  "Ts": 1780601826883,
  "ConnectionId": 534,
  "Seq": 272,
  "StatusId": 2,
  "Type": "Soccer",
  "Confirmed": false,
  "Clock": {
    "Running": true,
    "Seconds": 1602
  },
  "Score": {},
  "Participant": 2,
  "Possession": 2,
  "PossessionType": "DangerPossession",
  "Parti1State": {},
  "Parti2State": {}
}
🔴
corner_taken marker (LOCK signal)
blocker
— (none)No corner_taken action — next event = resumption of play. Lock must use a time-window.
Card + type (yellow / second_yellow / red)
yellow_card; red_card.Data.Typeyellow_card present; red_card.Type ∈ {SecondYellow} → second-yellow vs straight-red distinguishable.
live example
{
  "redTypes": [
    "SecondYellow"
  ]
}
Shot + classification (on_target / off_target / blocked)
shot.Data.Outcomeshot.Outcome ∈ {Blocked,OnTarget,OffTarget} (Woodwork is a bonus 4th value).
live example
{
  "outcomes": [
    "Blocked",
    "OnTarget",
    "OffTarget"
  ]
}
throw_in + team
throw_in actionthrow_in + Participant + ThrowInType danger class.
live example
{
  "FixtureId": 17882805,
  "GameState": "scheduled",
  "StartTime": 1780600200000,
  "IsTeam": true,
  "FixtureGroupId": 10116166,
  "CompetitionId": 430,
  "CountryId": 466,
  "SportId": 1,
  "Participant1IsHome": true,
  "Participant2Id": 2236,
  "Participant1Id": 1999,
  "CoverageSecondaryData": true,
  "CoverageType": "TV/Stream",
  "Action": "throw_in",
  "Id": 227,
  "Ts": 1780601517789,
  "ConnectionId": 534,
  "Seq": 234,
  "StatusId": 2,
  "Type": "Soccer",
  "Confirmed": false,
  "Clock": {
    "Running": true,
    "Seconds": 1293
  },
  "Data": {},
  "Participant": 1,
  "Possession": 2,
  "PossessionType": "AttackPossession"
}
🔴
foul + team (Archetype D)
blocker
— (none)No `foul` action and no foul leaf in Score. Over/under-fouls NOT settleable. Proxy = free_kick minus FreeKickType:Offside (disputable).

Archetype B — set-piece outcome

Data pointFeedNote / evidence
penalty_awarded (team)
penalty actionpenalty action (announce+confirm).
live example
{
  "FixtureId": 17932445,
  "GameState": "scheduled",
  "StartTime": 1780512300000,
  "IsTeam": true,
  "FixtureGroupId": 10116166,
  "CompetitionId": 430,
  "CountryId": 466,
  "SportId": 1,
  "Participant1IsHome": true,
  "Participant2Id": 2638,
  "Participant1Id": 2790,
  "CoverageSecondaryData": true,
  "CoverageType": "TV/Stream",
  "Action": "penalty",
  "Id": 646,
  "Ts": 1780518419261,
  "ConnectionId": 546,
  "Seq": 723,
  "StatusId": 4,
  "Type": "Soccer",
  "Confirmed": false,
  "Clock": {
    "Running": true,
    "Seconds": 4531
  },
  "Participant": 2
}
🔴
penalty_taken / run-up marker (LOCK)
blocker
— (none)Stream goes award→outcome; no taken/run-up frame. Lock via time-window.
🟡
penalty_outcome (goal/saved/off_target/woodwork)
low
penalty_outcome.Data.Outcomepenalty_outcome.Outcome ∈ {Scored} (only "Scored" seen on tier-1; saved/off/woodwork unconfirmed).
live example
{
  "outcomes": [
    "Scored"
  ]
}
🔴
retake_ordered
low
— (none)No retake action; inferable only via surrounding var.
🟡
free_kick_awarded + location (x,y/zone) + danger
high
free_kick.Data.FreeKickType (danger class only)FreeKickType danger class ∈ {Safe,Attack,Danger,Offside} — NO x/y/zone coordinates, AND arrives on Confirmed:true (post-kick) → cannot gate market OPENING at award. Location-gated FK market cannot open precisely.
live example
{
  "freeKickTypes": [
    "Safe",
    "Attack",
    "Danger",
    "Offside"
  ]
}
🔴
free_kick_taken marker (LOCK)
high
— (none)No taken marker.
🔴
Phase / set-piece linkage ID (corner outcome §6.2)
blocker
— (none)No PhaseId/SetPieceId/CornerId/ParentId on any frame (ConnectionId=feed session, Id=per-event, Possession flips with play). Corner-outcome must be bounded by a fixed time window from the award.

Archetype C — next-event

Data pointFeedNote / evidence
🟡
Event taxonomy coverage (next-event markets)
medium
Action verbsMost taxonomy verbs present and strictly ordered by Seq. MISSING as standalone: foul, offside (offside only via free_kick FreeKickType:Offside). Curate the next-event taxonomy to verbs that exist; note Confirmed adds ~1-15s latency.
live example
{
  "presentSample": [
    "goal",
    "shot",
    "corner",
    "throw_in",
    "free_kick",
    "card_yellow",
    "substitution",
    "goal_kick",
    "penalty"
  ]
}

Archetype E — possession

Data pointFeedNote / evidence
🟡
Possession time series (cumulative sec, time-in-control)
high
Possession/PossessionType event stream (no cumulative key)No cumulative seconds-in-possession key; integrate the Possession/PossessionType stream yourself (~127.1s median cadence, viable in a 5-min window). Basis (time-in-control vs danger heuristic) and final-vs-interim semantics UNCONFIRMED — escalate to TxOdds.
live example
{
  "possessionFrames": 2220,
  "types": [
    "SafePossession",
    "AttackPossession",
    "DangerPossession",
    "HighDangerPossession"
  ]
}