ONEDRUM Field notes

Field notes · 15 Aug 2026 · spec

Verifying a OneDrum certified score

Every finished run has a canonical URL that returns the score as signed JSON. This note documents the payload, what the signature covers, and the two ways to check a score without trusting the device — or the person — that handed it to you.

The endpoint

GET https://onedrum.io/api/session/<sessionId>/participant/<participantId>/certified

This is the link printed on every player's end card. It answers with application/json to browsers and programs alike (CORS is open), and the response looks like this:

{
  "participantId": "…",
  "sessionId":     "…",
  "clipId":        "chant-a",
  "certified":     17,
  "total":         18,
  "certRate":      0.9444,
  "calibrated":    true,
  "windowMs":      120,
  "trusted":       true,
  "flags":         [],
  "issuedAt":      "2026-08-15T09:41:00.000Z",
  "signature":     "…"
}

What the fields mean

fieldmeaning
certified / totalAnswers accepted as in-sync, out of the scored cues in the clip. The single number the score card shows.
certRatecertified / total, rounded to 4 decimal places.
windowMsThe acceptance half-window in force for this run: a tap is accepted when its post-calibration offset from the nearest scored cue is within ±this many milliseconds. Currently 120 (why).
calibratedWhether the player's device latency was calibrated (from the warm-up bar, or adaptively during play).
trusted / flagsThe plausibility verdict. A run whose timing is tighter than human jitter allows is reported with trusted: false and "too_perfect" in flags — reported, not hidden: the operator gets the verdict, not just the number.
issuedAtWhen this payload was issued (ISO 8601). Signatures cover the issue time, so re-fetching yields a fresh payload and a fresh signature.
signatureIntegrity seal over every other field — construction below.

Trust path 1 — fetch the canonical URL (anyone)

The simplest verification needs no cryptography: get the score from the server yourself. If someone hands you a screenshot or a number, fetch their certified URL over TLS and compare. The score was computed server-side from the raw tap log — nothing the player's device claims is trusted in the first place — so a TLS-authenticated response from onedrum.io is the record.

curl https://onedrum.io/api/session/SESSION/participant/PARTICIPANT/certified

Trust path 2 — check the signature (key-holding operators)

For offline verification — scores relayed through third parties, stored, or audited later — the payload carries a detached signature:

signature = base64url( HMAC-SHA256( key, canonical(payload) ) )

where canonical(payload) is the JSON serialization of every field except signature, with keys in sorted (code-point) order, no whitespace, numbers and strings exactly as JSON.stringify emits them; and base64url is unpadded. In Node:

import { createHmac } from 'node:crypto';

function verify(score, key) {
  const { signature, ...payload } = score;
  const canonical = JSON.stringify(payload, Object.keys(payload).sort());
  const expected = createHmac('sha256', key).update(canonical)
    .digest('base64url');
  return expected === signature;
}

In v0 the signing key is a single server-held secret, so signature verification is available to operators we share a key with, while the canonical-URL path serves everyone else. That is a deliberate v0 simplification: per-operator keys and public-key (asymmetric) signatures — where anyone can verify offline without any shared secret — are the planned production path.

What a valid signature does — and does not — claim

A verified payload proves the score was issued by the OneDrum server and has not been altered since. It does not by itself prove when the run happened (see issuedAt), and it is not a warranty of fitness for any purpose — see the terms. The scoring rules themselves (the audible clock, warm-up calibration, the ±120ms window, the plausibility gate) are described in the field notes and are subject to tuning as production data accumulates; windowMs in the payload records which rule was in force for a given run.

Questions from operators are welcome — the certified-score API is the part of OneDrum built for you. · More field notes · Terms