Skip to main content

Tools

Tools let your agent perform actions during a call — look up customer data, book appointments, process payments, and more. Tools are defined as webhooks that the SDK calls when the AI model invokes them.

Defining Tools

Each tool requires a name, description, parameters (JSON Schema), and webhookUrl:
const agent = phone.agent({
  systemPrompt: "You are a scheduling assistant.",
  tools: [
    {
      name: "check_availability",
      description: "Check available appointment slots for a given date.",
      parameters: {
        type: "object",
        properties: {
          date: {
            type: "string",
            description: "Date in YYYY-MM-DD format",
          },
        },
        required: ["date"],
      },
      webhookUrl: "https://api.example.com/availability",
    },
    {
      name: "book_appointment",
      description: "Book an appointment at the specified date and time.",
      parameters: {
        type: "object",
        properties: {
          date: { type: "string", description: "Date in YYYY-MM-DD format" },
          time: { type: "string", description: "Time in HH:MM format" },
          name: { type: "string", description: "Customer name" },
        },
        required: ["date", "time", "name"],
      },
      webhookUrl: "https://api.example.com/book",
    },
  ],
});

ToolDefinition Interface

interface ToolDefinition {
  name: string;
  description: string;
  parameters: Record<string, unknown>; // JSON Schema
  webhookUrl?: string;  // Required if handler is not provided
  handler?: (args: Record<string, unknown>, context: Record<string, unknown>) => Promise<string | object>;
}
Every tool must have either a webhookUrl or a handler. Providing neither raises an error.

Webhook Payload

When the AI model invokes a tool, the SDK sends a POST request to the webhookUrl with the following JSON body:
{
  "tool_name": "check_availability",
  "arguments": {
    "date": "2025-03-15"
  },
  "call_id": "call_abc123",
  "caller": "+15551234567",
  "callee": "+15550001234"
}
Your webhook must return a JSON response. The response text is fed back to the AI model as the tool result.

Webhook Behavior

SettingValue
HTTP methodPOST
Content typeapplication/json
Timeout10 seconds
Max response size64 KB
Retries3 attempts with 500ms delay
If all retries fail, the SDK returns an error message to the AI model so it can inform the caller gracefully.

SSRF Protection

All webhook URLs are validated before requests are sent. The following are blocked:
  • Private IP ranges: 127.x.x.x, 10.x.x.x, 172.16-31.x.x, 192.168.x.x
  • Link-local addresses: 169.254.x.x
  • Loopback: localhost, ::1
  • Cloud metadata endpoints: metadata.google.internal
  • Non-HTTP schemes (only http: and https: are allowed)
// Blocked — private address
webhookUrl: "http://127.0.0.1:3000/api"

// Blocked — cloud metadata
webhookUrl: "http://metadata.google.internal/computeMetadata/v1"

// Allowed
webhookUrl: "https://api.example.com/webhook"

System Tools

Two tools are automatically injected into every agent. You do not need to define them:

transfer_call

Transfers the current call to another phone number. The AI model invokes this when the caller asks to speak to a human or be transferred.
{
  "name": "transfer_call",
  "parameters": {
    "number": "+15559876543"
  }
}
The SDK uses the Twilio REST API to redirect the call to the target number.

end_call

Ends the current call. The AI model invokes this when the conversation is complete or the caller says goodbye.
{
  "name": "end_call",
  "parameters": {
    "reason": "conversation_complete"
  }
}

In-Process Handlers

Instead of webhook URLs, you can pass a function that runs in-process:
const agent = phone.agent({
  systemPrompt: "You are a product specialist.",
  tools: [
    Patter.tool({
      name: "check_inventory",
      description: "Check if a product is in stock.",
      parameters: {
        type: "object",
        properties: {
          productId: { type: "string", description: "Product ID" },
        },
        required: ["productId"],
      },
      handler: async (args, context) => {
        const stock = await db.getStock(args.productId as string);
        return { productId: args.productId, inStock: stock > 0, quantity: stock };
      },
    }),
  ],
});
The handler receives:
  • args — The arguments extracted by the AI
  • context — Call metadata (callId, caller, callee)

Validation

The phone.agent() method validates tools at creation time:
  • tools must be an array
  • Each tool must have a name field
  • Each tool must have either a webhookUrl or handler field
Missing fields throw descriptive errors:
// Throws: tools[0] requires either 'webhookUrl' or 'handler'
phone.agent({
  systemPrompt: "...",
  tools: [{ name: "test", description: "test", parameters: {} }] as any,
});