> ## Documentation Index
> Fetch the complete documentation index at: https://hanabiaiinc-codex-update-api-billing-link.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Webhook Tools

> Let your agent call your HTTP endpoints in the middle of a conversation

A webhook tool lets your agent call an HTTP endpoint mid-conversation — look up an order, create a ticket, check availability — and use the response in its next reply. You declare the arguments; the agent fills them in from the conversation and the platform makes the request.

<Note>
  Tools are workspace-level resources shared across agents. Removing a tool from an agent **detaches** it — the tool stays in your workspace and remains attached to other agents. Editing a tool updates every agent that uses it, and those agents show unpublished changes until you [publish](/agents/deploy/versions-publishing).
</Note>

## Create a webhook tool

In the Builder, open **Tools** and choose **Add tool → Webhook**. A tool created from the Builder is attached to the current agent immediately; use the tool's **Access** tab to enable it for other agents.

<Steps>
  <Step title="Name and describe the tool">
    The model decides when to call a tool based on its name and description. Write the description for the model: say what the tool does and when to use it — "Look up the status of an order. Use when the caller asks where their order is."
  </Step>

  <Step title="Declare arguments">
    Each argument is a name plus a description. Arguments are exposed to the agent as tool parameters — the description tells the model what value to extract from the conversation.
  </Step>

  <Step title="Configure the request">
    Pick a method (`GET`, `POST`, `PUT`, `PATCH`, or `DELETE` — default `POST`), the endpoint URL, a content type (default `application/json`), and an optional body template.
  </Step>

  <Step title="Add headers">
    Attach authentication or any custom headers — they are sent with every webhook request.
  </Step>

  <Step title="Choose an execution mode">
    Decide whether the agent waits for the response, fires the request and moves on, or keeps talking while the request runs in the background. See [Execution modes](#execution-modes).
  </Step>

  <Step title="Set response handling">
    Choose a timeout (1–120 seconds, or up to 300 for background tools; default 30) and how errors are surfaced to the agent.
  </Step>
</Steps>

## Argument templating

Reference any declared argument with `{{name}}` — in the URL, in the body template, or both. The platform substitutes the values the agent supplies before sending the request.

```text Endpoint URL theme={null}
https://api.example.com/orders/{{order_number}}
```

```json Body template theme={null}
{
  "subject": "{{subject}}",
  "details": "{{details}}",
  "source": "voice-agent"
}
```

## Authentication headers

Each header has a kind that identifies what it carries:

| Kind   | Wire value             | Sent as                                                                        |
| ------ | ---------------------- | ------------------------------------------------------------------------------ |
| Custom | `custom`               | The header name and value you provide, e.g. `X-API-Key`                        |
| Bearer | `authorization_bearer` | An `Authorization` header — provide the full value, e.g. `Bearer <token>`      |
| Basic  | `authorization_basic`  | An `Authorization` header — provide the full value, e.g. `Basic <credentials>` |

Header values are sent exactly as you store them. The Builder's Bearer and Basic presets create the `Authorization` header with the `Bearer ` or `Basic ` prefix pre-filled — complete the value with your credential.

<Warning>
  Bearer and Basic authorization values are write-only. The API accepts them on create and update but never echoes them when you read the tool back: credential headers return `value: null`, with `has_secret: true` confirming a secret is stored. To rotate a secret, submit a new value.
</Warning>

## Execution modes

`execution_mode` decides whether the agent waits for your endpoint (default `blocking`):

| Mode              | The agent                              | Your endpoint's response                                    |
| ----------------- | -------------------------------------- | ----------------------------------------------------------- |
| `blocking`        | Waits for the response before replying | Used in the agent's next reply                              |
| `fire_and_forget` | Continues immediately                  | Discarded — recorded in the tool-call history, never spoken |
| `background`      | Keeps talking while the request runs   | Announced at the next natural pause once it arrives         |

**Blocking** is right when the answer drives the conversation — an order lookup the caller is waiting on. Keep those endpoints fast: the caller hears silence while your backend works.

**Fire and forget** fits actions that need no spoken confirmation from your backend: recording a consent, logging an outcome to your CRM. The agent tells the model the request was dispatched and moves on. Failures appear only in the conversation's tool-call history — the agent is never told, so `error_handling` has no spoken effect in this mode.

**Background** fits slow work that would otherwise stall the call: aggregating a shipment status across carriers, generating a report, confirming a payment. The agent acknowledges that the request is running and continues the conversation; when the response arrives, it works the result into the conversation at the next natural pause. The model is explicitly told not to guess the result before it arrives. Failures are delivered the same way, shaped by `error_handling`.

```json Mark a tool as background theme={null}
{ "execution_mode": "background", "timeout_seconds": 180 }
```

A few things to know about background calls:

* Up to **10 background calls** can be in flight per conversation. Further calls fail immediately with an error the agent can react to ("let me finish checking the first thing you asked about").
* When the conversation ends, in-flight background calls are cancelled; the attempt stays visible in the conversation's tool-call history.
* In text-only runs — [agent tests](/agents/test/agent-tests), for example — every webhook tool executes as `blocking`, so results always appear in the transcript in order.

Client tools have their own lighter-weight equivalent: the [`expects_response` switch](/agents/build/client-tools), which makes a client tool fire-and-forget.

## Timeouts and error handling

`timeout_seconds` caps how long the platform waits for your endpoint: 1–120 seconds, default 30. Background tools may go up to 300 seconds — they don't hold up the conversation while they run. Voice conversations happen live — for blocking tools especially, keep endpoints fast and lower the timeout so a slow backend can't stall the call.

`error_handling` controls what the agent learns when a call fails (default `passthrough`):

| Option        | What the agent sees                                                                                     |
| ------------- | ------------------------------------------------------------------------------------------------------- |
| `passthrough` | The error response, so the agent can react to it in conversation ("I couldn't find that order number"). |
| `hide`        | Only that the call failed — no error details reach the agent.                                           |

Use `hide` when error responses might leak internal details you don't want spoken aloud. Under `fire_and_forget` the agent never learns about failures at all, whichever option is set.

## Mock responses

A tool can store mock responses — canned payloads, each with a `name`, a `status_code` (100–599), a `content_type`, and a `body`. Mocks are saved with the tool's configuration for test scenarios, but they don't intercept anything yet: preview and live calls always hit the real endpoint.

## Test your tool

The tool editor's **Test** tab fires a real request at your endpoint. Fill in the arguments as JSON (pre-filled with a sample based on your declared arguments) and send — you get back the status code, latency, response headers, and response body. A failing test never blocks saving the tool.

Response bodies are captured up to 64 KB; larger bodies are cut off and flagged with `response_truncated`.

## Create tools via the API

`POST /v1/agent/tools` creates a tool in your workspace. Tools created this way are not attached to any agent — enable them per agent afterwards.

```bash Create a webhook tool theme={null}
curl --request POST https://api.fish.audio/v1/agent/tools \
  --header "Authorization: Bearer $FISH_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "tool_type": "webhook",
    "name": "create_ticket",
    "description": "Open a support ticket. Use when the issue cannot be resolved in conversation.",
    "arguments": [
      { "name": "subject", "description": "One-line summary of the issue." },
      { "name": "details", "description": "Full description of the problem." }
    ],
    "method": "POST",
    "url": "https://api.example.com/tickets",
    "content_type": "application/json",
    "body_template": "{ \"subject\": \"{{subject}}\", \"details\": \"{{details}}\" }",
    "headers": [
      { "name": "X-API-Key", "value": "YOUR_API_KEY", "kind": "custom" }
    ],
    "timeout_seconds": 30,
    "error_handling": "passthrough"
  }'
```

## Escalate to a ticket mid-call

When the agent can't resolve an issue, the strongest close is a ticket opened while the caller is still on the line, with the ticket number read back aloud. The `create_ticket` tool above is the entire integration — what makes it work is the prompt around it and the response your endpoint returns.

**Set the escalation policy in the prompt.** The tool description says what the tool does; the [system prompt](/agents/build/configuration) says when escalating is the right move:

```text System prompt excerpt theme={null}
If you cannot resolve the caller's issue, offer to open a support ticket.
Confirm they agree before calling create_ticket. Write a one-line subject and
put what the caller reported and what you already tried into the details.
After the tool returns, read the ticket number back and say when to expect a
reply.
```

**Return something worth saying.** With `error_handling: passthrough` (the default), the agent sees your response body and uses it in its next reply — so respond with what the caller should hear:

```json Endpoint response theme={null}
{ "ticket_id": "T-1042", "expected_reply": "within 24 hours" }
```

Ticket numbers get spoken aloud: short, pronounceable IDs survive text-to-speech far better than UUIDs.

<Note>
  An in-call ticket depends on the model choosing to escalate. For a safety net
  that catches every unresolved call — including those where the agent never
  called the tool — pair this with [auto-ticketing from post-call
  analysis](/agents/monitor/webhooks#auto-ticket-unresolved-calls).
</Note>

## Limits

| Field                       | Limit                                                                                                                                                                                                                                 |
| --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name`                      | 1–120 characters. Display text — the model-facing function name is derived from it. [Client tool names](/agents/build/client-tools#naming-rules) are stricter: a 64-character pattern, since the SDK registers handlers by exact name |
| `description`               | up to 2,000 characters                                                                                                                                                                                                                |
| Argument `name`             | 1–64 characters                                                                                                                                                                                                                       |
| Argument `description`      | up to 500 characters                                                                                                                                                                                                                  |
| `url`                       | up to 4,000 characters                                                                                                                                                                                                                |
| `body_template`             | up to 100,000 characters                                                                                                                                                                                                              |
| Mock response `body`        | up to 100,000 characters                                                                                                                                                                                                              |
| Mock response `status_code` | 100–599                                                                                                                                                                                                                               |
| `timeout_seconds`           | 1–120 seconds (background tools: 1–300), default 30                                                                                                                                                                                   |
| `execution_mode`            | `blocking` (default), `fire_and_forget`, or `background`; webhook tools only                                                                                                                                                          |
| Background calls in flight  | 10 per conversation                                                                                                                                                                                                                   |
| Test response capture       | first 64 KB (`response_truncated` set beyond that)                                                                                                                                                                                    |

### URL restrictions

Endpoint URLs must use `http` or `https`. Requests to localhost, private network ranges, and cloud metadata endpoints are rejected, and URLs may not embed credentials. The Builder validates the URL as you type; the API enforces the same rules.

## Going further

<CardGroup cols={2}>
  <Card title="Client tools" icon="browser" href="/agents/build/client-tools">
    Run tool calls in your own app instead of over HTTP.
  </Card>

  <Card title="System tools" icon="gears" href="/agents/build/system-tools">
    Built-in capabilities you toggle per agent.
  </Card>

  <Card title="Preview calls" icon="phone" href="/agents/test/preview-calls">
    Talk to your agent and watch tool calls fire.
  </Card>

  <Card title="Agent tests" icon="vial" href="/agents/test/agent-tests">
    Assert on agent behavior, tools included.
  </Card>
</CardGroup>
