Skip to main content

Overview

The Twilio integration enables Fanfare to send SMS messages to consumers for transactional notifications and authentication. This includes:
  • One-time password (OTP) codes for login
  • Appointment confirmations and reminders
  • Draw and auction outcome notifications
  • Queue admission alerts
  • Waitlist updates

Prerequisites

Before using the Twilio integration, Fanfare must be configured with:
  • A Twilio account with an active phone number
  • Twilio Account SID and Auth Token
  • A messaging service or phone number for sending
Note: The Twilio integration is pre-configured for the Fanfare platform. Individual organizations do not need to set up their own Twilio accounts - all SMS messages are sent from Fanfare’s shared messaging infrastructure.

Supported Message Types

Authentication Messages

TemplateDescription
OTP_LOGINOne-time password for passwordless login
PERSONAL_ACCESS_CODEUnique access codes for experiences

Appointment Messages

TemplateDescription
APPOINTMENT_CONFIRMATIONConfirms booking details
APPOINTMENT_REMINDERReminds of upcoming appointment
APPOINTMENT_CANCELLEDNotifies of cancellation
APPOINTMENT_RESCHEDULEDNotifies of date/time change

Experience Outcome Messages

TemplateDescription
AUCTION_WONNotifies winner of auction
AUCTION_LOSTNotifies non-winners
DRAW_WONNotifies draw winner
DRAW_ENTEREDConfirms draw entry
DRAW_NOT_SELECTEDNotifies non-selection
QUEUE_ADMITTEDNotifies queue admission

Waitlist Messages

TemplateDescription
WAITLIST_CONFIRMATIONConfirms waitlist signup
WAITLIST_NOTIFIEDNotifies of availability

Message Delivery

How Messages Are Sent

┌─────────────┐     ┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│   Fanfare   │────▶│    SNS      │────▶│    SQS      │────▶│   Lambda    │
│   Event     │     │   Topic     │     │   Queue     │     │  Processor  │
└─────────────┘     └─────────────┘     └─────────────┘     └─────────────┘



                                                            ┌─────────────┐
                                                            │   Twilio    │
                                                            │    API      │
                                                            └─────────────┘
  1. An event triggers an SMS (e.g., consumer wins auction)
  2. Message is queued via SNS/SQS
  3. Lambda processor sends via Twilio API
  4. Delivery status tracked via webhooks

Delivery Status

Messages can have the following statuses:
StatusDescription
SENTMessage accepted by Twilio
DELIVEREDMessage delivered to device
FAILEDDelivery failed
READMessage was read (when supported)

Webhook Events

Fanfare receives delivery status updates from Twilio via webhooks:

Webhook Payload

Twilio sends status callbacks with the following fields:
FieldDescription
MessageSidUnique message identifier
MessageStatus / SmsStatusCurrent delivery status
ToRecipient phone number
FromSender phone number

Webhook Security

Twilio webhooks are verified using HMAC-SHA1 signatures:
// Signature computation
const signature = computeTwilioSignature(authToken, fullUrl, params);
const isValid = timingSafeEqual(signature, headerSignature);
The signature is computed over:
  1. The full webhook URL (including query parameters)
  2. All form parameters in alphabetical order

Engagement Tracking

When a message is marked as READ:
  • Consumer’s engagedCount is incremented
  • lastEngagedAt timestamp is updated
  • Used for engagement scoring and analytics

API Reference

Queue SMS Message

Send an SMS message to a consumer.
POST /api/messaging/send-sample
Content-Type: application/json

{
  "channel": "SMS",
  "template": "OTP_LOGIN",
  "toPhone": "+15551234567",
  "templateData": {
    "template": "OTP_LOGIN",
    "otpCode": "123456"
  }
}
Response:
{
  "status": "queued",
  "id": "msg_abc123"
}

Template Data Schemas

Each template requires specific data: OTP_LOGIN:
{
  "template": "OTP_LOGIN",
  "otpCode": "123456"
}
APPOINTMENT_CONFIRMATION:
{
  "template": "APPOINTMENT_CONFIRMATION",
  "appointmentDate": "2024-06-25T14:00:00Z",
  "timeZone": "America/Los_Angeles",
  "locationName": "Downtown Store",
  "productName": "Limited Edition Sneakers"
}
AUCTION_WON:
{
  "template": "AUCTION_WON",
  "productName": "Exclusive Watch",
  "winningBid": "$1,250.00"
}
QUEUE_ADMITTED:
{
  "template": "QUEUE_ADMITTED",
  "productName": "New Release"
}

Rate Limiting

API Rate Limits

The messaging endpoint is rate-limited to prevent abuse:
LimitWindowScope
10 requests60 secondsPer user per organization

Twilio Rate Limits

Twilio has carrier-level rate limits:
  • US/Canada: ~1 message/second per phone number
  • Use messaging services for higher throughput

Phone Number Validation

Phone numbers must be in E.164 format:
  • Start with + followed by country code
  • No spaces, dashes, or parentheses
  • Examples: +15551234567, +442071234567
Invalid phone numbers will result in an error:
{
  "error": "Invalid phone number format"
}

Testing

Sending Test Messages

Use the messaging endpoint to send test messages:
POST /api/messaging/send-sample
Content-Type: application/json

{
  "channel": "SMS",
  "template": "OTP_LOGIN",
  "toPhone": "+15551234567"
}
If templateData is omitted, sample data is generated automatically.

Test Metadata

Test messages include metadata:
  • isTest: true
  • requestedBy: <userId>
  • ts: <timestamp>

Troubleshooting

Common Issues

Message not delivered
  • Verify phone number is in E.164 format
  • Check if the number is valid and can receive SMS
  • Review Twilio logs for carrier errors
Webhook not received
  • Verify webhook URL is publicly accessible
  • Check Twilio signature validation
  • Review webhook configuration in Twilio console
Rate limit exceeded
  • Wait for the rate limit window to reset
  • Reduce message frequency
  • Contact support for higher limits
Invalid template data
  • Verify all required fields are provided
  • Check field types match the schema
  • Use the correct template name

Checking Message Status

Query the transactional messages table:
SELECT
  id,
  status,
  provider_message_id,
  created_at,
  sent_at
FROM transactional_messages
WHERE organization_id = 'org_123'
  AND channel_type = 'SMS'
ORDER BY created_at DESC;

Delivery Event Logs

Check delivery events for detailed status:
SELECT
  event_type,
  event_time,
  raw_webhook_data
FROM message_delivery_events
WHERE transactional_message_id = 'msg_123'
ORDER BY event_time;

Security

Message Content

  • Messages are sent from Fanfare’s verified sender
  • No sensitive data beyond the template variables
  • OTP codes expire after a short window

Phone Number Privacy

  • Phone numbers are stored encrypted
  • Only displayed in masked format in the UI
  • Not included in logs

Webhook Authentication

  • All callbacks verified via Twilio signature
  • Invalid signatures are rejected with 401
  • Timing-safe comparison prevents timing attacks

Limitations

LimitationDescription
E.164 format requiredPhone numbers must include country code
No MMS supportOnly plain text SMS supported
Carrier filteringSome carriers may filter automated messages
International ratesInternational SMS has varying delivery rates

Delivery Considerations

Carrier Filtering

Some messages may be filtered by carriers:
  • Use clear, non-promotional language
  • Include opt-out instructions where required
  • Monitor delivery rates for issues

Time Zones

Appointment messages respect time zones:
  • Store appointments in UTC
  • Pass timeZone parameter for display formatting
  • Messages show localized date/time