@warriorteam/messenger-sdk
Version:
TypeScript SDK for Facebook Messenger Platform API with Conversations support
1,658 lines (1,633 loc) • 112 kB
text/typescript
interface ClientConfig {
accessToken?: string;
version: string;
baseUrl?: string;
timeout?: number;
maxRetries?: number;
}
interface APIOptions {
accessToken?: string;
}
interface RequestOptions {
method: 'GET' | 'POST' | 'DELETE';
path: string;
body?: any;
query?: Record<string, string | number | boolean>;
accessToken?: string;
}
declare class HTTPClient {
private readonly config;
constructor(config: ClientConfig);
request<T>(options: RequestOptions): Promise<T>;
private buildUrl;
private makeRequest;
private handleResponse;
private delay;
}
interface Recipient {
id?: string;
phone_number?: string;
user_ref?: string;
comment_id?: string;
post_id?: string;
name?: {
first_name: string;
last_name: string;
};
}
interface QuickReply$1 {
content_type: 'text' | 'user_phone_number' | 'user_email';
title?: string;
payload?: string;
image_url?: string;
}
interface Message$2 {
text?: string;
attachment?: Attachment;
quick_replies?: QuickReply$1[];
metadata?: string;
}
interface Attachment {
type: 'image' | 'audio' | 'video' | 'file' | 'template';
payload: AttachmentPayload$1 | TemplatePayload;
}
interface AttachmentPayload$1 {
url?: string;
attachment_id?: string;
is_reusable?: boolean;
}
interface TemplatePayload {
template_type: 'generic' | 'button' | 'media' | 'product';
elements?: any[];
buttons?: any[];
[key: string]: any;
}
type SenderAction = 'mark_seen' | 'typing_on' | 'typing_off' | 'react' | 'unreact';
interface ReactionPayload {
message_id: string;
reaction?: string;
}
type MessagingType = 'RESPONSE' | 'UPDATE' | 'MESSAGE_TAG';
interface SendMessageRequest {
recipient: Recipient;
messaging_type: MessagingType;
message?: Message$2;
sender_action?: SenderAction;
sender_action_payload?: ReactionPayload;
notification_type?: 'REGULAR' | 'SILENT_PUSH' | 'NO_PUSH';
tag?: string;
}
interface SendMessageResponse {
recipient_id?: string;
message_id: string;
attachment_id?: string;
}
interface MessengerError {
message: string;
type: string;
code: number;
error_subcode?: number;
fbtrace_id: string;
}
interface ErrorResponse {
error: MessengerError;
}
type AttachmentType$1 = 'image' | 'audio' | 'video' | 'file';
interface AttachmentUploadRequest {
type: AttachmentType$1;
url: string;
is_reusable?: boolean;
}
interface AttachmentUploadResponse {
attachment_id: string;
}
declare class SendAPI {
private httpClient;
constructor(httpClient: HTTPClient);
message(request: SendMessageRequest, options?: APIOptions): Promise<SendMessageResponse>;
action(recipientId: string, action: SenderAction, options?: APIOptions & {
payload?: ReactionPayload;
}): Promise<SendMessageResponse>;
typingOn(recipientId: string, options?: APIOptions): Promise<SendMessageResponse>;
typingOff(recipientId: string, options?: APIOptions): Promise<SendMessageResponse>;
markSeen(recipientId: string, options?: APIOptions): Promise<SendMessageResponse>;
setTyping(recipientId: string, state: boolean, options?: APIOptions): Promise<SendMessageResponse>;
markRead(recipientId: string, options?: APIOptions): Promise<SendMessageResponse>;
addReaction(recipientId: string, content: {
messageId: string;
emoji: string;
}, options?: APIOptions): Promise<SendMessageResponse>;
removeReaction(recipientId: string, messageId: string, options?: APIOptions): Promise<SendMessageResponse>;
/**
* Send an attachment using a previously uploaded attachment_id
*/
attachment(options: {
recipient: Recipient;
type: AttachmentType$1;
attachment_id: string;
messaging_type?: 'RESPONSE' | 'UPDATE' | 'MESSAGE_TAG';
}, apiOptions?: APIOptions): Promise<SendMessageResponse>;
/**
* Upload and send an attachment from URL in a single request
*/
attachmentFromUrl(options: {
recipient: Recipient;
type: AttachmentType$1;
url: string;
messaging_type?: 'RESPONSE' | 'UPDATE' | 'MESSAGE_TAG';
}, apiOptions?: APIOptions): Promise<SendMessageResponse>;
}
declare class AttachmentsAPI {
private httpClient;
constructor(httpClient: HTTPClient);
upload(request: AttachmentUploadRequest, options?: APIOptions): Promise<AttachmentUploadResponse>;
}
interface UserId {
id: string;
}
type ModerationAction = 'block_user' | 'unblock_user' | 'ban_user' | 'unban_user' | 'move_to_spam';
interface ModerateConversationsRequest {
user_ids: UserId[];
actions: ModerationAction[];
}
interface ModerateConversationsResponse {
result: 'success' | 'failure';
}
declare class ModerationAPI {
private httpClient;
constructor(httpClient: HTTPClient);
/**
* Moderate conversations with specified actions
* Up to 10 user IDs and up to 2 actions per request
*/
moderate(request: ModerateConversationsRequest, options?: APIOptions): Promise<ModerateConversationsResponse>;
/**
* Block a user from messaging the page
* Prevents messaging but user can still interact with page content on Facebook
*/
blockUser(userIds: string | string[], options?: APIOptions): Promise<ModerateConversationsResponse>;
/**
* Unblock a user to allow messaging again
*/
unblockUser(userIds: string | string[], options?: APIOptions): Promise<ModerateConversationsResponse>;
/**
* Ban a user from both messaging and Facebook interactions
* More restrictive than blocking - prevents all interactions
* Note: Cannot ban user who was unbanned in last 48 hours
*/
banUser(userIds: string | string[], options?: APIOptions): Promise<ModerateConversationsResponse>;
/**
* Unban a user to restore all interactions
* Note: Banned user cannot be unblocked, they must be unbanned first
*/
unbanUser(userIds: string | string[], options?: APIOptions): Promise<ModerateConversationsResponse>;
/**
* Move conversation to spam folder in Meta Business Suite Inbox
*/
moveToSpam(userIds: string | string[], options?: APIOptions): Promise<ModerateConversationsResponse>;
/**
* Block user and move to spam (common moderation action)
*/
blockAndSpam(userIds: string | string[], options?: APIOptions): Promise<ModerateConversationsResponse>;
}
interface Button {
type: 'web_url' | 'postback' | 'phone_number' | 'game_play' | 'account_link' | 'account_unlink';
title?: string;
url?: string;
payload?: string;
webview_height_ratio?: 'compact' | 'tall' | 'full';
messenger_extensions?: boolean;
fallback_url?: string;
webview_share_button?: 'hide' | 'show';
game_metadata?: {
player_id?: string;
context_id?: string;
};
}
interface DefaultAction {
type: 'web_url';
url: string;
webview_height_ratio?: 'compact' | 'tall' | 'full';
messenger_extensions?: boolean;
fallback_url?: string;
webview_share_button?: 'hide' | 'show';
}
interface GenericTemplateElement {
title: string;
subtitle?: string;
image_url?: string;
default_action?: DefaultAction;
buttons?: Button[];
}
interface GenericTemplatePayload {
template_type: 'generic';
elements: GenericTemplateElement[];
image_aspect_ratio?: 'horizontal' | 'square';
}
interface ButtonTemplatePayload {
template_type: 'button';
text: string;
buttons: Button[];
}
interface MediaTemplateElement {
media_type: 'image' | 'video';
url?: string;
attachment_id?: string;
buttons?: Button[];
sharable?: boolean;
}
interface MediaTemplatePayload {
template_type: 'media';
elements: [MediaTemplateElement];
}
interface ProductTemplateElement {
id: string;
}
interface ProductTemplatePayload {
template_type: 'product';
elements: ProductTemplateElement[];
}
declare class TemplatesAPI {
private httpClient;
constructor(httpClient: HTTPClient);
generic(options: {
recipient: Recipient;
elements: GenericTemplateElement[];
messaging_type?: MessagingType;
image_aspect_ratio?: 'horizontal' | 'square';
notification_type?: 'REGULAR' | 'SILENT_PUSH' | 'NO_PUSH';
tag?: string;
}, apiOptions?: APIOptions): Promise<SendMessageResponse>;
button(options: {
recipient: Recipient;
text: string;
buttons: Button[];
messaging_type?: MessagingType;
notification_type?: 'REGULAR' | 'SILENT_PUSH' | 'NO_PUSH';
tag?: string;
}, apiOptions?: APIOptions): Promise<SendMessageResponse>;
media(options: {
recipient: Recipient;
element: MediaTemplateElement;
messaging_type?: MessagingType;
notification_type?: 'REGULAR' | 'SILENT_PUSH' | 'NO_PUSH';
tag?: string;
}, apiOptions?: APIOptions): Promise<SendMessageResponse>;
product(options: {
recipient: Recipient;
elements: ProductTemplateElement[];
messaging_type?: MessagingType;
notification_type?: 'REGULAR' | 'SILENT_PUSH' | 'NO_PUSH';
tag?: string;
}, apiOptions?: APIOptions): Promise<SendMessageResponse>;
}
type ProfileField = 'id' | 'name' | 'first_name' | 'last_name' | 'profile_pic' | 'locale' | 'timezone' | 'gender';
interface GetProfileRequest {
psid: string;
fields?: ProfileField[];
}
interface UserProfile {
id?: string;
name?: string;
first_name?: string;
last_name?: string;
profile_pic?: string;
locale?: string;
timezone?: number;
gender?: string;
}
declare class ProfileAPI {
private httpClient;
constructor(httpClient: HTTPClient);
/**
* Get user profile information using PSID
* Requires "Advanced User Profile Access" feature
*/
get(request: GetProfileRequest, options?: APIOptions): Promise<UserProfile>;
/**
* Get user profile with default fields (first_name, last_name, profile_pic)
*/
getBasic(psid: string, options?: APIOptions): Promise<UserProfile>;
/**
* Get comprehensive user profile with all available fields
*/
getFull(psid: string, options?: APIOptions): Promise<UserProfile>;
/**
* Get user's name (first_name and last_name)
*/
getName(psid: string, options?: APIOptions): Promise<UserProfile>;
/**
* Get user's profile picture URL
*/
getProfilePicture(psid: string, options?: APIOptions): Promise<UserProfile>;
}
/**
* Facebook Messenger Platform - Conversations API Types
*
* Type definitions for retrieving conversations and messages between users and Pages/Instagram Business accounts.
*
* @see https://developers.facebook.com/docs/messenger-platform/conversations
*/
/**
* Platform type for conversations
*/
type ConversationPlatform = 'instagram' | 'messenger';
/**
* Conversation folder types
*/
type ConversationFolder = 'inbox' | 'pending' | 'spam';
/**
* Basic conversation information
*/
interface Conversation {
/** The conversation ID */
id: string;
/** Timestamp of the most recent message (Unix timestamp) */
updated_time: string;
}
/**
* Participant in a conversation
*/
interface ConversationParticipant {
/** Instagram-scoped ID or Page-scoped ID of a person, or Page ID, or Instagram Business Account ID */
id: string;
/** Email of the person or Page (Messenger only) */
email?: string;
/** Name of the person or Page (Messenger only) */
name?: string;
/** Instagram username of a person or your Instagram Business Account (Instagram only) */
username?: string;
}
/**
* Detailed conversation with messages and participants
*/
interface ConversationDetail {
/** The conversation ID */
id: string;
/** Messages in the conversation */
messages?: {
data: MessageBasic[];
paging?: {
cursors?: {
before?: string;
after?: string;
};
next?: string;
previous?: string;
};
};
/** Participants in the conversation */
participants?: {
data: ConversationParticipant[];
};
/** Timestamp of the most recent message */
updated_time?: string;
}
/**
* Basic message information (ID and timestamp)
*/
interface MessageBasic {
/** The message ID */
id: string;
/** When the message was created (ISO 8601 timestamp) */
created_time: string;
}
/**
* Message sender/recipient information
*/
interface MessageParticipant {
/** Instagram-scoped ID or Page-scoped ID or Instagram Business Account ID */
id: string;
/** Email (Messenger only) */
email?: string;
/** Name (Messenger only) */
name?: string;
/** Instagram username (Instagram only) */
username?: string;
}
/**
* Message attachment types
*/
type MessageAttachmentType = 'image' | 'video' | 'audio' | 'file';
/**
* Image data in attachment
*/
interface ImageData {
/** Preview URL of the image */
preview_url?: string;
/** Full URL of the image */
url?: string;
/** Width in pixels */
width?: number;
/** Height in pixels */
height?: number;
/** Max width in pixels */
max_width?: number;
/** Max height in pixels */
max_height?: number;
/** URL of animated GIF preview */
animated_gif_preview_url?: string;
/** URL of animated GIF */
animated_gif_url?: string;
/** Whether to render as sticker */
render_as_sticker?: boolean;
}
/**
* Video data in attachment
*/
interface VideoData {
/** URL of the video */
url?: string;
/** Width in pixels */
width?: number;
/** Height in pixels */
height?: number;
/** Preview URL */
preview_url?: string;
}
/**
* Generic template in attachment
*/
interface GenericTemplate {
/** Call-to-action button */
cta?: {
title?: string;
type?: string;
url?: string;
};
/** Media URL */
media_url?: string;
/** Subtitle text */
subtitle?: string;
/** Title text */
title?: string;
}
/**
* Message attachment
*/
interface MessageAttachment$1 {
/** Attachment ID */
id?: string;
/** File URL */
file_url?: string;
/** Image data */
image_data?: ImageData;
/** Video data */
video_data?: VideoData;
/** Generic template */
generic_template?: GenericTemplate;
/** File name */
name?: string;
}
/**
* Reaction to a message
*/
interface MessageReaction {
/** Emoji reaction (e.g., "❤️", "😂", "👍") */
reaction: string;
/** Users who reacted with this emoji */
users: Array<{
id: string;
username?: string;
}>;
}
/**
* Reply information
*/
interface ReplyInfo {
/** Message ID being replied to */
mid: string;
/** Whether this is a self-reply (reply to own message) */
is_self_reply?: boolean;
}
/**
* Story share/mention
*/
interface StoryShare {
/** CDN URL of the story */
link: string;
/** Story ID */
id: string;
}
/**
* Product in a share
*/
interface SharedProduct {
/** Product ID (0 if business can't see this product) */
id: string;
/** ID assigned by the retailer */
retailer_id?: string;
/** Product image URL */
image_url?: string;
/** Product name */
name?: string;
/** Product price */
price?: string;
}
/**
* Share template payload
*/
interface ShareTemplatePayload {
product?: {
elements?: {
data: SharedProduct[];
};
};
}
/**
* Shared content
*/
interface MessageShare {
/** Share template */
template?: {
payload?: ShareTemplatePayload;
};
}
/**
* Message tags
*/
interface MessageTag {
/** Tag name (e.g., "inbox", "read", "source:chat") */
name: string;
}
/**
* Detailed message information
*/
interface Message$1 {
/** The message ID */
id: string;
/** When the message was created */
created_time: string;
/** Sender information */
from?: MessageParticipant;
/** Recipient information */
to?: {
data: MessageParticipant[];
};
/** Text content of the message (empty if no text) */
message?: string;
/** Message attachments */
attachments?: {
data: MessageAttachment$1[];
};
/** Reactions to the message */
reactions?: {
data: MessageReaction[];
};
/** Shared content (posts, products, etc.) */
shares?: {
data: MessageShare[];
};
/** Story reply or mention */
story?: StoryShare;
/** Reply information */
reply_to?: ReplyInfo;
/** Message tags */
tags?: {
data: MessageTag[];
};
/** Whether the message contains unsupported content */
is_unsupported?: boolean;
}
/**
* Request parameters for listing conversations
*/
interface ListConversationsParams {
/** Platform to filter by */
platform?: ConversationPlatform;
/** User ID to find conversations with specific user */
user_id?: string;
/** Folder to filter by */
folder?: ConversationFolder;
/** Number of conversations to return */
limit?: number;
/** Pagination cursor */
after?: string;
/** Pagination cursor */
before?: string;
}
/**
* Request parameters for getting conversation details
*/
interface GetConversationParams {
/** Fields to retrieve (e.g., 'messages', 'participants') */
fields?: string[];
/** Number of messages to return */
limit?: number;
/** Pagination cursor */
after?: string;
/** Pagination cursor */
before?: string;
}
/**
* Request parameters for getting message details
*/
interface GetMessageParams {
/** Fields to retrieve */
fields?: string[];
}
/**
* Response for listing conversations
*/
interface ListConversationsResponse {
data: Conversation[];
paging?: {
cursors?: {
before?: string;
after?: string;
};
next?: string;
previous?: string;
};
}
/**
* Response for getting messages in a conversation
*/
interface ListMessagesResponse {
data: MessageBasic[];
paging?: {
cursors?: {
before?: string;
after?: string;
};
next?: string;
previous?: string;
};
}
/**
* Conversations API Resource
*
* Handles retrieving conversations and messages between users and Pages/Instagram Business accounts.
*
* @see https://developers.facebook.com/docs/messenger-platform/conversations
*/
/**
* Conversations API class for retrieving conversation and message data
*
* @example
* ```typescript
* const messenger = new Messenger({ accessToken: 'PAGE_TOKEN' });
*
* // List all conversations
* const conversations = await messenger.conversations.list('PAGE_ID', {
* platform: 'messenger'
* });
*
* // Get conversation details
* const conversation = await messenger.conversations.get('CONVERSATION_ID');
*
* // Get message details
* const message = await messenger.conversations.getMessage('MESSAGE_ID');
* ```
*/
declare class ConversationsAPI {
private httpClient;
constructor(httpClient: HTTPClient);
/**
* Get a list of conversations for a Page or Instagram Business Account
*
* @param pageId - The Page ID or Instagram Business Account ID
* @param params - Optional parameters for filtering and pagination
* @param options - Optional request options (e.g., token override)
* @returns List of conversations
*
* @example
* ```typescript
* // List Messenger conversations
* const conversations = await messenger.conversations.list('PAGE_ID', {
* platform: 'messenger',
* limit: 25
* });
*
* // Find conversation with specific user
* const userConvos = await messenger.conversations.list('PAGE_ID', {
* platform: 'instagram',
* user_id: 'USER_INSTAGRAM_SCOPED_ID'
* });
*
* // Paginate through conversations
* const nextPage = await messenger.conversations.list('PAGE_ID', {
* platform: 'messenger',
* after: conversations.paging?.cursors?.after
* });
* ```
*/
list(pageId: string, params?: ListConversationsParams, options?: APIOptions): Promise<ListConversationsResponse>;
/**
* Get details about a specific conversation
*
* @param conversationId - The conversation ID
* @param params - Optional parameters for fields and pagination
* @param options - Optional request options (e.g., token override)
* @returns Conversation details
*
* @example
* ```typescript
* // Get conversation with messages
* const conversation = await messenger.conversations.get('CONVERSATION_ID', {
* fields: ['messages', 'participants']
* });
*
* // Get only participants
* const participants = await messenger.conversations.get('CONVERSATION_ID', {
* fields: ['participants']
* });
* ```
*/
get(conversationId: string, params?: GetConversationParams, options?: APIOptions): Promise<ConversationDetail>;
/**
* Get messages in a conversation
*
* @param conversationId - The conversation ID
* @param params - Optional parameters for pagination
* @param options - Optional request options (e.g., token override)
* @returns List of messages
*
* @example
* ```typescript
* // Get messages in a conversation
* const messages = await messenger.conversations.getMessages('CONVERSATION_ID', {
* limit: 20
* });
*
* // Paginate through messages
* const nextPage = await messenger.conversations.getMessages('CONVERSATION_ID', {
* after: messages.paging?.cursors?.after
* });
* ```
*/
getMessages(conversationId: string, params?: {
limit?: number;
after?: string;
before?: string;
}, options?: APIOptions): Promise<ListMessagesResponse>;
/**
* Get details about a specific message
*
* Note: You can only retrieve details for the 20 most recent messages in a conversation.
* Older messages will return an error indicating the message was deleted.
*
* @param messageId - The message ID
* @param params - Optional parameters for fields to retrieve
* @param options - Optional request options (e.g., token override)
* @returns Message details
*
* @example
* ```typescript
* // Get full message details
* const message = await messenger.conversations.getMessage('MESSAGE_ID', {
* fields: ['id', 'created_time', 'from', 'to', 'message', 'attachments', 'reactions']
* });
*
* // Get basic message info
* const basicMessage = await messenger.conversations.getMessage('MESSAGE_ID');
* ```
*/
getMessage(messageId: string, params?: GetMessageParams, options?: APIOptions): Promise<Message$1>;
/**
* Get the 20 most recent messages in a conversation with full details
*
* This is a convenience method that retrieves message IDs and then fetches
* full details for each message. Note that only the 20 most recent messages
* can have their details retrieved.
*
* @param conversationId - The conversation ID
* @param options - Optional request options (e.g., token override)
* @returns Array of detailed messages
*
* @example
* ```typescript
* // Get recent messages with full details
* const messages = await messenger.conversations.getRecentMessages('CONVERSATION_ID');
*
* for (const message of messages) {
* console.log(`${message.from?.username}: ${message.message}`);
* }
* ```
*/
getRecentMessages(conversationId: string, options?: APIOptions): Promise<Message$1[]>;
/**
* Find a conversation between a Page and a specific user
*
* This is a convenience method that finds a conversation with a specific user.
*
* @param pageId - The Page ID or Instagram Business Account ID
* @param userId - The user's Instagram-scoped ID or Page-scoped ID
* @param platform - The platform ('instagram' or 'messenger')
* @param options - Optional request options (e.g., token override)
* @returns The conversation ID, or null if not found
*
* @example
* ```typescript
* // Find conversation with Instagram user
* const conversationId = await messenger.conversations.findByUser(
* 'PAGE_ID',
* 'USER_INSTAGRAM_SCOPED_ID',
* 'instagram'
* );
*
* if (conversationId) {
* const messages = await messenger.conversations.getRecentMessages(conversationId);
* }
* ```
*/
findByUser(pageId: string, userId: string, platform: 'instagram' | 'messenger', options?: APIOptions): Promise<string | null>;
}
interface MessengerConfig {
accessToken?: string;
version?: string;
baseUrl?: string;
timeout?: number;
maxRetries?: number;
}
declare class Messenger {
readonly send: SendAPI;
readonly attachments: AttachmentsAPI;
readonly moderation: ModerationAPI;
readonly templates: TemplatesAPI;
readonly profile: ProfileAPI;
readonly conversations: ConversationsAPI;
private readonly httpClient;
constructor(config?: MessengerConfig);
private validateConfig;
}
/**
* Facebook Messenger Platform - Base Webhook Types
*
* This file contains the common base types and interfaces shared across
* all webhook event types. It provides the foundation for a properly
* structured type system with inheritance and discriminated unions.
*
* @module webhooks/base-types
*/
/**
* Common sender interface for all webhook events.
* Represents the user who initiated the action.
*/
interface WebhookSender {
/**
* Page-scoped ID (PSID) of the user.
* This is the unique identifier for the user within the context of your page.
*/
id: string;
/**
* User reference provided by the chat plugin, if applicable.
* Only present for chat plugin events where the user hasn't been identified yet.
*/
user_ref?: string;
}
/**
* Common recipient interface for all webhook events.
* Represents the Facebook Page that received the event.
*/
interface WebhookRecipient {
/** Facebook Page ID that received the event */
id: string;
}
/**
* Base interface for all webhook events.
* Contains the common properties shared by all event types.
*/
interface BaseWebhookEvent {
/** Information about the user who initiated the event */
sender: WebhookSender;
/** Information about the page that received the event */
recipient: WebhookRecipient;
/**
* Unix timestamp when the event occurred (in milliseconds since epoch).
* Represents when the action was performed, not when the webhook was sent.
*/
timestamp: number;
}
/**
* Webhook event types enum with discriminator values.
* Used for type narrowing in discriminated unions.
*/
declare enum WebhookEventType {
MESSAGE = "message",
MESSAGE_ECHO = "message_echo",
MESSAGE_EDIT = "message_edit",
MESSAGE_REACTION = "reaction",
MESSAGE_READ = "read",
MESSAGING_FEEDBACK = "messaging_feedback",
MESSAGING_POSTBACK = "postback",
FEED = "feed",
VIDEOS = "videos",
LIVE_VIDEOS = "live_videos"
}
/**
* Generic webhook entry structure.
* Represents a single entry in the webhook payload.
*/
interface WebhookEntry<T extends BaseWebhookEvent = BaseWebhookEvent> {
/** Unique ID of the page */
id: string;
/** Time of update (epoch time in milliseconds) */
time: number;
/** Array of messaging events */
messaging: T[];
}
/**
* Generic webhook payload structure.
* This is the top-level structure received from Facebook webhooks.
*/
interface WebhookPayload<T extends BaseWebhookEvent = BaseWebhookEvent> {
/** Always 'page' for Messenger webhooks */
object: 'page';
/** Array of entry objects containing the actual events */
entry: WebhookEntry<T>[];
}
/**
* Generic webhook entry structure for Page webhooks (uses 'changes' instead of 'messaging').
* Represents a single entry in a Page webhook payload.
*/
interface PageWebhookEntry<T = any> {
/** Unique ID of the page */
id: string;
/** Time of update (epoch time in milliseconds) */
time: number;
/** Array of change events */
changes: T[];
}
/**
* Generic webhook payload structure for Page webhooks.
* This is the top-level structure received from Facebook Page webhooks.
*/
interface PageWebhookPayload<T = any> {
/** Always 'page' for Page webhooks */
object: 'page';
/** Array of entry objects containing the actual events */
entry: PageWebhookEntry<T>[];
}
/**
* Extract all events from a Page webhook payload (uses 'changes' array)
*
* @param payload - The Page webhook payload to extract events from
* @returns Array of Page webhook events
*/
declare function extractPageEvents<T>(payload: PageWebhookPayload<T>): T[];
/**
* Common processing context for all webhook events
*/
interface BaseProcessingContext {
/** The user who initiated the event (PSID or user_ref) */
senderId?: string;
/** User reference for anonymous users */
userRef?: string;
/** The page that received the event */
recipientId: string;
/** When the event occurred */
timestamp: number;
/** Whether the sender is identified (has PSID) */
isIdentifiedUser: boolean;
/** Human-readable datetime for the event timestamp */
eventDate: Date;
}
/**
* Get event types from a Page webhook payload (uses 'changes' array)
*
* @param payload - The Page webhook payload to extract event types from
* @returns Array of unique WebhookEventType values found in the payload
*
* @example
* ```typescript
* const eventTypes = getPageWebhookEventTypes(payload);
* console.log('Page events:', eventTypes); // [WebhookEventType.FEED, WebhookEventType.VIDEOS]
*
* if (eventTypes.includes(WebhookEventType.FEED)) {
* // Process feed events
* }
* ```
*/
declare function getPageWebhookEventTypes(payload: PageWebhookPayload): WebhookEventType[];
/**
* Facebook Messenger Platform - Message Edits Webhook Types
*
* These types represent the webhook event structure for message_edits events.
* Triggered when a user edits a previously sent message.
*
* @see https://developers.facebook.com/docs/messenger-platform/reference/webhook-events/message-edits/
*/
/**
* Represents the edited message information
*/
interface MessageEdit {
/**
* Unique message identifier for the edited message
*/
mid: string;
/**
* New message content after the edit.
* Contains the updated text of the message.
*/
text: string;
/**
* Number of times the message has been edited.
* Maximum value is 5 (client-side constraint).
*/
num_edit: number;
}
/**
* Main webhook event structure for message edits with discriminator
*
* This event is triggered when a user edits a previously sent message.
* The webhook provides the updated message content and edit count.
*
* @example
* ```json
* {
* "type": "message_edit",
* "sender": {
* "id": "1234567890123456"
* },
* "recipient": {
* "id": "9876543210987654"
* },
* "timestamp": 1458668856463,
* "message_edit": {
* "mid": "mid.1458668856218:ed81099e15d3f4f233",
* "text": "This is the updated message content",
* "num_edit": 2
* }
* }
* ```
*/
interface MessageEditWebhookEvent extends BaseWebhookEvent {
/** Discriminator for type narrowing */
type: WebhookEventType.MESSAGE_EDIT;
/** Details about the edited message */
message_edit: MessageEdit;
}
/**
* Complete webhook payload structure that includes the message edit event
* along with other webhook metadata
*/
interface MessageEditWebhookPayload extends WebhookPayload<MessageEditWebhookEvent> {
}
/**
* Type guard to check if a webhook event is a message edit event
*
* @param event - The webhook event to check
* @returns True if the event contains a message_edit property
*
* @example
* ```typescript
* if (isMessageEditEvent(event)) {
* // TypeScript now knows event has message_edit property
* console.log(`Message edited ${event.message_edit.num_edit} times`);
* }
* ```
*/
declare function isMessageEditEvent(event: any): event is MessageEditWebhookEvent;
/**
* Utility type for common message edit properties that might be used in processing
*/
interface MessageEditProcessingContext extends BaseProcessingContext {
/** The edited message ID */
messageId: string;
/** Updated message content */
updatedText: string;
/** Number of edits made */
editCount: number;
}
/**
* Helper function to extract processing context from a message edit event
*
* @param event - The message edit webhook event
* @returns Simplified processing context
*
* @example
* ```typescript
* const context = extractMessageEditContext(webhookEvent);
* console.log(`User ${context.senderId} edited message to: "${context.updatedText}"`);
* ```
*/
declare function extractMessageEditContext(event: MessageEditWebhookEvent): MessageEditProcessingContext;
/**
* Constants related to message editing limits and constraints
*/
declare const MESSAGE_EDIT_CONSTANTS: {
/** Maximum number of edits allowed per message */
readonly MAX_EDITS: 5;
/** Webhook event type identifier */
readonly EVENT_TYPE: "message_edit";
};
/**
* Facebook Messenger Platform Message Reactions Webhook Types
*
* These types define the structure of webhook events received when users
* react to messages in Messenger conversations.
*
* @see https://developers.facebook.com/docs/messenger-platform/reference/webhook-events/message-reactions
*/
/**
* Types of reactions that can be applied to messages in Messenger.
* These are the predefined reaction types supported by Facebook.
*/
declare enum MessageReactionType {
/** Standard like reaction */
LIKE = "like",
/** Dislike reaction */
DISLIKE = "dislike",
/** Love reaction (heart) */
LOVE = "love",
/** Sad reaction */
SAD = "sad",
/** Angry reaction */
ANGRY = "angry",
/** Wow/surprised reaction */
WOW = "wow",
/** Smile/laugh reaction */
SMILE = "smile",
/** Other/unrecognized emoji reactions */
OTHER = "other"
}
/**
* Actions that can be performed on message reactions.
*/
declare enum MessageReactionAction {
/** Adding a reaction to a message */
REACT = "react",
/** Removing a reaction from a message */
UNREACT = "unreact"
}
/**
* Contains the detailed information about the reaction.
*/
interface MessageReactionData {
/**
* The type of reaction applied to the message.
* Can be one of the predefined types or "other" for unrecognized emojis.
*/
reaction: MessageReactionType;
/**
* The UTF-8 emoji representation of the reaction (optional).
* Example: "\u{2764}\u{FE0F}" for heart emoji
*/
emoji?: string;
/**
* The action performed - either adding or removing the reaction.
*/
action: MessageReactionAction;
/**
* The message ID that the reaction was applied to.
* This corresponds to the 'mid' field of the original message.
*/
mid: string;
}
/**
* Complete webhook event structure for message reactions with discriminator.
* This is the main payload received when a user reacts to a message.
*/
interface MessageReactionWebhookEvent extends BaseWebhookEvent {
/** Discriminator for type narrowing */
type: WebhookEventType.MESSAGE_REACTION;
/** Detailed information about the reaction */
reaction: MessageReactionData;
}
/**
* The complete webhook payload containing the message reaction event.
* This matches the structure of the webhook POST request body.
*/
interface MessageReactionWebhookPayload extends WebhookPayload<MessageReactionWebhookEvent> {
}
/**
* Context object for processing message reaction webhooks.
* Useful for handlers that need additional processing information.
*/
interface MessageReactionProcessingContext {
/** The original webhook event */
event: MessageReactionWebhookEvent;
/** Page ID that received the reaction */
pageId: string;
/** User ID who performed the reaction */
userId: string;
/** ID of the message that was reacted to */
messageId: string;
/** Whether this is a new reaction (true) or removal (false) */
isReactionAdded: boolean;
/** The type of reaction */
reactionType: MessageReactionType;
/** Raw emoji string if available */
emoji?: string;
/** Timestamp when the reaction occurred */
timestamp: Date;
}
/**
* Helper type for reaction statistics and aggregation.
* Useful for tracking reaction counts on messages.
*/
interface MessageReactionStats {
/** The message ID these stats apply to */
messageId: string;
/** Count of each reaction type */
reactions: {
[K in MessageReactionType]?: number;
};
/** Total number of reactions */
totalReactions: number;
/** Last updated timestamp */
lastUpdated: Date;
}
/**
* Configuration options for handling message reaction webhooks.
*/
interface MessageReactionWebhookConfig {
/** Whether to track reaction statistics */
enableStats?: boolean;
/** Whether to handle emoji reactions beyond predefined types */
handleCustomEmojis?: boolean;
/** Maximum age of reactions to process (in milliseconds) */
maxReactionAge?: number;
/** Whether to validate webhook signatures */
validateSignature?: boolean;
}
/**
* Facebook Messenger Platform - Message Reads Webhook Types
*
* These types represent the webhook event structure for message_reads events.
* Triggered when a user reads messages sent by a Page.
*
* The message_reads webhook event indicates that all messages up to a certain
* watermark timestamp have been read by the recipient.
*
* @see https://developers.facebook.com/docs/messenger-platform/reference/webhook-events/message-reads/
*/
/**
* Represents the read receipt information
*/
interface MessageRead {
/**
* Watermark timestamp indicating all messages up to this point have been read.
* This is a Unix timestamp in milliseconds.
* All messages with a timestamp less than or equal to this value have been read.
*/
watermark: number;
}
/**
* Main webhook event structure for message reads with discriminator
*
* This event is triggered when a user reads messages sent by a Page.
* The watermark indicates the timestamp up to which all messages have been read.
*
* @example
* ```json
* {
* "type": "read",
* "sender": {
* "id": "1234567890123456"
* },
* "recipient": {
* "id": "9876543210987654"
* },
* "timestamp": 1458668856463,
* "read": {
* "watermark": 1458668856253
* }
* }
* ```
*/
interface MessageReadsWebhookEvent extends BaseWebhookEvent {
/** Discriminator for type narrowing */
type: WebhookEventType.MESSAGE_READ;
/** Read receipt information containing the watermark */
read: MessageRead;
}
/**
* Complete webhook payload structure that includes the message reads event
* along with other webhook metadata
*/
interface MessageReadsWebhookPayload extends WebhookPayload<MessageReadsWebhookEvent> {
}
/**
* Type guard to check if a webhook event is a message reads event
*
* @param event - The webhook event to check
* @returns True if the event contains a read property
*
* @example
* ```typescript
* if (isMessageReadsEvent(event)) {
* // TypeScript now knows event has read property
* console.log(`Messages read up to timestamp: ${event.read.watermark}`);
* }
* ```
*/
declare function isMessageReadsEvent(event: any): event is MessageReadsWebhookEvent;
/**
* Utility type for extracting just the read data from a webhook event
*/
type MessageReadData = MessageRead;
/**
* Utility type for common message reads properties that might be used in processing
*/
interface MessageReadsProcessingContext {
/** The user who read the messages */
senderId: string;
/** The page that sent the messages */
recipientId: string;
/** Timestamp up to which all messages have been read */
watermarkTimestamp: number;
/** When the read event occurred */
readTimestamp: number;
/**
* Human-readable datetime for the watermark timestamp.
* Useful for logging and debugging.
*/
watermarkDate: Date;
/**
* Human-readable datetime for the read event timestamp.
* Useful for logging and debugging.
*/
readDate: Date;
}
/**
* Helper function to extract processing context from a message reads event
*
* @param event - The message reads webhook event
* @returns Simplified processing context with additional computed fields
*
* @example
* ```typescript
* const context = extractMessageReadsContext(webhookEvent);
* console.log(`User ${context.senderId} read messages up to ${context.watermarkDate.toISOString()}`);
* ```
*/
declare function extractMessageReadsContext(event: MessageReadsWebhookEvent): MessageReadsProcessingContext;
/**
* Helper function to check if a specific message timestamp was read
*
* @param messageTimestamp - The timestamp of the message to check
* @param watermark - The watermark timestamp from the read event
* @returns True if the message with the given timestamp has been read
*
* @example
* ```typescript
* const messageTime = 1458668855000;
* const watermark = 1458668856253;
*
* if (isMessageRead(messageTime, watermark)) {
* console.log('This message has been read');
* }
* ```
*/
declare function isMessageRead(messageTimestamp: number, watermark: number): boolean;
/**
* Helper function to determine which messages in a list have been read
*
* @param messages - Array of messages with timestamp property
* @param watermark - The watermark timestamp from the read event
* @returns Array of messages that have been read
*
* @example
* ```typescript
* const messages = [
* { id: '1', timestamp: 1458668855000, text: 'Hello' },
* { id: '2', timestamp: 1458668857000, text: 'World' }
* ];
* const watermark = 1458668856253;
*
* const readMessages = getReadMessages(messages, watermark);
* // Returns only the first message as it's before the watermark
* ```
*/
declare function getReadMessages<T extends {
timestamp: number;
}>(messages: T[], watermark: number): T[];
/**
* Helper function to get the count of read messages from a list
*
* @param messages - Array of messages with timestamp property
* @param watermark - The watermark timestamp from the read event
* @returns Number of messages that have been read
*
* @example
* ```typescript
* const messages = [
* { id: '1', timestamp: 1458668855000 },
* { id: '2', timestamp: 1458668857000 }
* ];
* const watermark = 1458668856253;
*
* const readCount = getReadMessageCount(messages, watermark);
* // Returns 1
* ```
*/
declare function getReadMessageCount<T extends {
timestamp: number;
}>(messages: T[], watermark: number): number;
/**
* Constants related to message reads functionality
*/
declare const MESSAGE_READS_CONSTANTS: {
/** Webhook event type identifier */
readonly EVENT_TYPE: "message_reads";
/**
* Property name in the webhook event that contains read data.
* Used for type guards and event identification.
*/
readonly READ_PROPERTY: "read";
};
/**
* Type for the watermark timestamp
* Represents a Unix timestamp in milliseconds indicating read status
*/
type WatermarkTimestamp = number;
/**
* Facebook Messenger Platform - Messaging Postbacks Webhook Types
*
* These types represent the webhook event structure for messaging_postbacks events.
* Triggered when a user clicks on a postback button, Get Started button, or persistent menu item.
*
* @see https://developers.facebook.com/docs/messenger-platform/reference/webhook-events/messaging_postbacks
*/
/**
* Represents referral information for postbacks that originated from external sources
*
* This object is included when a postback is triggered as part of a conversation
* that was started via m.me links, Click to Messenger ads, Messenger QR codes,
* or the Welcome Screen.
*/
interface PostbackReferral {
/**
* Arbitrary data that was included in the original referral.
* This is the custom parameter you set when creating the referral link.
*/
ref?: string;
/**
* Source of the referral. Indicates how the conversation was initiated.
* Common values include:
* - "SHORTLINK" - from m.me links
* - "ADS" - from Click to Messenger ads
* - "MESSENGER_CODE" - from Messenger QR codes
*/
source?: string;
ad_id?: string;
ads_context_data?: {
ad_title?: string;
photo_url?: string;
video_url?: string;
post_id?: string;
};
/**
* Type of referral action that initiated the conversation.
* Common value is "OPEN_THREAD" for most referral types.
*/
type?: string;
}
/**
* Represents the postback data in a messaging postback webhook event
*/
interface PostbackData {
/**
* Message ID associated with the postback.
* Unique identifier for the message that contained the postback button.
*/
mid?: string;
/**
* Title of the postback button that was clicked.
* This is the user-visible text that was displayed on the button.
*/
title?: string;
/**
* Developer-defined payload that was associated with the postback button.
* This contains the custom data you specified when creating the button.
* Maximum length is 1000 characters.
*/
payload: string;
/**
* Referral information if the postback is part of a referred conversation.
* Only present when the conversation was initiated through external sources
* like m.me links, ads, QR codes, or Welcome Screen.
*/
referral?: PostbackReferral;
}
/**
* Main webhook event structure for messaging postbacks with discriminator
*
* This event is triggered when a user interacts with postback buttons,
* including regular postback buttons, Get Started button, and persistent menu items.
*
* @example
* Basic postback from a button click:
* ```json
* {
* "type": "postback",
* "sender": {
* "id": "1234567890123456"
* },
* "recipient": {
* "id": "9876543210987654"
* },
* "timestamp": 1527459824,
* "postback": {
* "mid": "m_AG5Hz2Uq7tuwNEhXfYYKj8mJEM_QPpz5jdHtHaW",
* "title": "Get Started",
* "payload": "GET_STARTED_PAYLOAD"
* }
* }
* ```
*
* @example
* Postback with referral data from m.me link:
* ```json
* {
* "type": "postback",
* "sender": {
* "user_ref": "unique_ref_param"
* },
* "recipient": {
* "id": "9876543210987654"
* },
* "timestamp": 1527459824,
* "postback": {
* "title": "Contact Sales",
* "payload": "CONTACT_SALES",
* "referral": {
* "ref": "landing_page_ad_campaign",
* "source": "SHORTLINK",
* "type": "OPEN_THREAD"
* }
* }
* }
* ```
*/
interface MessagingPostbackWebhookEvent extends BaseWebhookEvent {
/** Discriminator for type narrowing */
type: WebhookEventType.MESSAGING_POSTBACK;
/** Details about the postback that was triggered */
postback: PostbackData;
}
/**
* Complete webhook payload structure that includes the messaging postback event
* along with other webhook metadata
*/
interface MessagingPostbackWebhookPayload extends WebhookPayload<MessagingPostbackWebhookEvent> {
}
/**
* Type guard to check if a webhook event is a messaging postback event
*
* @param event - The webhook event to check
* @returns True if the event contains a postback property
*
* @example
* ```typescript
* if (isMessagingPostbackEvent(event)) {
* // TypeScript now knows event has postback property
* console.log(`User clicked: ${event.postback.title}`);
* console.log(`Payload: ${event.postback.payload}`);
* }
* ```
*/
declare function isMessagingPostbackEvent(event: any): event is MessagingPostbackWebhookEvent;
/**
* Type guard to check if a postback event includes referral data
*
* @param event - The messaging postback event to check
* @returns True if the event contains referral information
*
* @example
* ```typescript
* if (hasReferralData(event)) {
* // Handle referred conversation
* console.log(`Referred from: ${event.postback.referral.source}`);
* console.log(`Ref parameter: ${event.postback.referral.ref}`);
* }
* ```
*/
declare function hasReferralData(event: MessagingPostbackWebhookEvent): event is MessagingPostbackWebhookEvent & {
postback: PostbackData & {
referral: PostbackReferral;
};
};
/**
* Type guard to check if sender is identified (has PSID) vs anonymous (has user_ref)
*
* @param sender - The sender object to check
* @returns True if sender has a PSID (is identified)
*
* @example
* ```typescript
* if (isIdentifiedSender(event.sender)) {
* // User has been identified and has a PSID
* console.log(`User PSID: ${event.sender.id}`);
* } else {
* // Anonymous user with user_ref (likely from chat plugin)
* console.log(`Anonymous user ref: ${event.sender.user_ref}`);
* }
* ```
*/
declare function isIdentifiedSender(sender: WebhookSender): sender is WebhookSender & {
id: string;
};
/**
* Utility type for extracting just the postback data from a webhook event
*/
type PostbackEventData = PostbackData;
/**
* Utility type for common postback properties that might be used in processing
*/
interface PostbackProcessingContext {
/** The postback payload data */
payload: string;
/** The user who t