Skip to main content
Pulse is built for the realities of a live sensor feed: retries, out-of-order arrival, and fast-but-uncertain detections that get confirmed a moment later.

At-least-once is fine

Resending is safe. Pulse de-duplicates on the tuple (session_id, event_id, revision). A resend of an already-seen event is counted in duplicates and never returns an error.
This means you can safely retry a request whose response you never received — just keep the same event_id. No double-counting.

Ordering: by occurrence, not arrival

Pulse orders events by eot (Event Occurrence Time), not by when they arrive. Out-of-order delivery is tolerated within a reorder window (default 500 ms), so a slightly-late event still lands in the right place. Always set eot to when the event actually happened.

Preliminary → confirmed

A fast, low-confidence detection can be sent immediately and confirmed a moment later:
  1. Send the preliminary event with revision: 0.
  2. Send the confirmed event with the same event_id and a higher revision, carrying the corrected confidence and payload.
Pulse correlates the two by event_id and upgrades the preliminary in place.
By convention the confirmation is revision: 1. Pulse accepts any revision higher than the last one it has seen for that event_id.

Example sequence

A BALL_BOUNCE sent preliminary (confidence: 0.7, revision: 0) and then confirmed (confidence: 0.95, revision: 1) under the same event_id:
[
  {
    "event_id": "b7e3a91c4f25d8a0c1e6f3b2",
    "session_id": "session-court1-20260609-001",
    "eot": "2026-06-09T20:00:06.120Z",
    "type": "BALL_BOUNCE",
    "confidence": 0.7,
    "revision": 0,
    "payload": { "x_ft": 4.2, "y_ft": 19.3, "is_in": true }
  },
  {
    "event_id": "b7e3a91c4f25d8a0c1e6f3b2",
    "session_id": "session-court1-20260609-001",
    "eot": "2026-06-09T20:00:06.120Z",
    "type": "BALL_BOUNCE",
    "confidence": 0.95,
    "revision": 1,
    "payload": { "x_ft": 4.2, "y_ft": 19.3, "is_in": true }
  }
]
Envelope fields (venue_id, court_id, source, schema_version) are omitted above for brevity — every event still carries the full envelope.