API Reference
Developers
Integrate ZeroVote into prediction markets, compliance systems, DAOs, or anything that needs trustless election results. All endpoints are public and unauthenticated — no API key required.
Endpoints
Base URL: https://api.zerovote.app. All responses are JSON.
/v/:slugEvent details including status, candidates, schedule, and results (if revealed).
{
"name": "Board Election 2025",
"slug": "board-election-2025-a1b2c3",
"status": "revealed",
"candidates": [{"index": 0, "label": "Alice"}, {"index": 1, "label": "Bob"}],
"voting_method": "fptp",
"ballot_open": "2025-06-01T00:00:00Z",
"ballot_close": "2025-06-08T00:00:00Z",
"reveal_at": "2025-06-08T00:01:00Z",
"results": { "..." : "see /v/:slug/results" }
}/v/:slug/resultsTally results. Only available after the event status is 'revealed'.
{
"method": "fptp",
"winner": "Alice",
"winner_index": 0,
"is_tie": false,
"totals": [
{ "candidate": "Alice", "index": 0, "votes": 25 },
{ "candidate": "Bob", "index": 1, "votes": 18 }
],
"total_ballots": 43,
"drand_round": 12345678,
"drand_signature": "abcdef..."
}/v/:slug/boardBulletin board: all encrypted ballots, ZKPs, and Merkle proofs. Used for independent verification.
{
"event_slug": "board-election-2025-a1b2c3",
"merkle_root": "hex...",
"ballots": [
{
"merkle_index": 0,
"encrypted_vote": "base64...",
"zkp": "base64..."
}
]
}/v/:slug/snapshotFull verifier snapshot. Everything needed for independent verification in one request.
{
"event_name": "Board Election 2025",
"event_slug": "board-election-2025-a1b2c3",
"voting_method": "fptp",
"drand_round": 12345678,
"drand_chain_hash": "52db9ba...",
"drand_public_key": "hex...",
"merkle_root": "hex...",
"ballots": [ ... ]
}/api/public-eventsList all public events with their current status.
{
"live": [ ... ],
"upcoming_reveals": [ ... ],
"recent_results": [ ... ]
}Webhooks
Set a webhook URL when creating an event. ZeroVote POSTs results to that URL immediately after the election is revealed.
Setting a webhook
Add a webhook URL in the “Advanced options” section of the event creation form. The URL must use HTTPS. You can also pass webhook_url in the create event API request.
Payload
POST https://your-server.com/webhook
Content-Type: application/json
X-ZeroVote-Signature: <hex HMAC-SHA256>
{
"event": "election.revealed",
"event_id": "uuid",
"event_slug": "board-election-2025-a1b2c3",
"event_name": "Board Election 2025",
"revealed_at": "2025-06-08T00:01:00Z",
"results": {
"method": "fptp",
"winner": "Alice",
"totals": [ ... ],
"total_ballots": 43,
"drand_round": 12345678,
"drand_signature": "abcdef..."
},
"snapshot_url": "https://api.zerovote.app/v/.../snapshot",
"verify_url": "https://api.zerovote.app/v/.../results"
}results has the same shape as GET /v/:slug/results. snapshot_url and verify_url are convenience links for downstream verification.
Signature verification
The X-ZeroVote-Signatureheader is a hex-encoded HMAC-SHA256 of the request body, keyed with your server secret. Verify it to confirm the webhook came from ZeroVote and wasn't tampered with.
Retry policy
Webhooks fire once with a 10-second timeout. No automatic retries. As a fallback, poll GET /v/:slug and check status === "revealed".
Integration Patterns
Simple polling
Poll GET /v/:slug until status === "revealed". Status progresses: draft → open → closed → revealing → revealed.
Webhook-driven
Set a webhook URL when creating an event. Your server receives results the instant they're available.
Independent verification
Run the open-source zerovote-verifier to trustlessly re-run the full cryptographic pipeline: beacon verification, ZKP checks, Merkle rebuild, decryption, and tally.
Hybrid
RecommendedWebhook triggers your pipeline, verifier confirms before you act. Speed of push + trustlessness of independent verification.
Code Examples
# Check event status curl -s https://api.zerovote.app/v/board-election-2025-a1b2c3 | jq .status # Fetch results once revealed curl -s https://api.zerovote.app/v/board-election-2025-a1b2c3/results | jq . # Download snapshot for offline verification curl -s https://api.zerovote.app/v/board-election-2025-a1b2c3/snapshot -o snapshot.json # Get the bulletin board (encrypted ballots + ZKPs) curl -s https://api.zerovote.app/v/board-election-2025-a1b2c3/board | jq .merkle_root # Browse all public events curl -s https://api.zerovote.app/api/public-events | jq '.[].name'
Use Cases
Prediction markets
Webhook triggers trade settlement. Verifier provides trustless confirmation — no dependency on the ZeroVote server.
Awards shows
No insider can front-run results. The decryption key doesn't exist until the drand beacon reveals it.
Corporate governance
Board votes with audit trail. Webhook notifies compliance. Verifier provides independent audit for regulators.
DAOs
Trigger on-chain settlement from webhook or verifier output. Deterministic pipeline means smart contracts can trust the result.
Unions
Members verify independently. No single authority counts. Merkle tree and ZKPs guarantee ballot integrity.
Verifier
The open-source zerovote-verifier independently verifies election results. It fetches the bulletin board and drand beacon, verifies every ZKP, rebuilds the Merkle tree, decrypts all ballots, and recomputes the tally. Available as both a CLI and a Rust library crate.
# Install
cargo install zerovote-verifier
# Verify an election
zerovote-verify --slug board-election-2025-a1b2c3 \
--api https://api.zerovote.app
# JSON output for automation
zerovote-verify --slug board-election-2025-a1b2c3 \
--api https://api.zerovote.app --jsonReady to integrate?
Create an event with a webhook URL, or start polling the API.