---
title: Twilio Reference
description: Twilio channel options, credentials, routes, inbound hooks, delivery, human-in-the-loop, proactive sessions, and media.
url: "https://eve.dev/docs/channels/twilio/reference"
docs_index: /llms.txt
type: reference
---

> For an index of all documentation, see [/llms.txt](/llms.txt).

This page documents every part of `twilioChannel` from `eve/channels/twilio`. For setup and common tasks, start with [Twilio](/docs/channels/twilio).

The Twilio channel puts your agent on a phone number that people can text or call. It lives in `agent/channels/twilio.ts`. eve answers calls with TwiML `<Gather input="speech">`. The transcript joins the same eve session as SMS from that number, keyed by `From:To`. eve checks `X-Twilio-Signature` on every request first. See [Channels](/docs/channels) for what every channel shares.

## Add the channel

```ts title="agent/channels/twilio.ts"
import { twilioChannel } from "eve/channels/twilio";

export default twilioChannel({
  allowFrom: "+15551234567",
  messaging: { from: "+15557654321" },
});
```

```bash
TWILIO_ACCOUNT_SID=AC...   # required for default outbound SMS
TWILIO_AUTH_TOKEN=...      # required for inbound signature verification
```

Or pass them as `credentials: { accountSid, authToken }`. The channel mounts three routes:

- `POST /eve/v1/twilio/messages`: Messaging webhook
- `POST /eve/v1/twilio/voice`: inbound call webhook
- `POST /eve/v1/twilio/voice/transcription`: speech transcript callback

Point your Twilio number's Messaging webhook at `/messages` and Voice webhook at `/voice`, using the exact public URL Twilio calls.

## Options

`twilioChannel(config)` requires `allowFrom`. Every other option is optional.

| Option                 | Default                                         | Description                                                                                                                |
| ---------------------- | ----------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| `allowFrom`            | Required                                        | A number, a list, an async resolver, or `"*"`. Gates every inbound hook.                                                   |
| `credentials`          | `TWILIO_ACCOUNT_SID` and `TWILIO_AUTH_TOKEN`    | `{ accountSid, authToken }`. Each field also takes a lazy resolver.                                                        |
| `messaging`            | Reply from the inbound `To` number              | `{ from, messagingServiceSid, statusCallbackUrl }` for outbound SMS. Proactive sends need `from` or `messagingServiceSid`. |
| `voice`                | See below                                       | `{ prompt, acknowledgement, voice, language, speechModel, speechTimeout, timeoutSeconds, hints, profanityFilter }`.        |
| `route`                | `/eve/v1/twilio`                                | Base path for the three webhook routes.                                                                                    |
| `webhookUrl`           | None                                            | Public URL, or a function of the request, that signature verification uses behind a proxy.                                 |
| `publicBaseUrl`        | The request's origin                            | Base used to build absolute voice callback URLs.                                                                           |
| `api`                  | `https://api.twilio.com` and the global `fetch` | `{ apiBaseUrl, fetch }` for Twilio REST calls and media downloads.                                                         |
| `turnPolicy`           | `"steer"`                                       | `"steer"` or `"queue"` for messages that arrive during a turn.                                                             |
| `onText`               | Dispatch with phone-number auth                 | `(ctx, message)` hook for inbound SMS.                                                                                     |
| `onVoice`              | Answer with the configured `voice` options      | `(ctx, call)` hook when a call comes in. Return `null` to reject it, or an object to override `voice` options.             |
| `onVoiceTranscription` | Dispatch with phone-number auth                 | `(ctx, transcription)` hook for speech transcripts.                                                                        |
| `events`               | eve's default handlers                          | Per-event handler overrides.                                                                                               |

`voice.prompt` defaults to `"Please say your message after the tone."`, `voice.acknowledgement`, spoken after a transcript arrives, defaults to `"Thanks. I'll follow up by text."`, and `voice.speechTimeout` defaults to `"auto"`.

The channel mounts `GET` and `POST` on `/eve/v1/twilio/messages`, `/eve/v1/twilio/voice`, and `/eve/v1/twilio/voice/transcription`.

## Dispatch

`allowFrom` is required and decides which phone numbers reach `onText`, `onVoice`, and `onVoiceTranscription`. Pass a number, a list, an async resolver, or `"*"`. The wildcard admits any caller, so use it only with an explicit check in `onText` and `onVoice`.

```ts
export default twilioChannel({ allowFrom: ["+15551234567", "+15557654321"] });
```

`onText` and `onVoiceTranscription` decide whether a message runs the agent, and as whom. Return `{ auth }` to run it, optionally with `title` to set the run title, or `null` to ignore the message. `onVoice` fires when a call comes in. Return `null` to reject it, or an object to override the spoken prompt, language, `<Say voice>`, and speech-recognition options.

```ts
export default twilioChannel({
  allowFrom: ["+15551234567"],
  onText: (ctx, message) => ({
    auth: {
      principalId: message.from,
      principalType: "user",
      authenticator: "twilio",
      attributes: { to: message.to ?? "" },
    },
  }),
});
```

## Delivery

By default, the bot sends each reply as SMS through Twilio's Messages API. A reply to an inbound message can use the webhook's `To` as the sender; a proactive send needs `messaging.from` or `messaging.messagingServiceSid`. Behind a proxy, set `webhookUrl` so signature verification matches the configured URL, and `publicBaseUrl` so voice TwiML builds absolute callback URLs.

## Human-in-the-loop (HITL)

By default, each question and tool approval goes out as an SMS with numbered options, including to callers on a voice call. A reply with an option's number or label answers the request, so `1` or `approve` runs an approval-gated tool and `2` or `deny` stops it. If the question allows a custom answer, any other text is taken as the answer. To render questions differently, set `events["interaction.opened"]`.

## Proactive sessions

To start a session without an incoming message, call `to(twilio, target).send(message, { auth })` from a schedule `run` handler, or `ctx.to(twilio, target).send(message, { auth })` from another channel. `target.phoneNumber` is required, and the channel needs `messaging.from` or `messaging.messagingServiceSid` as the sender.

## Attachments

MMS media reaches the agent as file parts. eve downloads each media URL with the account SID and auth token, only from the Twilio API origin (`https://api.twilio.com`, or `api.apiBaseUrl` when set). A failed download becomes a short note, and the turn continues.

## Disclaimer

As the deployer, it is your responsibility to ensure your agent complies with applicable laws.

For example, you may need to tell callers and texters that an automated AI system records, transcribes, and processes their calls. You may also need their consent, including in two-party-consent jurisdictions. For outbound SMS or calls you start, you may need prior express consent. You may also need to honor STOP/opt-out and quiet-hour rules and complete carrier registration.

## What to read next

- [Channels overview](/docs/channels): what every channel shares, and every built-in channel
- [Auth & route protection](/docs/guides/auth-and-route-protection): authenticating inbound traffic

---

For a semantic overview of all documentation, see [/sitemap.md](/sitemap.md)

For an index of all available documentation, see [/llms.txt](/llms.txt)

For agent-facing discovery, including API and MCP surfaces, see [/agents.md](/agents.md)