@maxnate/provider-twilio
v0.1.1
Published
Twilio SMS + WhatsApp provider for @maxnate/sms-core. Implements SmsProviderAdapter with HMAC-SHA1 webhook verification and delivery-receipt normalization.
Maintainers
Readme
@maxnate/provider-twilio
Twilio SMS + WhatsApp provider for @maxnate/sms-core.
Implements SmsProviderAdapter with HMAC-SHA1 webhook verification (X-Twilio-Signature) and delivery-receipt status normalization.
npm install @maxnate/provider-twilio @maxnate/sms-coreChannels
| Channel | channel value | From-format |
|---|---|---|
| SMS | "sms" | +15551234567 |
| WhatsApp | "whatsapp" | whatsapp:+15551234567 |
Credentials
| Field | Description |
|---|---|
| accountSid | Twilio Account SID (AC...). Console > Account > General. |
| authToken | Twilio Auth Token. Console > Account > General. |
| webhookSecret | Optional. Used for HMAC-SHA1 verification of inbound webhooks (defaults to authToken). |
Usage
import { createSmsProviderRegistry } from '@maxnate/sms-core'
import { TwilioSmsProvider } from '@maxnate/provider-twilio'
const registry = createSmsProviderRegistry({ configStore, secretsCodec })
registry.register(new TwilioSmsProvider())
await registry.configureProvider('tenant-1', {
id: 'twilio', name: 'Twilio', enabled: true,
credentials: {
accountSid: process.env.TWILIO_ACCOUNT_SID!,
authToken: process.env.TWILIO_AUTH_TOKEN!
},
fromNumber: '+15551234567',
channels: ['sms', 'whatsapp']
})
// SMS
await registry.send('tenant-1', 'twilio', {
to: '+15551112222',
body: 'Your code is 123456',
channel: 'sms'
})
// WhatsApp
await registry.send('tenant-1', 'twilio', {
to: 'whatsapp:+15551112222',
body: 'Hello via WhatsApp',
channel: 'whatsapp'
})Webhook Handling
Twilio signs inbound webhooks with HMAC-SHA1 over the full request URL + sorted form parameters. The provider exposes verifyWebhook + handleWebhook methods that adapt this scheme to the canonical SmsWebhookEvent shape.
app.post('/webhooks/sms/twilio', async (req, res) => {
const provider = registry.get('twilio')!
const signature = req.headers['x-twilio-signature'] as string
const ok = await provider.verifyWebhook?.(req.rawBody, signature, {
'x-twilio-signature': signature,
'x-original-url': fullRequestUrl(req) // include query string
})
if (!ok) return res.status(401).send('invalid signature')
const event = await provider.handleWebhook?.(req.rawBody, signature)
// event.type ∈ 'sms.queued' | 'sms.sent' | 'sms.delivered' | 'sms.failed' | 'sms.undelivered'
res.status(200).send('OK')
})Delivery Status Mapping
| Twilio MessageStatus | Mapped SmsDeliveryStatus |
|---|---|
| queued, accepted | queued |
| sending, sent | sent |
| delivered, read | delivered |
| failed | failed |
| undelivered | undelivered |
Requirements
- Node.js >= 18
@maxnate/sms-core^0.1.0
License
MIT
