Ta strona jest publikowana po angielsku i ukraińsku; poniżej wersja angielska.
Custom tools: connect your own API
For developers, in code: describing one HTTP call to your API so the assistant answers from live data — every field of a tool, how arguments are placed, the language parameter, scope, caps and the egress policy.
A custom tool is one HTTP call to your API, described once in the panel. The assistant decides when to call it from its description, fills the arguments you declared, and answers from the result. Use it for data that is too big or too fresh to index: a catalogue, an order status, a seat that was free a minute ago.
This page is the reference. To build one from the endpoint up, start with the worked example.
Custom tools are part of the Growth plan and above. On a plan without them the panel says so and the assistant does not call the ones you built.
In the panel: Tools → New tool (Tools and events). This page is the same tool field by field, as the API stores it.
The fields
| Field | What it is |
|---|---|
name |
a slug, unique per site — the name the model sees |
display_name |
the panel’s label |
enabled |
a disabled tool is not bound |
description |
when to call it. The model’s only signal: write it open-ended («search the product catalogue by a visitor’s words»), never as a closed list of values |
method |
GET or POST |
url |
with {param} path slots and {{…}} placeholders (Placeholders); https, with a host |
headers, query_params |
static values, placeholders allowed |
body_template |
a JSON skeleton for POST; placeholders substituted in nested strings, never in keys |
timeout_ms |
default 5000, capped at 10000 at run time |
parameters |
the arguments the model fills — below |
response_description |
what the response means, put in front of the body the model reads: «a list of products with a name, a price and a link» |
response_path |
a dotted path to the part of the response that matters (data.items); best-effort — on a miss the whole body is used; no list indexes |
languages, language_param, language_param_location |
which languages your API answers in and where to put the one chosen — filled by the runtime, never by the model, below |
cache_answers |
allow a repeated opening question to be served from the first-turn answer cache (off by default: a live tool’s data is fresh per call). This is not a cache of your endpoint’s response — that is Cache-Control (Response caching) |
scope, screens |
global binds on every turn; screen binds only on the screens (sources with routes or a page URL) that name it |
agent |
one agent of the site, or every agent |
emits_event |
fire an event deterministically on a non-empty result — Custom events |
Parameters
Each parameter is { name, type, description, required, location }, up to 20.
| Key | Values |
|---|---|
type |
string · number · integer · boolean · array |
location |
query (the default) · body · path · header |
required |
defaults to false. A required parameter is a hard guarantee — make the search query required, or the model may call the tool with nothing and dump the catalogue |
Where each lands: query merged onto the URL’s query string (a list becomes repeated params);
header sent as a string; body a top-level key of the JSON body; path replaces {name} in the
URL, percent-encoded. Arguments are validated against their declared types.
The language parameter
If your API answers in several languages, list them in languages and name the parameter in
language_param. The runtime fills it itself — the visitor’s language when both the site and your
API support it, else the site’s primary language — and removes it from the model’s arguments, so
the choice is never a guess. An empty languages means a monolingual API that always gets the
site’s primary. An empty 2xx result from a GET without a language parameter is retried once with
the string arguments translated into the tool’s language.
Test
The tool form’s Test runs the real call with example parameters and shows the raw response and, with a bound event, what would be emitted. It never uses the cache: a cached test would tell you an endpoint works when it may not. Rate-limited to 30 a minute per owner.
Caps
| calls per turn | 3 (the language retry counts) |
| timeout | your timeout_ms, at most 10 s; a call past it is dropped and the assistant answers without it |
| response size | 256 KB, truncated |
| concurrent calls | 8 per process |
| tools and events bound per turn | 12, by name — keep global tools few and scope the rest to screens, so a screen’s own tools always fit |
| tools per site | by plan: 6 / 8 / 11 global and 50 / 150 / 500 screen-scoped on Growth / Pro / Business |
Egress policy
Every call — model-made, proactive, Test or delivery — passes the same policy before it leaves:
- https only;
- the host is resolved at call time and every resolved address must be public: private, loopback, link-local, reserved and multicast ranges are refused, and a host that does not resolve is refused;
- no redirects are followed;
- the body is read up to the size cap.
A platform-level allowlist exists for our own hosts; it is not a per-owner setting. A stable egress IP for owners to allowlist is planned and not built: today the calls come from our servers, not from one address.
What the model sees
The model is told your response_description, then the response trimmed by response_path. A
401 or 403 from a tool that carries {{user}} is reported to the model as «the visitor appears to
be signed out». Secrets and the user token never appear in what the model reads.