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.

GET/v/:slug

Event 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" }
}
GET/v/:slug/results

Tally 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..."
}
GET/v/:slug/board

Bulletin 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..."
    }
  ]
}
GET/v/:slug/snapshot

Full 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": [ ... ]
}
GET/api/public-events

List 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

Recommended

Webhook 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 --json

View on GitHub

Ready to integrate?

Create an event with a webhook URL, or start polling the API.