Assistant tools
In the middle of a conversation, DoneTalk's AI assistant can look up or change data in your system: an order's status, a customer's account, an e-mail to change. It calls an address of yours, gets a short text back and answers the contact with that fact.
The company builds the tool in Settings › Tools: the connection (address and secret), the path, the fields the AI must find out, and whether the tool only reads or changes data. This page is for whoever builds the address that receives the call.
What arrives
POST /your-path HTTP/1.1
Content-Type: application/json
User-Agent: DoneTalk-Tools/1.0 (+https://donetalk.com/desenvolvedores)
DoneTalk-Signature: t=1792756800,v1=5f0c…{
"tool": "order_status",
"contact": { "phone": "+5511999990000", "name": "Camila", "fields": {} },
"conversation": { "id": "01a3e4f5-…", "test": false },
"assistant": { "id": "01a0c0de-…", "name": "Amanda" },
"input": { "number": "77" },
"test": false,
"sentAt": "2026-10-24T12:00:00.000Z"
}contact.phoneis the conversation's number, set by DoneTalk and covered by the signature. Use only it to find the account. The AI never chooses whose account it is; what it sends is ininput.inputcarries the fields the tool declares, already typed (text, number, yes/no, list, date).contact.fieldscarries only the contact fields the company ticked on the tool.confirmedcomes with tools that change data and ask first:falseasks only for a description of the change;truemakes it.test: truecomes from tests ("Test now" and the assistant's "Test"): change nothing.
The signature
The same as the webhooks': t is the time in seconds and v1 is the HMAC-SHA256, in hex, of t + "." + body, with the connection's secret. Refuse calls older than 5 minutes.
import { createHmac, timingSafeEqual } from "node:crypto";
function verify(header, rawBody, secret) {
const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
const age = Math.abs(Date.now() / 1000 - Number(parts.t));
const expected = createHmac("sha256", secret).update(`${parts.t}.${rawBody}`).digest("hex");
return age < 300 && timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1 ?? ""));
}A connection also takes a token (Authorization: Bearer), a key in a header of yours, or the Copiloto-format signature (X-Copiloto-Timestamp and X-Copiloto-Signature), for systems built for its external lookup.
What to answer
200 with JSON:
{
"ok": true,
"text": "Order 77 left for delivery today at 2 pm.",
"data": { "status": "shipped" }
}textis the only thing the AI reads: plain language, no markdown, up to 1,500 characters. Say the fact and the contact's next step.ok: falsewithtextalso reaches the AI as a fact ("No order found for this phone").datais optional and only kept in the call history.- Any other answer (another status, no
text, over 64 KB, over 8 seconds by default) becomes "unavailable now": the AI goes on without the data.
Tools that change data
The company chooses, per tool, how to confirm:
| Choice | What your system receives |
|---|---|
| Confirm with the contact | With "the system describes the change first": first confirmed: false (answer what would change, without changing it), then confirmed: true, with the same data, only after the contact agreed. Without it, only the call with confirmed: true. |
| A person approves | One call with confirmed: true, when someone from the team approves. |
| No confirmation | The call as soon as the AI decides. |
Limits
- Up to 5 calls of the same tool per conversation per hour.
- Public
httpsaddresses only; redirects are not followed. - A tool with the
GETmethod sends the call in the address'scallparameter instead of a body; the signature covers that parameter's value.
Any API
If your system already has an API, a tool can call it without this format: the company builds the path, headers and body with {{contact.phone}}, {{contact.name}}, {{input.field}} and {{conversation.id}}, and chooses what the AI reads: the whole answer, one field (data.status) or a sentence built from it.