Skip to main content

Vote Endpoints

The voting system provides endpoints for upvoting and downvoting items. Votes use a net-score model where the count represents upvotes minus downvotes. Public endpoints return vote counts while authenticated endpoints allow casting, updating, and removing votes. Blocked users are prevented from voting.

Overview

EndpointMethodAuthDescription
/api/items/[slug]/votesGETPublicGet vote count and user vote status
/api/items/[slug]/votesPOSTUserCast or update a vote
/api/items/[slug]/votesDELETEUserRemove a vote
/api/items/[slug]/votes/countGETPublicGet net vote count only
/api/items/[slug]/votes/statusGETUserGet full vote record for user

Combined Vote Endpoint

Get Vote Information

GET /api/items/[slug]/votes

Returns the net vote count for an item and the current user's vote status if authenticated. No authentication is required, but authenticated users receive their vote status in the response.

Path Parameters:

ParameterTypeDescription
slugstringItem slug

Success Response (200):

{
"success": true,
"count": 15,
"userVote": "up"
}
FieldTypeDescription
successbooleanAlways true on success
countintegerNet vote count (upvotes minus downvotes)
userVotestring or null"up", "down", or null if unauthenticated or no vote

For unauthenticated users, userVote is always null. The count can be negative if there are more downvotes than upvotes.

Source: template/app/api/items/[slug]/votes/route.ts

Cast or Update Vote

POST /api/items/[slug]/votes

Casts a new vote or replaces an existing vote on an item. If the user already has a vote, the previous vote is deleted before the new one is created. This means changing from upvote to downvote (or vice versa) is a single operation.

Authentication: Required

Request Body:

{
"type": "up"
}
FieldTypeRequiredDescription
typestringYes"up" for upvote, "down" for downvote

Success Response (200):

{
"success": true,
"count": 16,
"userVote": "up"
}

The response returns the updated net vote count after the vote is applied.

Error Responses:

StatusCondition
400Invalid vote type (must be "up" or "down")
401Not authenticated
403User is suspended or banned
404Client profile not found

Source: template/app/api/items/[slug]/votes/route.ts

Remove Vote

DELETE /api/items/[slug]/votes

Removes the current user's vote from an item. If no vote exists, the operation completes successfully without error (idempotent). After removal, userVote is null.

Authentication: Required

Success Response (200):

{
"success": true,
"count": 14,
"userVote": null
}
StatusCondition
401Not authenticated
404Client profile not found

Source: template/app/api/items/[slug]/votes/route.ts

Vote Count Endpoint

Get Vote Count

GET /api/items/[slug]/votes/count

Returns only the net vote count for an item. This is a lightweight public endpoint optimized for quick vote count retrieval without user-specific vote status.

Success Response (200):

{
"success": true,
"count": 15
}

The count can be positive, negative, or zero depending on the balance of upvotes and downvotes.

Source: template/app/api/items/[slug]/votes/count/route.ts

Vote Status Endpoint

Get User Vote Status

GET /api/items/[slug]/votes/status

Returns the full vote record for the authenticated user on a specific item. Returns null if the user has not voted on the item.

Authentication: Required

Success Response (200) -- User Has Voted:

{
"id": "vote_123abc",
"userId": "client_456def",
"itemId": "item_123abc",
"voteType": "UPVOTE",
"createdAt": "2024-01-20T10:30:00.000Z",
"updatedAt": "2024-01-20T10:30:00.000Z"
}

Success Response (200) -- No Vote:

null

Note that this endpoint returns the raw database voteType values ("UPVOTE" or "DOWNVOTE") rather than the simplified "up" / "down" format used by the combined endpoint.

StatusCondition
401Not authenticated
404Client profile not found

Source: template/app/api/items/[slug]/votes/status/route.ts

Key Implementation Details

  • Net Score: Vote count is calculated as upvotes minus downvotes. A negative count indicates more downvotes than upvotes.
  • Vote Replacement: When a user changes their vote type, the existing vote is deleted and a new one is created. There is no in-place update.
  • Blocked User Prevention: The isUserBlocked() check on the POST endpoint prevents suspended or banned users from voting. The block check is only enforced on vote creation, not on vote removal.
  • VoteType Enum: The database stores votes as VoteType.UPVOTE and VoteType.DOWNVOTE. The API translates these to "up" and "down" for external consumers.
  • Idempotent Delete: Deleting a vote that does not exist still returns a 200 response with the current count and userVote: null.