Sync layer
Webhooks
Data PlannedAPI PlannedElection data goes stale within hours rather than weeks, so instead of polling and hoping you subscribe once and receive a signed event the moment something changes.
Events
| Event | Fires when |
|---|---|
candidacy.created | A new candidate filing enters the graph |
candidacy.updated | Any candidacy field changes, including contact and filing status |
candidacy.withdrawn | A candidate withdraws or is disqualified |
contest.created | A new contest is scheduled |
result.reported | Unofficial results arrive from a state feed |
result.certified | Results are certified and a winner is provable |
region.redistricted | A district boundary is superseded by a new vintage |
Payload
Every event carries the fields that changed, both the old and new values, and the source that justified the change.
{
"id": "evt_01K2Q8…",
"type": "candidacy.updated",
"occurred_at": "2026-08-20T16:37:04Z",
"node": {
"slug": "candidacy:az-us-house-03-2026-general-jane-doe",
"kind": "candidacy"
},
"changes": [
{ "field": "filing_status", "from": "pending", "to": "qualified" },
{ "field": "ballot_position", "from": null, "to": 2 }
],
"provenance": {
"artifact": "artifact:az-sos-candidate-list-2026-08-20",
"source_url": "https://azsos.gov/…",
"source_status": "authoritative",
"confidence": 0.95
}
}Verifying a delivery
Each request carries an HMAC-SHA256 signature over the timestamp and the raw request body. Verify it against the raw bytes before parsing any JSON, compare the result in constant time, and reject anything whose timestamp is more than five minutes old so that a captured request cannot be replayed.
Civoren-Signature: t=1786291024,v1=5257a869e7e…
Civoren-Event-Type: candidacy.updated
Civoren-Delivery: dlv_01K2Q8…- Delivery is at least once. Failed deliveries are retried with increasing delays for 24 hours, so duplicates should be treated as expected rather than exceptional.
- Ordering is not guaranteed. Use
occurred_atto establish sequence and de-duplicate onid, which puts the burden of safe repetition on your write rather than on the transport. - Events are sent only after a change commits. Nothing is emitted for state that was subsequently rolled back.
- Filtering happens at subscription time. Choose event types, states and jurisdiction tiers up front so you only ever receive what you care about.