The ingestion and read API behind eArena's live scoreboards. Pulse accepts signed result webhooks, normalizes them per game, and serves tournament matches & leaderboards over a bearer-secured API.
A small Fastify + Postgres service that turns raw match results from external sources into clean, queryable tournament data.
External result sources POST to /webhooks/results. Every payload is
HMAC-signed and verified before it's accepted.
A pluggable adapter registry maps each game's raw result into a shared schema.
chess ships today; more games slot in cleanly.
Query tournament matches and leaderboards over a clean REST
API, secured with a bearer token. Validated with Zod.
The read API is secured with a bearer token. Generate a development token below, then
send it as an
Authorization
header on every request.
Read scopes power scoreboard overlays & casters. Write scope lets a source push signed results.
eap_live_…
curl -H "Authorization: Bearer $PULSE_TOKEN" \
https://pulse.cloud.earena.no/api/v1/tournaments/spring-open/leaderboard
{
"tournament": {
"id": "4e6f1c2a-9b3d-4f21-8e6a-7c1b2d3e4f5a",
"sanityId": "spring-open",
"name": "spring-open"
},
"standings": [
{ "key": "m.carlsen", "displayName": "m.carlsen", "totalScore": "8.500", "matchesPlayed": 9 },
{ "key": "h.nakamura", "displayName": "h.nakamura", "totalScore": "8.000", "matchesPlayed": 9 }
]
}
The full machine-readable contract lives in the OpenAPI spec. Here are the endpoints you'll reach for most — click any row to expand.
Entry point for external result sources. Requests are verified against the
X-Pulse-Source,
X-Pulse-Timestamp
and
X-Pulse-Signature
headers, then routed through the matching game adapter and persisted.
| X-Pulse-Source | string | Name of a registered webhook source. Required. |
| X-Pulse-Timestamp | string | Unix timestamp in seconds; must be within 5 minutes of server time. Required. |
| X-Pulse-Signature | string |
sha256=<hmac>
— HMAC-SHA256 of
${timestamp}.${rawBody}
using the source's secret. Required.
|
| gameType | string |
Game adapter key, e.g.
chess.
|
| tournamentSanityId | string? | Sanity document id of the tournament. |
| externalMatchId | string | Unique id for this match from the source system. |
| status | string |
scheduled
|
live
|
completed.
|
| result | object | Game-specific result payload, validated by the matching adapter. |
Returns the tournament and all of its matches, each with their participants, ordered by start time.
| sanityId | string | Sanity document id of the tournament. |
Returns a single match together with its participants.
| id | string (uuid) |
The match id, as returned by
/api/v1/tournaments/:sanityId/matches.
|
Returns aggregated standings — total score and matches played per participant — ordered by total score descending. This is what live scoreboard overlays poll.
| sanityId | string |
Sanity document id of the tournament, e.g.
spring-open.
|
No auth required. Returns
{ "status": "ok" }
when the service is running. Does not check database connectivity.
Every route, schema and example is generated from the running service via
@fastify/swagger. Try requests live, with your token, right in the browser.