Agents
Webhook tools
Give an agent one HTTP endpoint of your own to call mid-conversation, with the parameters the model fills in and the credentials the portal injects.
A webhook tool is one HTTP endpoint of yours, described once and handed to the agent. You give it a name, a description the agent reads, a URL and a list of parameters. When the agent decides to call it, the request arrives at your endpoint with your credentials already on it, and the agent reads your reply and keeps talking. The builder puts it in a line: "A server tool lets the agent call an external API mid-conversation."
When to use this kind
- One endpoint with a handful of parameters, where you want to write the request yourself. That is a webhook tool.
- A whole API with many operations. Import the document instead as an OpenAPI tool, rather than hand building one webhook tool per operation.
- An action inside a product you have already connected, such as posting a Slack reaction or creating a calendar event. Use an integration tool, which takes its operation and its credentials from the integration.
Webhook tools live in the workspace tool library and are given to an agent by selection, the same way every workspace tool is. See Tools overview for the difference between the library and a per-agent selection.
What you need
- A public endpoint reachable over HTTPS. Loopback, private and link-local addresses are rejected, so a service on your own network will not work.
- Membership of the workspace. Creating a tool needs no further permission.
- Any credential the endpoint requires, saved first as a secret or an auth connection.
Define
Open an agent, go to the Tools tab and press Add Tool, then the Webhook tab of the dialog. The same dialog is on the Tool Library page. Editing an existing tool opens a wider sheet titled Edit tool, which carries two controls the create dialog does not: body parameters and a per-parameter Required toggle.
Name
Required, and unique in the workspace. The placeholder suggests the shape the agent
works best with, e.g. lookup_order. Leading and trailing spaces are trimmed. A
name already taken is refused with
A tool named "<name>" already exists in this workspace.
Description
This is the text the agent reads to decide whether to call the tool, which is why the box prompts with "What does this tool do? The agent uses this to decide when to call it." The Add Tool dialog caps it at 500 characters and shows a counter. Write the cases you want the tool used for, not a restatement of the name.
Method
One of GET, POST, PUT, PATCH, DELETE. It is kept in upper case whatever
you type.
URL
Required, and it must be a public HTTPS URL. Path parameters appear as {curly}
placeholders, as the hint says: "A public https URL. Wrap path parameters in curly
braces." A URL that fails the check is rejected with
url must be a public HTTPS URL (no loopback, private, or link-local addresses).
Placeholders and path parameters have to line up exactly, in both directions. A
placeholder with no parameter behind it fails with
URL placeholder {orderId} has no matching path parameter, and a path parameter
that never appears in the URL fails with
Path parameter "orderId" does not appear in the URL.
Timeout [ms]
Optional. The field starts at 10000. Leave it empty and the call still gives up
after 10000 ms. Anything above 30000 ms is brought down to 30000 ms when the call is
made.
Parameters
Parameters are grouped by where they land on the request. The Add Tool dialog offers three groups:
| Group | What it does |
|---|---|
| Headers | Sent as HTTP headers. The only group that may hold a secret |
| Path parameters | Bound to a {placeholder} in the URL path, URL encoded |
| Query parameters | Appended to the URL as ?key=value |
The Edit tool sheet adds a fourth, Body parameters, described there as
"Fields sent in the JSON request body (POST/PUT/PATCH only)". Adding one under GET
or DELETE is refused with GET requests cannot have body parameters.
Each parameter carries:
| Field | Values | Notes |
|---|---|---|
| Name | Any non-empty string | Blank fails with Parameter name is required |
| Value | AI generated, Constant, Secret | Secret appears on header rows only |
| Data type | String, Number, Boolean | Decides how the value is coerced and what the agent is asked for |
| Description | Free text | The agent reads this for AI generated values |
| Required | On or off | Only on the Edit tool sheet. New rows in the Add Tool dialog are created required |
Two parameters with the same name in the same group are refused with
Duplicate query parameter "locale". A constant with no value is refused with
Constant parameter "locale" needs a value. A secret outside the headers group is
refused with Secret parameter "X-Api-Key" is only allowed in headers, and one with
no secret chosen with Secret parameter "X-Api-Key" needs a secretId.
An empty value is dropped rather than sent: a parameter whose value comes out
undefined, null or an empty string is skipped, so the placeholder stays in the
URL and the key never appears in the query string or the body.
Get it right
Two pieces of text decide whether this tool works: the description the agent reads, and the reply your endpoint sends back.
The description has to say when to call the tool and what comes back, because it is all the agent gets.
Recommended
Look up a customer's order by its order number. Call this when the caller asks
where an order is, when it will arrive, or what it contained. Returns the status,
the carrier and the expected delivery date.Less effective
Order lookup. Calls the orders API.Your reply is read out loud in a conversation, so return the few fields the agent needs and name them plainly. A full record dump makes the agent slower and can push the response past the 256 KB ceiling.
Recommended
{ "status": "shipped", "carrier": "Aramex", "expectedDelivery": "2026-09-18" }Less effective
{ "ok": true, "data": { "order": { "id": 4512, "lines": [], "customer": {}, "audit": [] } } }Auth
Authentication is a separate step from parameters, and there are two routes.
Auth connection. Pick one saved workspace connection under Auth connection,
or leave it at No authentication. Four kinds exist: basic, bearer, OAuth2 client
credentials and OAuth2 JWT. All four arrive as an Authorization header, so the
endpoint sees Basic … or Bearer …. The connection's header wins any header
parameter of the same name, because auth is written last. A connection that no
longer exists in the workspace is refused at save with
Referenced credential not found.
Secret header parameter. Add a header parameter, set its Value to Secret
and choose a workspace secret. The value is read when the call is made, never kept
on the tool and never shown to the agent. A secret that no longer exists is refused
at save with Referenced secret not found. If a secret cannot be read when the call
is made, the header is left out and the request still goes out.
When an OAuth2 connection is in play and your endpoint answers 401, EchoNova
fetches a fresh token and sends the request once more. That retry happens for 401
only, and only once.
Requests to your endpoint carry no EchoNova signature and no shared secret unless you add one yourself. Treat the endpoint as publicly reachable: require a credential through an auth connection or a secret header parameter, and reject every call that does not carry it.
The request your endpoint receives
Take a tool with method POST, URL https://api.example.com/orders/{orderId}, a
path parameter orderId filled by the agent, a constant query parameter locale, a
secret header X-Api-Key and a body parameter reason filled by the agent. The
request that arrives looks like this:
POST /orders/4512?locale=en HTTP/1.1
Host: api.example.com
X-Api-Key: <value of the workspace secret>
Content-Type: application/json
{"reason":"caller asked for a refund"}Three things are worth reading off that request. Content-Type: application/json is
set only when the method allows a body and at least one body parameter came out with
a value, and it never overwrites a Content-Type header you defined yourself. Path
values are URL encoded. Redirects are not followed, so a 301 or 302 comes back
as that status rather than as the page behind it.
Replay the same request from your own machine to confirm the endpoint, the credential and the response shape before you give the tool to an agent.
curl -X POST "https://api.example.com/orders/4512?locale=en" \
-H "X-Api-Key: $MY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"reason":"caller asked for a refund"}'import os
import requests
response = requests.post(
"https://api.example.com/orders/4512",
params={"locale": "en"},
headers={"X-Api-Key": os.environ["MY_API_KEY"]},
json={"reason": "caller asked for a refund"},
timeout=10,
)
print(response.status_code, response.text[:500])const response = await fetch('https://api.example.com/orders/4512?locale=en', {
method: 'POST',
headers: {
'X-Api-Key': process.env.MY_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({ reason: 'caller asked for a refund' }),
});
console.log(response.status, (await response.text()).slice(0, 500));What the agent sees
The agent receives the tool's name, its description and a JSON schema built from the parameters whose Value is AI generated. Constants and secrets are left out of that schema entirely, so the agent cannot see them, cannot change them and cannot be talked into revealing them. A tool with no AI generated parameter reaches the agent with no parameters at all, which the builder states plainly: "No parameters. The agent will call the endpoint as-is."
Each schema property carries the parameter's data type and, when you wrote one, its Description, which is the sentence the agent uses to work out what to put there. Parameters marked required are listed as required.
A selected webhook tool is in front of the agent on every turn. Nothing is searched and nothing is ranked, so when a webhook tool never fires, the description is where to look.
Your reply comes back to the agent as a status, an ok flag and a body. A body is
read as JSON when your response carries application/json, and passed through as
text otherwise.
Check it before a caller does
A webhook tool has no run button in the portal, and it does not appear in the retrieval bench, which searches imported OpenAPI operations and database questions only. Verify one in two moves:
- Replay the request yourself with the tabs above, to confirm the endpoint, the credential and the response shape.
- Talk to the agent in the playground and say the thing that should trigger the call. See Test your agent.
Limits
| Limit | Value | Applies to |
|---|---|---|
| Request timeout | 10000 ms by default, 30000 ms maximum | Every call to your endpoint |
| Response size | 256 KB | Declared sizes above it are refused, larger bodies are truncated |
| Redirects | Not followed | Returned as the redirect status |
| URL scheme | HTTPS only, public hosts only | Save time and call time |
| Secret parameters | Header group only | Save time |
| Body parameters | POST, PUT, PATCH only |
Save time |
| Description | 500 characters | The Add Tool dialog's box |
| Tool name | Unique inside the workspace | Create and rename |
Troubleshooting
The agent never calls the tool
The tool is in front of the agent on every turn, so this is a wording problem. Check that the tool is selected on this agent, then rewrite the Description to name the situations you want it used in. Do the same for each parameter's Description, which is the only hint the agent gets about what a value should contain.
The call fails with "Tool request failed or timed out"
Your endpoint did not answer inside the timeout, or the connection failed. Raise Timeout [ms], up to the 30000 ms ceiling, and confirm the host resolves publicly over HTTPS.
The call fails with "Tool response too large"
Your endpoint declared a response above 256 KB. Return a smaller payload: the agent has to read the result inside a conversation, so a trimmed object beats a full record.
Your endpoint sees no credential
Either no auth connection is picked, or the secret behind a header parameter could not be read. An unreadable secret is left out and the request still goes out, so the symptom is a missing header rather than a failed call. Re-pick the secret on the parameter and save.
A path placeholder is still in the URL
The value for that parameter came through empty, and an empty value is skipped,
which leaves its {placeholder} untouched. Mark the parameter required so the agent
has to fill it.
FAQ
Can the agent choose the URL?
No. The URL, the method and the placement of every parameter are fixed on the tool. The agent only fills the values of parameters set to AI generated.
What does my endpoint see the call coming from?
An ordinary HTTPS request from EchoNova, carrying only the parameters and credentials you configured. Nothing on it identifies the caller or the conversation, and nothing signs it, so your own credential check is the whole access control.
Is this the same as a developer webhook?
No, and the names are the one confusing thing here. A webhook tool is an outbound call the agent makes to your API during a conversation. A developer webhook is an inbound delivery EchoNova sends you when a platform event happens. See Configure a webhook for that one.
What happens when I delete the tool?
It is removed from the library and unselected from every agent that used it. The portal states it before you confirm: "This deletes the tool and its associated secret data, and deselects it from every agent that uses it. This action cannot be undone." Auth connections are reusable and are not deleted with the tool.
Can I point a tool at a service inside my network?
No. The host must be public. Loopback, private ranges, link-local addresses and carrier-grade NAT ranges are all blocked, on IPv4 and IPv6, at save time and again at call time.
Does removing a tool from one agent affect the others?
No. Removing it changes that agent's selection only. The library row and every other agent stay as they are.
Related
- OpenAPI tools: import a whole API instead of one endpoint at a time
- Workspace secrets: store the API key this tool sends
- Auth connections: basic, bearer and OAuth2 credentials
- Test your agent: trigger the call in the playground
- Tools overview: how the four kinds differ
- Configure a webhook: the inbound kind, which is a different feature