Voting events
Create, read, update, and delete voting events.
Use a voting event's id or its short code wherever a path has :idOrCode.
Endpoints
| Method | Path | Scope | Description |
|---|---|---|---|
GET | /voting-events | read | List accessible voting events. |
POST | /voting-events | write | Create a voting event. |
GET | /voting-events/:idOrCode | read | Get one voting event. |
PATCH | /voting-events/:idOrCode | write | Update allowed event settings. |
DELETE | /voting-events/:idOrCode | write | Delete a voting event. |
PUT | /voting-events/:idOrCode/logo | write | Set the event logo from an upload. |
DELETE | /voting-events/:idOrCode/logo | write | Remove the event logo. |
GET | /voting-events/:idOrCode/stats | read | Get event counts and turnout. |
List query parameters
| Name | Type | Required | Description |
|---|---|---|---|
limit | integer | No | Page size from 1 to 200. Default: 50. |
cursor | string | No | Cursor from nextCursor. |
type | election or poll | No | Filter by event type. |
status | draft, upcoming, ongoing, or ended | No | Filter by status. Same names as the dashboard. |
Create request fields
title is required. See uploads before setting a logo.
| Field | Type | Required | Description |
|---|---|---|---|
title | string | Yes | 1 to 200 characters. |
type | election or poll | No | Defaults to Pepvote's event type. |
desc | string | No | Up to 5,000 characters. |
startsAt, endsAt | integer | No | Unix milliseconds. |
resultSettings | object | No | How and when results are shown. See result settings. |
groupMode | boolean | No | Enable event groups. |
voterCanRegister, candidateCanRegister | boolean | No | Allow public registration. |
canContestMultiplePositions | boolean | No | Allow a candidate to enter more than one position. |
requireVoterIdToRegister | boolean | No | Require a voter ID during public voter registration. |
requireVoterIdToVote | boolean | No | Require a voter ID to cast a ballot. |
shuffleCandidates, multiStepVoting | boolean | No | Set the voting experience. |
enableWeightedVoting | boolean | No | Enable weighted voting. |
votingFormat | default, big_avatar, big_avatar_full_image, options_with_avatar, or options | No | Set the ballot layout. |
aliases | object | No | Rename Pepvote's default terms. See aliases. |
Update request fields
Send at least one field. Send null to clear desc, startsAt, or endsAt.
| Field | Type | Description |
|---|---|---|
title | string | 1 to 200 characters. |
desc | string or null | Up to 5,000 characters. |
startsAt, endsAt | integer or null | Unix milliseconds. |
voterCanRegister, candidateCanRegister | boolean | Allow public registration. |
resultSettings | object | How and when results are shown. See result settings. |
aliases | object | Rename Pepvote's default terms. See aliases. |
Result settings
resultSettings holds every result option in one object. Responses always
return all six keys. On POST and PATCH, send only the keys you want to
change.
| Key | Type | Description |
|---|---|---|
live | boolean | Candidates and voters can see results while voting is live. |
published | boolean | Results are visible after voting ends. |
displayLimit | integer or null | Candidates shown per position on the results page, 2 to 10. On PATCH, null restores the default of 3. |
groupByCandidateGroup | boolean | One row per candidate group. Needs groupMode. |
showWeightedVotes | boolean | Show weighted tallies on a weighted event. Default true. |
percentageBase | votes or voters | What shares are out of on plurality and approval positions that allow more than one pick. Default votes. |
With votes, each candidate's share is out of every pick made on the
position, so a position's shares add up to 100%. With voters, each share is
out of the voters who voted on the position. Use it when a rule says a winner
needs more than half of the voters: on a pick-2 position, a candidate every
voter picked shows 100%, not 50%, and the shares add up to as much as 200%.
groupByCandidateGroup cannot be true while percentageBase is voters.
A group row adds up its candidates' votes, so one voter could count twice.
Setting percentageBase to voters turns group view off.
curl -X PATCH "https://api.pepvote.com/voting-events/BOARD26" \
-H "Authorization: Bearer $PEPVOTE_API_KEY" \
-H "User-Agent: my-app/1.0" \
-H "Content-Type: application/json" \
-d '{"resultSettings":{"published":true,"percentageBase":"voters"}}'Aliases
An alias replaces one of Pepvote's default words everywhere voters and organizers read it. A student union can call a position a "role", and a quadratic budget event can call a credit a "token".
The aliases object takes the same keys the API returns. Send only the ones
you want to change. Each value is 1 to 60 characters and is trimmed.
| Key | Replaces |
|---|---|
votingEvent | election or poll |
votingCenter | voting center |
position | position |
group | group |
positionGroup, candidateGroup, voterGroup | group, for that one kind. Falls back to group. |
candidate | candidate |
voter | voter |
voterId | voter ID |
sponsor | sponsor |
weight | weight. Only kept while enableWeightedVoting is true. |
quadraticCredit | credit, the unit voters spend under quadratic voting |
On PATCH, send null for an alias to restore its default word. On POST,
omit the alias instead.
curl -X PATCH "https://api.pepvote.com/voting-events/BOARD26" \
-H "Authorization: Bearer $PEPVOTE_API_KEY" \
-H "User-Agent: my-app/1.0" \
-H "Content-Type: application/json" \
-d '{"aliases":{"quadraticCredit":"token","position":"role","sponsor":null}}'{
"data": {
"id": "j57event01",
"code": "BOARD26",
"aliases": {
"votingEvent": null,
"votingCenter": null,
"position": "role",
"group": null,
"positionGroup": null,
"candidateGroup": null,
"voterGroup": null,
"candidate": null,
"voter": null,
"voterId": null,
"sponsor": null,
"weight": null,
"quadraticCredit": "token"
}
}
}Create example
curl -X POST "https://api.pepvote.com/voting-events" \
-H "Authorization: Bearer $PEPVOTE_API_KEY" \
-H "User-Agent: my-app/1.0" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: board-2026" \
-d '{"title":"Board election 2026","type":"election","resultSettings":{"live":true}}'{
"data": {
"id": "j57event01",
"code": "BOARD26",
"type": "election",
"title": "Board election 2026",
"desc": null,
"startsAt": null,
"endsAt": null,
"status": "draft",
"locked": false,
"resultSettings": {
"live": true,
"published": false,
"displayLimit": null,
"groupByCandidateGroup": false,
"showWeightedVotes": true,
"percentageBase": "votes"
},
"groupMode": false,
"votingFormat": "default",
"shuffleCandidates": false,
"multiStepVoting": false,
"canContestMultiplePositions": false,
"enableWeightedVoting": false,
"enablePayToVote": false,
"enablePayToRegisterCandidate": false,
"voting": {
"requireVoterIdToVote": false
},
"registration": {
"voterCanRegister": false,
"voterPublicRegistrationClosesAt": null,
"candidateCanRegister": false,
"candidatePublicRegistrationClosesAt": null,
"requireVoterIdToRegister": false,
"voterIdValidationLogic": null,
"voterIdValidatingValue": null
},
"aliases": {
"votingEvent": null,
"votingCenter": null,
"position": null,
"group": null,
"positionGroup": null,
"candidateGroup": null,
"voterGroup": null,
"candidate": null,
"voter": null,
"voterId": null,
"sponsor": null,
"weight": null,
"quadraticCredit": null
},
"plan": {
"name": "Starter",
"maxVoters": 500
},
"logoUrl": null,
"createdAt": 1776900000000
}
}Logo example
Upload the image first. Then pass its storageId to the logo endpoint.
curl -X PUT "https://api.pepvote.com/voting-events/BOARD26/logo" \
-H "Authorization: Bearer $PEPVOTE_API_KEY" \
-H "User-Agent: my-app/1.0" \
-H "Content-Type: application/json" \
-d '{"storageId":"kg2storage01"}'{
"data": {
"id": "j57event01",
"code": "BOARD26",
"logoUrl": "https://storage.example/logo.png"
}
}Delete returns 204 for a voting event. The stats response has votingEventId, positionCount, candidateCount, approvedCandidateCount, sponsorCount, groupCount, voterCount, approvedVoterCount, pendingVoterCount, votedVoterCount, votesCast, votesConfirmed, and turnoutPercent.
Last updated October 27, 2026