Blog

Facebook Messenger API: Erstellen Sie interaktive Konversationserlebnisse

Erfahren Sie, wie Sie Chatbots mit der Facebook Messenger API erstellen. Umfassender Leitfaden zu Webhooks, Nachrichtenvorlagen, Schnellantworten und Mediennach

Von

+8

Überall posten. Eine API.

Try Free

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:

FeatureDescriptionAnwendungsfall
TextnachrichtenGrundlegendes Senden und Empfangen von NachrichtenKundenanfragen, Benachrichtigungen
NachrichtenvorlagenStrukturierte Layouts mit Bildern und SchaltflächenProduktkataloge, Quittungen
Schnelle AntwortenVorgeschlagene AntwortschaltflächenGeführte Gespräche, Umfragen
Persistentes MenüImmer stets verfügbare NavigationsmöglichkeitenBot-Navigation, häufige Aktionen
MediennachrichtenBilder, Videos, Audios und DateienProduktbilder, Tutorials
ÜbergabeprotokollÜbertragung zwischen Bots und menschlichen AgentenKomplexe 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 empfangen
  • pages_manage_metadata: Abonnieren Sie Webhooks
  • seiten_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 Nachrichten
  • Messaging-Postbacks: Button-Klicks und Menüauswahlen
  • NachrichtenoptionenNutzerzustimmungen
  • NachrichtenlieferungenLieferbestätigungen
  • Nachrichten 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

Build faster with Late

One API call to post everywhere. No OAuth headaches. No platform-specific code.

Free tier • No credit card • 99.97% uptime

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

LimittypThresholdWindow
Aufrufe pro Seite200 AufrufePro Stunde und Nutzer
Stapelanforderungen50 AnfragenPro Batch
API senden250 NachrichtenPro 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

  1. Schnell antwortenBestätigen Sie Nachrichten innerhalb von 20 Sekunden, um Timeout-Fehler zu vermeiden.
  2. Verwende TippanzeigenZeigen Sie den Nutzern, dass Ihr Bot ihre Anfrage bearbeitet.
  3. Fehler elegant handhabenBieten Sie hilfreiche Fehlermeldungen an, wenn etwas schiefgeht.
  4. Respektiere die NutzerpräferenzenOpt-out-Anfragen und Abmeldeaktionen respektieren
  5. Anhangs-IDs zwischenspeichernLaden Sie Medien einmal hoch und verwenden Sie die Anhangs-ID erneut.
  6. StapeloperationenGruppiere mehrere Anfragen, wenn möglich.
  7. 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

  1. Registrieren Sie sich unter getlate.dev
  2. Verbinde deine Facebook-Seite im Dashboard.
  3. 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.

Eine API. 13+ Plattformen.

Social Media Features in Minuten integrieren, nicht Wochen.

Für Entwickler gemacht. Von Agenturen geschätzt. Von 6.325 Nutzern vertraut.