Custom tools
Does your system have an API? We connect to it. No API? Write a small webhook — we connect to that too. Custom tools let the agent call your own systems, e.g. “live stock level and next delivery date for a SKU”.
Manage them under Settings → Integrations → Custom tools.
Two kinds
Section titled “Two kinds”| Kind | How it works | Best when |
|---|---|---|
| Webhook | We POST a signed envelope to your HTTPS endpoint and you answer it. | You can write a small endpoint. |
| HTTP | We call your site’s existing search or API in its own shape. No signature. | The API already exists. |
Define a tool
Section titled “Define a tool”- Give it a name and a clear description — the agent decides when to call the tool from the description.
- Describe its inputs as a JSON Schema (the parameters).
- For a webhook: your HTTPS endpoint. For HTTP: the request template.
- Set a timeout (default 10 seconds).
- Optionally turn on Ask a person before running — the call then waits as an approval card in Conversations.
- Run a test call. A tool cannot go live until one real call to your endpoint has succeeded — the agent must not be its first caller.
Webhook request
Section titled “Webhook request”POST https://your-endpoint.example.com/toolsContent-Type: application/jsonX-Fluxy-Signature: t=1760000000,v1=5f2b…
{ "tool_call_id": "9c1e…", "tool": "stock_level", "arguments": { "sku": "SH-42-WHT" }, "conversation_id": "c0ffee…"}Answer with JSON; the agent reads your response.
Verify the signature
Section titled “Verify the signature”The header carries the timestamp it was signed with. Recompute the HMAC-SHA256 with your tool secret over <t>.<raw body> and reject anything older than five minutes.
import crypto from 'node:crypto';
function verify(rawBody, header, secret) { const { t, v1 } = Object.fromEntries(header.split(',').map((p) => p.split('='))); if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false; const expected = crypto.createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex'); return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1));}Retries
Section titled “Retries”Every call carries a stable tool_call_id; a retry reuses it, so treat a repeated id as the same call (idempotent handling).
| When | What we do | What you do |
|---|---|---|
| Timeout (10 s by default) | Retry twice, same tool_call_id | Answer faster |
| 5xx from your endpoint | Retry with backoff, same tool_call_id | Make handling safe to repeat |
| 4xx from your endpoint | No retry | The agent is told the call failed and says so plainly |
| Webhook answers with more than 1 MB | No retry | Return a smaller response |
The address is not a public https:// address | No retry — the call is not made | Use a public HTTPS endpoint |
When a call can’t be completed, the agent does not claim it was done: it tells the customer it couldn’t be done right now and offers a human follow-up.
Limits
Section titled “Limits”- Every address must be a public
https://address. Addresses on a private or internal network are refused. - Webhook: redirects are not followed; we read up to 1 MB of your response.
- HTTP: up to 5 redirects are followed, and each step must also be a public HTTPS address; we read up to 5 MB of the response.