Skip to content

Twilio Integration

Receive and route Twilio webhooks for SMS messages, voice calls, and other communication events.

Setup

1. Create a Source in Hookbase

bash
curl -X POST https://api.hookbase.app/api/sources \
  -H "Authorization: Bearer whr_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Twilio",
    "slug": "twilio",
    "provider": "twilio",
    "verificationConfig": {
      "type": "twilio",
      "secret": "your-twilio-auth-token"
    }
  }'

Save your webhook URL:

https://api.hookbase.app/ingest/{orgSlug}/twilio

2. Configure Twilio Webhooks

For SMS/MMS

  1. Go to Twilio ConsolePhone Numbers
  2. Select your phone number
  3. Under Messaging, set:
    • A message comes in: Webhook, your Hookbase URL
    • HTTP Method: POST

For Voice

  1. Go to Phone Numbers → select your number
  2. Under Voice & Fax, set:
    • A call comes in: Webhook, your Hookbase URL
    • HTTP Method: POST

For Status Callbacks

Set the status callback URL on your API requests:

bash
curl -X POST "https://api.twilio.com/2010-04-01/Accounts/{AccountSid}/Messages.json" \
  -u "{AccountSid}:{AuthToken}" \
  -d "To=+15558675309" \
  -d "From=+15551234567" \
  -d "Body=Hello" \
  -d "StatusCallback=https://api.hookbase.app/ingest/{orgSlug}/twilio"

3. Create Destinations and Routes

bash
# Create a destination
curl -X POST https://api.hookbase.app/api/destinations \
  -H "Authorization: Bearer whr_your_api_key" \
  -d '{"name": "SMS Handler", "url": "https://myapp.com/webhooks/twilio"}'

# Create a route
curl -X POST https://api.hookbase.app/api/routes \
  -H "Authorization: Bearer whr_your_api_key" \
  -d '{"name": "Twilio to App", "sourceId": "src_...", "destinationIds": ["dst_..."]}'

Signature Verification

Twilio signs webhooks using your Auth Token. The signature is sent in the X-Twilio-Signature header.

Hookbase automatically verifies this when you configure:

json
{
  "verificationConfig": {
    "type": "twilio",
    "secret": "your-twilio-auth-token"
  }
}

TIP

The secret is your Twilio Auth Token, found on the Twilio Console dashboard.

Common Events

Incoming SMS

json
{
  "MessageSid": "SM1234567890abcdef",
  "AccountSid": "AC1234567890abcdef",
  "From": "+15551234567",
  "To": "+15558675309",
  "Body": "Hello from the customer",
  "NumMedia": "0",
  "FromCity": "NEW YORK",
  "FromState": "NY",
  "FromCountry": "US"
}

SMS Status Callback

json
{
  "MessageSid": "SM1234567890abcdef",
  "MessageStatus": "delivered",
  "To": "+15558675309",
  "From": "+15551234567",
  "ApiVersion": "2010-04-01",
  "AccountSid": "AC1234567890abcdef"
}

Message Statuses

StatusDescription
queuedMessage queued for sending
sendingMessage is being sent
sentMessage sent to carrier
deliveredMessage delivered to recipient
undeliveredMessage could not be delivered
failedMessage failed to send

Voice Call

json
{
  "CallSid": "CA1234567890abcdef",
  "AccountSid": "AC1234567890abcdef",
  "From": "+15551234567",
  "To": "+15558675309",
  "CallStatus": "ringing",
  "Direction": "inbound",
  "CallerCity": "NEW YORK",
  "CallerState": "NY",
  "CallerCountry": "US"
}

Call Statuses

StatusDescription
queuedCall queued
ringingPhone is ringing
in-progressCall connected
completedCall ended normally
busyBusy signal
no-answerNo answer
failedCall failed

Transform Examples

Slack Notification for SMS

javascript
function transform(payload) {
  return {
    blocks: [
      {
        type: "header",
        text: {
          type: "plain_text",
          text: "Incoming SMS"
        }
      },
      {
        type: "section",
        fields: [
          { type: "mrkdwn", text: `*From:*\n${payload.From}` },
          { type: "mrkdwn", text: `*To:*\n${payload.To}` }
        ]
      },
      {
        type: "section",
        text: {
          type: "mrkdwn",
          text: `*Message:*\n${payload.Body}`
        }
      }
    ]
  };
}

Normalize for Internal API

javascript
function transform(payload) {
  return {
    type: payload.CallSid ? 'call' : 'sms',
    sid: payload.MessageSid || payload.CallSid,
    from: payload.From,
    to: payload.To,
    body: payload.Body || null,
    status: payload.MessageStatus || payload.CallStatus,
    location: {
      city: payload.FromCity || payload.CallerCity,
      state: payload.FromState || payload.CallerState,
      country: payload.FromCountry || payload.CallerCountry
    },
    timestamp: new Date().toISOString()
  };
}

Filter Examples

Only Inbound SMS

json
{
  "name": "Inbound SMS Only",
  "conditions": [
    {
      "field": "payload.MessageSid",
      "operator": "exists"
    },
    {
      "field": "payload.Body",
      "operator": "exists"
    }
  ],
  "logic": "AND"
}

Failed Deliveries Only

json
{
  "name": "Failed Messages",
  "conditions": [
    {
      "field": "payload.MessageStatus",
      "operator": "in",
      "value": "failed,undelivered"
    }
  ]
}

Twilio Webhook Parameters

SMS Parameters

ParameterDescription
MessageSidUnique message ID
AccountSidTwilio account ID
FromSender phone number
ToRecipient phone number
BodyMessage text
NumMediaNumber of media attachments
MediaUrl{N}URL for media attachment N
FromCitySender's city
FromStateSender's state
FromCountrySender's country

Voice Parameters

ParameterDescription
CallSidUnique call ID
AccountSidTwilio account ID
FromCaller phone number
ToCalled phone number
CallStatusCurrent call status
Directioninbound or outbound-api
CallerCityCaller's city
CallerStateCaller's state
CallerCountryCaller's country

Troubleshooting

Webhook Not Triggering

  1. Verify the URL is set correctly in the Twilio Console
  2. Check Twilio's Debugger for errors
  3. Ensure the phone number is configured for the correct service (SMS/Voice)

Signature Verification Failed

  1. Use your Auth Token (not API Key SID) as the secret
  2. If using API Keys, use the account Auth Token, not the API Key Secret
  3. Ensure the webhook URL in Twilio matches exactly (including https://)

Duplicate Events

Enable deduplication using the MessageSid:

bash
curl -X PATCH .../sources/src_twilio \
  -d '{"dedupEnabled": true, "dedupStrategy": "auto"}'

Best Practices

  1. Verify signatures: Always enable signature verification
  2. Handle both formats: Twilio sends both form-encoded and JSON — Hookbase normalizes both to JSON
  3. Respond quickly: Twilio expects a response within 15 seconds for voice webhooks
  4. Use status callbacks: Track message delivery status for reliability
  5. Secure your endpoint: Use rejectInvalidSignatures: true for production

Released under the MIT License.