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. The API reads exclusively from our own database; Democracy Club is ingested in the background only, so request paths never depend on a third-party upstream.
Live ingest status - last sync time, success rate, per-election freshness.
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-electionsAll endpoints at a glance
Generated from the live election registry. Machine-readable JSON: /api/public.
Live tracker snapshots
| Election | Status | Snapshot URL | Page |
|---|---|---|---|
| Senedd 2026 | live | /api/public/results/senedd.2026 | /elections/senedd/2026 |
| Senedd 2021 | archive | /api/public/results/senedd.2021 | /elections/senedd/2021 |
| Scottish Parliament 2026 | live | /api/public/results/holyrood.2026 | /elections/holyrood/2026 |
| UK Parliament 2024 | archive | /api/public/results/westminster.2024 | /elections/westminster/2024 |
| English local councils 2026 | live | /api/public/results/english-locals.2026 | /elections/english-locals/2026 |
| Welsh local councils 2022 | archive | /api/public/results/locals.2022 | /elections/locals/2022 |
| Police & Crime Commissioners 2024 | archive | /api/public/results/pcc.2024 | /elections/pcc/2024 |
Aggregate public feeds
| Method | Path | Purpose |
|---|---|---|
| GET | /api/public/by-elections | Rolling UK by-elections snapshot (local + Senedd + PCC). |
| GET | /api/public/english-locals.2026 | Aggregated English principal council results, 7 May 2026. |
| GET | /api/public/holyrood.2026.ams | Holyrood 2026 constituency + AMS regional list output. |
| GET | /api/public/locals.2027 | Welsh principal council preview/snapshot for May 2027. |
| GET | /api/public | This manifest, as JSON. |
v1 API
| Method | Path | Scope | Purpose |
|---|---|---|---|
| GET | /api/v1/health | - | Service status. No auth. |
| GET | /api/v1/elections | read | List elections. |
| GET | /api/v1/elections/{electionId} | read | Single election with prediction windows. |
| GET | /api/v1/by-elections | read | By-elections feed with provenance flags. |
| GET | /api/v1/results/{electionId} | read | Per-constituency live results snapshot. |
| POST | /api/v1/crowd/submissions | crowd:write | Submit a crowd-sourced declaration. |
| GET | /api/v1/crowd/submissions/{id} | crowd:write | Status of a submission you authored. |
Internal hooks (cron only)
| Path | Purpose |
|---|---|
| /api/public/hooks/refresh-snapshots | Recompute every live snapshot. Cron-triggered. |
| /api/public/hooks/sync-live-results | Pull latest live results from Democracy Club. |
| /api/public/hooks/sync-election | Resync a single election's metadata + ballots. |
| /api/public/hooks/sync-democracy-club | Full DC ballot/candidate sync. |
| /api/public/hooks/reconcile-crowd | Match crowd submissions against verified DC ballots. |
Archive pages
- /elections/senedd/2021 - Senedd 2021
- /elections/westminster/2024 - UK Parliament 2024
- /elections/locals/2022 - Welsh local councils 2022
- /elections/pcc/2024 - Police & Crime Commissioners 2024
Underlying static datasets
- src/data/elections/archive.ts - Static archive index
- src/data/elections/westminster-2024-seats.ts - Westminster 2024 seats
- src/data/elections/notional-2021.ts - Notional 2021 (Westminster)
- src/data/elections/senedd-2026-regions.ts - Senedd 2026 regions
- src/data/elections/holyrood-regions.ts - Holyrood regions
- src/data/elections/english-councils.ts - English councils
- src/data/elections/welsh-councils.ts - Welsh councils
- src/data/elections/party-history.ts - Party history
- src/data/elections/registry.ts - Election registry
Authentication
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",
"candidate_votes": [
{ "party_id": "lab", "name": "A. Smith", "votes": 1234 },
{ "party_id": "con", "name": "B. Jones", "votes": 980 },
{ "party_id": "ld", "name": "C. Patel", "votes": 186 }
]
}' \
https://tallys.uk/api/v1/crowd/submissionscandidate_votes is optional but recommended - it powers per-candidate displays and lets us reconcile against Democracy Club at the row level.
GET /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. |