Candidates
Read and manage candidates in a voting event.
Endpoints
| Method | Path | Scope | Description |
|---|---|---|---|
GET | /voting-events/:idOrCode/candidates | read | List candidates. |
POST | /voting-events/:idOrCode/candidates | write | Create a candidate. |
POST | /voting-events/:idOrCode/candidates/batch | write | Create up to 100 candidates. |
POST | /voting-events/:idOrCode/candidates/approve | write | Approve up to 100 candidates. |
POST | /voting-events/:idOrCode/candidates/unapprove | write | Remove approval from up to 100 candidates. |
GET | /voting-events/:idOrCode/candidates/:id | read | Get a candidate. |
PATCH | /voting-events/:idOrCode/candidates/:id | write | Update a candidate. |
DELETE | /voting-events/:idOrCode/candidates/:id | write | Delete a candidate. |
PUT | /voting-events/:idOrCode/candidates/:id/avatar | write | Set an avatar from an upload. |
DELETE | /voting-events/:idOrCode/candidates/:id/avatar | write | Remove an avatar. |
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
positionId | string | No | Filter by position. |
groupId | string | No | Filter by group. |
status | not_approved, pending, or approved | No | Filter by registration status. |
search | string | No | Search candidate names and emails. |
expand | group, positions, or both | No | Add the candidate's group and positions. |
Send ?expand=group,positions on the list or one-candidate endpoint. Each returned candidate then includes a group object and a positions array. A missing group is null.
Request fields
name is required on a single create. Send at least one field on update. On update, groupId and referendumRole accept null to clear them. avatarUrl is an external image URL and is accepted on a create or in a batch row. To store an image in Pepvote, use the avatar endpoints after the upload flow.
| Field | Type | Description |
|---|---|---|
name | string | 1 to 200 characters. |
email | string | Up to 320 characters. |
positionIds | string array | Position IDs. |
groupId | string or null | Group ID. |
status | enum | not_approved, pending, or approved. |
referendumRole | enum or null | for, against, or abstain. |
avatarUrl | string | External image URL, up to 2,048 characters. Create and batch only. |
Create example
curl -X POST "https://api.pepvote.com/voting-events/BOARD26/candidates" \
-H "Authorization: Bearer $PEPVOTE_API_KEY" -H "User-Agent: my-app/1.0" \
-H "Content-Type: application/json" -H "Idempotency-Key: candidate-amina-001" \
-d '{"name":"Amina Bello","email":"amina@example.com","positionIds":["j57position01"],"status":"approved","avatarUrl":"https://images.example/amina.jpg"}'{
"data": {
"id": "j57candidate01",
"votingEventId": "j57event01",
"groupId": null,
"positionIds": [
"j57position01"
],
"name": "Amina Bello",
"email": "amina@example.com",
"status": "approved",
"selfRegistered": false,
"referendumRole": null,
"avatarUrl": "https://images.example/amina.jpg",
"createdAt": 1776900200000
}
}Batch create and approval
A batch accepts { "candidates": [...] } with 1 to 100 rows. It uses the batch rate limit bucket and returns { "data": { "created": [...], "skipped": [{ "index": 0, "reason": "..." }] } }.
curl -X POST "https://api.pepvote.com/voting-events/BOARD26/candidates/approve" \
-H "Authorization: Bearer $PEPVOTE_API_KEY" -H "User-Agent: my-app/1.0" \
-H "Content-Type: application/json" -d '{"ids":["j57candidate01","j57candidate02"]}'{
"data": {
"approvedCount": 2,
"errors": [
]
}
}unapprove returns unapprovedCount instead. Both endpoints accept 1 to 100 IDs. An error item has id and reason.
Avatar example
curl -X PUT "https://api.pepvote.com/voting-events/BOARD26/candidates/j57candidate01/avatar" \
-H "Authorization: Bearer $PEPVOTE_API_KEY" -H "User-Agent: my-app/1.0" \
-H "Content-Type: application/json" -d '{"storageId":"kg2storage01"}'{
"data": {
"id": "j57candidate01",
"name": "Amina Bello",
"avatarUrl": "https://storage.example/avatar.png"
}
}A successful create returns 201. Delete returns 202 with { "data": { "id": "...", "deletion": "queued" } }.
Last updated September 6, 2026