Um einen WhatsApp Cloud API-Webhook auf localhost zu testen, machen Sie Ihren lokalen Endpunkt über HTTPS verfügbar, implementieren Sie die GET-Verifizierungsherausforderung von Meta und überprüfen Sie dann jede POST-Anfrage X-Hub-Signature-256 anhand des Rohtexts.Registrieren Sie die Tunnel-URL in Ihrer Meta-App, abonnieren Sie das WhatsApp Business-Konto messages und senden Sie eine Testnachricht, um eine echte Nutzlast ohne Bereitstellung zu empfangen.
WhatsApp-Webhooks verwenden zwei verschiedene Verifizierungsabläufe
Der wichtigste Unterschied besteht darin, dass Webhook-Einrichtung und Webhook-Zustellung unterschiedlich authentifiziert werden. Während der Einrichtung sendet Meta eine GET-Anfrage mit hub.mode, hub.verify_token und hub.challenge. Ihr Endpunkt vergleicht das Verifizierungstoken und gibt die Herausforderung als Klartext zurück. Spätere Ereignislieferungen sind POST-Anfragen; Diese sollten durch Validierung der mit Ihrem Meta-App-Geheimnis erstellten HMAC-Signatur authentifiziert werden.
Ein Verifizierungstoken ist eine zufällige Zeichenfolge, die Sie auswählen. Es handelt sich nicht um das WhatsApp-Zugriffstoken und nicht um das App-Geheimnis. Die Rückgabe der Herausforderung beweist die Kontrolle über den Callback-Endpunkt. Zukünftige POST-Anfragen werden nicht authentifiziert. Meta's offizieller WhatsApp-Webhook-Leitfaden deckt Rückrufkonfiguration, Abonnements und Webhook-Felder ab.
Erstellen Sie einen Next.js App Router-Endpunkt
Die folgende Route behandelt beide Phasen. Beim Lesen von POST-Daten mit request.text() bleiben genau die Bytes erhalten, die für die Signaturüberprüfung erforderlich sind.
// app/api/webhooks/whatsapp/route.ts
import crypto from 'node:crypto';
import { NextRequest } from 'next/server';
export const runtime = 'nodejs';
export async function GET(request: NextRequest) {
const mode = request.nextUrl.searchParams.get('hub.mode');
const token = request.nextUrl.searchParams.get('hub.verify_token');
const challenge = request.nextUrl.searchParams.get('hub.challenge');
if (mode === 'subscribe' && token === process.env.META_VERIFY_TOKEN) {
return new Response(challenge ?? '', { status: 200 });
}
return new Response('Forbidden', { status: 403 });
}
export async function POST(request: Request) {
const rawBody = await request.text();
const supplied = request.headers.get('x-hub-signature-256') ?? '';
const expected = 'sha256=' + crypto
.createHmac('sha256', process.env.META_APP_SECRET!)
.update(rawBody)
.digest('hex');
const a = Buffer.from(supplied);
const b = Buffer.from(expected);
if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) {
return new Response('Invalid signature', { status: 401 });
}
const payload = JSON.parse(rawBody);
await enqueueWhatsAppPayload(payload);
return new Response('EVENT_RECEIVED', { status: 200 });
}
Rufen Sie nicht request.json() auf und rekonstruieren Sie dann den JSON für HMAC. Leerzeichen, Escapezeichen oder Schlüsselreihenfolge können sich ändern und zu einem anderen Digest führen. Wenn Sie Express verwenden, erfassen Sie ein Buffer vor einem globalen JSON-Parser. Der allgemeine Webhook-Signatur-Leitfaden erklärt die Raw-Body-Verarbeitung über Frameworks hinweg.
Starten Sie einen Tunnel und konfigurieren Sie den Rückruf
- Führen Sie die Next.js-App lokal aus, normalerweise mit
npm run devauf Port 3000. - Führen Sie
npx portpreview 3000in einem separaten Terminal aus. - Setzen Sie
META_VERIFY_TOKENauf einen zufälligen Wert undMETA_APP_SECRETauf das App-Geheimnis aus Metas App-Einstellungen. - Öffnen Sie im Meta-Entwickler-Dashboard die Konfiguration des WhatsApp-Produkts Seite.
- Setzen Sie die Rückruf-URL auf
https://YOUR-TUNNEL.portpreview.dev/api/webhooks/whatsappund geben Sie das gleiche Verifizierungstoken ein. - Nach erfolgreicher Verifizierung abonnieren Sie das Feld
messagesfür das WhatsApp Business-Konto.
Der Tunnel muss sowohl während der GET-Challenge als auch bei nachfolgenden POST-Zustellungen aktiv bleiben. Eine aus einer älteren Sitzung kopierte URL wird möglicherweise aufgelöst, aber nicht mehr an Ihren Computer weitergeleitet. Bestätigen Sie daher den genauen Rückruf, wenn sich der lokale Tunnel ändert.
Testen Sie die GET-Herausforderung unabhängig
Bevor Sie das Dashboard verwenden, reproduzieren Sie die Anfrage lokal:
curl -i \
"http://localhost:3000/api/webhooks/whatsapp?hub.mode=subscribe&hub.verify_token=${META_VERIFY_TOKEN}&hub.challenge=123456"
Eine korrekte Antwort ist Status 200 mit Text 123456, nicht JSON und nicht "123456" mit Anführungszeichen. Wenn das Token falsch ist, ist 403 angemessen. Protokollieren Sie keine Abfrageparameter, da dort das Verifizierungstoken angezeigt wird.
Verstehen Sie die Nutzlast einer Nachricht, bevor Sie Geschäftslogik schreiben
WhatsApp verpackt Daten mehrere Ebenen tief. Eine typische Benachrichtigung besteht aus object: "whatsapp_business_account", einem entry-Array, einem changes-Array und einer Änderung, deren field messages ist. Innerhalb von value werden eingehende Benutzerinhalte in messages angezeigt; Zustellungs-, Lese- und Fehleraktualisierungen für von Ihnen gesendete Nachrichten werden in statuses.
for (const entry of payload.entry ?? []) {
for (const change of entry.changes ?? []) {
if (change.field !== 'messages') continue;
for (const message of change.value.messages ?? []) {
await handleInboundMessage({
id: message.id,
from: message.from,
type: message.type,
text: message.text?.body,
});
}
for (const status of change.value.statuses ?? []) {
await updateDeliveryStatus(status.id, status.status);
}
}
}
Gehen Sie nicht davon aus, dass jede Benachrichtigung eine Textnachricht enthält. Bilder, Audio, Dokumente, Standorte, interaktive Antworten, Systemmeldungen und Nur-Status-Nutzlasten haben unterschiedliche Formen. Halten Sie einen Dispatcher mit message.type verschlüsselt, validieren Sie optionale Felder und behalten Sie unbekannte Ereignistypen zur Überprüfung bei, anstatt abzustürzen.
Überprüfen Sie die POST-Signatur korrekt
Der X-Hub-Signature-256-Wert verwendet die Form sha256=<hex digest>. Berechnen Sie HMAC-SHA256 über die Rohanforderungsbytes mithilfe des Meta App Secret. Für Graph-API-Aufrufe wird das permanente oder temporäre WhatsApp-Zugriffstoken verwendet; Es ist nicht der HMAC-Schlüssel. Verwenden Sie einen Vergleich mit konstanter Zeit und lehnen Sie eine fehlende Signatur ab.
Lassen Sie die lokale Überprüfung aktiviert. Jeder, der eine Tunnel-URL lernt, kann beliebiges JSON darin posten. Ohne Überprüfung könnte ein gefälschtes Ereignis automatische Antworten auslösen, CRM-Datensätze verändern oder den Kundenstatus offenlegen. Rotieren Sie das App-Geheimnis, wenn es versehentlich festgeschrieben, gedruckt oder geteilt wird.
Nachrichten schnell bestätigen und deduplizieren
Gibt 200 zurück, nachdem das Ereignis authentifiziert und dauerhaft in die Warteschlange gestellt wurde. Warten Sie nicht, während Sie Medien herunterladen, einen LLM anrufen oder mehrere Dienste aktualisieren. Anbieter versuchen die Zustellung erneut, wenn Bestätigungen fehlschlagen und Netzwerkmehrdeutigkeiten bedeuten, dass Duplikate normal sind.
Verwenden Sie die WhatsApp-Nachricht id als Idempotenzschlüssel für eingehende Nachrichten und Statusobjekte. Legen Sie eine eindeutige Einschränkung für verarbeitete IDs fest. Statusübergänge können legitim von „Gesendet“ über „Zugestellt“ bis „Lesen“ fortschreiten. Deduplizieren Sie daher jeden relevanten Übergang, ohne einen späteren Status zu verwerfen.
Fehlerbehebung bei der WhatsApp-Webhook-Einrichtung
Die Rückruf-URL konnte nicht validiert werden
Testen Sie die GET-Route über die öffentliche URL. Stellen Sie sicher, dass es GET akzeptiert, das genaue Verifizierungstoken vergleicht und nur mit der Herausforderung antwortet. Weiterleitungen, Authentifizierungs-Middleware, Gebietsschemaumschreibungen oder ein JSON-Wrapper können die Überprüfung unterbrechen. Bestätigen Sie, dass die Umgebungsvariable vom laufenden Entwicklungsprozess geladen wird.
Die Überprüfung ist erfolgreich, aber es kommen keine Nachrichten an.
Die Rückrufüberprüfung allein führt nicht dazu, dass das WhatsApp Business-Konto Felder abonniert. Bestätigen Sie das messages Abonnement im Dashboard und stellen Sie sicher, dass die Telefonnummer zur erwarteten App und zum erwarteten Konto gehört. Senden Sie eine Nachricht von einem zulässigen Empfänger, wenn sich die App noch im Entwicklungsmodus befindet.
Jeder POST schlägt bei der Signaturvalidierung fehl
Die üblichen Ursachen sind die Verwendung des Zugriffstokens anstelle von App Secret, das Hashing von geparstem JSON, das Weglassen des Präfixes sha256= oder der Vergleich verschiedener Codierungen. Protokollieren Sie die Länge des Hauptteils und ob der Header vorhanden ist, aber geben Sie niemals das Geheimnis oder die vollständige Kundennutzlast aus.
Textnachrichten funktionieren, aber die Medienverarbeitung schlägt fehl
Medienbenachrichtigungen enthalten eine ID, nicht unbedingt die Dateibytes. Rufen Sie Medien über die Graph-API mit einem gültigen Zugriffstoken ab und laden Sie sie dann herunter. Halten Sie diesen langsameren Workflow außerhalb des Webhook-Bestätigungspfads.
Der lokale Endpunkt erkennt doppelte Ereignisse.
Überprüfen Sie den Antwortstatus und die Latenz, fügen Sie dauerhafte Idempotenz hinzu und spielen Sie nach jedem Fix ein erfasstes Ereignis ab. Der Webhook-Wiedergabeleitfaden zeigt, wie Sie vermeiden, bei jeder Codeänderung eine neue echte Nachricht zu senden.
Kundendaten bei lokalen Tests schützen
- Verwenden Sie nach Möglichkeit Testtelefonnummern und synthetische Konversationen.
- Redigieren Sie Telefonnummern, Nachrichtentexte, Medien-URLs, Kontakte usw Profilnamen aus Protokollen.
- App Secret speichern, auf Token zugreifen und Token nur in ignorierten Umgebungsdateien oder einem Secret Manager überprüfen.
- Beschränken Sie, wer Tunnelerfassungen anzeigen und nach der Debugging-Sitzung löschen kann.
- Validieren Sie Objekt-, Feld- und Konto-IDs, bevor Sie Geschäftsaktionen ausführen.
Ein Tunnel führt eine Iteration durch schnell, aber es überträgt auch produktionsbezogene personenbezogene Daten auf einen Entwicklercomputer. Wenden Sie die Kontrollen in der Tunnelsicherheits-Checkliste an, bevor Sie mit echten Benutzern testen.
