Zustellverhalten

Die Standard-Nutzlast, das Zeitlimit von 5 Sekunden, warum es keine Wiederholungsversuche gibt und was die einzelnen Zustellstatus bedeuten.

Die Webhook-Zustellung ist bewusst einfach gehalten, und diese Einfachheit hat Folgen für Ihren Empfänger: ein HTTP-Versuch, fünf Sekunden, keine Wiederholung. Lesen Sie diese Seite, bevor Sie entscheiden, wie viel Arbeit Ihr Handler direkt ausführt.

Die Standard-Payload

Jedes Ereignis außer listing.submission wird mit derselben Struktur auf oberster Ebene zugestellt, wobei die ereignisspezifischen Felder unter data verschachtelt sind.

JSON
{  "event": "connection.location_connected",  "timestamp": "2026-08-25T14:32:10Z",  "account_id": 11073,  "location_id": "279381",  "data": {    "platform": "google",    "connected_account_id": "ba03bc4b-9f8c-4d3b-8e93-9628034c63cc"  }}
FeldTypHinweise
eventstringDer durch Punkte gegliederte Ereignisname. Verwenden Sie ihn zur Fallunterscheidung.
timestampstringISO-8601 in UTC, mit dem Zeitpunkt der Erstellung der Zustellung, nicht dem Zeitpunkt der zugrunde liegenden Änderung.
account_idintegerDas Konto, zu dem das Ereignis gehört.
location_idstringEine Zeichenfolge aus Ziffern: "279381", nicht 279381. Bei interaction.* erfolgt keine Typumwandlung; siehe die Ausnahme weiter unten.
dataobjectEreignisspezifische Felder. Für jedes Ereignis in der Ereignisreferenz dokumentiert.
agency_account_idintegerNur vorhanden, wenn das Konto von einem übergeordneten Agenturkonto verwaltet wird.

Optionale Felder innerhalb von data werden bei leerem Wert weggelassen, statt als null gesendet zu werden. Programmieren Sie defensiv: Behandeln Sie einen fehlenden Schlüssel genauso wie ein explizites null, und gehen Sie niemals davon aus, dass ein als optional dokumentierter Schlüssel vorhanden ist.

Zwei Ausnahmen

Das Zeitbudget von 5 Sekunden

Jede Zustellung besteht aus einem einzelnen POST mit einem Verbindungs-Timeout von 5 Sekunden und einem Lese-Timeout von 5 Sekunden. Wenn Ihr Endpunkt nicht rechtzeitig geantwortet hat, wird der Versuch abgebrochen und als timeout protokolliert.

Dieses Zeitbudget gilt für Ihren gesamten Handler. Nur der folgende Ablauf ist sicher:

  1. Prüfen Sie die Signatur.
  2. Speichern Sie die Payload dauerhaft: in einer Warteschlange, einer Tabelle oder einem Protokoll.
  3. Geben Sie 200 zurück.

Alles Weitere (Datenanreicherung, Verteilung an mehrere Empfänger, Rückaufrufe an die REST API und alle Zugriffe auf Drittanbieter) gehört in die Verarbeitung nach der Warteschlange.

Es gibt keine Wiederholungsversuche

Eine Zustellung wird genau einmal versucht. Es gibt weder Backoff noch eine Warteschlange für Wiederholungsversuche oder eine Dead-Letter-Warteschlange. Wenn Ihr Endpunkt zwei Minuten lang nicht erreichbar ist, gehen die in diesen zwei Minuten ausgelösten Ereignisse verloren. Sie werden nicht später zugestellt.

Zwei Folgen sind dabei ausdrücklich zu beachten:

  • Weiterleitungen werden nicht verfolgt. Weiterleitungen sind vollständig deaktiviert, sodass ein 301 oder 302 von Ihrem Endpunkt als fehlgeschlagene Zustellung protokolliert wird, statt die Zustellung an einer zweiten URL fortzusetzen. Konfigurieren Sie die endgültige URL als Ihre Webhook-URL. Achten Sie auf Weiterleitungen von der Domain ohne Subdomain zu www sowie auf Weiterleitungen zum Anhängen eines abschließenden Schrägstrichs, die viele Webserver standardmäßig hinzufügen.
  • Nur ein 2xx gilt als zugestellt. 3xx, 4xx und 5xx werden alle als Fehler protokolliert.

Duplikate und Reihenfolge

  • Sie können dasselbe Ereignis zweimal und dieselbe id für zwei verschiedene Änderungen erhalten. Die Kennungen in data (eine Interaktions-id, eine Beitragsobjekt-id, eine id eines verbundenen Kontos) bezeichnen die Ressource, nicht die Änderung. interaction.review wird bei jeder Änderung der Bewertung erneut mit derselben Interaktions-id ausgelöst, und keine Nutzlast enthält eine Version oder ein updated-at-Feld. Ein Handler, der Ereignisse anhand von id + event dauerhaft unterdrückt, verwirft daher unbemerkt tatsächliche Änderungen. Erkennen Sie stattdessen exakte Duplikate: Berechnen Sie einen Hash der unverarbeiteten Bytes des Bodys und ignorieren Sie Wiederholungen desselben Hashs innerhalb eines kurzen, begrenzten Zeitfensters (Minuten, nicht dauerhaft). Ein anderer Body mit derselben id ist eine neue Änderung, kein Duplikat. Lesen Sie anschließend die Ressource erneut über die REST API aus und betrachten Sie das Ergebnis als maßgeblich; verwenden Sie die Ressourcen-id als Schlüssel für den Schreibvorgang, statt ihn zu überspringen.
  • Die Reihenfolge ist nicht garantiert, und timestamp ändert daran nichts. Ereignisse stammen aus mehreren unabhängigen Verarbeitungswegen und werden bei Eingang zugestellt. Daher kann ein local_post.published vor dem local_post.created eintreffen, das Sie zuerst erwartet haben. Ordnen Sie zwei Änderungen an derselben Ressource nicht anhand von timestamp: Dieser Zeitstempel wird beim Erstellen der Zustellung gesetzt, nicht zum Zeitpunkt der Änderung, und die Nutzlast enthält weder eine Version noch eine Sequenznummer. Wenn die Reihenfolge relevant ist, lesen Sie die Ressource erneut aus und verwenden Sie das Ergebnis der API.
  • profile.updated wird durch Debouncing begrenzt: auf eine Zustellung pro Standort alle 60 Sekunden, jeweils zu Beginn des Zeitfensters. Dabei werden Änderungen tatsächlich zusammengefasst und nicht verzögert: Die erste Änderung öffnet das Zeitfenster und wird zugestellt, jede Änderung innerhalb des Zeitfensters wird verworfen und trifft nie ein, und changed_fields beschreibt nur die Änderung, die das Zeitfenster geöffnet hat. Das Ereignis erreicht Sie daher zu Beginn des Zeitfensters, sodass ein bei seinem Eingang ausgelöstes erneutes Auslesen immer nur diese erste Änderung erfassen kann. Planen Sie ein zweites Auslesen nach Ende des Zeitfensters, frühestens 60 Sekunden nach dem Ereignis, und gleichen Sie Standorte zusätzlich zeitgesteuert ab, da auch die Benachrichtigung selbst verloren gehen kann: ein Versuch, keine Wiederholung. Für nichts anderes wird Debouncing angewendet.

Wiederherstellung nach einem verpassten Ereignis

Es gibt weder einen erneuten Zustellversuch noch eine erneute Auslieferung vergangener Ereignisse. Daher benötigen Sie für jede Ereignisfamilie eine maßgebliche Leseabfrage, auf die Sie zurückgreifen können. Führen Sie den Abgleich nach einem Zeitplan durch, nicht nur, wenn etwas falsch erscheint.

FamilieErneut auslesen mitEmpfohlenes IntervallWas sich durch Auslesen nicht wiederherstellen lässt
listing.submissionGET /locations/{locationId}/listings/premium, einmal mit listingType=premium und einmal mit additional: die vom Ereignis angekündigten Werte für syncStatus und listingUrl je Website.Täglich pro Standort und nach einer Massenbearbeitung von Standorten.Die alte Nutzlast enthält weder timestamp noch account_id, sodass ein verpasstes Ereignis weder zeitlich eingeordnet noch einem Konto zugeordnet werden kann. error_message bei einer incomplete-Übermittlung ist über keine Leseabfrage verfügbar.
profile.*GET /locations, GET /locations/search oder GET /locations-by-ids. An updatedAt jedes Standorts erkennen Sie, welche sich geändert haben.Stündlich, zusätzlich zum oben beschriebenen erneuten Auslesen nach Ende des Zeitfensters.source (user / api / bulk_edit) und changed_fields: Eine Leseabfrage zeigt den aktuellen Zustand, niemals, wer was geändert hat. Änderungen, die durch das Debouncing innerhalb von 60 Sekunden zusammengefasst werden, hinterlassen keinerlei Spuren, und der Zustand eines gelöschten Standorts vor der Löschung ist nicht mehr verfügbar.
connection.*GET /connected-accounts und GET /connected-accounts/{connectedAccountId}/details für das Herstellen und Trennen von Verbindungen sowie den Authentifizierungszustand. Für das Ereignispaar zur Google-Verifizierung lesen Sie googleVerificationStatus { status, message } aus einer beliebigen Standortabfrage aus.Stündlich; während einer laufenden Verifizierung alle paar Minuten.failure_type (rejected gegenüber transient) und die Zeichenfolge reason. Wiederholte Verbindungsabbrüche bleiben unsichtbar: Eine Verbindung, die unterbrochen und wiederhergestellt wurde, wird beim Auslesen als verbunden angezeigt.
interaction.*GET /locations/{locationId}/reviews pro Standort, GET /rollup_interactions standortübergreifend, GET /reviewDetails anhand der id.Alle 15 Minuten für neue Bewertungen, täglich für einen umfassenderen Abgleich.Dass sich etwas geändert hat. Die dokumentierten Interaktionsfelder enthalten kein updated-at-Feld, sodass eine bearbeitete Bewertung genauso aussieht wie eine bereits gespeicherte: Vergleichen Sie die Felder, die Sie speichern.
local_post.*GET /locations/{locationId}/posts, GET /locations/{locationId}/bulk-posts, GET /posts/{postId} für den aktuellen Veröffentlichungsstatus je Website.Stündlich, solange die Veröffentlichung von Beiträgen läuft.rejection_reason in der zugestellten Form und die Abfolge der Zustände, die ein Beitragsobjekt durchlaufen hat. Leseabfragen liefern den aktuellen Status, nicht die Übergänge.
review_analytics.*GET /locations/{locationId}/review-analytics-overview mit startDate und endDate des Zeitraums.Täglich nach dem Aggregationszeitfenster, wöchentlich für die wöchentliche Ereignisfamilie.Die Zahlen zum damaligen Stand. Die Übersicht wird beim Auslesen neu berechnet, sodass eine verspätet eingegangene oder gelöschte Bewertung zu einer Abweichung von den Werten der Momentaufnahme führt.

Zustellergebnisse

Jeder Versuch wird mit einem Status protokolliert, auch wenn dabei keine Anfrage gesendet wird. Dies sind die exakten Zeichenfolgen.

Die vier Ergebnisse und die Statuszeichenfolgen, mit denen sie protokolliert werden. „Blockiert“ und „Ratenlimit überschritten“ bedeuten, dass überhaupt keine HTTP-Anfrage gesendet wurde. Deshalb sollten sie von einem tatsächlichen Fehlschlag unterschieden werden.
StatusErgebnisBedeutungMaßnahme
successZugestelltIhr Endpunkt hat 2xx zurückgegeben.Keine.
ein HTTP-Code als Zeichenfolge, e.g. "404", "500"FehlgeschlagenIhr Endpunkt hat diesen Code außerhalb des 2xx-Bereichs zurückgegeben. 3xx fällt ebenfalls darunter, da Weiterleitungen nicht gefolgt wird.Prüfen Sie den Pfad, die Weiterleitungskette und die Fehlerrate Ihres Handlers.
999FehlgeschlagenEine Antwort wurde ohne verwertbaren Statuscode zurückgegeben.Die Ursache ist normalerweise ein Proxy oder Load Balancer vor Ihrem Endpunkt.
timeoutFehlgeschlagenKeine Antwort innerhalb des Zeitlimits von 5 Sekunden.Verlagern Sie die Verarbeitung aus der Anfragebearbeitung und bestätigen Sie den Empfang früher.
network_errorFehlgeschlagenDer Host konnte nicht aufgelöst oder erreicht werden.Prüfen Sie DNS und stellen Sie sicher, dass der Host öffentlich auflösbar ist.
errorFehlgeschlagenBeim Versuch trat ein Fehler auf, der keiner der oben genannten Kategorien entspricht, etwa ein fehlgeschlagener TLS-Handshake.Prüfen Sie Ihre Zertifikatskette und die Serverprotokolle.
blocked_urlBlockiertDie URL hat die Sicherheitsprüfung beim Verbindungsaufbau nicht bestanden: kein HTTPS, kein Host oder Auflösung zu einer privaten Adresse, einer Loopback-Adresse, einer Link-Local-Adresse oder einer Metadatenadresse.Lassen Sie die URL auf einen öffentlichen HTTPS-Host verweisen. Beachten Sie, dass diese Prüfung bei jeder Zustellung erneut durchgeführt wird, sodass eine DNS-Änderung dazu führen kann, dass eine zuvor funktionierende URL blockiert wird.
endpoint_unverifiedBlockiertFür das Konto ist ein Signaturgeheimnis hinterlegt, aber der Endpunkt hat die Verifizierung nicht bestanden oder die Verifizierung wurde zurückgesetzt.Führen Sie im Dashboard erneut Verify endpoint aus.
rate_limitedRatenlimit überschrittenDie Obergrenze pro Minute oder pro Tag wurde überschritten. Das Ereignis wurde verworfen.Reduzieren Sie das Volumen oder wechseln Sie zu einem Tarif mit einer höheren Obergrenze. Siehe Tarife und Limits.

Checkliste für den Empfänger

  • Prüfen Sie bei jeder Anfrage die Signatur; geben Sie bei einer Abweichung 401 zurück und verarbeiten Sie nichts.
  • Berechnen Sie den Hash aus den unveränderten Bytes des Anfragebodys, niemals aus einem erneut serialisierten Objekt.
  • Geben Sie 2xx deutlich vor Ablauf von 5 Sekunden zurück; stellen Sie die Verarbeitung in eine Warteschlange.
  • Verwenden Sie bei jedem Schreibvorgang des Handlers die IDs in data als Schlüssel, damit eine Wiederholung dasselbe Ergebnis liefert, aber gehen Sie bei einer wiederholten ID niemals davon aus, dass nichts zu tun ist.
  • Leiten Sie aus der Empfangsreihenfolge keine Reihenfolge ab und sortieren Sie nicht nach timestamp.
  • Normalisieren Sie location_id beim Eingang zu einer Zeichenfolge.
  • Ignorieren Sie unbekannte Werte für event und geben Sie trotzdem 200 zurück.
  • Stellen Sie die Webhook-URL als endgültige URL ohne Weiterleitungen bereit.
  • Gleichen Sie die Daten regelmäßig mit der REST API ab; es gibt keine Wiederholungsversuche, die dies auffangen.