# Tools

> Let an agent call your API mid-call to look up an account, open a ticket or check availability.

Source: https://docs.vlayers.ai/build/tools

Kind: How-to guide

## What you'll learn

How to register an HTTP tool, call it from a flow, and turn its answer into values the agent can speak. A tool is an HTTP endpoint your agent calls during the conversation. It is how an agent stops guessing and starts knowing.

## Two ways to call an API

| Way | How | When |
|---|---|---|
| **A registered tool** (recommended) | Define it once under **Tools**, then pick it by name in any flow. The URL, headers and credentials live on the server; the flow only names the tool. | Anything you use more than once. Change the endpoint in one place and every agent follows. |
| **Inline on a step** | Set the URL directly on a **Call an API** step. | A one-off, or while you try something out. The setup lives in that one flow. |

## Prerequisites

- An HTTPS endpoint that answers quickly with a small JSON object.
- If it needs a key: the key saved as a connection under **Dashboard → Settings → Provider accounts**.

## Step 1: Save your API key as a connection

Under **Settings → Provider accounts**, save the key as a connection. It is encrypted and attached on the server for each call; tools and flows only hold a reference to it.

By default the key is sent as `Authorization: Bearer <key>`. If your API reads another header, name it on the connection (for example `X-API-Key`).

## Step 2: Register the tool

Open **Dashboard → Tools → New HTTP tool** and fill in the fields:

```text
Name          lookup_order          # snake_case name the agent refers to
Method        GET
URL template  https://api.example.com/orders/{{ order_id }}
Allowed hosts api.example.com       # the only hosts this tool may reach
Sign in with  Orders API key        # the connection from step 1
Headers       { "accept": "application/json" }   # never a key or token
Inputs        [{ "name": "order_id", "type": "string", "required": true }]
Body template { "id": "{{ order_id }}" }   # POST, PUT and PATCH only
Timeout       8000
```

**Inputs** fill themselves from [variables](https://docs.vlayers.ai/build/variables) of the same name. Capture `order_id` with an **Ask** step, and a tool that declares an `order_id` input gets it with no wiring.

**Allowed hosts** are required on purpose. A tool may only reach the hosts you list, checked again after the URL is built, so a variable cannot redirect the call somewhere else. Calls are made from the server, so your credentials never reach the agent or the caller.

> **Warning:** Never put a key in a header value or in the URL. A header that looks secret is masked and flagged in the flow builder, and URLs end up in logs. Use **Sign in with** instead.

## Step 3: Call it from a flow

Add a **Call an API** step and pick the tool. The step has two exits, **Success** and **Failure**. Connect both: an API that is down should get a human sentence, not dead air.

## Step 4: Save fields from the answer

On the step, use **Save outputs to variables**, one `name = path` per line:

```text
Response:
{
  "ok": true,
  "customer": { "name": "Jane Doe", "plan": "pro" },
  "eta": "Thursday"
}

Save outputs to variables:
  customer_name = customer.name
  eta           = eta
```

Later steps use `{{ customer_name }}` directly.

## Test it

Tools run in a [dry run](https://docs.vlayers.ai/build/testing) exactly as they do on a call, so you can prove an integration over text before dialling. The call detail shows each tool call and what it saved.

## Common problems

| Problem | Fix |
|---|---|
| The agent says it worked, but it did not | Your API answered 200 with an error inside. Answer with a non-2xx status so the step takes the **Failure** exit. |
| Long silence while the tool runs | Answer in under a second. The timeout is for the bad day, not the normal one. |
| The agent reads out raw data | Return speakable values: "arriving Thursday", not a timestamp. Whatever you return may be read aloud. |
| A retry opened two tickets | Make create calls idempotent. |
| The step fails with `url_placeholder_empty` | A placeholder in the URL path had no value, so the tool was not called. Capture the value first. |

## Next steps

- [Variables](https://docs.vlayers.ai/build/variables): Where tool inputs come from, and how outputs are stored.
- [Playbooks](https://docs.vlayers.ai/build/playbooks): Let a goal-driven step call tools when it needs to.
