Push live scores from your scoreboard

Scoring is an append-only event ledger per fixture. Your integration appends events with a score key; the platform folds them into live state, standings and dashboards.

1 — Read the fixture state

curl https://seazn.club/api/v1/fixtures/$FIXTURE_ID/state \
  -H "Authorization: Bearer sc_your_key"

# → { ok: true, data: { seq: 4, phase: "in_play", summary: {...} } }

seq is the ledger tip — every append must carry it as expected_seq. That is how two scorers can’t silently overwrite each other.

2 — Append an event

curl -X POST https://seazn.club/api/v1/fixtures/$FIXTURE_ID/events \
  -H "Authorization: Bearer sc_your_key" \
  -H "Content-Type: application/json" \
  -d '{ "expected_seq": 4,
        "type": "generic.result",
        "payload": { "p1Score": 21, "p2Score": 18 } }'

Event types are per sport (generic.result, cricket.toss, …) plus the core set (core.start, core.void, core.finalize). The reference documents the payload schema for each.

3 — Recover from a 409

Someone scored first. The 409 tells you the real tip — resync and retry:

conflict loop (TypeScript)
async function append(fixtureId: string, event: object, seq: number) {
  for (let attempt = 0; attempt < 3; attempt++) {
    const res = await fetch(
      `https://seazn.club/api/v1/fixtures/${fixtureId}/events`,
      {
        method: "POST",
        headers: {
          Authorization: `Bearer ${KEY}`,
          "Content-Type": "application/json",
        },
        body: JSON.stringify({ ...event, expected_seq: seq }),
      },
    );
    const body = await res.json();
    if (body.ok) return body.data;
    if (body.error.code === "SEQ_CONFLICT") {
      seq = body.error.current_seq; // resync and go again
      continue;
    }
    throw new Error(body.error.message);
  }
  throw new Error("gave up after 3 conflicts");
}

Good to know

  • Scoring opens when the division starts — POST /divisions/{id}/start is also score.
  • Finalizing locks the ledger and needs manage — that stays a deliberate, human step.
  • Stay under the per-key rate budget (X-RateLimit-*); batch reads with GET /events?since_seq= instead of polling state.
  • For a one-day event without any integration, day-of device links do this same job from a phone browser.