Skip to content

AI Reactions

React to AI runs and messages with 10 reaction types. Reactions use toggle semantics -- the same endpoint adds or removes a reaction.

Endpoints

MethodPathDescriptionAuthRate Limit
POST/ai/reactions/toggleToggle a reactionJWT + Entitlement30/min
GET/ai/reactions/runs/:runIdGet reactions for a runJWT + Entitlement60/min
GET/ai/reactions/messages/:messageIdGet reactions for a messageJWT + Entitlement60/min
GET/ai/reactions/runs/:runId/statsAggregate stats for a runJWT + Entitlement60/min
GET/ai/reactions/messages/:messageId/statsAggregate stats for a messageJWT + Entitlement60/min
DELETE/ai/reactions/:idRemove a reaction by IDJWT + Entitlement30/min

Reaction Types

TypeDescription
likeGeneral positive signal
dislikeGeneral negative signal
accurateFactually correct
creativeNovel or surprising
fastQuick response
helpfulDirectly useful
inspiringMotivating content
confusingHard to understand
wrongFactually incorrect
slowResponse took too long

POST /ai/reactions/toggle

Toggle a reaction on a run or message. If the reaction already exists, it is removed. If it does not exist, it is added.

Authentication: JWT Bearer token + active AI entitlement required. Rate limit: 30/min

Request

FieldTypeRequiredDescription
reactionTypestringYesOne of the 10 reaction types
runIdstring (uuid)NoTarget run ID (at least one of runId/messageId required)
messageIdstring (uuid)NoTarget message ID
commentstringNoOptional comment (max 1000 chars, only for like/dislike)

Response

Response Example (Added)
json
{
  "data": {
    "action": "added",
    "reaction": {
      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "chainerId": "u1234567-abcd-ef01-2345-6789abcdef00",
      "reactionType": "helpful",
      "comment": null,
      "createdAt": "2026-03-17T14:00:00.000Z"
    }
  }
}
Response Example (Removed)
json
{
  "data": {
    "action": "removed"
  }
}
Response Fields
FieldTypeDescription
action"added" | "removed"Whether the reaction was created or deleted
reactionobject | undefinedThe created reaction (only when action is "added")
reaction.idstringReaction UUID
reaction.chainerIdstringUser who reacted
reaction.reactionTypestringThe reaction type
reaction.commentstring | nullOptional comment
reaction.createdAtstringISO 8601 timestamp

Code Examples

Use the id of an existing AI run as $RUN_ID.

bash
curl -X POST https://api.chainabit.com/api/v1/ai/reactions/toggle \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "reactionType": "helpful",
    "runId": "'"$RUN_ID"'"
  }'
javascript
const runId = process.env.RUN_ID; // id of the AI run you're reacting to

const res = await fetch(`${BASE_URL}/ai/reactions/toggle`, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${TOKEN}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    reactionType: "helpful",
    runId,
  }),
});
const { data } = await res.json();
python
import os
import requests

run_id = os.environ["RUN_ID"]  # id of the AI run you're reacting to

res = requests.post(
    f"{BASE_URL}/ai/reactions/toggle",
    headers={"Authorization": f"Bearer {TOKEN}"},
    json={
        "reactionType": "helpful",
        "runId": run_id,
    },
)
data = res.json()["data"]

GET /ai/reactions/runs/:runId

Get aggregate reaction stats and the current user's reactions for a run.

Authentication: JWT Bearer token + active AI entitlement required. Rate limit: 60/min

Request

  • Path params: runId

Response

Response Example
json
{
  "data": {
    "stats": [
      { "reactionType": "helpful", "count": 12 },
      { "reactionType": "accurate", "count": 8 },
      { "reactionType": "like", "count": 5 }
    ],
    "userReactions": ["helpful", "like"]
  }
}
Response Fields
FieldTypeDescription
statsarrayAggregate counts per reaction type, sorted by count descending
stats[].reactionTypestringReaction type name
stats[].countnumberTotal reactions of this type
userReactionsstring[]Reaction types the current user has applied

Code Examples

Use the id of an existing AI run as $RUN_ID.

bash
curl https://api.chainabit.com/api/v1/ai/reactions/runs/$RUN_ID \
  -H "Authorization: Bearer $TOKEN"
javascript
const runId = process.env.RUN_ID; // id of the AI run

const res = await fetch(
  `${BASE_URL}/ai/reactions/runs/${runId}`,
  { headers: { Authorization: `Bearer ${TOKEN}` } }
);
const { data } = await res.json();
python
import os
import requests

run_id = os.environ["RUN_ID"]  # id of the AI run

res = requests.get(
    f"{BASE_URL}/ai/reactions/runs/{run_id}",
    headers={"Authorization": f"Bearer {TOKEN}"},
)
data = res.json()["data"]

GET /ai/reactions/runs/:runId/stats

Get aggregate reaction counts for a run without user-specific data.

Authentication: JWT Bearer token + active AI entitlement required. Rate limit: 60/min

Request

  • Path params: runId

Response

Response Example
json
{
  "data": {
    "stats": [
      { "reactionType": "helpful", "count": 12 },
      { "reactionType": "accurate", "count": 8 }
    ],
    "userReactions": []
  }
}

Code Examples

Use the id of an existing AI run as $RUN_ID.

bash
curl https://api.chainabit.com/api/v1/ai/reactions/runs/$RUN_ID/stats \
  -H "Authorization: Bearer $TOKEN"
javascript
const runId = process.env.RUN_ID; // id of the AI run

const res = await fetch(
  `${BASE_URL}/ai/reactions/runs/${runId}/stats`,
  { headers: { Authorization: `Bearer ${TOKEN}` } }
);
const { data } = await res.json();
python
import os
import requests

run_id = os.environ["RUN_ID"]  # id of the AI run

res = requests.get(
    f"{BASE_URL}/ai/reactions/runs/{run_id}/stats",
    headers={"Authorization": f"Bearer {TOKEN}"},
)
data = res.json()["data"]

DELETE /ai/reactions/:id

Remove a specific reaction by its ID. Only the reaction owner can delete it.

Authentication: JWT Bearer token + active AI entitlement required. Rate limit: 30/min

Request

  • Path params: id

Response

Response Example
json
{
  "data": {
    "deleted": true
  }
}

Code Examples

Use the id from Toggle Reaction's "added" response (data.reaction.id) as $REACTION_ID.

bash
curl -X DELETE https://api.chainabit.com/api/v1/ai/reactions/$REACTION_ID \
  -H "Authorization: Bearer $TOKEN"
javascript
const reactionId = process.env.REACTION_ID; // id from the "added" response of POST /ai/reactions/toggle

const res = await fetch(
  `${BASE_URL}/ai/reactions/${reactionId}`,
  {
    method: "DELETE",
    headers: { Authorization: `Bearer ${TOKEN}` },
  }
);
const { data } = await res.json();
python
import os
import requests

reaction_id = os.environ["REACTION_ID"]  # id from the "added" response of POST /ai/reactions/toggle

res = requests.delete(
    f"{BASE_URL}/ai/reactions/{reaction_id}",
    headers={"Authorization": f"Bearer {TOKEN}"},
)
data = res.json()["data"]

Built with purpose.