Replies
Send a message, follow the reply, steer or stop it, and answer approvals and questions.
A turn is one reply. Sending a message starts a turn and returns its id straight away. Follow it on the events socket, or poll GET /bots/{id} until runningTurnId is gone.
Send a message
POST /bots/{id}/messages
| Field | Type | |
|---|---|---|
text |
string | The message |
attachments |
array | Optional. Each { "name", "mediaType", "kind", "data" }, with kind one of Image, Pdf, Text, and data the file's bytes in base64 |
replyToId |
string | Optional. The id of the message this one replies to |
worksIn |
string | Optional. Auto, Browser, Computer or ThisPc for this message only |
curl -s -X POST $INKBOT/api/bots/scout/messages \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{ "text": "Find three recent papers on speculative decoding." }'
{ "turnId": "6c1e…", "message": { "id": "a41f…", "fromUser": true, "text": "Find three recent papers on speculative decoding.", "at": "2026-10-30T14:02:11+00:00" } }
Sending to a bot that's already replying fails with an error. Steer the running reply instead, or wait.
Respond
POST /bots/{id}/respond with {} runs a reply to the chat as it is, when its last message is yours. Use it after editing a message or truncating to regenerate. Returns the same { turnId, message }.
Steer
POST /turns/{turnId}/steer
{ "id": "q1", "text": "Only papers from 2026, please." }
Returns { "accepted": true } when the reply takes the message at its next step (its step id is steer-q1). It's false when the reply can't take messages midway (Claude Code and Grok Build replies, group chats, or a reply that already ended). Send it as a normal message then.
Stop
POST /turns/{turnId}/stop returns 204. The reply ends with outcome Stopped.
Approvals
When a bot asks for approval, an ApprovalRequested event carries an ApprovalPrompt, which is also in the conversation's pendingApprovals. Answer it:
POST /approvals/{approvalId}
{ "choice": "AllowOnce" }
choice |
|
|---|---|
AllowOnce |
Just this action |
AllowForChat |
This kind of action for the rest of the conversation |
AllowCommand |
Add the prompt's commandPattern to the host's allowlist, and allow |
Deny |
Don't allow it |
An approval nobody answers resolves as TimedOut after the server's waiting time (see PUT /settings/approval-timeout).
Questions
A QuestionAsked event carries a QuestionPrompt with one to four questions (also in pendingQuestions). Answer them in order:
POST /questions/{questionId}
{
"answers": [
{ "chosen": ["PostgreSQL"] },
{ "chosen": [], "text": "Friday at the latest" }
]
}
chosen holds option labels (several for a question with multiple: true); text is a free answer. Send { "skipped": true } to let the bot decide. Unanswered questions count as skipped after the waiting time.
A complete exchange
# 1. Send
TURN=$(curl -s -X POST $INKBOT/api/bots/scout/messages -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" -d '{"text":"Summarize README.md"}' | jq -r .turnId)
# 2. Wait for it to finish (or listen on /api/events)
while curl -s $INKBOT/api/bots/scout -H "Authorization: Bearer $TOKEN" | jq -e '.runningTurnId' >/dev/null; do sleep 2; done
# 3. Read the reply
curl -s $INKBOT/api/bots/scout -H "Authorization: Bearer $TOKEN" | jq -r '.messages[-1].text'