Record whether an answer helped. A rating is up or down.
POST https://app.kelu.dev/api/v1/public/feedback
DELETE https://app.kelu.dev/api/v1/public/feedback/:messageId
Auth: client key. Public keys also need a CAPTCHA token on POST when CAPTCHA is on. DELETE does not.
Rate an answer
| Field | Type | Required | Description |
|---|
message_id | string | Yes | The message_id from the chat stream’s last frame, the WebSocket done frame, or form-deflect |
rating | "up" or "down" | Yes | Whether the answer helped. The older values 5 and 1 also work |
comment | string | No | Free text |
curl https://app.kelu.dev/api/v1/public/feedback \
-H "X-Client-Id: kl_ci_..." \
-H "X-Client-Secret: kl_cs_..." \
-H "Content-Type: application/json" \
-d '{"message_id": "c3a2...", "rating": "up", "comment": "Spot on"}'
Returns 201 with the stored rating. Note the field is vote:
{
"id": "0d9e...",
"workspace_id": "51b0...",
"message_id": "c3a2...",
"vote": "up",
"comment": "Spot on",
"source": "widget",
"created_at": "2026-09-27T10:12:03Z",
"updated_at": "2026-09-27T10:12:03Z"
}
- Each answer holds one rating. Posting again replaces it.
DELETE /feedback/:messageId withdraws the rating and returns 204.
- Errors:
400 for a bad rating or message_id, 403 for a message from another knowledge base, 404 for an unknown message.
A rating needs a stored answer. With Zero data retention, answers are not stored and carry no message_id. Hide your rating buttons when it is missing.
Ratings from the API, the widget and the bots land in the same place. They show up in analytics, and down-rated answers count as knowledge gaps.
SDKs
// @kelu/sdk
await kelu.feedback({ messageId: "c3a2...", rating: "up", comment: "Spot on" });
await kelu.clearFeedback("c3a2...");
// @kelu/react (useKeluChat)
await sendFeedback(messageId, "down", "Wrong answer");
await clearFeedback(messageId);