WhatsApp Webhook-Referenzdokumentation — Tabelle der Abonnement-Felder, HMAC-Header-Spezifikation und Wiederholungszeitplan auf dunklem Entwickler-Terminal-Hintergrund
Abschnitte: Webhook-Grundlagen · Vollständige Eigenschaften-Referenz · Alle Abonnement-Felder · Ereignisse pro Feld · Wiederholungszeitplan · HTTP-Antwortverhalten · HMAC-SHA256-Spezifikation · WABA vs. Telefon-Ebene · At-Least-Once-Zustellung · Payload-Schemata · Sicherheits-Checkliste · Fehlerkatalog · SocialHook-normalisiertes Format · FAQ

Webhook-Grundlagen

Die WhatsApp Cloud API liefert Ereignisse über ein push-basiertes Webhook-System an Ihre Anwendung. Anstatt einen Endpunkt auf neue Ereignisse abzufragen, senden Metas Server eine JSON-Payload per POST an eine von Ihnen registrierte URL — Ihren Webhook-Endpunkt. Ihr Server verarbeitet die Payload und gibt HTTP 200 zurück, um den Empfang zu bestätigen.

Zwei HTTP-Methoden operieren auf derselben URL:

  • GET — einmaliger Verifizierungs-Challenge während der Registrierung. Ihr Endpunkt muss den Query-Parameter hub.challenge als Klartext zurückgeben.
  • POST — Live-Ereignisbenachrichtigungen. Jede eingehende Nachricht, Statusaktualisierung und Konto-Ereignis kommt hier an.

Die wichtigsten Einschränkungen, die Sie verinnerlichen müssen, bevor Sie Code schreiben:

  • Antworten Sie innerhalb von 20 Sekunden — alles Langsamere löst einen Wiederholungsversuch aus. Bestätigen Sie sofort, verarbeiten Sie asynchron.
  • At-Least-Once-Zustellung — dasselbe Ereignis kann mehr als einmal eintreffen. Ihr Handler muss idempotent sein.
  • Keine Garantie für Reihenfolge — Ereignisse können außer der Reihe eintreffen. Niemals chronologische Reihenfolge annehmen.
  • 3 MB Payload-Größenlimit — einzelne Webhook-Payloads überschreiten nicht 3 MB. Mediendateien sind nicht inline enthalten.
  • HTTPS erforderlich — Meta lehnt reine HTTP-Endpunkte ab. Gültiges SSL-Zertifikat erforderlich.

Vollständige Webhook-Eigenschaften-Referenz

Eigenschaft Wert / Spezifikation Hinweise
ProtokollNur HTTPSGültiges SSL-Zertifikat erforderlich. HTTP wird vollständig abgelehnt.
RichtungAnbieter → Verbraucher (Push)Meta pusht zu Ihnen. Kein Polling erforderlich.
VerifizierungsmethodeGET + hub.verify_tokenEinmalig bei Registrierung. hub.challenge als Klartext zurückgeben.
Authentifizierung bei EreignissenX-Hub-Signature-256 HMAC-SHA256Mit App Secret signiert. Jeden POST verifizieren.
HTTP-Methode für EreignissePOSTImmer POST. Niemals GET für Live-Ereignisse.
DatenformatJSONContent-Type: application/json
Antwort-Timeout20 SekundenÜberschreitung löst Wiederholung aus. Sofort 200 zurückgeben.
ErfolgskriteriumHTTP 200Jeder nicht-200-Status löst Wiederholungsmechanismus aus.
Payload-Größenlimit3 MBMedien nicht inline — referenziert per ID.
WiederholungsdauerBis zu 7 TageExponentielles Backoff. Vollständiger Zeitplan unten.
ZustellgarantieAt-Least-OnceDuplikate möglich. Handler idempotent gestalten.
ReihenfolgegarantieKeineEreignisse können außer chronologischer Reihenfolge eintreffen.
Webhook-EbenenTelefonnummer + WABATelefonnummer hat Vorrang vor WABA-Fallback.
Manuelles ReplayNicht unterstütztKein natives Replay. Ereignisse nach 7 Tagen verloren.
Signatur-AlgorithmusHMAC-SHA256Schlüssel = App Secret. Eingabe = rohe Body-Bytes.
Signatur-HeaderX-Hub-Signature-256Format: sha256=<hex>
Gleichzeitige ZustellungenMehrere pro SekundeHigh-Volume-Nummern erhalten viele Ereignisse/Sekunde.

Alle Webhook-Abonnement-Felder

Sie abonnieren einzelne Felder im Meta Developer Dashboard (WhatsApp → Configuration → Webhooks → Manage). Das Abonnieren von messages ist für die meisten Integrationen obligatorisch. Jedes Feld repräsentiert eine Kategorie von Ereignissen — abonnieren Sie nur, was Sie benötigen, um das Payload-Volumen zu reduzieren.

Feld Abdeckung Priorität
messages Alle eingehenden Kundennachrichten + alle ausgehenden Statusaktualisierungen (sent / delivered / read / failed). Das primäre Feld für jede Messaging-Integration. Immer abonnieren
account_update Richtlinienverstöße (ACCOUNT_VIOLATION) und aktive Einschränkungen (ACCOUNT_RESTRICTION) bei Ihren Telefonnummern. Essenziell für Produktions-Monitoring. Empfohlen
message_template_status_update Template-Genehmigung, -Ablehnung, -Pausierung und -Deaktivierung. Wird ausgelöst, wenn Meta den Status eines von Ihnen eingereichten Templates ändert. Empfohlen
phone_number_quality_update Änderungen der Qualitätsbewertung (GREEN / YELLOW / RED) für Ihre Telefonnummern. Qualität beeinflusst Ihr Messaging-Tier. Abonnieren, um Verschlechterung früh zu erkennen. Empfohlen
phone_number_name_update Ereignisse zur Genehmigungs- oder Ablehnung des Anzeigenamens. Wird ausgelöst, wenn Meta einen von Ihnen für Ihre WhatsApp Business-Nummer eingereichten Namen prüft. Situativ
business_capability_update Änderungen des Messaging-Limit-Tiers — wenn Meta Ihr tägliches Konversations-Tier hoch- oder herabstuft (1K / 10K / 100K / Unlimited). Situativ
flows WhatsApp Flows-Interaktionen — Datenübermittlungs-Ereignisse, wenn ein Nutzer einen mit Ihrer Nummer verknüpften Flow abschließt oder interagiert. Bei Verwendung von Flows
security Two-Step-Verification-PIN-Ereignisse. Wird ausgelöst, wenn die PIN einer Telefonnummer geändert oder deaktiviert wird. Optional
message_template_components_update Wird ausgelöst, wenn Meta die Komponenten eines genehmigten Templates ändert (selten — Meta kann Templates zur Richtlinienkonformität anpassen). Optional
account_alerts Abrechnungswarnungen, Kapazitätswarnungen und andere Konto-Ebenen-Betriebshinweise von Meta. Optional

Ereignisse pro Abonnement-Feld

Feld messages — eingehende Nachrichtentypen

Das Feld messages liefert zwei Kategorien: eingehende Nachrichten von Kunden (identifiziert durch ein messages-Array im value-Objekt) und ausgehende Zustell-Statusaktualisierungen (identifiziert durch ein statuses-Array). Prüfen Sie, welches Array vorhanden ist, bevor Sie verarbeiten.

msg.typeContent-PositionHinweise
textmsg.text.bodyKlartext-Nachrichten-Body. Kann URLs enthalten.
imagemsg.image.id, .mime_type, .captionID → URL auflösen → herunterladen. Caption optional.
audiomsg.audio.id, .voicevoice: true wenn in-App aufgenommen. Immer sofort herunterladen.
videomsg.video.id, .captionCaption optional.
documentmsg.document.id, .filename, .mime_typeFilename enthalten — speichern.
stickermsg.sticker.id, .animatedAnimated-Flag unterscheidet WebP von animiertem Sticker.
locationmsg.location.latitude, .longitude, .name, .addressName und Adresse sind optional.
contactsmsg.contacts[n].name, .phonesArray — Kunde kann mehrere Kontakte teilen.
reactionmsg.reaction.emoji, .message_idReferenziert die Message-ID, auf die der Kunde reagiert hat.
interactivemsg.interactive.type, dann .button_reply oder .list_replytype prüfen, bevor Sub-Objekt gelesen wird.
ordermsg.order.catalog_id, .product_itemsWhatsApp Commerce — Produktbestellung aus Katalog.
systemmsg.system.body, .typeSystem-Ereignisse: Kunde hat Nummer geändert, etc.
buttonmsg.button.text, .payloadQuick-Reply-Button-Klick von einer Template-Nachricht.
referralmsg.referral.source_url, .source_type, .source_idClick-to-WhatsApp-Ad-Referral-Daten neben der Nachricht.

Feld messages — ausgehende Statusaktualisierungen

StatuswertBedeutungZusätzliche Felder
sentNachricht von Meta akzeptiert und an WhatsApp weitergeleitet. Noch nicht am Gerät zugestellt.timestamp, recipient_id, conversation, pricing
deliveredNachricht hat das Gerät des Empfängers erreicht (doppeltes graues Häkchen).timestamp, recipient_id, conversation, pricing
readEmpfänger hat den Chat geöffnet (doppeltes blaues Häkchen). Wird nur ausgelöst, wenn Lesebestätigungen aktiviert sind.timestamp, recipient_id
failedZustellung dauerhaft fehlgeschlagen. status.errors[0].code auf spezifischen Fehler prüfen.errors-Array mit code und title

Exakter Wiederholungszeitplan mit Backoff-Zeiten

Meta wiederholt fehlgeschlagene Webhook-Zustellungen bis zu 7 Tage lang mit exponentiellem Backoff. "Fehlgeschlagen" bedeutet, dass Ihr Endpunkt einen nicht-200-Status zurückgegeben hat, ein Timeout hatte (länger als 20 Sekunden brauchte) oder nicht erreichbar war. Nach 7 Tagen wird das Ereignis endgültig verworfen — es gibt keinen nativen Wiederherstellungspfad.

1Sofort (erste Zustellung)
2~5 Sekunden~5 Sekunden nach erstem Versuch
3~30 Sekunden~35 Sekunden
4~2 Minuten~2,5 Minuten
5~10 Minuten~12 Minuten
6~30 Minuten~42 Minuten
7~2 Stunden~2 Stunden 42 Minuten
8~6 Stunden~8,5 Stunden
9~12 Stunden~20 Stunden
10~24 Stunden~44 Stunden
11+~24 StundenAlle 24h bis 7 Tage
FinalNach 7 TagenEreignis endgültig verworfen — keine Wiederherstellung
Praktische Implikation: Wenn Ihr Server wegen Wartung ausfällt, werden Ereignisse bei Meta bis zu 7 Tage lang in der Warteschlange gehalten. Wenn Ihr Server wieder online geht und 200 zurückgibt, liefert Meta den Rückstau aus — potenziell ein Burst von Tausenden von Ereignissen, die gleichzeitig eintreffen. Gestalten Sie Ihren Webhook-Handler und Ihre Queue so, dass sie High-Concurrency-Bursts absorbieren können, ohne Ereignisse zu verlieren oder Kaskadenfehler zu verursachen.

HTTP-Antwortcode-Verhalten

Was Sie an Meta zurückgeben, bestimmt, ob das Ereignis als zugestellt gilt, wiederholt wird oder einen Alarm auslöst. Der Entscheidungsbaum ist einfacher, als die meisten Entwickler erwarten — alles ist binär: 200 bedeutet Erfolg, alles andere bedeutet Wiederholung.

200
Bestätigt — Zustellung abgeschlossen
Meta betrachtet das Ereignis als zugestellt. Keine Wiederholung geplant. Geben Sie 200 sofort nach der HMAC-Verifizierung zurück, unabhängig davon, ob Sie die Verarbeitung abgeschlossen haben. Verschieben Sie die gesamte Verarbeitung in eine asynchrone Queue.
403
Forbidden — löst Wiederholung aus
Geben Sie 403 zurück, wenn die HMAC-Verifizierung fehlschlägt. Meta behandelt dies als fehlgeschlagene Zustellung und plant eine Wiederholung. Nützlich, um Anfragen, die nicht mit Ihrer Signatur übereinstimmen, explizit abzulehnen — in der Praxis jedoch: 200 für verifizierte Sicherheitsanfragen zurückgeben und 403 nur bei echten Fälschungsversuchen.
4xx (andere)
Client-Fehler — löst Wiederholung aus
Jede 4xx-Antwort löst Metas Wiederholungsmechanismus aus. Geben Sie niemals 4xx für Business-Logik-Fehler innerhalb valider Payloads zurück — geben Sie immer 200 zurück, um den Empfang zu bestätigen, und behandeln Sie den Fehler in Ihrer Anwendung. Ein 400 oder 404 von Ihrem Handler ist aus Metas Sicht nicht von einem Server-Konfigurationsfehler zu unterscheiden.
5xx
Server-Fehler — löst Wiederholung aus
Echte Server-Fehler (Absturz, OOM, unbehandelte Exception) geben 5xx zurück. Meta wiederholt. Der kritische Design-Punkt: Lassen Sie Business-Logik-Fehler niemals als 5xx hochblasen. Wickeln Sie die gesamte Verarbeitung in try-catch, geben Sie 200 zurück, um den Empfang zu bestätigen, und loggen Sie den Fehler intern. 5xx sollte nur bei echten Infrastruktur-Fehlern feuern.
Timeout
Keine Antwort innerhalb von 20s — löst Wiederholung aus
Wenn Ihr Handler länger als 20 Sekunden für eine Antwort braucht, behandelt Meta dies als Fehler. Dies ist das häufigste Produktionsproblem. Jede synchrone Operation (Datenbank-Schreibvorgang, LLM-Aufruf, HTTP-Request) innerhalb Ihres Webhook-Handlers ist ein Timeout-Risiko. Geben Sie 200 in <100ms zurück. Schieben Sie alles andere an einen Queue-Worker.

Vollständige HMAC-SHA256-Signatur-Spezifikation

Jede POST-Anfrage von Meta enthält eine kryptografische Signatur, mit der Sie verifizieren können, dass die Anfrage tatsächlich von Meta stammt und während der Übertragung nicht manipuliert wurde. Das Überspringen dieser Prüfung bedeutet, dass jeder Angreifer, der Ihre Webhook-URL entdeckt, willkürliche Daten an Ihre Anwendung füttern kann.

Header-Format

Header-Spezifikation
X-Hub-Signature-256
X-Hub-Signature-256: sha256=a1b2c3d4e5f6... Format: sha256= + hex_digest (kleingeschriebenes Hex, 64 Zeichen) Schlüssel: Ihr App Secret (NICHT Ihr Access Token) Nachricht: Rohe Request-Body-Bytes — VOR jeglichem JSON-Parsing Fundort: Meta Developer Dashboard → App Settings → Basic → App Secret

Verifizierung in Node.js

Node.js
verify.js
const crypto = require('crypto'); function verifyWebhook(rawBody, signatureHeader, appSecret) { if (!signatureHeader?.startsWith('sha256=')) return false; const received = signatureHeader.slice(7); // 'sha256=' entfernen const expected = crypto .createHmac('sha256', appSecret) .update(rawBody) // ← roher Buffer, NICHT geparstes JSON .digest('hex'); try { return crypto.timingSafeEqual( // verhindert Timing-Angriffe Buffer.from(received, 'hex'), Buffer.from(expected, 'hex') ); } catch { return false; // Längen-Ungleichheit → ungültig } } // Verwendung in Express — erfordert express.raw() Middleware app.post('/webhook', (req, res) => { const valid = verifyWebhook( req.body, // roher Buffer req.headers['x-hub-signature-256'], // Header process.env.WHATSAPP_APP_SECRET ); if (!valid) return res.sendStatus(403); res.sendStatus(200); enqueue(JSON.parse(req.body)); });

Verifizierung in Python

Python
verify.py
import hmac, hashlib def verify_webhook(raw_body: bytes, sig_header: str, app_secret: str) -> bool: if not sig_header.startswith("sha256="): return False received = sig_header[7:] # 'sha256='-Präfix entfernen expected = hmac.new( app_secret.encode(), raw_body, # ← rohe Bytes, NICHT decodiert/geparst hashlib.sha256 ).hexdigest() return hmac.compare_digest(received, expected) # timing-sicher
Der #1 HMAC-Bug: Berechnung der Signatur nach dem JSON-Parsing. JSON.stringify(JSON.parse(body)) erzeugt andere Bytes als das Original — Leerzeichen, Schlüsselreihenfolge und Zahlenpräzision können sich alle ändern. Berechnen Sie HMAC immer auf den exakten Bytes, die in der HTTP-Anfrage angekommen sind, vor jeglicher Transformation.

WABA-Ebene vs. Telefonnummer-Ebene Webhooks

Die WhatsApp Cloud API unterstützt zwei Webhook-Konfigurationsebenen, die in einer spezifischen Prioritätsreihenfolge interagieren. Das Verständnis hierfür verhindert stillen Ereignisverlust beim Verwalten mehrerer Telefonnummern.

AspektTelefonnummer-WebhookWABA-Webhook
KonfigurationsortMeta Developer Dashboard → WhatsApp → ConfigurationMeta Business Settings → WhatsApp Accounts → [WABA] → Webhook
GeltungsbereichEine spezifische TelefonnummerAlle Telefonnummern im WABA
PrioritätHöher — hat VorrangNiedriger — nur Fallback
Fallback-VerhaltenWenn gesetzt, erhält WABA-Webhook keine Ereignisse für diese NummerErhält Ereignisse für Nummern ohne Telefonnummer-Webhook
Am besten fürEinzelnummern-Integrationen, pro-Nummer-Routing-LogikMehrnummern-Operationen, Agentur verwaltet viele Kundenummern
Ereignis-RoutingEreignisse gehen nur an diese URLEreignisse für alle nicht konfigurierten Nummern kommen hier an
Abonnement-FelderSeparat konfiguriertSeparat konfiguriert
Agentur-Muster: Konfigurieren Sie einen WABA-Ebenen-Webhook, der auf einen zentralen Endpunkt zeigt, der Ereignisse nach metadata.phone_number_id dispatcht. Fügen Sie einen Telefonnummer-Ebenen-Webhook nur für Nummern hinzu, die unterschiedliches Routing benötigen. Dies ist sauberer als separate Webhooks pro Kundenummer zu verwalten, und SocialHook unterstützt mehrere Nummern pro Konto unter einem einzigen normalisierten Ereignis-Stream.

At-Least-Once-Zustellung — Implikationen und Deduplizierung

Metas Webhook-System garantiert, dass ein gegebenes Ereignis mindestens einmal zugestellt wird. Es garantiert nicht genau einmal. Das Duplikat-Szenario: Ihr Server verarbeitet ein Ereignis, gibt 200 zurück, aber die Bestätigung geht auf dem Weg zu Metas System verloren. Meta wiederholt. Ihr Handler verarbeitet dasselbe Ereignis erneut.

Für einen einfachen Echo-Bot ist dies belanglos. Für einen AI-Agenten, der eine CRM-Aktion, eine Zahlung oder eine ausgehende Nachricht auslöst — verursachen Duplikate echte Probleme. Ihr Handler muss idempotent sein.

Deduplizierungs-Muster

Node.js + Redis
dedup.js
const redis = getRedisClient(); const DEDUP_TTL = 86400; // 24 Stunden — länger als 7-Tage-Wiederholungsfenster zur Sicherheit async function processIfNew(messageId, processFn) { const key = `whatsapp:dedup:${messageId}`; // SET ... NX — setzt nur, wenn Schlüssel nicht existiert const isNew = await redis.set(key, '1', 'EX', DEDUP_TTL, 'NX'); if (!isNew) { console.log(`Duplikat-Ereignis übersprungen: ${messageId}`); return; // bereits verarbeitet — idempotentes Überspringen } await processFn(); } // In Ihrem Worker: await processIfNew(msg.id, () => handleMessage(msg));

Der Wert msg.id (die Zeichenkette wamid.HBgL...) ist eindeutig pro Nachricht. Status-Updates verwenden die ausgehende Nachrichten-ID. Reaktionen und andere Ereignistypen haben ihre eigenen eindeutigen IDs. Verwenden Sie immer die ereignisspezifische ID — niemals einen abgeleiteten Wert — als Ihren Deduplizierungsschlüssel.

Payload-Schemata für Schlüssel-Ereignistypen

Top-Level-Envelope (alle Ereignisse)

JSON
top-level-envelope.json
{ "object": "whatsapp_business_account", // immer diese Zeichenkette "entry": [{ // Array — normalerweise 1 Eintrag "id": "WABA_ID", "changes": [{ "field": "messages", // Name des Abonnement-Felds "value": { /* ereignisspezifische Daten */ } }] }] }

Eingehende Textnachricht (value-Objekt)

JSON
inbound-text-value.json
{ "messaging_product": "whatsapp", "metadata": { "display_phone_number": "+1 555 000 1234", "phone_number_id": "PHONE_NUMBER_ID" // zur Routierung in WABA-Setups verwenden }, "contacts": [{ "profile": { "name": "Alice" }, "wa_id": "15550002345" }], "messages": [{ "id": "wamid.HBgL...", // eindeutige Nachrichten-ID — für Deduplizierung verwenden "from": "15550002345", // ohne +-Präfix "timestamp": "1747231892", // String — vor Verwendung parseInt() "type": "text", "text": { "body": "Hello!" } }] }

Ausgehende Nachrichten-Statusaktualisierung (value-Objekt)

JSON
status-update-value.json
{ "messaging_product": "whatsapp", "metadata": { "display_phone_number": "...", "phone_number_id": "..." }, "statuses": [{ // Hinweis: 'statuses' nicht 'messages' "id": "wamid.HBgL...", // Ihre ausgehende Nachrichten-ID "status": "delivered", // sent | delivered | read | failed "timestamp": "1747231900", "recipient_id": "15550002345", "conversation": { "id": "CONVERSATION_ID", "origin": { "type": "service" } // Preiskategorie }, "pricing": { "billable": true, "pricing_model": "CBP", "category": "service" } }] }

Sicherheits-Checkliste

HMAC-SHA256-Signatur bei jedem POST verifizieren
Jede Anfrage ablehnen mit 403, bei der der X-Hub-Signature-256-Header fehlt, fehlerhaft ist oder nicht übereinstimmt. Ohne dies akzeptiert Ihr Endpunkt gefälschte Ereignisse von jedem.
Timing-sicheren Vergleich für Signatur-Abgleich verwenden
crypto.timingSafeEqual() in Node.js, hmac.compare_digest() in Python. Einfache String-Gleichheit (=== / ==) leckt Timing-Informationen, die Angreifer ausnutzen können, um Signaturen Zeichen für Zeichen zu fälschen.
Rohen Body vor HMAC parsen, nicht danach
HMAC auf den rohen Request-Body-Bytes berechnen. JSON-Parsing verändert die Byte-Repräsentation. In Express: express.raw()-Middleware auf der Webhook-Route. In FastAPI: await request.body() vor jeglicher JSON-Deserialisierung.
App Secret in Umgebungsvariablen speichern, niemals im Quellcode
Das App Secret ist der HMAC-Signaturschlüssel. Jeder, der es hat, kann gültige Webhook-Signaturen fälschen. In process.env.WHATSAPP_APP_SECRET (Node.js) oder os.environ["WHATSAPP_APP_SECRET"] (Python) speichern. Sofort rotieren, wenn es leakt.
Idempotente Ereignisverarbeitung implementieren
At-Least-Once-Zustellung bedeutet, dass Duplikat-Ereignisse eintreffen werden. Verarbeitete msg.id-Werte in Redis mit 24h+ TTL speichern. Vor Verarbeitung prüfen. Duplikate still überspringen — niemals darauf mit Fehler reagieren.
Rate-Limiting auf Ihrem Webhook-Endpunkt implementieren
Während des Normalbetriebs sendet Meta Bursts bei hohem Traffic. Pro-IP-Rate-Limiting implementieren, das Metas legitime Zustellrate erlaubt, aber unerwartete High-Volume-Anfragen von unbekannten IPs drosselt. 1000 req/min ist eine vernünftige Obergrenze für die meisten Integrationen.
Nicht-ratbares Verify-Token verwenden
Das Verify-Token wird nur während der Registrierung geprüft, aber die Verwendung einer vorhersagbaren Zeichenkette ("mytoken", "test", "whatsapp") macht Ihr Setup leichter zu sondieren. Eine zufällige 32-Byte-Hex-Zeichenkette generieren: crypto.randomBytes(32).toString('hex').
7-Tage-Wiederholungsfenster mit Alerting überwachen
Wenn Ihr Webhook-Endpunkt nicht erreichbar ist, werden Ereignisse still bei Meta für 7 Tage in der Warteschlange gehalten. Danach — weg. Uptime-Monitoring einrichten (Uptime Robot, Better Uptime oder ähnlich) mit Alerting bei HTTP-Fehlern an Ihrer Webhook-URL. Beim ersten Fehler pagen; nicht auf Berichte über verlorene Nachrichten warten.

Häufige Fehler und Lösungen

Fehler / SymptomUrsacheLösung
Verifizierung schlägt bei Registrierung fehl JSON statt Klartext zurückgeben, falsches Verify-Token oder hub.challenge in ein JSON-Objekt eingewickelt zurückgeben hub.challenge als Klartext mit Content-Type: text/plain zurückgeben. Exakte Zeichenkette — kein JSON-Wrapping.
HMAC schlägt immer fehl HMAC nach JSON-Parsing berechnen, Access Token statt App Secret verwenden, Body doppelt encodieren express.raw() in Express verwenden. await request.body() in FastAPI vor dem Parsen aufrufen. Schlüssel = App Secret aus App Settings → Basic.
Ereignisse kommen überhaupt nicht an messages-Feld nicht abonniert oder Webhook nicht gespeichert/verifiziert Dashboard → WhatsApp → Configuration → Webhooks → Manage → messages-Feld aktivieren. Bestätigen, dass Webhook als verifiziert angezeigt wird.
Dasselbe Ereignis mehrfach empfangen At-Least-Once-Zustellung — erwartetes Verhalten, kein Bug Deduplizierung implementieren mit msg.id als Redis-Schlüssel mit 24h TTL. Vor Verarbeitung prüfen.
Ereignisse kommen außer Reihenfolge an Keine Reihenfolge-Garantie — by design timestamp-Feld verwenden, um beim Aufbau von Konversations-Threads zu sortieren. Niemals sequenzielle Zustellreihenfolge annehmen.
Meta-Wiederholungen kommen ständig Handler gibt nicht-200 zurück, Timeout (>20s) oder Absturz Sofort 200 zurückgeben. gesamte Verarbeitung in asynchrone Queue verschieben. Handler in try-catch wickeln. Server-Stabilität überwachen.
Media-Download gibt 401 zurück Falsches Token verwendet oder Token abgelaufen Media-Downloads erfordern dasselbe Access Token wie für die API. Sicherstellen, dass es ein permanentes System-User-Token ist, kein temporäres User-Token. Prüfen, dass Token nicht widerrufen wurde.
messages-Array fehlt in Payload Es ist eine Statusaktualisierung — das Array heißt statuses, nicht messages Separat auf value.messages UND value.statuses prüfen. Beide kommen unter dem messages-Feld-Abonnement an.
Absendernummer hat kein +-Präfix Cloud API liefert from ohne +-Präfix (z.B. 15550001234 statt +15550001234) Beim Empfang normalisieren: '+' + msg.from für E.164-Format. SocialHook normalisiert dies automatisch.
Timestamp ist String, nicht Integer Cloud API liefert timestamp als Unix-Timestamp-String Immer parseInt(msg.timestamp, 10) (Node.js) oder int(msg["timestamp"]) (Python) vor Datum-Operationen.

SocialHook: die verwaltete Webhook-Schicht

Alles in dieser Referenz — HMAC-Verifizierung, Payload-Extraktion aus der verschachtelten Envelope, Timestamp-Parsing, Absender-Normalisierung, Wiederholungsbehandlung, Deduplizierungs-Infrastruktur, WABA- vs. Telefon-Ebenen-Routing — ist Infrastruktur-Arbeit, auf der Ihr Produkt nicht differenziert.

SocialHook übernimmt die gesamte Cloud-API-Webhook-Schicht und liefert ein normalisiertes Ereignis an Ihren Endpunkt, sodass Ihr Anwendungscode nur sauberes, konsistentes JSON sieht — niemals die rohe verschachtelte Meta-Payload mit ihren Eigenheiten.

BetreffRohe Cloud APISocialHook normalisiert
Nachrichten-Extraktionentry[0].changes[0].value.messages[0]Flaches message-Objekt auf Top-Level
Absender-Format"15550001234" — kein +-Präfix"+15550001234" — E.164 normalisiert
Timestamp"1747231892" — String1747231892 — Integer
HMAC-VerifizierungSie implementieren esErledigt — signature_verified: true
Wiederholung bei Ihrer DowntimeMeta wiederholt (7 Tage)SocialHook wiederholt (3x exponentiell)
Multi-Channel-FormatUnterschiedliches Schema pro PlattformGleiches Schema: WhatsApp + FB + Instagram
Zustell-LogsNicht verfügbarVollständiges Log pro Ereignis
Monatliche KostenIhre Server-Infrastrukturkosten50 $ pauschal

SocialHook deckt WhatsApp, Facebook Messenger und Instagram DMs ab — alle drei Meta-Messaging-Kanäle — unter einem Konto, einer Webhook-URL, einem normalisierten Payload-Format. Siehe die vollständige Payload-Referenz oder starten Sie mit dem 5-Minuten-Quickstart.

Häufige Fragen

Welche Webhook-Abonnement-Felder unterstützt die WhatsApp Cloud API?
10+ Felder: messages (eingehende Nachrichten + ausgehende Status), account_update (Verstöße, Einschränkungen), message_template_status_update (Genehmigung/Ablehnung), phone_number_quality_update (Qualitätsbewertung), phone_number_name_update (Anzeigename), business_capability_update (Tier-Änderungen), flows (WhatsApp Flows-Interaktionen), security (2FA-Änderungen), message_template_components_update (Template-Modifikationen) und account_alerts. Pro Feld im Meta Developer Dashboard abonnieren.
Wie lange wiederholt WhatsApp fehlgeschlagene Webhook-Zustellungen?
Bis zu 7 Tage mit exponentiellem Backoff: ~5s → ~30s → ~2 Min. → ~10 Min. → ~30 Min. → ~2 Std. → ~6 Std. → ~12 Std. → ~24 Std., dann alle 24 Std. bis 7 Tage. Nach 7 Tagen wird das Ereignis endgültig verworfen, ohne nativen Wiederherstellungspfad.
Was ist At-Least-Once-Zustellung und wie gehe ich damit um?
Meta garantiert, dass Ereignisse mindestens einmal zugestellt werden, kann aber dasselbe Ereignis mehr als einmal zustellen. Machen Sie Ihren Handler idempotent: Speichern Sie die msg.id in Redis mit 24h TTL mittels SET ... NX. Prüfen Sie vor der Verarbeitung jedes Ereignisses, ob die ID existiert. Wenn ja, überspringen. Wenn nein, hinzufügen und verarbeiten. Dies verhindert doppelte CRM-Einträge, doppelte AI-Antworten und doppelte Zahlungen.
Welches Format hat der X-Hub-Signature-256-Header?
Format: sha256=<64-stelliger kleingeschriebener Hex>. Der Hex-Wert ist HMAC-SHA256 der rohen Request-Body-Bytes, wobei Ihr App Secret als Schlüssel verwendet wird (finden Sie es in App Settings → Basic — dies ist anders als Ihr Access Token). Das sha256=-Präfix vor dem Vergleich entfernen. Immer timing-sicheren Vergleich verwenden.
Warum sind eingehende Nachrichten und Statusaktualisierungen im selben Webhook-Feld?
Sowohl eingehende Nachrichten als auch ausgehende Statusaktualisierungen (sent/delivered/read/failed) werden unter dem Abonnement-Feld messages zugestellt, unterscheiden sich aber im value-Objekt: eingehende Ereignisse enthalten ein messages-Array, Statusaktualisierungen enthalten ein statuses-Array. Immer prüfen, welches Array vorhanden ist, bevor verarbeitet wird — der Versuch, value.messages[0] bei einer Statusaktualisierungs-Payload zu lesen, gibt undefined zurück.
Was ist der Unterschied zwischen WABA-Ebenen- und Telefonnummer-Ebenen-Webhooks?
Telefonnummer-Webhooks werden pro Nummer konfiguriert und haben Vorrang. WABA-Webhooks werden auf WhatsApp Business Account-Ebene konfiguriert und dienen als Fallback für Nummern ohne Telefonnummer-Webhook. Für Agenturen, die mehrere Kundenummern verwalten: einen WABA-Ebenen-Webhook als zentralen Empfänger konfigurieren, der nach metadata.phone_number_id dispatcht, und Telefonnummer-Ebenen-Webhooks nur dort hinzufügen, wo unterschiedliches Routing benötigt wird.

Referenz gelesen.
Jetzt den ersten Webhook empfangen.

Sie kennen die Spezifikation. SocialHook übernimmt die HMAC-Verifizierung, Payload-Normalisierung, Wiederholungslogik und Zustell-Logging — sodass Ihr Anwendungscode nur sauberes JSON sieht. Verbinden Sie Ihre Nummer in unter 5 Minuten.

Keine Kreditkarte erforderlich · 50 $/Monat nach Testphase · Jederzeit kündbar