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

@zernio/chat-sdk-adapter

v0.3.0

Published

Official Zernio adapter for Chat SDK — build chatbots across Instagram, Facebook, Twitter/X, Telegram, WhatsApp, Bluesky, and Reddit through a single integration

Readme

@zernio/chat-sdk-adapter

npm Listed on chat-sdk.dev CI License: MIT

Official Zernio adapter for Chat SDK. Build chatbots that work across Instagram, Facebook, Twitter/X, Telegram, WhatsApp, Bluesky, and Reddit through a single integration.

Even with native Chat SDK adapters for each platform, you'd still need to apply to Meta's developer program, go through App Review, get WhatsApp Business verification, apply for X elevated access, and more. With Zernio, your users connect accounts in a dashboard and you get one API key. No developer programs, no app reviews, no token management.

Installation

npm install @zernio/chat-sdk-adapter chat @chat-adapter/state-memory

For production, swap @chat-adapter/state-memory for a persistent state adapter like @chat-adapter/state-redis or @chat-adapter/state-pg. See State Adapters for all options.

Quick Start

import { Chat } from "chat";
import { createZernioAdapter } from "@zernio/chat-sdk-adapter";
import { createMemoryState } from "@chat-adapter/state-memory";

export const bot = new Chat({
  userName: "pizza-bot",
  adapters: {
    zernio: createZernioAdapter(),
  },
  state: createMemoryState(),
});

// Register a handler. The pattern is a RegExp — use /.*/ to match every message.
bot.onNewMessage(/.*/, async (thread, message) => {
  // This handler fires for messages from ALL connected platforms
  const platform = (message.raw as any).platform; // "instagram", "telegram", etc.
  await thread.post(`Hello from ${platform}!`);
});

Next.js Webhook Route

// app/api/chat-webhook/route.ts
import { bot } from "@/lib/bot";

export async function POST(request: Request) {
  return bot.webhooks.zernio(request);
}

Configuration

Environment Variables

| Variable | Required | Description | |----------|----------|-------------| | ZERNIO_API_KEY | Yes | Your Zernio API key for sending messages | | ZERNIO_WEBHOOK_SECRET | Recommended | HMAC-SHA256 secret for verifying inbound webhooks | | ZERNIO_API_BASE_URL | No | Override API base URL (default: https://zernio.com/api) | | ZERNIO_BOT_NAME | No | Bot display name (default: "Zernio Bot") |

Explicit Configuration

const adapter = createZernioAdapter({
  apiKey: "your-api-key",
  webhookSecret: "your-webhook-secret",
  baseUrl: "https://zernio.com/api",
  botName: "My Bot",
});

Setup

1. Get a Zernio API Key

Sign up at zernio.com and create an API key from the dashboard. Make sure the key has read-write permissions.

2. Connect Social Accounts

Connect the social accounts you want your bot to handle through the Zernio dashboard or API.

3. Configure a Webhook

Create a webhook in your Zernio dashboard pointing to your bot's webhook endpoint:

  • URL: https://your-app.com/api/chat-webhook
  • Events: Select message.received and comment.received
  • Secret: Set a strong secret and pass it as ZERNIO_WEBHOOK_SECRET

4. Enable the Inbox Addon

The inbox addon must be enabled on your Zernio account to receive message webhooks.

How It Works

Incoming message flow:
  User sends DM on Instagram/Telegram/etc.
    -> Platform delivers to Zernio
    -> Zernio fires message.received webhook
    -> Adapter verifies signature & parses payload
    -> chat-sdk processes message through your handlers

Outgoing message flow:
  Your handler calls thread.post("Hello!")
    -> Adapter calls Zernio REST API
    -> Zernio delivers to the correct platform
    -> User receives the message on Instagram/Telegram/etc.

Thread ID Format

Thread IDs follow the format zernio:{accountId}:{conversationId}:

  • accountId: The Zernio social account ID (which platform account received the message)
  • conversationId: The Zernio conversation ID (the specific DM thread)
  • For comments: zernio:{accountId}:comment:{postId}
import { ZernioAdapter } from "@zernio/chat-sdk-adapter";

// Decode a thread ID to get platform-specific details
const adapter = new ZernioAdapter({ apiKey: "..." });
const { accountId, conversationId } = adapter.decodeThreadId(threadId);

Supported Features

| Feature | Supported | Notes | |---------|-----------|-------| | Send messages | Yes | Text messages across all platforms | | Rich messages (cards) | Yes | Buttons and templates on FB, IG, Telegram, WhatsApp | | Edit messages | Partial | Telegram only | | Delete messages | Partial | Telegram, X (full delete); Bluesky, Reddit (self-only) | | Send reactions | Partial | Telegram and WhatsApp (add/remove emoji) | | Receive reactions (onReaction) | Partial | WhatsApp, Telegram (via the reaction.received webhook) | | Typing indicators | Partial | Facebook Messenger, Telegram, and WhatsApp (requires recent inbound message) | | AI streaming | Partial | Post+edit on Telegram; single post on others | | File attachments | Yes | Via media upload endpoint | | Fetch messages | Yes | Full conversation history (supports limit, cursor, direction) | | Fetch thread info | Yes | Participant details, platform, status | | Webhook verification | Yes | HMAC-SHA256 signature | | Comment webhooks | Yes | comment.received routed through handlers |

Platform Support Matrix

| Feature | FB | IG | Telegram | WhatsApp | X | Bluesky | Reddit | |---------|----|----|----------|----------|---|---------|--------| | Send text | Y | Y | Y | Y | Y | Y | Y | | Buttons | Y | Y | Y | Y | - | - | - | | Typing | Y | - | Y | Y | - | - | - | | Delete | - | - | Y | - | Y | Self | Self | | Reactions | - | - | Y | Y | - | - | - | | Media | Y | Y | Y | Y | Y | - | - | | Edit | - | - | Y | - | - | - | - |

Rich Messages

The adapter maps chat-sdk Card elements to native platform formats instead of rendering as fallback text:

import { Card, Button, Actions, CardText, LinkButton } from "chat";

await thread.post(
  Card({
    title: "Order #1234",
    subtitle: "Total: $50.00",
    imageUrl: "https://example.com/product.jpg",
    children: [
      CardText("Your order is ready for pickup."),
      Actions([
        Button({ id: "confirm", label: "Confirm", style: "primary" }),
        LinkButton({ label: "Track Order", url: "https://example.com/track" }),
      ]),
    ],
  })
);
// Renders as interactive card on FB/IG/Telegram/WhatsApp
// Falls back to text on X/Bluesky/Reddit

AI Streaming

Stream AI responses with the post+edit pattern (works best on Telegram). thread.post() accepts an AsyncIterable<string>, so you can pass the textStream from streamText directly:

import { streamText } from "ai";
import { openai } from "@ai-sdk/openai";

bot.onNewMessage(/.*/, async (thread, message) => {
  const result = streamText({
    model: openai("gpt-4o"),
    prompt: message.text,
  });

  // On Telegram: posts initial message, edits as tokens arrive
  // On other platforms: collects full response, posts once
  await thread.post(result.textStream);
});

Platform-Specific Data

Access the underlying platform through the raw message:

bot.onNewMessage(/.*/, async (thread, message) => {
  const raw = message.raw as any;

  // Check which platform the message came from
  console.log(raw.platform); // "instagram", "facebook", "telegram", etc.

  // Access platform-specific sender info
  if (raw.sender.instagramProfile) {
    console.log(`Follower count: ${raw.sender.instagramProfile.followerCount}`);
    console.log(`Is verified: ${raw.sender.instagramProfile.isVerified}`);
  }

  // WhatsApp phone number
  if (raw.sender.phoneNumber) {
    console.log(`Phone: ${raw.sender.phoneNumber}`);
  }
});

API Client

The adapter exports a standalone API client for direct Zernio API calls:

import { ZernioApiClient } from "@zernio/chat-sdk-adapter";

const client = new ZernioApiClient("your-api-key", "https://zernio.com/api");

// List conversations
const { data, pagination } = await client.listConversations({
  platform: "instagram",
  status: "active",
  limit: 20,
});

// Fetch messages (optionally paginated: limit, opaque cursor, sortOrder)
const messages = await client.fetchMessages(conversationId, accountId, {
  limit: 20,
  sortOrder: "desc", // newest first; omit for oldest-first (default)
});

// Send typing indicator
await client.sendTyping(conversationId, accountId);

// Add reaction
await client.addReaction(conversationId, messageId, accountId, "👍");

// Upload media
const { url } = await client.uploadMedia(fileBuffer, "image/jpeg");

Webhook Verification

The adapter automatically verifies webhook signatures when webhookSecret is configured. You can also use the verification utility directly:

import { verifyWebhookSignature } from "@zernio/chat-sdk-adapter";

const isValid = verifyWebhookSignature(rawBody, signature, secret);

Error Handling

The adapter maps Zernio API errors to standard chat-sdk error classes:

| HTTP Status | Error Class | Description | |-------------|------------|-------------| | 401 | AuthenticationError | Invalid or expired API key | | 403 | PermissionError | Read-only key, missing addon, etc. | | 404 | ResourceNotFoundError | Conversation or message not found | | 429 | AdapterRateLimitError | Rate limit hit (includes retryAfter) | | 5xx | NetworkError | Server error |

License

MIT