Census
A census is the list of who can vote in an election and how they prove who they are. Publishing a census produces a cryptographic root that binds the eligible voters to a process.
A census is the eligible-voter list for an election, anchored to a cryptographic root that the election binds to. When you create a census you also choose how voters prove who they are.
¶Authentication fields
authFields- the fields a voter must present to authenticate (e.g.memberNumber). With onlyauthFieldsset, the census is auth-only: no second factor.twoFaFields- fields used for a one-time-code second factor:emailorphone.
These combine into four census types: auth (auth-only), mail, sms, and
sms_or_mail. The type is derived from the two-factor fields you choose.
authFields options: name, surname, memberNumber, nationalId, birthDate.
twoFaFields options: email, phone.
¶Creating a census
Create a census for an organization, declaring the authentication and two-factor fields it will use. The response returns the census id.
| Field | Type | Description |
|---|---|---|
orgAddressObligatori |
string | The organization the census belongs to. |
authFields |
string[] | Fields the voter must provide to authenticate. |
twoFaFields |
string[] | Channels for the second factor: email or phone. |
CENSUS=$(curl -s "${auth[@]}" -X POST "$B/census" \
-d "{\"orgAddress\":\"$ORG\",\"authFields\":[\"memberNumber\"]}" | jq -r .id)
{ "id": "6a1f..." } // carry forward: census id
Add "twoFaFields":["email"] for an email-OTP census.
var census = (await Post("/census",
new { orgAddress = org, authFields = new[] { "memberNumber" } })).GetProperty("id").GetString();
census = post("/census", {"orgAddress": org, "authFields": ["memberNumber"]}).json()["id"]
¶Adding participants
For a 2FA census, add organization members by id before publishing. Auth-only censuses are populated from their group at publish time, so they skip this step. Members already present are skipped.
curl "${auth[@]}" -X POST "$B/census/$CENSUS" \
-d '{ "memberIds": ["<id1>", "<id2>"] }'
¶Publishing a census
Publishing locks the participant list and produces the root the election binds to. How you publish depends on the census type - this is the single most common stumble.
2FA types (mail / sms / sms_or_mail) publish directly:
curl "${auth[@]}" -X POST "$B/census/$CENSUS/publish"
Auth-only censuses are rejected by the plain publish (census type not found). Publish them
through a group instead - this both supports auth-only and populates participants from the group:
curl "${auth[@]}" -X POST "$B/census/$CENSUS/group/$GROUP/publish" \
-d '{"authFields":["memberNumber"],"weighted":false}'
Either way you get the published census:
{ "root": "deadbeef...", "size": 1, "uri": "https://..." }
The size is the eligible-voter count - useful later for turnout (see Results). Set
"weighted": true to make each member's weight count as vote weight.
await Post($"/census/{census}/group/{group}/publish",
new { authFields = new[] { "memberNumber" }, weighted = false });
post(f"/census/{census}/group/{group}/publish",
{"authFields": ["memberNumber"], "weighted": False})
Weighted voting
Set "weighted": true when publishing to make each member's weight field count as their vote
weight - use it for shareholder meetings or any vote where members do not count equally.
¶Inspecting participants
curl "${auth[@]}" "$B/census/$CENSUS/participants"
{ "censusId": "6a1f...", "memberIds": ["..."] }
¶Gotchas
- Auth-only must be published via a group (
/census/{id}/group/{groupId}/publish). The plain/publishrejects it. - The auth-only credential is derived from the auth field, so
memberNumbermust be unique across the census - duplicates fail at publish. - One published census can back multiple processes - reuse it across votes.