Die Facebook Messenger API ermöglicht es Entwicklern, interaktive Erlebnisse zu schaffen, die über 1,3 Milliarden monatlich aktive Nutzer erreichen. Egal, ob Sie einen Kundenservice-Bot, einen E-Commerce-Assistenten oder eine interaktive Marketingkampagne erstellen, die Messenger-Plattform-API bietet die Werkzeuge, die Sie benötigen, um Nutzer in bedeutungsvollen Gesprächen zu engagieren.
Dieser Leitfaden führt Sie durch alles, von der ersten Einrichtung bis hin zu fortgeschrittenen Funktionen wie Nachrichtenvorlagen, schnellen Antworten und dem Übergabeprotokoll an einen Menschen. Sie finden durchgehend funktionierende TypeScript-Beispiele, die Sie für Ihre eigenen Projekte anpassen können.
Einführung in die Messenger-Plattform
Die Messenger-Plattform ist Metas Rahmenwerk für den Aufbau von Bots und Integrationen, die mit Nutzern über Facebook Messenger kommunizieren. Im Gegensatz zu herkömmlichen Webschnittstellen schafft die Facebook-Chat-API ein dialogorientiertes Erlebnis, bei dem Nutzer über Nachrichten, Schaltflächen und reichhaltige Medien interagieren.
Die wichtigsten Funktionen der Messenger-Bot-API umfassen:
| Feature | Description | Anwendungsfall |
|---|---|---|
| Textnachrichten | Grundlegendes Senden und Empfangen von Nachrichten | Kundenanfragen, Benachrichtigungen |
| Nachrichtenvorlagen | Strukturierte Layouts mit Bildern und Schaltflächen | Produktkataloge, Quittungen |
| Schnelle Antworten | Vorgeschlagene Antwortschaltflächen | Geführte Gespräche, Umfragen |
| Persistentes Menü | Immer stets verfügbare Navigationsmöglichkeiten | Bot-Navigation, häufige Aktionen |
| Mediennachrichten | Bilder, Videos, Audios und Dateien | Produktbilder, Tutorials |
| Übergabeprotokoll | Übertragung zwischen Bots und menschlichen Agenten | Komplexe Unterstützungseskalation |
Die Plattform basiert auf einer Webhook-Architektur. Ihr Server empfängt eingehende Nachrichten über Webhooks, verarbeitet sie und antwortet über die Send API. Dieses asynchrone Modell ermöglicht es Ihnen, reaktionsschnelle Erlebnisse zu schaffen, ohne Verbindungen offen halten zu müssen.
Einrichten Ihrer Meta-App
Bevor Sie die Facebook Messenger API nutzen können, müssen Sie eine Meta-App erstellen und konfigurieren. Dieser Prozess legt die Identität Ihrer Anwendung fest und gewährt Zugriff auf die Messenger-Plattform.
Schritt 1: Erstellen Sie eine Meta-App
Navigiere zu der Meta für Entwickler Portal und erstellen Sie eine neue App. Wählen Sie „Business“ als Ihren App-Typ aus, um Zugriff auf die Messenger-Funktionen zu erhalten.
```typescript
// Umgebungsvariablen, die Sie nach der Einrichtung benötigen
interface MessengerConfig {
FACEBOOK_APP_ID: string;
FACEBOOK_APP_SECRET: string;
FACEBOOK_PAGE_ID: string;
FACEBOOK_PAGE_ACCESS_TOKEN: string;
MESSENGER_VERIFY_TOKEN: string;
}
// Validieren Sie Ihre Konfiguration beim Start
function validateConfig(): MessengerConfig {
const required = [
'FACEBOOK_APP_ID',
'FACEBOOK_APP_SECRET',
'FACEBOOK_PAGE_ID',
'FACEBOOK_PAGE_ACCESS_TOKEN',
'MESSENGER_VERIFY_TOKEN'
];
const missing = required.filter(key => !process.env[key]);
if (missing.length > 0) {
throw new Error(`Fehlende erforderliche Umgebungsvariablen: ${missing.join(', ')}`);
}
return {
FACEBOOK_APP_ID: process.env.FACEBOOK_APP_ID!,
FACEBOOK_APP_SECRET: process.env.FACEBOOK_APP_SECRET!,
FACEBOOK_PAGE_ID: process.env.FACEBOOK_PAGE_ID!,
FACEBOOK_PAGE_ACCESS_TOKEN: process.env.FACEBOOK_PAGE_ACCESS_TOKEN!,
MESSENGER_VERIFY_TOKEN: process.env.MESSENGER_VERIFY_TOKEN!
};
}
```
Schritt 2: Messenger-Produkt hinzufügen
Klicken Sie im Dashboard Ihrer App auf „Produkt hinzufügen“ und wählen Sie Messenger aus. Dadurch werden die Funktionen der Messenger-Plattform für Ihre App aktiviert.
Schritt 3: Verbinde eine Facebook-Seite
Ihr Bot benötigt eine Facebook-Seite, um Nachrichten zu senden und zu empfangen. Gehen Sie in den Messenger-Einstellungen auf „Seiten hinzufügen oder entfernen“ und wählen Sie die Seite aus, die Sie verbinden möchten. Generieren Sie ein Seitenzugriffstoken, das Sie zur Authentifizierung von API-Anfragen verwenden.
Hinweis: Seitenzugriffstoken können kurzlebig oder langlebig sein. Für Produktionsanwendungen tauschen Sie Ihr Token gegen eine langlebige Version, die etwa 60 Tage hält.
interface TokenExchangeResponse {
access_token: string;
token_type: string;
expires_in?: number;
}
async function exchangeForLongLivedToken(
shortLivedToken: string,
appId: string,
appSecret: string
): Promise {
const baseUrl = 'https://graph.facebook.com/v18.0';
const params = new URLSearchParams({
grant_type: 'fb_exchange_token',
client_id: appId,
client_secret: appSecret,
fb_exchange_token: shortLivedToken,
});
const response = await fetch(`${baseUrl}/oauth/access_token?${params.toString()}`);
if (!response.ok) {
const error = await response.text();
throw new Error(`Token-Austausch fehlgeschlagen: ${error}`);
}
const data = await response.json();
if (!data.access_token) {
throw new Error('Kein Zugriffstoken vom Token-Austausch zurückgegeben');
}
const expiresInDays = data.expires_in
? Math.floor(data.expires_in / 86400)
: 'unbekannt';
console.log(`Token erfolgreich ausgetauscht (läuft in ${expiresInDays} Tagen ab)`);
return {
access_token: data.access_token,
token_type: data.token_type || 'bearer',
expires_in: data.expires_in,
};
}
Schritt 4: App-Berechtigungen konfigurieren
Fordern Sie die erforderlichen Berechtigungen für Ihren Bot an. Mindestens benötigen Sie:
seiten_messagingNachrichten senden und empfangenpages_manage_metadata: Abonnieren Sie Webhooksseiten_lesen_engagement: Zugriff auf Gesprächsdaten
Webhook-Konfiguration und -Verifizierung
Webhooks sind das Rückgrat der Messenger-Plattform-API. Sie ermöglichen es Facebook, Ihren Server zu benachrichtigen, wenn Ereignisse eintreten, wie z. B. eingehende Nachrichten oder Nachrichtenlieferungen.
Einrichten Ihres Webhook-Endpunkts
Erstellen Sie einen Endpunkt, der sowohl GET-Anfragen (zur Überprüfung) als auch POST-Anfragen (zum Empfang von Ereignissen) verarbeitet.
import express, { Request, Response } from 'express';
import crypto from 'crypto';
const app = express();
// Rohdaten für die Signaturüberprüfung parsen
app.use(express.json({
verify: (req: any, res, buf) => {
req.rawBody = buf;
}
}));
// Webhook-Überprüfungsendpunkt
app.get('/webhook', (req: Request, res: Response) => {
const mode = req.query['hub.mode'];
const token = req.query['hub.verify_token'];
const challenge = req.query['hub.challenge'];
const verifyToken = process.env.MESSENGER_VERIFY_TOKEN;
if (mode === 'subscribe' && token === verifyToken) {
console.log('Webhook erfolgreich verifiziert');
res.status(200).send(challenge);
} else {
console.error('Webhook-Überprüfung fehlgeschlagen');
res.sendStatus(403);
}
});
// Webhook-Ereignisempfänger
app.post('/webhook', (req: Request, res: Response) => {
// Signatur der Anfrage überprüfen
const signature = req.headers['x-hub-signature-256'] as string;
if (!verifySignature(req, signature)) {
console.error('Ungültige Signatur');
return res.sendStatus(401);
}
const body = req.body;
if (body.object !== 'page') {
return res.sendStatus(404);
}
// Jedes Eintrag verarbeiten
body.entry?.forEach((entry: any) => {
entry.messaging?.forEach((event: any) => {
handleMessagingEvent(event);
});
});
// Immer schnell mit 200 OK antworten
res.sendStatus(200);
});
function verifySignature(req: any, signature: string): boolean {
if (!signature) return false;
const appSecret = process.env.FACEBOOK_APP_SECRET!;
const expectedSignature = 'sha256=' + crypto
.createHmac('sha256', appSecret)
.update(req.rawBody)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
}
async function handleMessagingEvent(event: any): Promise {
const senderId = event.sender.id;
if (event.message)
Webhook-Ereignisse abonnieren
Nachdem Sie Ihren Endpunkt eingerichtet haben, abonnieren Sie die Ereignisse, die Sie empfangen möchten. Konfigurieren Sie in der Meta App-Dashboard Ihre Webhook-URL und wählen Sie die entsprechenden Abonnementsfelder aus:
messages: Eingehende NachrichtenMessaging-Postbacks: Button-Klicks und MenüauswahlenNachrichtenoptionenNutzerzustimmungenNachrichtenlieferungenLieferbestätigungenNachrichten gelesen: Lesebestätigungen
Nachrichten empfangen
Wenn Nutzer Nachrichten an deinen Bot senden, liefert die Facebook-Chat-API diese an dein Webhook. Nachrichten können Text, Anhänge oder beides enthalten.
interface MessengerMessage {
mid: string;
text?: string;
attachments?: Array<{
type: 'image' | 'video' | 'audio' | 'file' | 'location' | 'fallback';
payload: {
url?: string;
coordinates?: {
lat: number;
long: number;
};
};
}>;
quick_reply?: {
payload: string;
};
reply_to?: {
mid: string;
};
}
async function handleMessage(
senderId: string,
message: MessengerMessage
): Promise {
console.log(`Nachricht von ${senderId} erhalten:`, message);
// Schnelle Antworten verarbeiten
if (message.quick_reply) {
await handleQuickReply(senderId, message.quick_reply.payload);
return;
}
// Anhänge verarbeiten
if (message.attachments && message.attachments.length > 0) {
for (const attachment of message.attachments) {
await handleAttachment(senderId, attachment);
}
return;
}
// Textnachrichten verarbeiten
if (message.text) {
await processTextMessage(senderId, message.text);
}
}
async function handleAttachment(
senderId: string,
attachment: MessengerMessage['attachments'][0]
): Promise {
switch (attachment.type) {
case 'image':
await sendTextMessage(senderId, `Danke für das Bild! Ich habe erhalten: ${attachment.payload.url}`);
break;
case 'location':
const { lat, long } = attachment.payload.coordinates!;
await sendTextMessage(senderId, `Deinen Standort erhalten: ${lat}, ${long}`);
break;
default:
await sendTextMessage(senderId, `Dein ${attachment.type} erhalten`);
}
}
async function processTextMessage(
senderId: string,
text: string
): Promise {
const lowerText = text.toLowerCase();
if (lowerText.includes('hilfe')) {
await sendHelpMessage(senderId);
} else if (lowerText.includes('produkte')) {
await sendProductCatalog(senderId);
} else {
await sendTextMessage(senderId, `Du hast gesagt: "${text}". Wie kann ich dir heute helfen?`);
}
}
Textnachrichten senden
Die Send API ist Ihr zentrales Werkzeug, um über die Messenger-Bot-API auf Nutzer zu reagieren. Textnachrichten sind die einfachste Form der Antwort.
const GRAPH_API_URL = 'https://graph.facebook.com/v18.0';
interface SendMessageResponse {
recipient_id: string;
message_id: string;
}
interface SendMessageError {
message: string;
type: string;
code: number;
error_subcode?: number;
fbtrace_id: string;
}
async function sendTextMessage(
recipientId: string,
text: string
): Promise {
const pageAccessToken = process.env.FACEBOOK_PAGE_ACCESS_TOKEN!;
const response = await fetch(
`${GRAPH_API_URL}/me/messages?access_token=${pageAccessToken}`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
recipient: { id: recipientId },
message: { text },
messaging_type: 'RESPONSE'
}),
}
);
const data = await response.json();
if (!response.ok) {
const error = data.error as SendMessageError;
throw new Error(`Send failed: ${error.message} (code: ${error.code})`);
}
return data as SendMessageResponse;
}
// Send typing indicator for better UX
async function sendTypingIndicator(
recipientId: string,
isTyping: boolean
): Promise {
const pageAccessToken = process.env.FACEBOOK_PAGE_ACCESS_TOKEN!;
await fetch(
`${GRAPH_API_URL}/me/messages?access_token=${pageAccessToken}`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
recipient: { id: recipientId },
sender_action: isTyping ? 'typing_on' : 'typing_off'
}),
}
);
}
// Helper function to send messages with typing indicator
async function sendMessageWithTyping(
recipientId: string,
text: string,
typingDuration: number = 1000
): Promise {
await sendTypingIndicator(recipientId, true);
await new Promise(resolve => setTimeout(resolve, typingDuration));
return sendTextMessage(recipientId, text);
}
Nachrichtenvorlagen (Allgemein, Schaltfläche, Quittung)
Nachrichtenvorlagen schaffen reichhaltige, interaktive Erlebnisse, die über einfachen Text hinausgehen. Die Facebook Messenger API unterstützt verschiedene Vorlagentypen, die jeweils für spezifische Anwendungsfälle entwickelt wurden.
Generische Vorlage
Die generische Vorlage zeigt ein Karussell von Elementen, ideal für Produktlisten oder Inhaltsfeeds.
interface GenericTemplateElement {
title: string;
subtitle?: string;
image_url?: string;
default_action?: {
type: 'web_url';
url: string;
webview_height_ratio?: 'compact' | 'tall' | 'full';
};
buttons?: Array;
}
type TemplateButton =
| { type: 'web_url'; url: string; title: string }
| { type: 'postback'; title: string; payload: string }
| { type: 'phone_number'; title: string; payload: string }
| { type: 'account_link'; url: string }
| { type: 'account_unlink' };
async function sendGenericTemplate(
recipientId: string,
elements: GenericTemplateElement[]
): Promise {
const pageAccessToken = process.env.FACEBOOK_PAGE_ACCESS_TOKEN!;
// Limit to 10 elements per carousel
const limitedElements = elements.slice(0, 10);
const response = await fetch(
`${GRAPH_API_URL}/me/messages?access_token=${pageAccessToken}`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
recipient: { id: recipientId },
message: {
attachment: {
type: 'template',
payload: {
template_type: 'generic',
elements: limitedElements
}
}
},
messaging_type: 'RESPONSE'
}),
}
);
if (!response.ok) {
const error = await response.json();
throw new Error(`Template send failed: ${error.error?.message}`);
}
return response.json();
}
// Beispiel: Produktkatalog
async function sendProductCatalog(recipientId: string): Promise {
const products: GenericTemplateElement[] = [
{
title: 'Kabellose Kopfhörer',
subtitle: '$149.99 - Premium Klangqualität',
image_url: 'https://example.com/headphones.jpg',
default_action: {
type: 'web_url',
url: 'https://example.com/products/headphones'
},
buttons: [
{ type: 'postback', title: 'Jetzt kaufen', payload: 'BUY_HEADPHONES' },
{ type: 'postback', title: 'Mehr
Schaltflächenvorlage
Die Schaltflächenvorlage zeigt eine Textnachricht mit bis zu drei Schaltflächen an, ideal für einfache Entscheidungen.
async function sendButtonTemplate(
recipientId: string,
text: string,
buttons: TemplateButton[]
): Promise<SendMessageResponse> {
const pageAccessToken = process.env.FACEBOOK_PAGE_ACCESS_TOKEN!;
// Begrenzung auf 3 Buttons
const limitedButtons = buttons.slice(0, 3);
const response = await fetch(
`${GRAPH_API_URL}/me/messages?access_token=${pageAccessToken}`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
recipient: { id: recipientId },
message: {
attachment: {
type: 'template',
payload: {
template_type: 'button',
text,
buttons: limitedButtons
}
}
},
messaging_type: 'RESPONSE'
}),
}
);
if (!response.ok) {
const error = await response.json();
throw new Error(`Button-Vorlage fehlgeschlagen: ${error.error?.message}`);
}
return response.json();
}
// Beispiel: Hilfemenü
async function sendHelpMessage(recipientId: string): Promise<void> {
await sendButtonTemplate(
recipientId,
'Wie kann ich Ihnen heute helfen?',
[
{ type: 'postback', title: 'Produkte durchsuchen', payload: 'BROWSE_PRODUCTS' },
{ type: 'postback', title: 'Bestellung verfolgen', payload: 'TRACK_ORDER' },
{ type: 'postback', title: 'Support kontaktieren', payload: 'CONTACT_SUPPORT' }
]
);
}
Rechnungsvorlage
Die Empfangsbestätigungsvorlage zeigt Bestellbestätigungen mit detaillierten Auflistungen der Artikel an.
interface ReceiptElement {
titel: string;
untertitel?: string;
menge?: number;
preis: number;
währung?: string;
bild_url?: string;
}
interface ReceiptSummary {
zwischenbetrag?: number;
versandkosten?: number;
gesamtsteuer?: number;
gesamtbetrag: number;
}
interface ReceiptAddress {
strasse_1: string;
strasse_2?: string;
stadt: string;
postleitzahl: string;
bundesland: string;
land: string;
}
async function sendReceiptTemplate(
empfängerId: string,
quittung: {
empfängerName: string;
bestellnummer: string;
währung: string;
zahlungsmethode: string;
bestellUrl?: string;
zeitstempel?: string;
adresse?: ReceiptAddress;
elemente: ReceiptElement[];
zusammenfassung: ReceiptSummary;
}
): Promise<SendMessageResponse> {
const seitenZugangsToken = process.env.FACEBOOK_PAGE_ACCESS_TOKEN!;
const antwort = await fetch(
`${GRAPH_API_URL}/me/messages?access_token=${seitenZugangsToken}`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
empfänger: { id: empfängerId },
nachricht: {
anhang: {
typ: 'template',
payload: {
template_typ: 'quittung',
empfänger_name: quittung.empfängerName,
bestell_nummer: quittung.bestellnummer,
währung: quittung.währung,
zahlungsmethode: quittung.zahlungsmethode,
bestell_url: quittung.bestellUrl,
zeitstempel: quittung.zeitstempel,
adresse: quittung.adresse,
elemente: quittung.elemente,
zusammenfassung: quittung.zusammenfassung
}
}
},
messaging_typ: 'ANTWORT'
}),
}
);
if (!antwort.ok) {
const fehler = await antwort.json();
throw new Error(`Quittungsvorlage fehlgeschlagen: ${fehler
Schnelle Antworten und Persistentes Menü
Schnelle Antworten und das persistente Menü leiten die Nutzer durch Gespräche, indem sie klare Optionen anbieten.
Schnelle Antworten
Schnelle Antworten erscheinen als Schaltflächen über der Tastatur und bieten vorgeschlagene Antworten, die nach der Auswahl verschwinden.
```typescript
interface QuickReply {
content_type: 'text' | 'user_phone_number' | 'user_email';
title?: string;
payload?: string;
image_url?: string;
}
async function sendQuickReplies(
recipientId: string,
text: string,
quickReplies: QuickReply[]
): Promise {
const pageAccessToken = process.env.FACEBOOK_PAGE_ACCESS_TOKEN!;
// Begrenzung auf 13 schnelle Antworten
const limitedReplies = quickReplies.slice(0, 13);
const response = await fetch(
`${GRAPH_API_URL}/me/messages?access_token=${pageAccessToken}`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
recipient: { id: recipientId },
message: {
text,
quick_replies: limitedReplies
},
messaging_type: 'RESPONSE'
}),
}
);
if (!response.ok) {
const error = await response.json();
throw new Error(`Schnelle Antworten fehlgeschlagen: ${error.error?.message}`);
}
return response.json();
}
// Beispiel: Zufriedenheitsumfrage
async function sendSatisfactionSurvey(recipientId: string): Promise {
await sendQuickReplies(
recipientId,
'Wie würden Sie Ihre Erfahrung heute bewerten?',
[
{ content_type: 'text', title: '😄 Großartig', payload: 'RATING_5' },
{ content_type: 'text', title: '🙂 Gut', payload: 'RATING_4' },
{ content_type: 'text', title: '😐 Okay', payload: 'RATING_3' },
{ content_type: 'text', title: '😕 Schlecht', payload: 'RATING_2' },
{ content_type: 'text', title: '😞 Sehr schlecht', payload: 'RATING_1' }
]
);
}
async function handleQuickReply(
senderId: string,
payload: string
): Promise {
if (payload.startsWith('RATING_')) {
const rating = parseInt(payload.split('_')[1]);
await sendTextMessage(
senderId,
`Vielen Dank für Ihr Feedback! Sie haben uns ${rating}/5 bewertet
Persistentes Menü
Das persistente Menü bietet jederzeit verfügbare Navigation über das Hamburger-Icon.
```typescript
interface MenuItem {
type: 'postback' | 'web_url' | 'nested';
title: string;
payload?: string;
url?: string;
webview_height_ratio?: 'compact' | 'tall' | 'full';
call_to_actions?: MenuItem[];
}
async function setPersistentMenu(
menuItems: MenuItem[],
locale: string = 'default'
): Promise {
const pageAccessToken = process.env.FACEBOOK_PAGE_ACCESS_TOKEN!;
const response = await fetch(
`${GRAPH_API_URL}/me/messenger_profile?access_token=${pageAccessToken}`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
persistent_menu: [
{
locale,
composer_input_disabled: false,
call_to_actions: menuItems
}
]
}),
}
);
if (!response.ok) {
const error = await response.json();
throw new Error(`Einrichten des persistenten Menüs fehlgeschlagen: ${error.error?.message}`);
}
console.log('Permanentes Menü erfolgreich konfiguriert');
}
// Beispiel: E-Commerce-Bot-Menü
async function setupBotMenu(): Promise {
await setPersistentMenu([
{
type: 'postback',
title: '🛍️ Jetzt einkaufen',
payload: 'SHOP_NOW'
},
{
type: 'nested',
title: '📦 Meine Bestellungen',
call_to_actions: [
{ type: 'postback', title: 'Bestellung verfolgen', payload: 'TRACK_ORDER' },
{ type: 'postback', title: 'Bestellverlauf', payload: 'ORDER_HISTORY' },
{ type: 'postback', title: 'Rücksendungen', payload: 'RETURNS' }
]
},
{
type: 'postback',
title: '💬 Support kontaktieren',
payload: 'CONTACT_SUPPORT'
}
]);
}
```
Mediennachrichten (Bilder, Videos, Dateien)
Die Messenger-Plattform-API unterstützt reichhaltige Medienanhänge, sodass Sie Bilder, Videos, Audiodateien und Dokumente senden können.
type AttachmentType = 'image' | 'video' | 'audio' | 'file';
interface AttachmentPayload {
url?: string;
is_reusable?: boolean;
attachment_id?: string;
}
async function sendMediaAttachment(
recipientId: string,
type: AttachmentType,
payload: AttachmentPayload
): Promise {
const pageAccessToken = process.env.FACEBOOK_PAGE_ACCESS_TOKEN!;
const response = await fetch(
`${GRAPH_API_URL}/me/messages?access_token=${pageAccessToken}`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
recipient: { id: recipientId },
message: {
attachment: {
type,
payload
}
},
messaging_type: 'RESPONSE'
}),
}
);
if (!response.ok) {
const error = await response.json();
throw new Error(`Das Senden des Mediums ist fehlgeschlagen: ${error.error?.message}`);
}
return response.json();
}
// Bild über URL senden
async function sendImage(
recipientId: string,
imageUrl: string,
reusable: boolean = true
): Promise {
return sendMediaAttachment(recipientId, 'image', {
url: imageUrl,
is_reusable: reusable
});
}
// Video über URL senden
async function sendVideo(
recipientId: string,
videoUrl: string
): Promise {
return sendMediaAttachment(recipientId, 'video', {
url: videoUrl,
is_reusable: true
});
}
// Datei/Dokument senden
async function sendFile(
recipientId: string,
fileUrl: string
): Promise {
return sendMediaAttachment(recipientId, 'file', {
url: fileUrl,
is_reusable: true
});
}
// Anhang zum Wiederverwenden hochladen
async function uploadAttachment(
type: AttachmentType,
url: string
): Promise {
const pageAccessToken = process.env.FACEBOOK_PAGE_ACCESS_TOKEN!;
const response = await fetch(
`${GRAPH_API_URL}/me/message_attachments?access_token=${pageAccessToken}`,
{
method: 'POST',
headers: {
Hinweis: Mediendateien müssen über HTTPS zugänglich sein. Facebook lädt die Datei von Ihrer URL herunter, daher sollte Ihr Server den Datenverkehr bewältigen können. Für häufig verwendete Medien laden Sie die Datei einmal hoch und verwenden Sie die Anhangs-ID wieder.
Menschliche Übergabeprotokolle
Das Übergabeprotokoll ermöglicht nahtlose Übergänge zwischen automatisierten Bots und menschlichen Agenten. Dies ist entscheidend für komplexe Support-Szenarien, die menschliches Eingreifen erfordern.
type ThreadOwner = 'primary' | 'secondary';
interface HandoverMetadata {
reason?: string;
conversationHistory?: string;
customData?: Record;
}
// Thread-Kontrolle an eine andere App übergeben (z.B. Posteingang eines menschlichen Agenten)
async function passThreadControl(
recipientId: string,
targetAppId: string,
metadata?: HandoverMetadata
): Promise {
const pageAccessToken = process.env.FACEBOOK_PAGE_ACCESS_TOKEN!;
const response = await fetch(
`${GRAPH_API_URL}/me/pass_thread_control?access_token=${pageAccessToken}`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
recipient: { id: recipientId },
target_app_id: targetAppId,
metadata: metadata ? JSON.stringify(metadata) : undefined
}),
}
);
if (!response.ok) {
const error = await response.json();
throw new Error(`Übergabe der Thread-Kontrolle fehlgeschlagen: ${error.error?.message}`);
}
console.log(`Thread-Kontrolle an die App ${targetAppId} übergeben`);
}
// Thread-Kontrolle vom sekundären Empfänger zurücknehmen
async function takeThreadControl(
recipientId: string,
metadata?: HandoverMetadata
): Promise {
const pageAccessToken = process.env.FACEBOOK_PAGE_ACCESS_TOKEN!;
const response = await fetch(
`${GRAPH_API_URL}/me/take_thread_control?access_token=${pageAccessToken}`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
recipient: { id: recipientId },
metadata: metadata ? JSON.stringify(metadata) : undefined
}),
}
);
if (!response.ok) {
const error = await response.json();
throw new Error(`Zurücknehmen der Thread-Kontrolle fehlgeschlagen: ${error.error?.message}`);
}
console.log('Thread-Kontrolle zurückgenommen');
}
// Thread-Kontrolle vom primären Empfänger anfordern
async function requestThreadControl(
recipientId: string,
metadata?: HandoverMetadata
): Promise {
const pageAccessToken = process.env.FACEBOOK_PAGE_ACCESS
Nachrichtentags für Nachverfolgungen
Außerhalb des 24-Stunden-Nachrichtenfensters benötigst du Nachrichten-Tags, um Folge-Nachrichten zu senden. Diese Tags geben den Zweck deiner Nachricht an und müssen korrekt verwendet werden.
type MessageTag =
| 'BESTÄTIGTE_VERANSTALTUNGSÄNDERUNG'
| 'BESTELLSTATUS_UPDATE'
| 'KONTO_UPDATE'
| 'MENSCHLICHER_AGENT';
async function sendTaggedMessage(
recipientId: string,
text: string,
tag: MessageTag
): Promise {
const pageAccessToken = process.env.FACEBOOK_PAGE_ACCESS_TOKEN!;
const response = await fetch(
`${GRAPH_API_URL}/me/messages?access_token=${pageAccessToken}`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
recipient: { id: recipientId },
message: { text },
messaging_type: 'MESSAGE_TAG',
tag
}),
}
);
if (!response.ok) {
const error = await response.json();
throw new Error(`Tagged message failed: ${error.error?.message}`);
}
return response.json();
}
// Beispiel: Versandaktualisierung der Bestellung
async function sendShippingUpdate(
recipientId: string,
orderId: string,
trackingNumber: string
): Promise {
await sendTaggedMessage(
recipientId,
`Tolle Neuigkeiten! Ihre Bestellung #${orderId} wurde versandt. Verfolgen Sie sie hier: https://example.com/track/${trackingNumber}`,
'BESTELLSTATUS_UPDATE'
);
}
// Beispiel: Sicherheitswarnung für das Konto
async function sendSecurityAlert(
recipientId: string,
alertType: string
): Promise {
await sendTaggedMessage(
recipientId,
`Sicherheitswarnung: ${alertType}. Wenn das nicht Sie waren, sichern Sie bitte sofort Ihr Konto.`,
'KONTO_UPDATE'
);
}
// Beispiel: Nachverfolgung durch einen menschlichen Agenten (innerhalb von 7 Tagen nach der Nachricht des Nutzers)
async function sendHumanAgentFollowup(
recipientId: string,
message: string
): Promise {
await sendTaggedMessage(
recipientId,
message,
'MENSCHLICHER_AGENT'
);
}
Hinweis: Nachrichtentags unterliegen strengen Nutzungsrichtlinien. Missbrauch kann dazu führen, dass Ihr Bot eingeschränkt oder gesperrt wird. Der HUMAN_AGENT-Tag ist nur innerhalb von 7 Tagen nach der letzten Nachricht des Nutzers verfügbar und erfordert menschliches Eingreifen in die Antwort.
Ratenlimits und bewährte Praktiken
Die Facebook Messenger API setzt Ratenlimits durch, um die Stabilität der Plattform zu gewährleisten. Das Verständnis dieser Limits hilft Ihnen, zuverlässige Bots zu entwickeln.
Übersicht der Rate Limits
| Limittyp | Threshold | Window |
|---|---|---|
| Aufrufe pro Seite | 200 Aufrufe | Pro Stunde und Nutzer |
| Stapelanforderungen | 50 Anfragen | Pro Batch |
| API senden | 250 Nachrichten | Pro Sekunde und pro Seite |
Umgang mit Rate Limits
interface RateLimitState {
requestCount: number;
windowStart: number;
isThrottled: boolean;
}
class RateLimiter {
private state: Map = new Map();
private readonly maxRequests: number;
private readonly windowMs: number;
constructor(maxRequests: number = 200, windowMs: number = 3600000) {
this.maxRequests = maxRequests;
this.windowMs = windowMs;
}
async checkLimit(pageId: string): Promise {
const now = Date.now();
let state = this.state.get(pageId);
if (!state || now - state.windowStart > this.windowMs) {
state = { requestCount: 0, windowStart: now, isThrottled: false };
}
if (state.requestCount >= this.maxRequests) {
state.isThrottled = true;
this.state.set(pageId, state);
return false;
}
state.requestCount++;
this.state.set(pageId, state);
return true;
}
getResetTime(pageId: string): number {
const state = this.state.get(pageId);
if (!state) return 0;
return Math.max(0, this.windowMs - (Date.now() - state.windowStart));
}
}
const rateLimiter = new RateLimiter();
async function sendWithRateLimiting(
pageId: string,
recipientId: string,
text: string
): Promise {
const canProceed = await rateLimiter.checkLimit(pageId);
if (!canProceed) {
const resetTime = rateLimiter.getResetTime(pageId);
console.warn(`Rate limit erreicht. Zurücksetzen in ${Math.ceil(resetTime / 1000)}s`);
return null;
}
return sendTextMessage(recipientId, text);
}
Beste Praktiken
- Schnell antwortenBestätigen Sie Nachrichten innerhalb von 20 Sekunden, um Timeout-Fehler zu vermeiden.
- Verwende TippanzeigenZeigen Sie den Nutzern, dass Ihr Bot ihre Anfrage bearbeitet.
- Fehler elegant handhabenBieten Sie hilfreiche Fehlermeldungen an, wenn etwas schiefgeht.
- Respektiere die NutzerpräferenzenOpt-out-Anfragen und Abmeldeaktionen respektieren
- Anhangs-IDs zwischenspeichernLaden Sie Medien einmal hoch und verwenden Sie die Anhangs-ID erneut.
- StapeloperationenGruppiere mehrere Anfragen, wenn möglich.
- Implementiere eine WiederholungslogikBehandle vorübergehende Fehler mit exponentiellem Backoff.
async function sendWithRetry(
recipientId: string,
text: string,
maxRetries: number = 3
): Promise<SendMessageResponse> {
let lastError: Error | null = null;
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await sendTextMessage(recipientId, text);
} catch (error) {
lastError = error as Error;
// Überprüfen, ob der Fehler wiederholbar ist
const errorMessage = lastError.message.toLowerCase();
const isRetryable =
errorMessage.includes('timeout') ||
errorMessage.includes('vorübergehend nicht verfügbar') ||
errorMessage.includes('rate limit');
if (!isRetryable || attempt === maxRetries) {
throw lastError;
}
// Exponentielles Backoff
const delay = Math.pow(2, attempt) * 1000;
console.log(`Wiederholungsversuch ${attempt}/${maxRetries} in ${delay}ms`);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
throw lastError;
}
Late für die Integration mit Messenger nutzen
Der Aufbau und die Pflege einer Messenger-Integration erfordern die Handhabung von Webhooks, das Management von Tokens, die Verarbeitung verschiedener Nachrichtentypen und das Mitverfolgen von API-Änderungen. Late vereinfacht diesen gesamten Prozess mit einer einheitlichen API, die über mehrere Messaging-Plattformen hinweg funktioniert.
Warum Late für Messenger nutzen?
Anstatt individuelle Webhook-Handler, Token-Management und Nachrichtenformatierungen für jede Plattform zu erstellen, bietet Late:
- Einheitliche APIEin einziger Endpunkt zum Versenden von Nachrichten an Messenger, WhatsApp, Instagram und mehr.
- Automatische Token-AktualisierungLangfristige Tokens, die automatisch verwaltet werden
- Webhook-AggregationEin Webhook-Endpunkt für alle Plattformen
- VorlagenabstraktionEinmal schreiben, korrekt für jede Plattform anzeigen.
- Integrierte RatenbegrenzungAutomatische Handhabung von Plattformgrenzen
- FehlernormalisierungKonsistente Fehlermeldungen über alle Plattformen hinweg
Schnellstart mit Late
import { LateClient } from '@anthropic/late-sdk';
const late = new LateClient({
apiKey: process.env.LATE_API_KEY!
});
// Nachricht an Messenger (oder eine andere Plattform) senden
async function sendMessage(
channelId: string,
recipientId: string,
content: string
): Promise {
await late.messages.send({
channel: channelId,
recipient: recipientId,
content: {
type: 'text',
text: content
}
});
}
// Eine Vorlage senden, die plattformübergreifend funktioniert
async function sendProductCard(
channelId: string,
recipientId: string,
product: { name: string; price: number; imageUrl: string }
): Promise {
await late.messages.send({
channel: channelId,
recipient: recipientId,
content: {
type: 'card',
title: product.name,
subtitle: `€${product.price.toFixed(2)}`,
imageUrl: product.imageUrl,
buttons: [
{ type: 'postback', title: 'Jetzt kaufen', payload: 'BUY' },
{ type: 'url', title: 'Details', url: 'https://example.com' }
]
}
});
}
Late übernimmt automatisch die plattformspezifische Formatierung. Der gleiche Code funktioniert für Messenger, Instagram Direct, WhatsApp Business und andere unterstützte Plattformen.
Verwaltung eingehender Nachrichten
Late bündelt Webhooks von allen verbundenen Plattformen in einem einzigen Endpunkt:
// Ein einzelner Webhook-Handler für alle Plattformen
app.post('/late-webhook', async (req, res) => {
const event = req.body;
// Plattformunabhängige Nachrichtenverarbeitung
if (event.type === 'message') {
const { platform, channelId, senderId, content } = event;
console.log(`Nachricht von ${platform}: ${content.text}`);
// Antwort über Late's einheitliche API
await late.messages.send({
channel: channelId,
recipient: senderId,
content: {
type: 'text',
text: `Danke für deine Nachricht!`
}
});
}
res.sendStatus(200);
});
Erste Schritte
- Registrieren Sie sich unter getlate.dev
- Verbinde deine Facebook-Seite im Dashboard.
- Nutze die einheitliche API von Late, um Nachrichten zu senden und zu empfangen.
Die Dokumentation von Late enthält ausführliche Anleitungen für Messenger-Integration, Webhook-Einrichtung, und Nachrichtenvorlagen.
Das Erstellen von Konversationserlebnissen sollte nicht erfordern, separate Codebasen für jede Plattform zu pflegen. Mit Late schreibst du deine Bot-Logik einmal und erreichst Nutzer dort, wo sie am liebsten kommunizieren.