πŸš€ DAY 5 OF LAUNCH WEEK: Introducing Socket Firewall Enterprise.Learn more β†’
Socket
Book a DemoInstallSign in
Socket

@warriorteam/messenger-sdk

Package Overview
Dependencies
Maintainers
3
Versions
11
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@warriorteam/messenger-sdk

TypeScript SDK for Facebook Messenger Platform API with Conversations support

latest
Source
npmnpm
Version
1.5.3
Version published
Maintainers
3
Created
Source

@warriorteam/messenger-sdk

A modern TypeScript SDK for the Facebook Messenger Platform API, designed with simplicity and type safety in mind.

Features

  • πŸš€ Zero runtime dependencies - Built with native fetch
  • πŸ“ Full TypeScript support - Complete type definitions with discriminated unions
  • πŸ”„ Dual module support - ESM and CommonJS
  • βœ… Comprehensive validation - Built-in message and template validation
  • πŸ›‘οΈ Error handling - Detailed error types and messages
  • πŸ“š Complete API coverage - Send API, Templates, Attachments, Moderation, Profile, Conversations
  • πŸ’¬ Conversations API - Retrieve conversation history and messages for Messenger & Instagram
  • πŸ” Webhook utilities - Complete webhook type system and signature verification
  • 🎯 Token override - Per-method access token override support
  • πŸ”§ Type-safe webhooks - Discriminated unions for proper TypeScript narrowing

Installation

npm install @warriorteam/messenger-sdk

Requirements

  • Node.js 18+ (for native fetch support)
  • A Facebook Page Access Token

Quick Start

import { Messenger } from '@warriorteam/messenger-sdk';

const messenger = new Messenger({
  accessToken: 'YOUR_PAGE_ACCESS_TOKEN',
  version: 'v23.0'
});

// Send a text message
const result = await messenger.send.message({
  recipient: { id: 'USER_PSID' },
  message: { text: 'Hello from RedAI Messenger SDK!' }
});

console.log('Message sent:', result.message_id);

API Reference

Client Configuration

const messenger = new Messenger({
  accessToken?: string;   // Optional: Default page access token
  version?: string;       // Optional: API version (default: 'v23.0')
  baseUrl?: string;       // Optional: Custom base URL
  timeout?: number;       // Optional: Request timeout in ms (default: 30000)
  maxRetries?: number;    // Optional: Max retry attempts (default: 3)
});

Token Override Support

Every API method supports per-call access token override, perfect for multi-tenant applications:

const messenger = new Messenger({
  accessToken: 'default_page_token'
});

// Use default token
await messenger.send.message({
  recipient: { id: 'USER_PSID' },
  message: { text: 'Hello from default page!' }
});

// Override token for this specific call
await messenger.send.message({
  recipient: { id: 'USER_PSID' },
  message: { text: 'Hello from different page!' }
}, {
  accessToken: 'other_page_token'
});

// Works with all API methods
const profile = await messenger.profile.getBasic('USER_PSID', {
  accessToken: 'specific_token'
});

Send API

Send Text Message

await messenger.send.message({
  recipient: { id: 'USER_PSID' },
  message: { text: 'Hello World!' }
});

Send Message with Quick Replies

await messenger.send.message({
  recipient: { id: 'USER_PSID' },
  message: {
    text: 'Pick a color:',
    quick_replies: [
      { content_type: 'text', title: 'Red', payload: 'PICKED_RED' },
      { content_type: 'text', title: 'Blue', payload: 'PICKED_BLUE' }
    ]
  }
});

Send Typing Indicators

await messenger.send.typingOn('USER_PSID');
await messenger.send.typingOff('USER_PSID');
await messenger.send.markSeen('USER_PSID');

Response Format

The Send API response includes a message_id and optionally a recipient_id:

const result = await messenger.send.message({...});
console.log('Message ID:', result.message_id); // Always present
console.log('Recipient ID:', result.recipient_id || 'Not provided'); // Optional

Note: recipient_id is only included when using recipient.id (PSID). It's not included when using recipient.user_ref or recipient.phone_number.

Attachments API

Upload Attachment from URL

const attachment = await messenger.attachments.upload({
  type: 'image',
  url: 'https://example.com/image.jpg',
  is_reusable: true
});

// Use the attachment ID to send
await messenger.send.message({
  recipient: { id: 'USER_PSID' },
  message: {
    attachment: {
      type: 'image',
      payload: { attachment_id: attachment.attachment_id }
    }
  }
});

Send Attachment Directly

await messenger.send.message({
  recipient: { id: 'USER_PSID' },
  message: {
    attachment: {
      type: 'image',
      payload: { url: 'https://example.com/image.jpg' }
    }
  }
});

Templates API

Generic Template

await messenger.templates.generic({
  recipient: { id: 'USER_PSID' },
  elements: [{
    title: 'Welcome',
    subtitle: 'Check out our products',
    image_url: 'https://example.com/image.jpg',
    buttons: [{
      type: 'web_url',
      title: 'Shop Now',
      url: 'https://example.com/shop'
    }]
  }]
});

Button Template

await messenger.templates.button({
  recipient: { id: 'USER_PSID' },
  text: 'What would you like to do?',
  buttons: [{
    type: 'postback',
    title: 'Get Started',
    payload: 'GET_STARTED'
  }]
});

Moderation API

User Moderation

// Block a user from messaging (can still see page content)
await messenger.moderation.blockUser('USER_PSID');

// Ban a user completely (no messaging + no Facebook interactions)
await messenger.moderation.banUser('USER_PSID');

// Move conversation to spam folder
await messenger.moderation.moveToSpam('USER_PSID');

// Block and spam (common combo)
await messenger.moderation.blockAndSpam('USER_PSID');

// Multiple users at once
await messenger.moderation.blockUser(['USER_1', 'USER_2', 'USER_3']);

// Unblock/unban users
await messenger.moderation.unblockUser('USER_PSID');
await messenger.moderation.unbanUser('USER_PSID');

Profile API

Get User Profile Information

// Get basic profile info (first_name, last_name, profile_pic)
const profile = await messenger.profile.getBasic('USER_PSID');
console.log(`Hello ${profile.first_name}!`);

// Get comprehensive profile with all fields
const fullProfile = await messenger.profile.getFull('USER_PSID');
console.log('Profile:', fullProfile);
// Returns: { id, name, first_name, last_name, profile_pic, locale, timezone, gender }

// Get specific fields only
const customProfile = await messenger.profile.get({
  psid: 'USER_PSID',
  fields: ['first_name', 'locale', 'timezone']
});

// Helper methods for common use cases
const nameInfo = await messenger.profile.getName('USER_PSID');
const profilePic = await messenger.profile.getProfilePicture('USER_PSID');

Personalize Messages

// Use profile info to personalize messages
const profile = await messenger.profile.getName('USER_PSID');
const greeting = profile.first_name 
  ? `Hello ${profile.first_name}! Welcome back!`
  : 'Hello! Welcome back!';

await messenger.send.message({
  recipient: { id: 'USER_PSID' },
  messaging_type: 'RESPONSE',
  message: { text: greeting }
});

Note: Profile API requires "Advanced User Profile Access" feature and user interaction to grant permissions.

Conversations API

Retrieve conversation history and messages between users and your Page or Instagram Business Account.

Permissions Required

For Messenger conversations:

  • pages_manage_metadata
  • pages_read_engagement
  • pages_messaging

For Instagram conversations:

  • instagram_basic
  • instagram_manage_messages
  • pages_manage_metadata
  • Your app must be owned by a verified business

List Conversations

// List Messenger conversations
const conversations = await messenger.conversations.list('PAGE_ID', {
  platform: 'messenger',
  limit: 25
});

// List Instagram conversations
const igConversations = await messenger.conversations.list('PAGE_ID', {
  platform: 'instagram',
  limit: 25
});

// Find conversation with specific user
const conversationId = await messenger.conversations.findByUser(
  'PAGE_ID',
  'USER_INSTAGRAM_SCOPED_ID',
  'instagram'
);

Get Conversation Details

// Get conversation with messages and participants
const conversation = await messenger.conversations.get('CONVERSATION_ID', {
  fields: ['messages', 'participants'],
  limit: 20
});

// Access participants
conversation.participants?.data.forEach(participant => {
  console.log(`${participant.name || participant.username} (${participant.id})`);
});

// Access messages
conversation.messages?.data.forEach(msg => {
  console.log(`Message ID: ${msg.id}, Created: ${msg.created_time}`);
});

Get Message Details

// Get full message details
const message = await messenger.conversations.getMessage('MESSAGE_ID', {
  fields: ['id', 'created_time', 'from', 'to', 'message', 'attachments', 'reactions', 'reply_to']
});

console.log(`From: ${message.from?.username}`);
console.log(`Text: ${message.message}`);

// Check attachments
if (message.attachments?.data) {
  message.attachments.data.forEach(att => {
    console.log(`Attachment: ${att.file_url || att.image_data?.url}`);
  });
}

// Check reactions
if (message.reactions?.data) {
  message.reactions.data.forEach(reaction => {
    console.log(`${reaction.reaction} (${reaction.users.length} users)`);
  });
}

Get Recent Messages (Convenience Method)

// Get the 20 most recent messages with full details
const messages = await messenger.conversations.getRecentMessages('CONVERSATION_ID');

messages.forEach(msg => {
  const sender = msg.from?.name || msg.from?.username;
  const text = msg.message || '(attachment)';
  console.log(`${sender}: ${text}`);
});

Pagination

// Paginate through conversations
let after: string | undefined;
let hasMore = true;

while (hasMore) {
  const conversations = await messenger.conversations.list('PAGE_ID', {
    platform: 'messenger',
    limit: 25,
    after
  });

  // Process conversations
  console.log(`Fetched ${conversations.data.length} conversations`);

  // Check for next page
  if (conversations.paging?.cursors?.after) {
    after = conversations.paging.cursors.after;
  } else {
    hasMore = false;
  }
}

Important Limitations

  • 20 Message Limit: You can only retrieve full details for the 20 most recent messages in a conversation. Older messages will return an error.
  • Pending Messages: Conversations in the "pending" folder that are inactive for 30+ days are not returned.
  • Private Keys: Accounts linked with private keys (email/phone) require Advanced Access approval to retrieve conversations.

Webhook Support

The SDK provides comprehensive webhook support with full TypeScript safety through discriminated unions.

Webhook Types and Processing

import {
  processWebhookEvents,
  extractWebhookEvents,
  getWebhookEventType,
  getWebhookPayloadEventTypes,
  getPageWebhookEventTypes,
  WebhookEventType,
  GenericWebhookPayload,
  PageWebhookPayload
} from '@warriorteam/messenger-sdk';

// Process webhook with type-safe handlers
app.post('/webhook', express.json(), async (req, res) => {
  const payload: GenericWebhookPayload = req.body;
  
  await processWebhookEvents(payload, {
    onMessage: async (event) => {
      // TypeScript knows this is MessageWebhookEvent
      console.log(`Received message: ${event.message.text}`);
    },
    onMessageEdit: async (event) => {
      // TypeScript knows this is MessageEditWebhookEvent
      console.log(`Message edited to: ${event.message_edit.text}`);
    },
    onMessageReaction: async (event) => {
      // TypeScript knows this is MessageReactionWebhookEvent
      console.log(`Reaction: ${event.reaction.reaction}`);
    },
    onMessagingPostback: async (event) => {
      // TypeScript knows this is MessagingPostbackWebhookEvent
      console.log(`Postback: ${event.postback.payload}`);
    }
  });
  
  res.sendStatus(200);
});

Manual Event Processing

// Extract events manually
const events = extractWebhookEvents(payload);
for (const event of events) {
  const eventType = getWebhookEventType(event);
  
  switch (eventType) {
    case WebhookEventType.MESSAGE:
      // Handle message event
      break;
    case WebhookEventType.MESSAGE_EDIT:
      // Handle edit event
      break;
    // ... other cases
  }
}

// Check what event types are in the payload (Messenger events)
const eventTypes = getWebhookPayloadEventTypes(payload);
console.log('Received Messenger event types:', eventTypes); // e.g., ['message', 'postback']

// For Page webhooks, use getPageWebhookEventTypes instead:
// const pagePayload: PageWebhookPayload = req.body;
// const pageEventTypes = getPageWebhookEventTypes(pagePayload);
// console.log('Received Page event types:', pageEventTypes); // e.g., [WebhookEventType.FEED, WebhookEventType.VIDEOS]

Webhook Verification

The SDK provides utilities for both subscription verification and signature validation:

import { 
  verifyWebhookSubscription, 
  verifyWebhookSignature 
} from '@warriorteam/messenger-sdk';

// Subscription verification (GET request)
app.get('/webhook', (req, res) => {
  const challenge = verifyWebhookSubscription(
    req.query as any, 
    process.env.VERIFY_TOKEN!
  );
  
  if (challenge) {
    res.send(challenge);
  } else {
    res.status(403).send('Forbidden');
  }
});

// Signature verification (POST request)
app.post('/webhook', express.raw({type: 'application/json'}), async (req, res) => {
  const signature = req.get('X-Hub-Signature-256');
  const result = await verifyWebhookSignature(
    req.body, 
    signature, 
    process.env.APP_SECRET!
  );
  
  if (!result.isValid) {
    return res.status(401).json({error: result.error});
  }
  
  // Process webhook events...
  const payload = JSON.parse(req.body.toString());
  // ... handle events
});

Type-Safe Event Handling

The SDK uses discriminated unions for perfect TypeScript support:

import { 
  MessengerWebhookEvent,
  isMessageEvent,
  isMessageEditEvent,
  isMessagingPostbackEvent 
} from '@warriorteam/messenger-sdk';

function handleWebhookEvent(event: MessengerWebhookEvent) {
  if (isMessageEvent(event)) {
    // TypeScript knows event.message exists
    console.log(`Message: ${event.message.text}`);
  } else if (isMessageEditEvent(event)) {
    // TypeScript knows event.message_edit exists
    console.log(`Edit: ${event.message_edit.text}`);
  } else if (isMessagingPostbackEvent(event)) {
    // TypeScript knows event.postback exists
    console.log(`Postback: ${event.postback.payload}`);
  }
}

Supported Webhook Event Types

Messenger Platform Events

  • MESSAGE - User sends a message
  • MESSAGE_EDIT - User edits a sent message
  • MESSAGE_REACTION - User reacts to a message
  • MESSAGE_READ - User reads messages (read receipts)
  • MESSAGING_FEEDBACK - User submits feedback via templates
  • MESSAGING_POSTBACK - User clicks buttons/quick replies

Page Webhook Events

  • FEED - Page feed changes (posts, photos, videos, status updates)
  • VIDEOS - Video encoding status changes (processing, ready, error)
  • LIVE_VIDEOS - Live video status changes (live, stopped, scheduled, VOD ready)

Page Webhook Type Helpers

The SDK provides specialized type guards and helpers for Page webhook events:

import {
  isFeedEvent,
  isVideoEvent,
  isLiveVideoEvent,
  isVideoProcessing,
  isVideoReady,
  isLiveVideoProcessing,
  isLive,
  extractVideoContext,
  extractLiveVideoContext,
  getPageWebhookEventTypes,
  FeedActionVerb,
  VideoStatus,
  LiveVideoStatus,
  PageWebhookPayload
} from '@warriorteam/messenger-sdk';

// Handle Page webhooks
app.post('/webhook/page', express.json(), async (req, res) => {
  const payload: PageWebhookPayload = req.body;

  // Check what types of Page events are in this payload
  const eventTypes = getPageWebhookEventTypes(payload);
  console.log('Received Page event types:', eventTypes); // e.g., [WebhookEventType.FEED, WebhookEventType.VIDEOS]

  for (const entry of payload.entry) {
    for (const change of entry.changes || []) {
      // Feed events (posts, photos, videos, status)
      if (isFeedEvent(change)) {
        console.log(`Feed ${change.value.verb}: ${change.value.item} by ${change.value.from.id}`);
        if (change.value.verb === FeedActionVerb.ADD) {
          console.log('New post created!');
        }
      }

      // Video encoding events
      if (isVideoEvent(change)) {
        const context = extractVideoContext(entry.id, entry.time, change);
        if (context.isReady) {
          console.log(`Video ${context.videoId} is ready!`);
        } else if (context.isProcessing) {
          console.log(`Video ${context.videoId} is still processing...`);
        }
      }

      // Live video events
      if (isLiveVideoEvent(change)) {
        const context = extractLiveVideoContext(entry.id, entry.time, change);
        if (context.isLive) {
          console.log(`Live stream ${context.videoId} is now live!`);
        } else if (context.isVODReady) {
          console.log(`Live stream ${context.videoId} VOD is ready!`);
        }
      }
    }
  }

  res.sendStatus(200);
});

Note: Page webhooks use a different structure (entry[].changes[]) compared to Messenger webhooks (entry[].messaging[]). The SDK provides helpers for both.

Complete Controller Example (NestJS/Express)

Here's a complete TypeScript controller for handling webhooks with proper types:

import { Controller, Post, Body, Headers, Res, Get, Query } from '@nestjs/common';
import { Response } from 'express';
import {
  GenericWebhookPayload,
  PageWebhookPayload,
  verifyWebhookSignature,
  verifyWebhookSubscription,
  processWebhookEvents,
  isFeedEvent,
  isVideoEvent,
  isLiveVideoEvent,
} from '@warriorteam/messenger-sdk';

@Controller('webhook')
export class WebhookController {
  // Subscription verification (GET)
  @Get()
  verifyWebhook(@Query() query: any, @Res() res: Response) {
    const challenge = verifyWebhookSubscription(
      query,
      process.env.VERIFY_TOKEN!
    );

    if (challenge) {
      return res.send(challenge);
    }
    return res.status(403).send('Forbidden');
  }

  // Messenger webhooks (POST)
  @Post('messenger')
  async handleMessenger(
    @Body() payload: GenericWebhookPayload,  // ← Correct type for Messenger
    @Headers('x-hub-signature-256') signature: string,
    @Res() res: Response
  ) {
    // Verify signature
    const verification = await verifyWebhookSignature(
      JSON.stringify(payload),
      signature,
      process.env.APP_SECRET!
    );

    if (!verification.isValid) {
      return res.status(401).json({ error: 'Invalid signature' });
    }

    // Process events with type-safe handlers
    await processWebhookEvents(payload, {
      onMessage: async (event) => {
        // event is MessageWebhookEvent - fully typed!
        console.log(`From ${event.sender.id}: ${event.message.text}`);
      },
      onMessagingPostback: async (event) => {
        // event is MessagingPostbackWebhookEvent
        console.log(`Button clicked: ${event.postback.payload}`);
      },
      onMessageReaction: async (event) => {
        // event is MessageReactionWebhookEvent
        console.log(`Reaction: ${event.reaction.reaction}`);
      },
    });

    return res.sendStatus(200);
  }

  // Page webhooks (POST)
  @Post('page')
  async handlePage(
    @Body() payload: PageWebhookPayload,  // ← Correct type for Page webhooks
    @Headers('x-hub-signature-256') signature: string,
    @Res() res: Response
  ) {
    // Verify signature
    const verification = await verifyWebhookSignature(
      JSON.stringify(payload),
      signature,
      process.env.APP_SECRET!
    );

    if (!verification.isValid) {
      return res.status(401).json({ error: 'Invalid signature' });
    }

    // Process Page events
    for (const entry of payload.entry) {
      for (const change of entry.changes || []) {
        if (isFeedEvent(change)) {
          console.log(`Page feed: ${change.value.verb} ${change.value.item}`);
        }

        if (isVideoEvent(change)) {
          console.log(`Video status: ${change.value.status.video_status}`);
        }

        if (isLiveVideoEvent(change)) {
          console.log(`Live video status: ${change.value.status}`);
        }
      }
    }

    return res.sendStatus(200);
  }
}

Key Types to Use:

  • GenericWebhookPayload - For Messenger Platform webhooks (entry[].messaging[])
  • PageWebhookPayload - For Page webhooks (entry[].changes[])

Error Handling

The SDK provides specific error types for different scenarios:

import { 
  MessengerAPIError, 
  MessengerNetworkError, 
  MessengerTimeoutError,
  MessengerConfigError 
} from '@warriorteam/messenger-sdk';

try {
  await messenger.send.message({
    recipient: { id: 'USER_PSID' },
    message: { text: 'Hello!' }
  });
} catch (error) {
  if (error instanceof MessengerAPIError) {
    console.error('API Error:', error.message, error.code);
  } else if (error instanceof MessengerNetworkError) {
    console.error('Network Error:', error.message);
  } else if (error instanceof MessengerTimeoutError) {
    console.error('Timeout Error:', error.timeout);
  }
}

Examples

Check the examples/ directory for complete usage examples:

  • send-message.ts - Basic message sending
  • upload-attachment.ts - Attachment handling
  • send-template.ts - Template messages
  • user-profile.ts - Profile API usage
  • moderation.ts - User moderation
  • conversations.ts - Retrieve conversations and messages
  • webhook-handler.ts - Complete webhook setup with type safety
  • multi-tenant.ts - Token override for multi-tenant applications
  • signature-verification.ts - Webhook security implementation

Development

# Install dependencies
npm install

# Build the project
npm run build

# Run tests
npm test

# Lint code
npm run lint

# Format code
npm run format

Changelog

v1.5.2 (Latest)

  • Added: getPageWebhookEventTypes() utility function for extracting event types from Page webhooks
    • Returns WebhookEventType[] array with proper enum values (e.g., [WebhookEventType.FEED, WebhookEventType.VIDEOS])
    • Maps Page webhook field values to WebhookEventType enum for type safety
    • Similar to getWebhookPayloadEventTypes() but for PageWebhookPayload structure
    • Properly exported from main package
  • Improved: Documentation with usage examples for Page webhook event type extraction

v1.5.1

  • Added: Complete NestJS/Express webhook controller example in README
  • Updated: WebhookEventType enum to include FEED, VIDEOS, LIVE_VIDEOS
  • Improved: Documentation with clear type usage for webhook handlers and Page webhook utilities

v1.5.0

  • Added: Conversations API for retrieving conversation history and messages
    • List conversations for Messenger and Instagram
    • Get conversation details with participants and messages
    • Retrieve individual message details with attachments, reactions, and replies
    • Convenience method for getting recent messages with full details
    • Find conversations by user ID
    • Full pagination support
    • Support for both Messenger and Instagram platforms
    • Token override support for multi-tenant applications
  • Added: Comprehensive TypeScript types for Conversations API
    • Conversation, ConversationDetail, Message types
    • Message attachments, reactions, shares, story replies
    • Image/video data types for media attachments
    • Request/response types for all operations

v1.4.2

  • Fixed: Resolved export naming conflicts for isProcessing function between video and live video webhooks
    • isProcessing from videos module now exported as isVideoProcessing
    • isProcessing from live-videos module now exported as isLiveVideoProcessing
    • Added explicit exports for all video and live video helper functions with unique names
    • Similar to existing pattern used for ReferralType and ReferralSource conflicts
  • Improved: Better TypeScript type safety with no export ambiguities

v1.4.x

  • Added: Comprehensive Facebook Page webhook types
    • Feed webhook events (posts, photos, videos, status updates)
    • Video encoding webhook events (processing, ready, error states)
    • Live video webhook events (live, stopped, scheduled, VOD ready)
  • Added: Type guards and helper functions for all Page webhook events
  • Added: Context extraction utilities for video events

v1.3.x

  • Added: Token override support for multi-tenant applications
  • Improved: All API methods now accept optional RequestOptions parameter

v1.1.0

  • Added: User Profile API support

License

MIT

Support

For issues and questions, please visit our GitHub repository.

Keywords

facebook

FAQs

Package last updated on 14 Oct 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts