Developers
Tallys API v1
Read UK election data and contribute crowd-sourced declarations. All endpoints live under /api/v1/ and require a Bearer API key.
Quickstart
- Ask an admin for an API key (or create one in the admin panel).
- Pass it as
Authorization: Bearer tly_live_.... - Hit any endpoint below. Errors are JSON:
{ error: { code, message } }.
curl -H "Authorization: Bearer $TALLYS_KEY" \
https://tallys.uk/api/v1/by-electionsAuthentication
Bearer tokens. Two scopes: read for public data, crowd:writefor posting declarations. Keys are hashed at rest and shown once on creation. Default rate limit: 60 requests / minute / key. Responses include X-RateLimit-Limit and X-RateLimit-Remaining headers.
Endpoints
GET /api/v1/health
No auth. Returns service status.
GET /api/v1/elections
List elections. Optional query: ?nation=wales, ?status=live.
GET /api/v1/elections/{electionId}
Single election with prediction windows.
GET /api/v1/by-elections
Snapshot of UK by-elections (local + Senedd + PCC) with provenance flags (dc, crowd, crowd-dc-verified,crowd-dc-mismatch).
GET /api/v1/results/{electionId}
Per-constituency live results snapshot.
POST /api/v1/crowd/submissions
Scope crowd:write. Owner of the key must hold a contributor or verifier role. Submissions are reconciled against Democracy Club every minute.
curl -X POST \
-H "Authorization: Bearer $TALLYS_KEY" \
-H "Content-Type: application/json" \
-d '{
"ballot_paper_id": "local.example.ward.2026-05-07",
"election_id": "local.example.2026-05-07",
"winning_party_id": "lab",
"winner_votes": 1234,
"second_party_id": "con",
"second_votes": 980,
"total_votes": 2400,
"turnout_pct": 32.1,
"source_type": "council",
"source_url": "https://council.example/results"
}' \
https://tallys.uk/api/v1/crowd/submissionsGET /api/v1/crowd/submissions/{id}
Status of a submission you authored, including the current ballot reconciliation state.
Errors
| Code | Meaning |
|---|---|
| missing_api_key | No Bearer token in Authorization header. |
| invalid_api_key | Key not recognised, malformed, or revoked. |
| insufficient_scope | Key lacks the required scope for the endpoint. |
| rate_limited | Per-minute quota exceeded. See Retry-After. |
| validation_error | Body failed schema validation. |