# Twilio Binding
This binding integrates with the Twilio (opens new window) cloud communications platform. It allows sending and receiving SMS, MMS, and WhatsApp messages, as well as making and receiving voice calls with text-to-speech and DTMF input support.
Typical use cases include:
- Sending SMS/MMS alerts when events occur (door opens, alarm triggers, temperature threshold)
- Receiving SMS commands to control your smart home ("status", "arm alarm", "turn on lights")
- Making voice calls for critical alerts with text-to-speech
- Receiving incoming calls with an interactive voice menu (press 1 for X, press 2 for Y)
- Sending and receiving WhatsApp messages
# Supported Things
| Thing Type | Description |
|---|---|
account | A Twilio account (bridge). Holds API credentials and shared settings. |
phone | A Twilio phone number. Sends/receives messages and calls. Requires an account bridge. |
# Discovery
Once a Twilio Account bridge is added and goes online, the binding automatically discovers all phone numbers associated with the account and adds them to the inbox. You can also trigger a manual scan from the UI.
The account bridge itself must be created manually with your Twilio Console (opens new window) credentials.
# Thing Configuration
# account Bridge Configuration
| Name | Type | Description | Default | Required | Advanced |
|---|---|---|---|---|---|
| accountSid | text | Twilio Account SID (starts with AC) | N/A | yes | no |
| authToken | text | Twilio Auth Token | N/A | yes | no |
| publicUrl | text | Public-facing base URL for webhooks (e.g. https://my.domain.com) | N/A | no | yes |
| autoConfigureWebhooks | boolean | Automatically set webhook URLs on Twilio phone numbers via API | true | no | yes |
| useCloudWebhook | boolean | Use openHAB Cloud for webhook callbacks (no port forwarding needed) | false | no | yes |
The Account SID and Auth Token can be found in the Twilio Console (opens new window).
To receive incoming messages and calls, you need one of the following:
- openHAB Cloud Webhooks (recommended): Set
useCloudWebhooktotrue. Requires the openHAB Cloud Connector add-on to be installed and connected. No port forwarding or reverse proxy needed. - Public URL: Set
publicUrlto a publicly-reachable URL for your openHAB instance. You can use a reverse proxy, port forwarding, or a service like ngrok.
# phone Thing Configuration
| Name | Type | Description | Default | Required | Advanced |
|---|---|---|---|---|---|
| phoneNumber | text | Twilio phone number in E.164 format (e.g. +15551234567) | N/A | yes | no |
| voiceGreeting | text | TwiML template for incoming voice calls | See below | no | yes |
| gatherResponse | text | TwiML returned after DTMF digits are gathered (fallback) | <Response><Say>Thank you. Goodbye.</Say></Response> | no | yes |
| responseTimeout | integer | Seconds to wait for a rule to respond with TwiML (1-14) | 10 | no | yes |
The default voiceGreeting includes a <Gather> element that collects one DTMF digit:
<Response>
<Gather numDigits="1" action="{gatherUrl}">
<Say>Hello. This is the openHAB smart home system. Press any key.</Say>
</Gather>
<Say>No input received. Goodbye.</Say>
</Response>
The {gatherUrl} placeholder is automatically replaced with the correct webhook URL.
# Channels
# State Channels
| Channel | Type | Description |
|---|---|---|
| last-message-body | String | Body text of the last received SMS/WhatsApp message |
| last-message-from | String | Phone number of the last message sender |
| last-message-date | DateTime | Timestamp of the last received message |
| last-message-media-url | String | URL of the first media attachment (MMS/WhatsApp) |
| last-message-sid | String | Twilio Message SID of the last received message |
| last-call-from | String | Phone number of the last incoming caller |
| last-call-status | String | Status of the last call (ringing, in-progress, completed) |
| last-call-date | DateTime | Timestamp of the last incoming call |
| last-dtmf-digits | String | Last DTMF digits received from a caller |
# Trigger Channels
| Channel | Payload | Description |
|---|---|---|
| sms-received | JSON | Triggered on incoming SMS/MMS |
| whatsapp-received | JSON | Triggered on incoming WhatsApp message |
| call-received | JSON | Triggered on incoming voice call |
| dtmf-received | JSON | Triggered when DTMF digits are gathered |
| message-status | JSON | Triggered on message delivery status change |
| call-status-update | JSON | Triggered on call status change |
Trigger channel payloads are JSON objects. Example sms-received payload:
{"from":"+15559876543","to":"+15551234567","body":"Hello!","messageSid":"SM...","numMedia":"0","mediaUrls":[]}
# Rule Actions
Actions are available on phone things under the twilio scope.
# SMS Actions
| Action | Parameters | Description |
|---|---|---|
sendSMS | String to, String message | Send a plain SMS |
sendSMS | String to, String message, String mediaUrl | Send an MMS with media. message is optional (may be null) to send media only. |
# WhatsApp Actions
| Action | Parameters | Description |
|---|---|---|
sendWhatsApp | String to, String message | Send a WhatsApp message |
sendWhatsApp | String to, String message, String mediaUrl | Send WhatsApp with media. message is optional (may be null) to send media only. |
# Voice Actions
| Action | Parameters | Description |
|---|---|---|
makeCall | String to, String twiml | Make a call with raw TwiML |
makeTTSCall | String to, String text | Make a call with text-to-speech |
makeTTSCall | String to, String text, String voice | TTS with voice selection (e.g. "alice", "Polly.Joanna") |
respondWithTwiml | String callSid, String twiml | Respond to an active call with TwiML (see Dynamic Voice below) |
# Media URL Actions
| Action | Parameters | Returns | Description |
|---|---|---|---|
createItemMediaUrl | String itemName | String (URL) | Create a temporary public URL from an openHAB Image item |
createProxyMediaUrl | String sourceUrl | String (URL) | Create a temporary public URL that proxies a local/internal URL |
These actions create time-limited (5 minute) public URLs for media that Twilio can fetch.
This is useful for sending camera snapshots or locally-hosted media as MMS/WhatsApp attachments.
Either publicUrl must be configured on the bridge or useCloudWebhook must be enabled for these actions to work.
Supported media types: Any content type works (images, audio, video, PDFs).
For Image items, the MIME type is determined from the item's RawType state.
For proxy URLs, the MIME type is detected from the source server's response.
# Dynamic Voice Calls (respondWithTwiml)
The binding supports fully interactive voice calls where rules control the call flow in real time.
When an incoming call arrives or DTMF digits are pressed, the binding holds the HTTP response open and waits for a rule to provide TwiML via the respondWithTwiml action.
How it works:
- Twilio sends a webhook (incoming call or DTMF digits)
- The binding fires a trigger channel (
call-receivedordtmf-received) - The binding waits up to
responseTimeoutseconds (default: 10) for a rule to callrespondWithTwiml - If the rule responds in time, that TwiML is returned to Twilio
- If the timeout expires, the default TwiML from the thing config is used as fallback
The {gatherUrl} placeholder can be used in your TwiML to create multi-step menus.
It is automatically replaced with the correct URL for the phone thing's gather endpoint.
# Timeout Behavior
If a rule does not call respondWithTwiml within the configured responseTimeout (default: 10 seconds), the binding returns the default TwiML from the thing configuration:
- For incoming calls: the
voiceGreetingconfig parameter - For DTMF gather: the
gatherResponseconfig parameter
This means existing rules that don't use respondWithTwiml continue to work as before.
The timeout is configurable per phone thing via the responseTimeout advanced parameter (1-14 seconds).
# Webhook Setup
To receive incoming messages and calls, you need to configure webhooks so Twilio can reach your openHAB instance.
# Option 1: openHAB Cloud Webhooks (Recommended)
The simplest approach is to use the openHAB Cloud service to provide publicly-reachable webhook URLs. This eliminates the need for port forwarding, reverse proxies, or a public IP address.
Requirements:
- The openHAB Cloud Connector (opens new window) add-on must be installed and connected
Setup:
- Enable
useCloudWebhookon the bridge (set totrue) - If not using auto-configure, copy the webhook URLs from the phone thing properties in the UI and paste them into the Twilio Console (opens new window)
The binding will register cloud webhook URLs (e.g. https://myopenhab.org/api/hooks/{uuid}) for each endpoint.
These URLs are shown in the phone thing properties.
Bridge twilio:account:myaccount "Twilio Account" [ accountSid="ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", authToken="your_auth_token", useCloudWebhook=true ] {
Thing phone myphone "My Twilio Number" [ phoneNumber="+15551234567" ]
}
# Option 2: Public URL
- Set the
publicUrlon the bridge (e.g.https://my.domain.com) - The binding will automatically configure the webhook URLs on your Twilio phone numbers via the API
If you disable autoConfigureWebhooks, you can manually copy the webhook URLs from the phone thing properties in the UI and paste them into the Twilio Console (opens new window):
- Messaging > A Message Comes In: paste the
smsWebhookUrlproperty value - Voice & Fax > A Call Comes In: paste the
voiceWebhookUrlproperty value
# URL Structure
All webhook and media endpoints are served under /twilio/callback/ on your openHAB instance.
If using a reverse proxy, you must forward this entire path prefix.
| Path | Method | Purpose |
|---|---|---|
/twilio/callback/{thingUID}/sms | POST | Incoming SMS/MMS messages |
/twilio/callback/{thingUID}/whatsapp | POST | Incoming WhatsApp messages (equivalent to /sms) |
/twilio/callback/{thingUID}/voice | POST | Incoming voice calls |
/twilio/callback/{thingUID}/gather | POST | DTMF digit gather callbacks |
/twilio/callback/{thingUID}/status | POST | Message/call status updates |
/twilio/callback/media/{uuid} | GET | Temporary media serving (for MMS/WhatsApp attachments) |
The {thingUID} is the full thing UID (e.g. twilio:phone:myaccount:myphone).
The {uuid} is a randomly generated identifier for temporary media entries.
Both /sms and /whatsapp route incoming messages to the same handler; WhatsApp is detected from the From: prefix Twilio sends.
Auto-configuration only sets a single Messaging webhook on Twilio (via /sms), which is sufficient for both SMS/MMS and WhatsApp when using a Twilio Messaging Service.
The /whatsapp path is available for users who prefer to configure a separate WhatsApp webhook manually.
Example full URLs (assuming publicUrl is https://my.domain.com):
https://my.domain.com/twilio/callback/twilio:phone:myaccount:myphone/sms
https://my.domain.com/twilio/callback/twilio:phone:myaccount:myphone/voice
https://my.domain.com/twilio/callback/media/550e8400-e29b-41d4-a716-446655440000
# Full Example
# Thing Configuration
Bridge twilio:account:myaccount "Twilio Account" [ accountSid="ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", authToken="your_auth_token", publicUrl="https://my.domain.com" ] {
Thing phone myphone "My Twilio Number" [ phoneNumber="+15551234567" ]
}
# Item Configuration
String TwilioLastMessage "Last SMS [%s]" { channel="twilio:phone:myaccount:myphone:last-message-body" }
String TwilioLastFrom "From [%s]" { channel="twilio:phone:myaccount:myphone:last-message-from" }
DateTime TwilioLastDate "Received [%1$tF %1$tR]" { channel="twilio:phone:myaccount:myphone:last-message-date" }
String TwilioLastCallFrom "Last Caller [%s]" { channel="twilio:phone:myaccount:myphone:last-call-from" }
String TwilioLastDtmf "DTMF [%s]" { channel="twilio:phone:myaccount:myphone:last-dtmf-digits" }