npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@xenterprises/fastify-xrcs

v1.2.1

Published

Fastify plugin for building and sending RCS rich cards and carousels via Twilio

Downloads

62

Readme

@xenterprises/fastify-xrcs

Fastify plugin for building and sending RCS rich cards and carousels via Twilio's Content API.

Installation

npm install @xenterprises/fastify-xrcs

Quick Start

import Fastify from "fastify";
import xRCS from "@xenterprises/fastify-xrcs";

const fastify = Fastify();

await fastify.register(xRCS, {
  accountSid: process.env.TWILIO_ACCOUNT_SID,
  authToken: process.env.TWILIO_AUTH_TOKEN,
  messagingServiceSid: process.env.TWILIO_MESSAGING_SERVICE_SID,
});

// Build and send a product card
const card = fastify.xrcs
  .card()
  .title("iPhone 15 Pro")
  .body("Starting at $999")
  .media("https://example.com/iphone.jpg")
  .quickReply("Buy Now", "buy_iphone")
  .urlButton("Learn More", "https://example.com/iphone");

await fastify.xrcs.sendCard("+15551234567", card);

Options

| Name | Type | Default | Required | Description | |------|------|---------|----------|-------------| | active | boolean | true | No | Enable/disable the plugin | | accountSid | string | — | No | Twilio Account SID. Must be provided with authToken | | authToken | string | — | No | Twilio Auth Token. Must be provided with accountSid | | messagingServiceSid | string | — | No | Twilio Messaging Service SID. Required for sending messages |

When accountSid and authToken are omitted the plugin runs in builder-only mode — you can construct card/carousel payloads locally but cannot call the Twilio API.

Environment Variables

| Name | Required | Description | |------|----------|-------------| | TWILIO_ACCOUNT_SID | Yes (for API mode) | Twilio Account SID (starts with AC) | | TWILIO_AUTH_TOKEN | Yes (for API mode) | Twilio Auth Token | | TWILIO_MESSAGING_SERVICE_SID | Yes (for sending) | Twilio Messaging Service SID (starts with MG) |

Decorated Properties

All methods and builders are available on fastify.xrcs.

Builder Factory Methods

| Method | Returns | Description | |--------|---------|-------------| | fastify.xrcs.card() | CardBuilder | Create a new card builder | | fastify.xrcs.carousel() | CarouselBuilder | Create a new carousel builder | | fastify.xrcs.template(name) | ContentTemplateBuilder | Create a new content template builder |

API Methods (require credentials)

| Method | Returns | Description | |--------|---------|-------------| | createTemplate(builder, register?) | Promise<object> | Create and optionally register a content template. Pass register=false to get the payload without calling Twilio | | sendMessage(to, contentSid, vars?) | Promise<object> | Send a message using a registered template SID | | sendCard(to, card, name?) | Promise<object> | Create a template from a card and send it in one step | | sendCarousel(to, carousel, name?) | Promise<object> | Create a template from a carousel and send it in one step | | getTemplate(contentSid) | Promise<object> | Fetch a template by SID | | listTemplates(limit?) | Promise<object[]> | List all content templates (default limit: 50) | | deleteTemplate(contentSid) | Promise<boolean> | Delete a content template | | getMessageStatus(messageSid) | Promise<object> | Get delivery status for a sent message |

Validation Helpers

| Method | Returns | Description | |--------|---------|-------------| | validate.card(card) | { valid, errors } | Validate a card object against RCS constraints | | validate.carousel(carousel) | { valid, errors } | Validate a carousel object against RCS constraints |

Configuration

| Property | Type | Description | |----------|------|-------------| | config.hasCredentials | boolean | Whether Twilio credentials are configured | | config.accountSid | string\|null | Masked account SID (first 8 chars) | | config.messagingServiceSid | string\|null | Messaging Service SID |

Classes & Constants

| Export | Description | |--------|-------------| | CardBuilder | Class for building RCS card structures | | CarouselBuilder | Class for building RCS carousel structures | | ContentTemplateBuilder | Class for building Twilio Content API payloads | | CONTENT_TYPES | Enum of supported content types (TEXT, MEDIA, CARD, CAROUSEL, QUICK_REPLY, CALL_TO_ACTION, LIST_PICKER) | | ACTION_TYPES | Enum of button action types (QUICK_REPLY, URL, PHONE_NUMBER) | | MEDIA_HEIGHT | Enum of media height options (SHORT, MEDIUM, TALL) |

Card Builder

const card = fastify.xrcs
  .card()
  .title("Product Name")                                    // Max 200 chars
  .body("Product description")
  .media("https://example.com/image.jpg", "tall")           // short | medium | tall
  .quickReply("Buy", "action_buy")                          // Quick reply button (max 25 chars)
  .urlButton("Details", "https://example.com/product")      // URL button
  .phoneButton("Call", "+15551234567");                      // Phone button

const cardData = card.build();  // Max 2 buttons per card

Carousel Builder

const carousel = fastify.xrcs
  .carousel()
  .body("Choose a product")     // RCS drops body text; WhatsApp shows it
  .addCard(fastify.xrcs.card().title("Laptop").body("$999").quickReply("Buy", "buy_laptop"))
  .addCard(fastify.xrcs.card().title("Tablet").body("$499").quickReply("Buy", "buy_tablet"));

await fastify.xrcs.sendCarousel("+15551234567", carousel);

Constraints: 2–10 cards, button types must be in the same order across all cards.

Content Template Builder

Build complete Twilio Content API payloads for any content type:

// Text with variables
const template = fastify.xrcs
  .template("Welcome")
  .language("en")
  .variables({ "1": "John" })
  .text("Hello {{1}}, welcome!")
  .build();

// Register with Twilio
const registered = await fastify.xrcs.createTemplate(template);

// Or get payload without registering
const payload = await fastify.xrcs.createTemplate(
  fastify.xrcs.template("Preview").text("Hello"),
  false
);

Supported Content Types

| Type | Constant | RCS | WhatsApp | |------|----------|-----|----------| | Text | CONTENT_TYPES.TEXT | Yes | Yes | | Media | CONTENT_TYPES.MEDIA | Yes | Yes | | Card | CONTENT_TYPES.CARD | Yes | Yes | | Carousel | CONTENT_TYPES.CAROUSEL | Yes | Yes | | Quick Reply | CONTENT_TYPES.QUICK_REPLY | Yes | Yes | | Call to Action | CONTENT_TYPES.CALL_TO_ACTION | No | Yes | | List Picker | CONTENT_TYPES.LIST_PICKER | No | Yes |

Error Reference

All errors are prefixed with [xRCS].

| Error | When | |-------|------| | [xRCS] accountSid must be a string | Non-string accountSid option at startup | | [xRCS] authToken must be a string | Non-string authToken option at startup | | [xRCS] messagingServiceSid must be a string | Non-string messagingServiceSid option at startup | | [xRCS] Both accountSid and authToken must be provided together | Only one of the pair is provided | | [xRCS] Twilio credentials required to register templates | Calling createTemplate without credentials | | [xRCS] Twilio credentials required to send messages | Calling sendMessage without credentials | | [xRCS] Twilio credentials required | Calling any read API without credentials | | [xRCS] messagingServiceSid required to send messages | Sending without messagingServiceSid | | [xRCS] 'to' must be a non-empty string | Empty/missing recipient | | [xRCS] 'contentSid' must be a non-empty string | Empty/missing template SID | | [xRCS] 'messageSid' must be a non-empty string | Empty/missing message SID | | [xRCS] 'limit' must be a positive number | Invalid limit for listTemplates | | [xRCS] Card title must be 200 characters or less | Title exceeds 200 chars | | [xRCS] Button title must be 25 characters or less | Button label exceeds 25 chars | | [xRCS] Cards can have a maximum of 2 buttons | More than 2 actions on a card | | [xRCS] Carousel must have at least 2 cards | Fewer than 2 cards | | [xRCS] Carousel can have a maximum of 10 cards | More than 10 cards | | [xRCS] Button types must be in the same order across all carousel cards | Inconsistent action types | | [xRCS] Content template must have at least one content type | Empty template | | [xRCS] Failed to create template: ... | Twilio API error on create | | [xRCS] Failed to send message: ... | Twilio API error on send | | [xRCS] Failed to get template '...': ... | Twilio API error on fetch | | [xRCS] Failed to list templates: ... | Twilio API error on list | | [xRCS] Failed to delete template '...': ... | Twilio API error on delete | | [xRCS] Failed to get message status '...': ... | Twilio API error on status check |

How It Works

The plugin wraps Twilio's Content API with a fluent builder pattern and a thin Fastify integration layer:

  1. Registration — the plugin validates options, initialises a Twilio client (if credentials are supplied), and decorates the Fastify instance with fastify.xrcs.
  2. BuildersCardBuilder, CarouselBuilder, and ContentTemplateBuilder are plain classes with no network dependencies. They enforce Twilio's structural constraints (character limits, button counts, carousel card counts, button-order consistency) at build time so you get immediate validation errors.
  3. Template creationcreateTemplate() accepts a builder or a raw payload object. With register=true (default) it calls twilioClient.content.v1.contents.create() to register the template with Twilio and returns the SID.
  4. SendingsendMessage() sends a message via twilioClient.messages.create() using a registered template SID and the configured Messaging Service. sendCard() and sendCarousel() are convenience wrappers that create a template and send it in one call.
  5. Builder-only mode — when credentials are omitted the plugin still registers all builders, constants, and validation helpers. Only the API methods throw.

License

UNLICENSED