← Back to Lessons
Voice Agents

Give Your Agent Tools With Webhooks (Using n8n)

A tool is a webhook your agent calls mid-conversation to actually do something, book an appointment, look up an order, check availability. Here's how that works, with n8n as the automation layer on the other end.
⏱ ~20 min

What this covers. A talking agent that can only talk isn't worth much. The moment it can do things, book the appointment, look up the order, check what times are free, it becomes useful. It does those things by calling tools, which are just webhooks. This lesson explains the concept end to end and uses n8n as the example automation layer that receives the call.

The one idea to hold onto. A tool is a doorway. The agent stays on the phone and speaks; behind the scenes it sends a small packet of data to a URL, your automation does the real work, and a result comes back, all while the caller keeps talking. The agent never leaves the conversation.

This is the tools step from Build a Voice Agent From a Transcript, explained on its own. Everything here is generic; swap in whatever automation platform you like.

1
Understand what a tool actually is
3 min

A tool (often called a "server tool" or "webhook tool") has three parts:

A name and description

Like book_appointment with a clear description of when to use it. This is what the agent reads to decide whether to call it. Descriptive names and a good description are what make the agent pick the right tool at the right moment.

A URL and method

The webhook endpoint and how to hit it, usually a POST to something like https://YOUR-N8N-INSTANCE/webhook/book-appointment. This is where your automation lives.

A body schema

The shape of the data the agent will send: which fields, what each one means, which are required. For a booking that's the caller's name, phone, and the requested time.

When the agent decides to use the tool, ElevenLabs makes the HTTP request from its own servers (not from the caller's phone) and waits for your response.

2
See how the agent calls it mid-call
3 min

Here's the sequence during a live conversation. The caller never sees any of the machinery.

  1. The caller says enough to trigger the tool: "Can you book me in for Thursday morning?"
  2. The agent has already collected the required fields (name, phone, time) one at a time.
  3. The agent says a quick filler line out loud, "Let me get that booked for you", and fires the webhook.
  4. Your automation receives the data, does the work, and returns a result like { "status": "booked", "time": "Thursday 9am" }.
  5. The agent reads the result and speaks it: "You're all set for Thursday at 9. Anything else?"
Why the filler line matters

Without it, the caller hears silence while the webhook runs, which on a phone feels broken. Telling the agent to say what it's doing before every tool call (and enabling the platform's pre-tool-speech setting) turns a multi-second dead pause into a natural "one moment" beat.

3
Think in terms of three common tools
3 min

Most business voice agents need some combination of these. The pattern is identical; only the data changes.

check_availability

Read-only. The agent sends a requested date or window and gets back open slots. Usually called before booking so the agent only offers times that are actually free.

book_appointment

Write. The agent sends the caller's details and a chosen time, and the automation creates the booking. The rule in the prompt: always check availability first, then book.

lookup_order

Read-only. The caller gives an order number, the agent sends it, and the automation returns status and details. The agent reads the status back in plain language.

The sequencing lives in your system prompt, not in the tool itself. "Always call check_availability before book_appointment" is a prompt instruction the agent follows.

4
Picture the n8n side
3 min

On the receiving end, n8n (or any automation platform) is just a workflow that starts with a Webhook node. The flow is straightforward:

  1. Webhook node listens at your URL, e.g. https://YOUR-N8N-INSTANCE/webhook/book-appointment. It receives the JSON the agent sent.
  2. Action nodes do the real work: create a calendar event, write a row to a database, send a confirmation text.
  3. Respond node sends a small JSON result back to the agent so it can speak the outcome.

You never expose this URL or any secret in your agent's prompt. The webhook URL is configured on the tool, and any API keys live in the automation platform or as a stored secret on the tool's headers, never in text the model reads.

Keep secrets out of the prompt and out of public files

Use placeholder URLs like https://YOUR-N8N-INSTANCE/webhook/book-appointment while you build. The real URL and keys belong in your tool config and your automation platform, not in the system prompt, not in anything you'd share.

5
Glance at the tool definition
2 min

A webhook tool is a small JSON file. You don't have to memorize it, the workflow generates it, but it helps to recognize the shape. A POST tool always needs a requestBodySchema with a top-level description, or it may not fire correctly.

{ "type": "webhook", "name": "book_appointment", "description": "Books a service appointment after availability is confirmed. Use only after check_availability returns an open slot.", "apiSchema": { "url": "https://YOUR-N8N-INSTANCE/webhook/book-appointment", "method": "POST", "requestBodySchema": { "type": "object", "description": "Creates a confirmed appointment for the caller.", "properties": { "customer_name": { "type": "string", "description": "Caller's full name." }, "phone": { "type": "string", "description": "Digits only, e.g. 5551234567." }, "requested_time": { "type": "string", "description": "Confirmed slot, e.g. 'Thursday 9am'." } }, "required": ["customer_name", "phone", "requested_time"] } } }

Note the conventions: tool name in snake_case, JSON properties in camelCase, and every field carries a description so the agent knows exactly what to send.

6
Test with mocked responses first
3 min

You do not need a working n8n flow to test the agent's behavior around a tool. The test suite mocks every tool, it feeds the agent a fake response so you can check the conversation logic with no backend at all.

This lets you test two things that matter most:

  • Success path: the mock returns { "status": "booked" } and you confirm the agent reads it back correctly and ends cleanly.
  • Failure path: the mock returns an error, and you confirm the agent does the right thing, acknowledges it, doesn't invent a fake confirmation, and offers a callback.
/test acme-plumbing --runs 5

The generated tool-failure scenario sets the mock to return an error on purpose, then checks that the agent never claims success it didn't get. That's the test you most want to pass before going live, because a tool failing on a real call is a matter of when, not if. (See the testing lesson for how to read those results.)

Mocked now, real later

Build and test the whole conversation with mocks first. Wire up the actual n8n workflow only once the agent talks to the tool correctly. That order keeps you from debugging two things at once.

7
Recap the loop
1 min

How a tool comes together

  • The tool has a clear name, a description, a webhook URL, and a body schema
  • The agent collects the required fields one at a time before calling it
  • The agent says a filler line out loud before the webhook fires
  • Read-before-write sequencing (check availability, then book) lives in the prompt
  • The webhook hits an n8n workflow: Webhook node, action nodes, Respond node
  • URLs and keys stay in the tool config and automation platform, never in the prompt
  • Test success and failure paths with mocked responses before wiring the real flow

Questions?

Built by AI Service Engine · back to the main voice-agent lesson · install Claude Code first