whitebox-pro-sms-twilio
v0.2.0
Published
Twilio provider for whitebox-pro-server-plugin-sms — send (Messages API), inbound + delivery-status webhooks, X-Twilio-Signature verification. No SDK (raw REST).
Readme
whitebox-pro-sms-twilio
Twilio provider for whitebox-pro-server-plugin-sms. Lives in its own repo; the SMS plugin stays provider-agnostic and composes this in like any other integration. Raw REST (no SDK): send via the Messages API, inbound + status parsed from Twilio's form posts, X-Twilio-Signature verified.
import { sms } from 'whitebox-pro-server-plugin-sms'
import { twilio } from 'whitebox-pro-sms-twilio'
sms({
provider: twilio({
accountSid: process.env.WB_TWILIO_SID,
authToken: process.env.WB_TWILIO_TOKEN,
from: process.env.WB_TWILIO_FROM, // a Twilio number, or use messagingServiceSid
statusCallback: 'https://YOUR_HOST/sms/webhooks/twilio/status',
// messagingServiceSid: process.env.WB_TWILIO_MSID, // use a Messaging Service instead of `from`
// webhookBaseUrl: 'https://YOUR_HOST', // override host used for signature validation (proxies)
// validateWebhooks: true, // set false only for local testing
}),
auth: { secret: process.env.WB_SMS_TOKEN },
})What it implements
The neutral SMS-provider contract the plugin consumes:
| method | Twilio specifics |
|---|---|
| send({ to, from, body, media }) → { messageId } | POST Messages.json; From or MessagingServiceSid; MediaUrl for MMS; returns the message sid |
| verifySignature(req, kind) | X-Twilio-Signature — HMAC-SHA1 over the full URL + alphabetically-sorted POST params, base64, timing-safe compared |
| parseInbound(req) | From/To/Body + NumMedia/MediaUrl{n} → canonical inbound (drives STOP/START) |
| parseStatus(req) | MessageStatus → sent/delivered/undelivered/failed; ErrorCode → error message |
| classifyError(err) | known permanent codes (invalid/unreachable/landline/unsubscribed) ⇒ blocklist instead of retry |
Webhook setup
Both endpoints are public but HMAC-verified by this provider — Twilio signs every request with your auth token, and the plugin rejects anything unsigned or tampered. If WhiteBox sits behind a proxy that rewrites the host, set webhookBaseUrl so the signature base string matches what Twilio signed.
1. Status callbacks. Set statusCallback (above) to https://YOUR_HOST/sms/webhooks/twilio/status. Twilio POSTs MessageStatus transitions there:
| Twilio MessageStatus | canonical | effect in WhiteBox |
|---|---|---|
| sent | sent | outbox status → sent |
| delivered | delivered | → delivered |
| undelivered | undelivered | → undelivered (+ invalid list) |
| failed | failed | → failed (+ invalid list) |
(queued/sending/accepted/scheduled are in-flight — no status advance.)
2. Inbound replies (MO). In the Twilio console, set your number's (or Messaging Service's) inbound webhook to https://YOUR_HOST/sms/webhooks/twilio/inbound (POST). Replies become awareness, and STOP/START keywords flip the suppression list automatically.
Both routes live under the SMS plugin's mount, so the full URLs are https://YOUR_HOST/sms/webhooks/twilio/status and …/twilio/inbound.
Credentials
accountSid + authToken from the Twilio console. Keep them in the environment (WB_TWILIO_SID, WB_TWILIO_TOKEN) — never commit them.
