Skip to main content

Twilio Module

Connect your workflows to the world's phones — SMS, MMS, WhatsApp, voice calls, OTP verification, and number lookup.

The Twilio Module lets a Process send and receive SMS, MMS, and WhatsApp messages, answer and drive voice calls, verify users with one-time codes, and validate phone numbers. It requires Environment configuration: each Environment supplies its own Twilio credentials and service SIDs, and the Module registers the matching Twilio webhooks for you on every Deployment.

How it works

The Module adds three Channels, so the same Process runs over different transports without modification:

ChannelStarted whenWhat happens
TwilioSmsAn SMS arrives on your Twilio numberA new Session starts on the TwilioSms Channel
TwilioWhatsAppA WhatsApp message arrivesSame path as SMS; the Session starts on the TwilioWhatsApp Channel because the inbound address carries the whatsapp: prefix
TwilioVoiceA voice call reaches your Twilio numberA new Session starts on the TwilioVoice Channel and replies are rendered as TwiML voice instructions

The same OutputTask saying "Hi there!" is delivered as an SMS reply, a WhatsApp message, or spoken text on a call, depending on which Channel the Session started on.

Inbound SMS and WhatsApp arrive through a single unified webhook, POST /api/TwilioModule/Conversations/event/{token} (where {token} is the Environment's token). At Deployment time the Module configures your Twilio Conversation Service's post-event webhook with the filters onConversationAdded and onMessageAdded, both pointing at that one URL:

  1. onConversationAdded (a new conversation starts) → a new Session starts, bound to that Twilio conversation.
  2. onMessageAdded (the user sends another message) → the existing Session resumes with the new message.

Events for the same conversation are always processed in order, one at a time, even when several arrive in quick succession.

Inbound voice works differently: Twilio expects the voice instructions back in the same HTTP round-trip, so calls hit POST /api/TwilioModule/Voice/start/{token} and the engine answers each request directly with TwiML.

Quick start (5 minutes, SMS only)

The fastest path to seeing an inbound SMS run a Process:

  1. Create a Twilio account. Note the Account SID (AC...) and Auth Token on the Console dashboard.
  2. Buy a Twilio number that can send SMS. Console → Phone Numbers → Buy a Number.
  3. Find your Conversations Service. Console → Conversations → Manage → Services → "Default Messaging Service" → note the SID (IS...). Make sure your phone number is attached to a Messaging Service, and the Messaging Service is integrated with this Conversations Service ("Autocreate a Conversation" enabled).
  4. Configure the Module's Environment configuration. Open Environments, select your Environment, and open the Twilio Module configuration:
    • Top section: Account SID + Auth Token.
    • SMS Configuration section: paste the Conversations Service SID into Conversation Service SID. Toggle Auto-Deploy SMS Webhook = on.
  5. Deploy a Process with StartTask → OutputTask("Hi {execution.channelSender}") → InputTask(Variable="reply") → OutputTask("You said: {reply}") → EndTask. The Deployment log shows a row like:

    "SMS post-event webhook updated on Conversation Service IS… → https://…/api/TwilioModule/Conversations/event/… (filters: onConversationAdded, onMessageAdded)"

  6. Text your Twilio number. The bot replies. Done.

For Voice and WhatsApp, fill in the matching section's SID and toggle that section's Auto-Deploy Webhook.

info

Webhook URLs are built from the platform's public engine address and registered on Twilio automatically by the Auto-Deploy toggles — you never have to construct them by hand.

Configuration

Configuration is per Environment — each Environment supplies its own Twilio credentials and service SIDs. Open Environments, select the Environment, and open the Twilio Module configuration. The form has core credentials at the top followed by four sections, each with its own Auto-Deploy Webhook toggle.

Core Credentials

FieldTypeRequiredDescription
Account SIDstring (secret)YesTwilio Account SID (AC...)
Auth Tokenstring (secret)YesTwilio Auth Token
Webhook Signing Secretstring (secret)NoOptional override key for webhook signature checks
Validate SignaturesbooleanNo (default: on)Verify the signature on every inbound Twilio webhook

Account SID

Twilio Account SID — starts with AC. Find on the Twilio Console main dashboard under Account Info. Example: ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.

Required. Stored as a secret.

Auth Token

Twilio Auth Token — next to Account SID on the Console dashboard. Used to authenticate Twilio API calls and to verify the signature on inbound webhooks.

Required. Stored as a secret.

Webhook Signing Secret

Optional override for webhook signature verification. Default: empty — the Auth Token is used.

Set only if you rotate your Auth Token but want a separate key for webhook signing.

Validate Signatures

When on, every inbound Twilio webhook is rejected with 403 if the X-Twilio-Signature header doesn't match. When off, the engine accepts any request. Default: on.

Leave on in shared Environments. Disable only for local debugging — in Production the check is always enforced, even if this toggle is off.


Phone (Voice) Configuration

Voice-call settings.

FieldTypeRequiredDescription
Phone Number SIDstringFor voice auto-deployTwilio Incoming Phone Number SID (PN...)
Default VoicestringNoDefault text-to-speech voice
Default LanguagestringNoDefault language tag for spoken prompts
Speech ModelstringNoSpeech-recognition model hint
Auto-Deploy Voice WebhookbooleanNo (default: off)Register the voice webhook on every Deployment

Phone Number SID

Twilio Incoming Phone Number SID — starts with PN. Example: PNxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.

Where to find it: Twilio Console → Phone Numbers → Manage → Active Numbers → click your number → Properties tab → "Phone Number SID".

Used by Auto-Deploy Voice Webhook to set this phone number's voice webhook.

Default Voice

Default text-to-speech voice for spoken prompts. Examples: alice, Polly.Joanna, Polly.Matthew, Google.en-US-Standard-A. Default: empty — Twilio's standard voice.

Reference: Twilio Voice TTS voices.

Default Language

Default IETF language tag (BCP-47) for spoken prompts and speech recognition. Examples: en-US, it-IT, es-ES. Default: empty — Twilio's standard language.

Speech Model

Speech-recognition model hint used when a voice InputTask listens for spoken input. One of default, phone_call, phone_call_enhanced.

phone_call_enhanced is the most accurate but incurs an upgrade fee.

Auto-Deploy Voice Webhook

When on, every Deployment sets the phone number's voice webhook to this Environment's voice start URL (.../api/TwilioModule/Voice/start/{token}). Default: off.

Requires Phone Number SID to be set and start with PN.

Last-write-wins across Environments that share a phone number.


SMS Configuration

Outbound SMS defaults plus inbound SMS routing via Conversations.

FieldTypeRequiredDescription
Default From NumberstringNoFallback sender number for outbound SMS/MMS
Messaging Service SIDstringNoTwilio Messaging Service (MG...) used in place of a From number
Conversation Service SIDstringFor inbound SMSTwilio Conversations Service (IS...)
Auto-Deploy SMS WebhookbooleanNo (default: off)Register the Conversations webhook on every Deployment
Clear Messaging Service Inbound Webhook on DeploybooleanNo (default: off)Remove stale Messaging Service webhooks on every Deployment

Default From Number

Fallback sender phone number in E.164 format (e.g. +1234567890). Used by TwilioSendSmsTask / TwilioSendMmsTask when the Task omits the From field. Default: empty.

Must be a verified Twilio number on your account.

Messaging Service SID

Optional Twilio Messaging Service SID — starts with MG. When set, used in place of From for outbound SMS (enables automatic number pooling, sticky sender, and opt-out management). Default: empty.

Where to find it: Twilio Console → Messaging → Services → your service.

Conversation Service SID

Twilio Conversations Service SID — starts with IS. Required for inbound SMS routing. Example: ISxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.

Where to find it: Twilio Console → Conversations → Manage → Services → your service SID.

warning

Do not confuse the Conversation Service SID (IS...) with the Messaging Service SID (MG...). Twilio rejects the wrong one with error 50051 Service sid not provided, and the Deployment rejects it up front with a clear error.

Auto-Deploy SMS Webhook

When on, every Deployment updates the Conversation Service's post-event webhook with filters onConversationAdded and onMessageAdded, pointing at this Environment's unified event URL (.../api/TwilioModule/Conversations/event/{token}). Default: off.

Requires Conversation Service SID to be set and start with IS.

Both events land on the same URL; the engine routes each by its event type and processes events for the same conversation in order.

Clear Messaging Service Inbound Webhook on Deploy

When on, every Deployment clears the Messaging Service's Inbound Request URL and disables its Use webhook on number option. This matters when the Messaging Service has a stale per-service or per-number webhook that would hijack inbound traffic away from the Conversation Service autocreate path. Shared setting: applies to SMS and WhatsApp, because both use the same Messaging Service SID. Default: off.

Symptom that tells you to enable this: inbound WhatsApp replies arriving at the voice webhook URL, or at a per-number legacy URL, instead of at the /Conversations/event/… endpoint.


WhatsApp Configuration

Outbound WhatsApp and (when Conversations integration is enabled) inbound WhatsApp routing.

FieldTypeRequiredDescription
WhatsApp From NumberstringNoDefault sender for outbound WhatsApp
Conversation Service SIDstringFor inbound WhatsAppTwilio Conversations Service (IS...)
Auto-Deploy WhatsApp WebhookbooleanNo (default: off)Register the Conversations webhook on every Deployment
Migrate Active Conversations on DeploybooleanNo (default: off)Close running WhatsApp conversations so they re-bind to a new From Number
Migration MessagestringNoText posted into each conversation before the migration closes it

WhatsApp From Number

Default sender for TwilioSendWhatsAppTask. Must include the whatsapp: prefix. Default: empty.

Example: whatsapp:+14155238886 (the Twilio WhatsApp sandbox number).

For production, use your approved WhatsApp Business number.

Conversation Service SID

Twilio Conversations Service SID — starts with IS. Same place to find as SMS: Twilio Console → Conversations → Manage → Services.

In most setups this is identical to the SMS Conversation Service SID — the Deployment de-duplicates when both match.

Auto-Deploy WhatsApp Webhook

Same semantics as Auto-Deploy SMS Webhook. Enable if your WhatsApp Conversations Service is different from the SMS one; otherwise the SMS auto-deploy already covers WhatsApp. Default: off.

Migrate Active Conversations on Deploy

Twilio pins each conversation to the sender number it started with, so a changed WhatsApp From Number has no effect on conversations that were already running. With this flag on, the Deployment walks every active conversation in the Conversation Service, posts the configured Migration Message (if any), and closes the conversation. On the user's next inbound message, Twilio creates a fresh conversation bound to the new From Number. Default: off.

Only WhatsApp conversations are touched — SMS conversations in a shared service are left alone.

Toggle off once the migration wave is done, otherwise every subsequent Deployment re-closes active conversations.

Migration Message

Plain text posted into every active WhatsApp conversation right before it is closed by the migration. Default: empty — close silently. The author shown to users is system.

Example: We're updating our WhatsApp service. Please send us a new message to continue the conversation.


Verify (OTP) Configuration

FieldTypeRequiredDescription
Verify Service SIDstringFor OTP TasksTwilio Verify Service (VA...)

Verify Service SID

Twilio Verify Service SID — starts with VA. Required by TwilioSendOtpTask and TwilioVerifyOtpTask. Example: VAxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.

Where to find it: Twilio Console → Verify → Services → your service. Create a new one if you don't have one.


Tasks

The Twilio Module ships two kinds of Tasks:

  • Generic Tasks — runnable in any Process regardless of how it started (any Channel: Chat, Web, an inbound Twilio Session, ...). These cover outbound sends, number lookup, and OTP. They need no inbound call or message — only valid credentials in the Module's Environment configuration.
  • Channel-specific Tasks and overrides — the voice Tasks run only on the TwilioVoice Channel, and the standard StartTask / InputTask / OutputTask / EndTask get Twilio-specific behavior on the TwilioSms, TwilioWhatsApp, and TwilioVoice Channels.

Several Tasks below have a Store variable output: a field where you type a variable name (no braces) — the Task saves its result there and later Tasks can reference it as {name}.

TwilioSendSmsTask (Generic)

Send a one-shot outbound SMS — fire-and-forget, no conversation needed.

Use it for: notifications, alerts, magic-link delivery — anywhere you want to push a single SMS without expecting a reply.

Properties

PropertyTypeRequiredExampleDescription
FromstringNo+15551230000Sender number in E.164 format. Default: empty — falls back to the Environment's Default From Number or Messaging Service SID.
TostringYes{phone}Recipient in E.164 format. Supports {variable} placeholders.
BodystringYesHi {execution.channelSender}, your order shipped.SMS text. Supports {variable} placeholders.
StatusCallbackUrlstringNohttps://example.com/sms-statusTwilio delivery-status callback URL. Default: empty.
OutputVariableStore variableNosmsSidVariable name (no braces) that receives the Twilio message ID; later Tasks read it as {smsSid}. Default: empty — the ID is not stored.

Example

A Process triggered by an API call sets {phone} and {orderId}, then a TwilioSendSmsTask with To = {phone}, Body = Order {orderId} has shipped. delivers the text. If Twilio rejects the request (invalid number, unverified sender), the Task routes to its error output with error 4001.

TwilioSendMmsTask (Generic)

Send an outbound SMS with one or more media attachments (image, audio, video, document).

Use it for: delivering boarding passes, receipts with logos, photo confirmations.

Properties

PropertyTypeRequiredExampleDescription
FromstringNo+15551230000Sender number. Default: empty — falls back to the Environment's Default From Number or Messaging Service SID.
TostringYes+15557654321Recipient in E.164 format.
BodystringNoYour receipt is attached.Optional caption text. Default: empty.
MediaUrlsstringYeshttps://cdn.example.com/receipt.pdfOne absolute http:// or https:// URL per line (or comma-separated). Twilio fetches each URL from the public internet, so localhost and private addresses are rejected up front. Each URL must return 200 with a supported content type (image/jpeg, image/png, image/gif, video/mp4, application/pdf, ...).
OutputVariableStore variableNommsSidVariable name (no braces) that receives the Twilio message ID. Default: empty.

Example

MediaUrls = https://cdn.example.com/boardingpass/{bookingRef}.png, To = {phone} — the recipient gets an MMS with the rendered boarding pass. If Twilio can't fetch or accept a URL, the error log includes the failing Twilio code and the full media URL list, so a 12300 (unsupported content type) or 11200 (fetch failure) tells you immediately which URL failed.

TwilioSendWhatsAppTask (Generic)

Send an outbound WhatsApp message — free-form within the 24-hour session window, or an approved template outside it.

Use it for: customer support replies, order updates, appointment reminders.

Properties

PropertyTypeRequiredExampleDescription
FromstringNowhatsapp:+14155238886Sender. Default: empty — falls back to the Environment's WhatsApp From Number. The whatsapp: prefix is added automatically if missing.
TostringYes{phone}Recipient. The whatsapp: prefix is added automatically if missing.
BodystringConditionalYour order {orderId} is on its way!Free-form message. Required when ContentSid is empty. Only allowed inside the 24-hour session window.
ContentSidstringConditionalHXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxApproved WhatsApp template SID. Required when Body is empty.
ContentVariablesstringNo{"1":"Maria","2":"Tuesday"}JSON-encoded template variable map, used with ContentSid. Default: empty.
MediaUrlsstringNohttps://cdn.example.com/photo.jpgNewline- or comma-separated public URLs. Default: empty.
OutputVariableStore variableNowaSidVariable name (no braces) that receives the Twilio message ID. Default: empty.

The Task fails with error 3005 if neither Body nor ContentSid is set.

WhatsApp 24-hour session window

WhatsApp only allows free-form Body messages within 24 hours of the user's last inbound message. Outside the window, send an approved template via ContentSid. New templates must be submitted through Twilio for WhatsApp approval before they can be used.

TwilioLookupNumberTask (Generic)

Validate a phone number with Twilio Lookup and store the verdict in Session variables.

Use it for: rejecting landlines from SMS-only workflows, detecting SIM swap before sending an OTP, displaying the carrier or caller name.

It runs in any Process regardless of the Channel it started on — no inbound call or message needed; the only requirement is a valid Account SID / Auth Token in the Module's Environment configuration.

Properties

PropertyTypeRequiredExampleDescription
PhoneNumberstringYes+442071234567E.164 number to look up. Supports {variable} placeholders.
FieldsstringNoline_type_intelligence,sim_swapComma-separated Lookup add-ons: line_type_intelligence, caller_name, sim_swap, call_forwarding, identity_match. Some incur per-lookup charges. Default: empty — basic validation only.
OutputPrefixstringNolookupPrefix for the result variables: {lookup.valid}, {lookup.countryCode}, {lookup.lineTypeIntelligence.type}, etc. Default: lookup.

Example

PhoneNumber = {phone}, Fields = line_type_intelligence — afterwards {lookup.valid} is true/false and {lookup.lineTypeIntelligence.type} says mobile, landline, or voip, ready for a SwitchTask. Invalid numbers return {lookup.valid} = false without failing the Task; API errors also set {lookup.error} with the reason.

TwilioSendOtpTask (Generic)

Send a Twilio Verify one-time code over SMS, voice call, email, or WhatsApp.

Use it for: the first half of a two-factor verification. Pair with TwilioVerifyOtpTask.

Properties

PropertyTypeRequiredExampleDescription
TostringYes+15557654321Phone number (for sms / call / whatsapp) or email address (for email).
ChannelstringYessmsDelivery channel: sms, call, email, or whatsapp. Default: sms.
LocalestringNoitIETF language tag for the OTP message (en, it, fr, ...). Default: empty — Twilio picks the language.
OutputSidVariableStore variableNoverifySidVariable name (no braces) that receives the verification ID. Default: empty.

Requires Verify Service SID in the Module's Environment configuration — otherwise the Task fails with error 4008.

TwilioVerifyOtpTask (Generic)

Check a one-time code submitted by the user against Twilio Verify.

Use it for: the second half of a two-factor verification. Wire a SwitchTask after it to branch on the status variable.

Properties

PropertyTypeRequiredExampleDescription
TostringYes{phone}The same identifier used when sending the code.
CodestringYes{code}The code entered by the user. Supports {variable} placeholders.
OutputStatusVariableStore variableNootpStatusVariable name (no braces) that receives the verification status: approved, pending, or canceled. Default: empty.

When the status is anything other than approved, the Task routes to its error output and logs error 4021.

TwilioVoicePlayTask (Channel: TwilioVoice)

Play a remote audio file to the caller on the active voice call.

Use it for: hold music, pre-recorded greetings, brand sounds. Only runs in Sessions on the TwilioVoice Channel.

Properties

PropertyTypeRequiredExampleDescription
MediaUrlstringYeshttps://cdn.example.com/hold-music.mp3Publicly accessible audio URL. Supports {variable} placeholders.
LoopnumberNo1How many times to play. 0 loops until the caller hangs up. Default: 1.

TwilioVoiceRecordTask (Channel: TwilioVoice)

Record the caller's voice and store the recording's URL and ID in Session variables.

Use it for: voicemail, post-call surveys, claims intake. Only runs in Sessions on the TwilioVoice Channel. In the Process Editor it is placed as a Message Intermediate Catch Event — the Session waits until the recording completes, then continues.

Properties

PropertyTypeRequiredExampleDescription
MaxLengthSecondsnumberNo60Maximum recording length in seconds. Twilio's maximum is 3600. Default: 30.
PlayBeepbooleanNotruePlay a beep tone before recording. Default: true.
TrimstringNotrim-silencetrim-silence or do-not-trim. Default: trim-silence.
TranscribebooleanNofalseRequest Twilio transcription of the recording (extra cost). Default: false.
OutputUrlVariableStore variableNorecordingUrlVariable name (no braces) that receives the recording's playback URL. Default: empty.
OutputSidVariableStore variableNorecordingSidVariable name (no braces) that receives the recording's Twilio ID. Default: empty.

TwilioVoiceDialTask (Channel: TwilioVoice)

Forward the active call to another phone number.

Use it for: "press 0 for an agent", overflow routing, ringing a desk-and-mobile pair. Only runs in Sessions on the TwilioVoice Channel.

Properties

PropertyTypeRequiredExampleDescription
DestinationstringYes+15550001111E.164 number to dial. Supports {variable} placeholders.
TimeoutSecondsnumberNo30How long to ring before considering the call unanswered. Default: 30.
RecordCallstringNodo-not-recorddo-not-record, record-from-answer, or record-from-answer-dual. Default: do-not-record.
CallerIdstringNo+15551230000Optional caller ID presented to the dialed party. Must be a verified Twilio number. Default: empty — the caller's own number.

Example

A voice IVR: OutputTask("Press 1 for sales, 2 for support")InputTask(Variable="digit") (collects the keypress) → SwitchTask({digit}) → on 1, a TwilioVoiceDialTask with Destination = +15550001111 forwards the call to the sales line.

Channel override Tasks

On the TwilioSms, TwilioWhatsApp, and TwilioVoice Channels, the standard Standard Module Tasks behave Twilio-natively — you don't pick anything special in the Process Editor; the right behavior is selected automatically from the Session's Channel:

  • StartTask — binds the Session to the inbound conversation or call.
  • InputTask — waits for the user's next SMS / WhatsApp message, or collects a keypress / speech on a call.
  • OutputTask — sends an SMS / WhatsApp reply, or speaks the text on the call.
  • EndTask — posts an optional farewell message, then the Session ends.

Conversation lifecycle

Every SMS or WhatsApp Session is bound to one Twilio conversation. When the Session ends — whether it completes normally or stops with an error — the Module automatically closes that conversation on Twilio's side. Closing it is what makes the user's next inbound message create a fresh conversation and therefore start a new Session.

This cleanup runs for every Session, including ones that end without an explicit EndTask. The EndTask itself only adds the optional farewell message.

Common recipes

Verify a user's phone number with a one-time code

Send an OTP to the number the user provides, then branch on whether the code checks out.

  1. InputTask (Standard Module) — prompt "What's your phone number?", Variable = phone.
  2. TwilioSendOtpTask — To = {phone}, Channel = sms, OutputSidVariable = verifySid. The user receives a code by SMS. Requires Verify Service SID in the Environment configuration.
  3. InputTask — prompt "Enter the code we sent you", Variable = code.
  4. TwilioVerifyOtpTask — To = {phone}, Code = {code}, OutputStatusVariable = otpStatus.
  5. SwitchTask — Variable = {otpStatus}, routes approved / everything else.
  6. On the approved Sequence Flow: OutputTask — "You're verified!". On the other branch: OutputTask — "That code didn't match. Please try again."

Auto-reply to inbound SMS with AI

A user texts your Twilio number; the Process answers their question with an AI-generated reply on the same conversation.

  1. StartTask — the Session starts automatically on the TwilioSms Channel when the user texts your number (with Auto-Deploy SMS Webhook on, no manual webhook setup is needed).
  2. OutputTask — Message = Hi! How can I help today? — delivered as an SMS reply.
  3. InputTask — Variable = question. The Session waits for the user's next SMS.
  4. OpenAIChatCompletionTask (OpenAI Module) — Prompt = {question}, output variable = answer.
  5. OutputTask — Message = {answer}.
  6. EndTask — Message = Thanks for texting us!. The Session ends and the conversation closes, so the user's next text starts a fresh Session.

Troubleshooting

"50051 Service sid not provided" on Deployment

The Conversation Service SID field has a Messaging Service SID (MG...) instead of a Conversations Service SID (IS...). Move the MG... value into the Messaging Service SID field, then look up the correct IS... in Console → Conversations → Manage → Services.

WhatsApp messages hit the voice webhook (or vice-versa)

Twilio's WhatsApp Sandbox has its own webhook URL in Console → Messaging → Try it out → Send a WhatsApp Message → Sandbox Settings. If you ever pasted a voice URL there, sandbox WhatsApp bypasses Conversations. Point that field at /api/TwilioModule/Conversations/event/{token} or leave it blank and rely on the Conversations integration.

Webhook returns 403

Validate Signatures = on and either:

  • The URL registered on Twilio doesn't match the URL the engine sees (e.g. http vs https, or a stale tunnel URL), or
  • The Auth Token in the Module's Environment configuration doesn't match the one Twilio is signing with.

For local debugging only, toggle Validate Signatures = off to confirm the rest of the workflow works, then re-enable.

Deployment log shows "Auto-deploy is off in every section"

None of the Auto-Deploy Webhook toggles in the Phone / SMS / WhatsApp sections are on. Either toggle the relevant section(s) on, or configure the Twilio webhooks manually in the Console using the Webhook URLs table.

Inbound SMS doesn't trigger any workflow

Three things to check, in order:

  1. The phone number is attached to a Messaging Service.
  2. The Messaging Service is integrated with a Conversations Service ("Autocreate a Conversation" enabled).
  3. The Conversations Service's post-event webhook points at your /api/TwilioModule/Conversations/event/{token} URL with both filters onConversationAdded and onMessageAdded.

If you have Auto-Deploy SMS Webhook on, step 3 is done for you on every Deployment.

Reference

Webhook URLs

These are the endpoints the Auto-Deploy toggles register for you. You only need this table if you configure Twilio manually. {token} is the Environment's token, shown in the Deployment log.

InboundEngine routeWhere it's configured
Conversations events — SMS and WhatsApp (onConversationAdded + onMessageAdded)POST /api/TwilioModule/Conversations/event/{token}The Conversation Service's post-event webhook, with both filters selected. This is the endpoint for all inbound SMS/WhatsApp — set automatically by Auto-Deploy SMS/WhatsApp Webhook.
Voice — call startedPOST /api/TwilioModule/Voice/start/{token}The phone number's "A call comes in" webhook — set automatically by Auto-Deploy Voice Webhook.
Voice — keypress / recording callbackPOST /api/TwilioModule/Voice/next/{environmentId}Nothing to configure — the engine embeds this URL in its own voice responses. The Environment id in the URL selects the right Twilio configuration; the call itself is identified by the CallSid Twilio sends in the signed request body.

Channels

ChannelPurpose
TwilioSmsBidirectional SMS over Twilio Conversations
TwilioWhatsAppBidirectional WhatsApp over Twilio Conversations
TwilioVoiceVoice calls (spoken prompts, keypress and speech input)

WhatsApp notes

WhatsApp has unique constraints worth highlighting:

  • Sandbox onboarding — users must first text the "join code" to the sandbox number before they can receive anything.
  • 24-hour session window — free-form messages (via Body) are only allowed within 24 hours of the user's last inbound message. Outside the window, use ContentSid to send an approved template.
  • Template approval — new message templates must be submitted for WhatsApp approval through Twilio before they can be sent.

Gotchas

Italian SMS carrier rewrites

Replies in an SMS conversation are posted without an explicit sender — Twilio picks the outbound number from the Messaging Service's sender pool. For recipients on Italian carriers, the operator's SMS gateway may rewrite the sender on the downstream leg and deliver the message from a shared short code instead of the long code it was sent from. The end user sees the reply arriving from a short code and, if they try to reply to it, gets the carrier template "Can't reply to this short code".

This happens even when the Messaging Service pool contains only long codes — the rewrite happens downstream of Twilio. Fixes:

  • Register the Italian long code for A2P (Twilio Console → Messaging → Regulatory Compliance).
  • Or steer the conversation over WhatsApp (whatsapp:+… is not subject to the rewrite).

Short-code entries in the Messaging Service pool

If your Messaging Service sender pool contains an actual US / international short code in addition to the long code, Twilio may pick the short code for some replies even when the inbound was on the long code. Remove the short code from the pool, or enable Sticky Sender on the Messaging Service so subsequent messages in a conversation stay on whichever sender was used first.

Messaging Service Inbound Request URL hijacking inbound messages

If the Messaging Service has a stale Inbound Request URL set, it overrides the Conversation Service autocreate. Inbound WhatsApp / SMS never reaches the /Conversations/event/… endpoint — it hits whatever URL the Messaging Service points at (in one observed case, the voice webhook on the same phone number). Enable Clear Messaging Service Inbound Webhook on Deploy to wipe the override on every Deployment.

Best practices

  1. Keep Validate Signatures on — it's the only thing standing between your webhooks and forged requests; disable it only briefly for local debugging.
  2. Use a Messaging Service for outbound SMS — number pooling, sticky sender, and opt-out handling come for free, and you stop hardcoding From numbers in Tasks.
  3. Gate OTP sends with a number lookup — run TwilioLookupNumberTask first and branch on {lookup.valid} to avoid paying for Verify attempts to landlines and invalid numbers.
  4. Use templates outside the WhatsApp window — set ContentSid on TwilioSendWhatsAppTask for any message that might land more than 24 hours after the user's last reply.
  5. Turn migration off after the wave — leave Migrate Active Conversations on Deploy enabled only while you're actually changing the WhatsApp From Number; otherwise every Deployment closes live conversations.

Error codes

The Twilio failure modes map to these codes — see the full reference for resolutions:

CodeNameDescription
4001ModuleExceptionTwilio rejected an API request (invalid number, unverified sender, bad media URL, ...)
4008ModuleMissingConfigurationAccount SID, Auth Token, or a required service SID is not set in the Environment configuration
4012ModuleInvalidDataAn inbound webhook payload was malformed (missing call or conversation identifier)
4020WebhookSignatureInvalidAn inbound webhook failed the signature check
4021OtpNotApprovedTwilio Verify returned a status other than approved