Skip to content

Connect a Twilio phone number and one of your agents will reply to inbound SMS. The same channel can also be used in Signal mode to capture verification codes and route them to whichever agent is waiting.

What you need

  • A Twilio account with an SMS-capable phone number
  • The Account SID and auth token from the Twilio console
  • A publicly reachable URL for the engine. See server.external_url. For local development, ngrok works.

Connecting the channel

  1. In Frona, open Settings → Channels and click Add channel.
  2. Pick Twilio SMS.
  3. Choose the space the conversation will live in and the agent that will respond.
  4. Fill in the Twilio fields (defaults pull from voice config if you've set up Twilio voice).
  5. Save.

The adapter registers a Twilio Messaging webhook on the phone number and moves the channel into Pairing.

Pairing your number

After connecting, the channel shows a one-time pairing code. Text the code from your phone to the Twilio number you're connecting. The adapter records your phone number as a paired address, and the channel transitions to Connected.

From then on, SMS from that number is treated as you and runs full inference. Other senders are dropped unless you add a policy that allows them. To pair another phone, repeat the flow; paired addresses accumulate.

Configuration fields

FieldRequiredDescription
account_sidYesTwilio Account SID (starts with AC). Defaults from voice.twilio_account_sid if set.
auth_tokenYesTwilio auth token. Defaults from voice.twilio_auth_token if set. Stored encrypted.
from_numberYesThe Twilio phone number to send from, in E.164 format (e.g., +15551234567). Defaults from voice.twilio_from_number if set.

How messages flow

  • Inbound SMS to your Twilio number is delivered to Frona via webhook.
  • The agent runs through its tool loop and composes a single reply.
  • The adapter sends one outbound SMS per turn (tool calls are folded into the same body, so you pay for one message per turn).
  • Twilio status callbacks update the message state in the UI: queued → sent → delivered.

The single-message-per-turn behavior is deliberate: SMS billing is per-segment, and splitting tool progress into separate texts is expensive.

Signal mode

Switch the channel's dispatch mode to Signal in its settings to use it for capture-only:

  • Inbound messages are annotated and run against active signal watches.
  • The channel does not reply.
  • This is the right setup for "wait for the verification code" flows where the agent that asked is in a different space.

You can leave a single SMS channel in Signal mode and have any agent wait on it via await_signal.

Allowlisting senders

By default only paired addresses pass receive_message. To allow another contact (e.g., a partner's phone), add a policy:

cedar
permit(
  principal == Policy::Agent::"assistant",
  action == Policy::Action::"receive_message",
  resource in Policy::Channel::"sms"
) when { resource.sender.address == "+15559876543" };

To block a known spam shortcode while still allowing it to feed signal matching:

cedar
forbid(
  principal,
  action == Policy::Action::"receive_message",
  resource
) when { resource.sender.address == "22000" };

See Policies for more patterns.

Tips

  • Pair before you test. Until the channel is paired, even your own messages are dropped.
  • Use voice.* defaults if you already have Twilio configured. The SMS form auto-fills from those values.
  • One Twilio number can only do one mode at a time. If you switch the channel from Message to Signal, the agent stops replying to that number.
  • Use ngrok for local development. Twilio won't deliver webhooks to localhost.
  • Watch the status callback URL. If outbound messages stay queued, the status webhook isn't reaching the engine.

Troubleshooting

SymptomLikely cause
Channel marked Failed right after creationBad credentials, the number isn't SMS-capable, or the engine's external URL isn't reachable
Stuck in PairingThe pairing SMS never arrived at Twilio. Check Twilio's logs for inbound messages.
Inbound from your phone is ignoredThe number you texted from doesn't match the paired address. Re-pair.
Outbound stays queued foreverStatus callbacks aren't reaching the engine. Check server.external_url.

Next steps

  • Channels. How channels work in general.
  • Signals. Channels in Signal mode feed signal matching.
  • Twilio Voice. Same provider, different feature.
  • Policies. Allowlist or block specific senders.