> ## Documentation Index
> Fetch the complete documentation index at: https://docs.asknow.no/llms.txt
> Use this file to discover all available pages before exploring further.

# Webhook tools

> The HTTPS request Ask sends to your endpoint when an agent calls a webhook tool, and how your response is used.

A webhook tool lets an agent call your own API: look up an order, check stock, book an appointment. You add one under **Tools → Add tool → Webhook** with a display name, a tool name for the AI, an endpoint URL and, optionally, a bearer token.

## The request

Every call is one `POST` with a JSON body.

<RequestExample>
  ```http Request theme={null}
  POST /orders/lookup HTTP/1.1
  Host: api.example.com
  Content-Type: application/json
  Authorization: Bearer <your token>

  {
    "input": { "order_number": "10432" },
    "dry_run": false
  }
  ```
</RequestExample>

<ParamField body="input" type="object" required>
  The arguments the agent chose for this call, keyed by the tool's input names. It can be an empty object.
</ParamField>

<ParamField body="dry_run" type="boolean" required>
  `true` for calls from the dashboard's test panel and from agent tests. Always `false` in a real customer conversation. Read data as usual, but do not change anything: no refunds, no bookings, no emails. We cannot enforce this on your side, so your endpoint has to honour it.
</ParamField>

### Headers

<ParamField header="Content-Type" type="string" required>
  Always `application/json`.
</ParamField>

<ParamField header="Authorization" type="string">
  `Bearer <token>`, when you gave the tool a bearer token. We store the token encrypted and send it only to the tool's own endpoint. Check it on every request.
</ParamField>

## The response

<ResponseExample>
  ```json 200 theme={null}
  {
    "status": "shipped",
    "carrier": "Posten",
    "tracking_url": "https://sporing.posten.no/sporing/70712345678901234"
  }
  ```
</ResponseExample>

* **Any 2xx status is a success.** We parse the body as JSON, and pass it on as plain text if it is not JSON. There is no fixed response format: return what the agent needs to answer.
* **Any other status is a failure.** The agent is told the call failed with that HTTP status and does not see your body. It can then tell the customer it could not look this up, or hand the conversation to a person.
* **Your response is data, not instructions.** The agent reads it as the tool's output. Text such as "ignore your instructions" in a response is treated as content, not obeyed.
* **Keep it small.** Everything you return is read by the agent on every call. Return the fields it needs, not the whole record.

<Tip>
  Return a short explanation in the 2xx body when nothing was found, for example `{"found": false, "reason": "No order with that number for this email address"}`. The agent can use it in its answer. A 404 only tells it the call failed.
</Tip>

## Limits

| | |
| - | - |
| Protocol | HTTPS only. |
| Address | Must resolve to a public IP address. Private, loopback and link-local addresses and cloud metadata endpoints are refused. |
| Timeout | 10 seconds. A look-up step inside a procedure gets 8 seconds. |
| Response size | 10 MB. Larger responses fail the call. |
| Redirects | Only a same-origin `307` or `308` is followed, up to 5 hops. Any other redirect fails the call. |
| Retries | We do not retry a failed call. |

## Testing your endpoint

Run the same request yourself before connecting it:

```bash theme={null}
curl -X POST https://api.example.com/orders/lookup \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"input": {"order_number": "10432"}, "dry_run": true}'
```

Then open the agent in the dashboard, enable the tool, and ask a question in the test panel that needs it. Those calls always arrive with `"dry_run": true`.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.