@xenterprises/fastify-xtwilio
v1.3.0
Published
Fastify plugin for Twilio communications (SMS, Conversations, RCS) and SendGrid email.
Readme
@xenterprises/fastify-xtwilio
Fastify v5 plugin for Twilio communications (SMS, Conversations, RCS) and SendGrid email. One registration decorates the Fastify instance with a single xTwilio namespace exposing sms, conversations, rcs, and email services — for SaaS apps that need transactional messaging with the least possible setup code.
Installation
npm install @xenterprises/fastify-xtwilio fastify@5Minimal example
import Fastify from "fastify";
import xTwilio from "@xenterprises/fastify-xtwilio";
const fastify = Fastify();
await fastify.register(xTwilio, {
twilio: {
accountSid: process.env.TWILIO_ACCOUNT_SID, // consumer owns env access
authToken: process.env.TWILIO_AUTH_TOKEN,
phoneNumber: process.env.TWILIO_PHONE_NUMBER,
},
});
// Send SMS
await fastify.xTwilio.sms.send("+1234567890", "Hello!");The plugin never reads process.env itself — all configuration arrives via register options. Register with only the services you need: a service whose option object (twilio or sendgrid) is omitted is skipped silently, and you can still disable one explicitly with active: false. A service object that is present but missing credentials is a hard registration error.
Options
All options are optional at the top level: omit twilio or sendgrid entirely to skip that service group. Once a service object is present, its credential options are required unless active: false.
twilio (object)
| Name | Type | Default | Required | Description |
|------|------|---------|----------|-------------|
| accountSid | string | — | Yes (if active) | Twilio Account SID |
| authToken | string | — | Yes (if active) | Twilio Auth Token |
| phoneNumber | string | — | One of phone/msgSvc | Phone number for SMS (E.164 format) |
| messagingServiceSid | string | — | One of phone/msgSvc | Messaging Service SID (required for RCS and scheduled SMS) |
| active | boolean | true | No | Set false to disable all Twilio services (omitting twilio entirely does the same) |
sendgrid (object)
| Name | Type | Default | Required | Description |
|------|------|---------|----------|-------------|
| apiKey | string | — | Yes (if active) | SendGrid API key |
| fromEmail | string | — | Yes (if active) | Verified sender email address |
| fromName | string | — | No | Display name for the sender (sends { email, name } as the from field) |
| active | boolean | true | No | Set false to disable the email service (omitting sendgrid entirely does the same) |
Decorators
fastify.xTwilio
Single namespace holding the four services. A service is absent (undefined) when its option object is omitted or disabled via active: false; rcs is additionally absent unless twilio.messagingServiceSid is provided.
fastify.xTwilio.sms
| Method | Signature | Description |
|--------|-----------|-------------|
| send | (to, body, extraOptions?) => Promise | Send an SMS message |
| sendMMS | (to, body, mediaUrl, extraOptions?) => Promise | Send an MMS with media attachment(s) |
| schedule | (to, body, sendAt) => Promise | Schedule an SMS (requires messagingServiceSid) |
| cancelScheduled | (messageSid) => Promise | Cancel a scheduled message |
| get | (messageSid) => Promise | Fetch a message by SID |
| getStatus | (messageSid) => Promise | Get delivery status of a message |
| list | (filters?) => Promise | List messages with optional filters |
| delete | (messageSid) => Promise<boolean> | Delete a message |
| getMedia | (messageSid) => Promise | Get media items from an MMS |
| validatePhoneNumber | (phoneNumber, options?) => Promise | Validate a phone number via Twilio Lookup v2 |
| sendBulk | (messages) => Promise | Send multiple SMS concurrently |
fastify.xTwilio.conversations
| Method | Signature | Description |
|--------|-----------|-------------|
| create | (friendlyName, attributes?) => Promise | Create a new conversation |
| get | (conversationSid) => Promise | Get conversation by SID |
| update | (conversationSid, updates) => Promise | Update conversation properties |
| list | (filters?) => Promise | List all conversations |
| delete | (conversationSid) => Promise<boolean> | Delete a conversation |
| addParticipant | (conversationSid, identity?, address?) => Promise | Add a chat or SMS participant |
| listParticipants | (conversationSid) => Promise | List conversation participants |
| removeParticipant | (conversationSid, participantSid) => Promise<boolean> | Remove a participant |
| sendMessage | (conversationSid, body, author?, attributes?) => Promise | Send a text message |
| sendMediaMessage | (conversationSid, mediaUrl, body?, author?) => Promise | Send a media message |
| getMessages | (conversationSid, options?) => Promise | List conversation messages |
| getMessage | (conversationSid, messageSid) => Promise | Get a specific message |
| deleteMessage | (conversationSid, messageSid) => Promise<boolean> | Delete a message |
| getWebhooks | (conversationSid) => Promise | List conversation webhooks |
| createWebhook | (conversationSid, webhookConfig) => Promise | Create a conversation webhook |
fastify.xTwilio.rcs
Only registered when twilio.messagingServiceSid is provided.
| Method | Signature | Description |
|--------|-----------|-------------|
| send | (to, body, extraOptions?) => Promise | Send a basic RCS text message |
| sendMedia | (to, body, mediaUrl) => Promise | Send an RCS message with media |
| sendTemplate | (to, contentSid, contentVariables?) => Promise | Send using a Content Template |
| sendRichCard | (to, card) => Promise | Send a rich card (title, description, media, actions) |
| sendCarousel | (to, cards) => Promise | Send a carousel of cards |
| sendQuickReplies | (to, body, replies) => Promise | Send with suggested quick replies |
| getStatus | (messageSid) => Promise | Get RCS message delivery status |
| listTemplates | (options?) => Promise | List Content API templates |
| getTemplate | (contentSid) => Promise | Get a template by SID |
| deleteTemplate | (contentSid) => Promise<boolean> | Delete a template |
fastify.xTwilio.email
| Method | Signature | Description |
|--------|-----------|-------------|
| send | (to, subject, html, text?, extraOptions?) => Promise | Send an email |
| sendTemplate | (to, subject, templateId, dynamicData?, extraOptions?) => Promise | Send using a SendGrid template |
| sendWithAttachments | (to, subject, html, attachments) => Promise | Send with file attachments |
| sendBulk | (to[], subject, html) => Promise | Send same content to multiple recipients |
| sendPersonalizedBulk | (messages[]) => Promise | Send different content per recipient |
| validate | (email) => Promise | Validate an email address |
| addContact | (email, data?, listIds?) => Promise | Add/update a marketing contact |
| searchContact | (email) => Promise | Search for a contact by email |
| deleteContact | (contactId) => Promise<boolean> | Delete a marketing contact |
| createList | (name) => Promise | Create a contact list |
| getLists | () => Promise | Get all contact lists |
| deleteList | (listId) => Promise<boolean> | Delete a contact list |
Routes
None. The plugin adds no routes and no request hooks; it only decorates the instance.
Error behavior
Registration fails fast on missing or invalid options. Option errors name the plugin, the option, and show an example registration:
xtwilio: missing required option `twilio.accountSid` (string), e.g. `app.register(xTwilio, { twilio: { accountSid: 'AC...', authToken: 'your_auth_token', phoneNumber: '+15551234567' } })`
xtwilio: option `sendgrid.apiKey` must be a string, e.g. ...Every public method validates its arguments before calling external APIs; argument errors are prefixed with the service and method (e.g. [xTwilio] sms.send: to (string) is required.).
External API failures are logged via fastify.log.error (message only — no request config or credentials) and re-thrown as [xTwilio] Failed to <operation>: <original message>. Two methods intentionally do not throw on API failure and instead return a result object: sms.validatePhoneNumber returns { valid: false, ... } and email.validate returns { valid: false, verdict: "Unknown", error }.
Requirements
- Node.js >= 20
- Fastify ^5.0.0 (peer dependency)
License
Proprietary — All Rights Reserved X Enterprises. See LICENSE.
