POST / DELETE /ideabank/proposals/{proposalId}/vote
Cast or update a panelist’s vote on a proposal with POST, and remove it with DELETE. Requires the canVote capability (see Get Idea Bank). Casting a vote on a proposal the panelist has already voted on updates the existing vote.
To list every proposal the panelist has voted on, use My Votes.
Request
Cast or update a vote
POST /public/ideabank/proposals/{proposalId}/vote
Remove a vote
DELETE /public/ideabank/proposals/{proposalId}/vote
Path Parameters
| Parameter | Type | Description |
|---|---|---|
| proposalId | string | The proposal identifier from the proposal listing |
Headers
| Header | Required | Description |
|---|---|---|
| Authorization | Yes | Compound idea-bank token from Tenant API |
| Content-Type | Yes (POST) | application/json |
Request Body (POST only)
| Field | Type | Description |
|---|---|---|
| vote | integer | The vote value: 1 for, -1 against |
| voteType | string | Alternative to vote: for (maps to 1) or against (maps to -1) |
Send either vote or voteType. When both are present, vote takes precedence.
{
"vote": 1
}
DELETE takes no request body.
Response
POST
{
"proposalId": "p-abc123",
"vote": 1
}
| Field | Type | Description |
|---|---|---|
| proposalId | string | The proposal the vote was recorded on |
| vote | integer | The recorded vote value (1 or -1) |
DELETE
Returns HTTP 204 No Content with an empty body when the vote is removed.
Examples
cURL
# Cast an upvote
curl -X POST \
"https://api.votito.com/public/ideabank/proposals/p-abc123/vote" \
-H "Authorization: abc123:xyz789:ses456" \
-H "Content-Type: application/json" \
-d '{"vote":1}'
# Remove the vote
curl -X DELETE \
"https://api.votito.com/public/ideabank/proposals/p-abc123/vote" \
-H "Authorization: abc123:xyz789:ses456"
JavaScript
const castVote = async (publicKey, proposalId, vote) => {
const response = await fetch(`https://api.votito.com/public/ideabank/proposals/${proposalId}/vote`, {
method: 'POST',
headers: {
'Authorization': publicKey,
'Content-Type': 'application/json'
},
body: JSON.stringify({ vote })
});
if (!response.ok) {
throw new Error(`Failed to vote: ${response.status}`);
}
return response.json();
};
const removeVote = async (publicKey, proposalId) => {
const response = await fetch(`https://api.votito.com/public/ideabank/proposals/${proposalId}/vote`, {
method: 'DELETE',
headers: { 'Authorization': publicKey }
});
if (!response.ok) {
throw new Error(`Failed to remove vote: ${response.status}`);
}
};
// Usage
await castVote(publicKey, 'p-abc123', 1);
await removeVote(publicKey, 'p-abc123');
Python
import requests
def cast_vote(public_key, proposal_id, vote):
response = requests.post(
f"https://api.votito.com/public/ideabank/proposals/{proposal_id}/vote",
headers={
"Authorization": public_key,
"Content-Type": "application/json"
},
json={"vote": vote}
)
response.raise_for_status()
return response.json()
def remove_vote(public_key, proposal_id):
response = requests.delete(
f"https://api.votito.com/public/ideabank/proposals/{proposal_id}/vote",
headers={"Authorization": public_key}
)
response.raise_for_status()
# Usage
cast_vote(public_key, "p-abc123", 1)
remove_vote(public_key, "p-abc123")
Error Handling
| Status | Error | Description |
|---|---|---|
| 400 | invalid-request | Neither vote nor a valid voteType was supplied |
| 401 | Unauthorized | Missing or invalid token |
| 403 | Forbidden | Token expired, or the panelist cannot vote |
| 404 | idea-bank-not-found | Proposal not found, not open, or idea bank not panelist-accessible |
| 429 | resource-busy | Server is busy. Retry after a short delay. |
Notes
- Voting is only permitted on open proposals. If a proposal was merged into another, the server resolves the effective open proposal and records the vote there.
- A second
POSTfor the same proposal overwrites the panelist’s previous vote rather than adding a new one. DELETEis idempotent from the caller’s perspective: removing a vote the panelist does not have still succeeds.