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.1.1

Published

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

Readme

xRCS

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

Features

  • Card Builder: Fluent API for creating RCS rich cards with media, buttons, and actions
  • Carousel Builder: Build horizontally scrolling card carousels
  • Content Template Builder: Create complete Twilio Content API payloads
  • Validation Helpers: Validate cards and carousels before sending
  • Builder-Only Mode: Use builders without Twilio credentials for testing/preview
  • Full API Integration: Send messages directly when credentials are provided

Installation

npm install xrcs

Quick Start

import Fastify from "fastify";
import xRCS from "xrcs";

const fastify = Fastify();

// Register with Twilio credentials for full API access
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);

Configuration Options

| Option | Type | Default | Description | |--------|------|---------|-------------| | active | boolean | true | Enable/disable the plugin | | accountSid | string | - | Twilio Account SID | | authToken | string | - | Twilio Auth Token | | messagingServiceSid | string | - | Twilio Messaging Service SID |

Card Builder

Create rich cards with media, text, and interactive buttons.

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

// Build the card object
const cardData = card.build();

Button Constraints

  • Maximum 2 buttons per card
  • Button titles max 25 characters
  • Button types: QUICK_REPLY, URL, PHONE_NUMBER

Carousel Builder

Create horizontally scrolling card collections.

const carousel = fastify.xrcs
  .carousel()
  .body("Choose a product")  // Note: RCS drops body text
  .addCard(
    fastify.xrcs
      .card()
      .title("Laptop Pro")
      .body("$999")
      .media("https://example.com/laptop.jpg")
      .quickReply("Buy", "buy_laptop")
  )
  .addCard(
    fastify.xrcs
      .card()
      .title("Tablet Plus")
      .body("$499")
      .media("https://example.com/tablet.jpg")
      .quickReply("Buy", "buy_tablet")
  );

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

Carousel Constraints

  • Minimum 2 cards, maximum 10 cards
  • Button order must be consistent across all cards
  • RCS drops body text (WhatsApp displays it)

Content Template Builder

Create complete Twilio Content API payloads for any content type.

// Text message
const textTemplate = fastify.xrcs
  .template("Welcome Message")
  .language("en")
  .variables({ "1": "John" })
  .text("Hello {{1}}, welcome to our service!")
  .build();

// Card template
const cardTemplate = fastify.xrcs
  .template("Product Card")
  .card(fastify.xrcs.card().title("Product").body("Description"))
  .build();

// Quick reply template
const quickReplyTemplate = fastify.xrcs
  .template("Survey")
  .quickReply("How was your experience?", [
    { title: "Great", id: "great" },
    { title: "Poor", id: "poor" },
  ])
  .build();

// Register the template with Twilio
const registered = await fastify.xrcs.createTemplate(cardTemplate);
console.log("Template SID:", registered.sid);

Supported Content Types

| Type | Description | RCS | WhatsApp | |------|-------------|-----|----------| | twilio/text | Plain text | Yes | Yes | | twilio/media | Images, video, documents | Yes | Yes | | twilio/card | Rich card with media & buttons | Yes | Yes | | twilio/carousel | Multiple scrolling cards | Yes | Yes | | twilio/quick-reply | Quick reply buttons | Yes | Yes | | twilio/call-to-action | URL/Phone buttons | No | Yes | | twilio/list-picker | Selection list | No | Yes |

Validation

Validate cards and carousels before sending.

const card = {
  title: "A".repeat(250),  // Too long!
  actions: [
    { type: "QUICK_REPLY", title: "This title is way too long for a button" },
    { type: "URL", title: "Two" },
    { type: "PHONE_NUMBER", title: "Three" },  // Too many buttons!
  ],
};

const result = fastify.xrcs.validate.card(card);
// {
//   valid: false,
//   errors: [
//     "Title exceeds 200 characters",
//     "Card cannot have more than 2 buttons",
//     "Button 1 title exceeds 25 characters"
//   ]
// }

API Reference

Decorators

| Method | Description | |--------|-------------| | fastify.xrcs.card() | Create a new CardBuilder | | fastify.xrcs.carousel() | Create a new CarouselBuilder | | fastify.xrcs.template(name) | Create a new ContentTemplateBuilder | | fastify.xrcs.createTemplate(builder, register) | Create/register a content template | | fastify.xrcs.sendMessage(to, contentSid, vars) | Send message using template SID | | fastify.xrcs.sendCard(to, card, name) | Create template and send card | | fastify.xrcs.sendCarousel(to, carousel, name) | Create template and send carousel | | fastify.xrcs.getTemplate(sid) | Get template by SID | | fastify.xrcs.listTemplates(limit) | List all templates | | fastify.xrcs.deleteTemplate(sid) | Delete a template | | fastify.xrcs.getMessageStatus(sid) | Get message delivery status | | fastify.xrcs.validate.card(card) | Validate card structure | | fastify.xrcs.validate.carousel(carousel) | Validate carousel structure |

Constants

import { CONTENT_TYPES, ACTION_TYPES, MEDIA_HEIGHT } from "xrcs";

// Content types
CONTENT_TYPES.TEXT      // "twilio/text"
CONTENT_TYPES.MEDIA     // "twilio/media"
CONTENT_TYPES.CARD      // "twilio/card"
CONTENT_TYPES.CAROUSEL  // "twilio/carousel"

// Action types
ACTION_TYPES.QUICK_REPLY   // "QUICK_REPLY"
ACTION_TYPES.URL           // "URL"
ACTION_TYPES.PHONE_NUMBER  // "PHONE_NUMBER"

// Media heights
MEDIA_HEIGHT.SHORT   // "short"
MEDIA_HEIGHT.MEDIUM  // "medium"
MEDIA_HEIGHT.TALL    // "tall"

Builder-Only Mode

Use the builders without Twilio credentials for testing or preview.

// Register without credentials
await fastify.register(xRCS, {});

// Builders still work
const card = fastify.xrcs.card().title("Test").body("Preview").build();

// Get template payload without registering
const payload = await fastify.xrcs.createTemplate(
  fastify.xrcs.template("Test").card(card),
  false  // Don't register with Twilio
);

console.log(JSON.stringify(payload, null, 2));

Error Handling

try {
  await fastify.xrcs.sendCard("+15551234567", card);
} catch (error) {
  if (error.message.includes("credentials required")) {
    // Missing Twilio credentials
  }
  // Handle other errors
}

Testing

npm test

License

MIT