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

# Tools overview

A tool is a function the agent can call **mid-conversation**. The caller asks for something. The model decides it needs help, calls the tool, waits for the answer, and speaks it. You describe the tool. We wire the call.

Tools do two jobs. They **fetch information** the agent doesn't have, like an order's status. And they **take an action** live, like booking a slot or opening a ticket.

**Anti-pattern.** If the information is known before the call and won't change during it, don't make it a tool. Pass it in with the call as [variables](/voice-agents/personalization/variables) or [additional instructions](/voice-agents/personalization/per-call-instructions), and the agent has it in the prompt from the first word, with no round trip while the caller waits.

Every tool is the same three things: a **name**, a **description**, and a **JSON schema** for the arguments. The description does the heavy lifting. The model picks the tool from that text alone, so write it like an instruction to a new hire.

```json theme={null}
{
  "name": "get_order_status",
  "description": "Look up an order by its number. Call this when the caller asks where their order is.",
  "parameters": {
    "type": "object",
    "properties": {
      "orderNumber": { "type": "string", "description": "The order number the caller read out" }
    },
    "required": ["orderNumber"]
  }
}
```

This shape is the same everywhere: [`config.agent.tools`](/api-reference/assistants/create-an-assistant#body-config-agent-tools) on the API, the tool picker in the studio, and the tools a campaign goal ships with. What differs is **where the tool runs**.

## Three places a tool can run

```mermaid theme={null}
flowchart LR
    Agent["Agent"]
    Client["Your app<br/>web page or mobile"]
    Server["Your server"]
    Uplift["Uplift AI runtime"]
    Agent -->|"client tool<br/>RPC over the session"| Client
    Agent -->|"webhook tool<br/>signed POST from us"| Server
    Agent -->|"system tool<br/>we run it"| Uplift
```

* **[Client tools](/voice-agents/tools/client-tools)** run on the caller's device, in your web page or mobile app. The agent sends an RPC to your app with the tool name as the method. Your code handles it and returns JSON. Use them when the tool needs what's on screen: open a page, fill a form, add to cart, highlight a product. A phone call has no app on the other end, so these are web sessions only.
* **[Webhook tools](/voice-agents/tools/webhook-tools)** run on your server. We POST `{ "tool": ..., "args": ... }` to your HTTPS endpoint, signed exactly like [event webhooks](/voice-agents/webhooks/overview#verifying-the-signature), and you answer with JSON in the same request. Use them for anything that lives in your systems: order status, account balance, stock, a new ticket.
* **[System tools](#what-ships-with-a-campaign-goal)** run on us. No code from you, and nothing to pick. We add them to a campaign as its goal needs them: booking, address checks, outcome capture.

## What ships with a campaign goal

You don't wire system tools up yourself. Pick a [campaign goal](/voice-agents/campaigns/goals-and-scorecards) and we add the tools that goal needs. Appointment and order confirmation goals also get a call procedure that drives them. What they can do today:

* **Check a calendar and book a slot.** Reads free slots from your Google Calendar, offers a few, and books the one the caller picks. Comes with the appointment goal and a Google Calendar connection.
* **Validate a delivery address.** Checks a spoken Pakistani address for deliverability and returns it normalized, or the one question to ask when something is missing. Comes with the order confirmation goal.
* **Record the outcome.** Logs what happened in a fixed shape, like `record_order_confirmation` with one of six statuses such as `confirmed`, `cancelled` or `address_incomplete`. The post-call pipeline starts from that record when it extracts the [conversion](/voice-agents/campaigns/results), then checks it against the transcript and throws out a "confirmed" the caller never said. Comes with every goal, one logger each.
* **[End the call.](/voice-agents/tools/system/end-call)** After the goodbye, with a short reason recorded. Comes with every assistant, always on.
* **Hang up on voicemail.** Hears the answering machine, marks the call and hangs up. When unsure, assumes a human. Comes with every outbound call, and the model never calls it.

## Which one to use

|             | Client tool              | Webhook tool                  |
| ----------- | ------------------------ | ----------------------------- |
| Runs        | on the caller's device   | on your server                |
| Channels    | web sessions only        | phone and web                 |
| You write   | a handler in your app    | an HTTPS endpoint             |
| Time budget | 10 seconds, configurable | 10 seconds                    |
| Best for    | driving the UI           | reading and writing your data |

The rule of thumb: if the agent needs **your data** or has to **act** in your systems, that's a webhook tool. If it needs **your screen**, that's a client tool. Most phone deployments need neither. A goal's system tools and a good prompt are enough. I recommend launching with no custom tools at all, reading the transcripts, and adding a webhook tool when the agent gets asked something the prompt can't answer, like where an order is.

## While the tool runs

```mermaid theme={null}
sequenceDiagram
    participant Caller
    participant Agent
    participant Tool as Your endpoint
    Caller->>Agent: "Where is my order?"
    Note over Agent: model picks get_order_status
    Agent->>Tool: { "tool": "get_order_status", "args": { "orderNumber": "4471" } }
    Note over Caller,Agent: the caller waits. Silence, or room tone and<br/>a typing sound if background noise is on
    Tool-->>Agent: { "status": "shipped", "eta": "Thursday" }
    Agent->>Caller: "It has shipped, it will reach you Thursday"
    Note over Agent: on timeout or failure the model gets<br/>an error result and keeps talking
```

* **The result is what the agent hears.** Return short, speakable JSON. A stack trace becomes a very odd sentence.
* **Say you're checking.** Put it in the prompt. The order confirmation procedure already does: "order pe address likha hai, main system mein check kar leti hoon".
* **A slow tool never drops the call.** Plan for it in the prompt: "if the lookup fails, offer a callback".
* **Every tool call is on the record.** Arguments and result are on the [session detail](/api-reference/sessions-%26-call-records/get-a-calls-transcript-and-outcomes) afterwards.
