Zustellungslebenszyklus
Jede ausgehende Nachricht, die Sie über Orbit senden, trägt einstatus-Feld, das fortschreitet, während die Nachricht von Ihrem API-Aufruf zum Gerät des Empfängers – oder zu einem Fehlerergebnis – wandert. Diese Seite erläutert die konzeptuelle Zustandsmaschine: was die Zustände bedeuten, was jede Transition antreibt und wo die betreiberabhängigen Ränder liegen. Lesen Sie sie, bevor Sie Ihren ersten Webhook abonnieren oder Ihre Integration auf ein Nachrichtenergebnis verzweigen.
Die Zustandssemantik, die vollständige Transitionstabelle und die Webhook-Ereigniszuordnung leben in der Referenz zum Nachrichtenstatus-Lebenszyklus; das Antwortschema zum Lesen des aktuellen Status einer Nachricht steht in der Messaging-API-Referenz. Diese Seite verbindet beides auf einer höheren Ebene.
Der Glückspfad
Eine Nachricht, die Ende zu Ende erfolgreich ist, durchläuft:pending → queued → sending → sent → delivered → read
Jede Transition wird von einer anderen Komponente angetrieben – keine einzelne Partei sieht den gesamten Weg:
Zwei Komponenten sitzen neben diesem Pfad und können einen Datensatz daraus entfernen:
- No-DLR-Planer. Wenn ein Carrier nie eine Zustellbestätigung zurücksendet, überträgt der Planer
sentnach einem kanalspezifischen Gnadenfenster zusubmitted_no_receipt— siehe Carrier-bestätigt vs. intermediär am Draht. - Sie (der Sender). Die Stornierung einer geplanten, noch nicht gesendeten Nachricht stellt sie auf
cancelled, einen Endzustand, den kein Provider-Aufruf und keine DLR berührt. Sandbox-Sendungen werden zutest_sentaufgelöst, einem Endzustand, der gemeldet wird, bevor irgendetwas beim Provider veröffentlicht wird. Das Löschen eines Datensatzes verschiebt jeden Endzustand indeleted; danach kann nichts mehr ihn berühren.
scheduled, bis die Startzeit erreicht ist, und tritt dann der Warteschlange bei. scheduled kann nur auf drei Weisen verlassen werden: Beförderung zu queued zur Startzeit, cancelled von Ihnen, oder expired, wenn ihr Gültigkeitsfenster vor der Veröffentlichung abläuft.
Carrier-bestätigt vs. intermediär am Draht
Die wichtigste Unterscheidung für Berichte und Abgleich ist, ob ein Zustand eine carrier-bestätigte oder eine intermediäre am Draht Streitigkeit ist:deliveredundreadsind carrier-bestätigt. Es kam eine echte DLR; der Carrier selbst hat sich auf das Ergebnis geeinigt.submitted_no_receiptist intermediär. Es bedeutet „Zum Versand angenommen, und innerhalb des gnaden Fensters wurde keine Bestätigung zurückgegeben.“ Es wird als intermediär bezeichnet (state_class: "intermediate",is_terminal: false) in jedem Webhook, weil eine echtedelivered-,read- oder fehlerhafte DLR später eintreffen und es ersetzen kann.
submitted_no_receipt als unbekanntes Ergebnis, nicht als Zustellung. Ob sich „unbekannt“ zu positiv oder bloß intermediär neigt, hängt vom Kanal ab — siehe Kanalvariationen.
expired ist die andere Seite der Sicht: Es kam eine DLR, aber so spät, dass das Bestätigungsfenster bereits geschlossen war. Das Ergebnis kann nicht ermittelt werden und der Datensatz ist geschlossen; expired wird an die Abonnenten als message.failed-Ereignis verteilt.
Kanalvariationen
- Meta DM-Kanäle (Instagram, Messenger). Metas Versandoberfläche gibt niemals Zustellbestätigungen aus. Der Versand verlässt Orbit als
sent, markiertno_dlr_channelin den Nachrichten-Metadaten und verfällt nach 5 Minuten insubmitted_no_receipt. Bei einem optional akzeptierten Empfänger garantiert Meta die Zustellung bei der Annahme — deshalb verhält sichsubmitted_no_receiptauf diesen Kanälen wie ein funktionales Zustellsignal, und die Nachrichten-Metadaten tragenno_dlr_channel: true, damit Sie den Zustand unterscheiden können. - SMPP-unterstützte Kanäle (SMS, MMS, Voice, Fax, RCS). Das Gnadenfenster beträgt 30 Minuten. Hier ist
submitted_no_receiptein echtes intermediäres Signal: Das Gerät hat die Nachricht vielleicht ohne berichtete Bestätigung erhalten, der Carrier sendet auf dieser Route vielleicht niemals Bestätigungen, oder die Bestätigung ging vielleicht im Transit verloren. Verfolgen Sie diese Quote als ein von der Zustellquote unterschiedliches Signal — eine dauerhaft hohesubmitted_no_receipt-Quote auf einem Ziel deutet auf eine schlechte Route oder eine kaputte Bestätigungsroute hin und verdient in beiden Fällen eine Untersuchung. - E-Mail. Fügt ein Fehlerergebnis hinzu, das reine DM-Kanäle nicht kennen:
bounced, wenn der Mailserver den Empfang der Nachricht ablehnt. Bounce zählt zu Ihrer endgültigen Fehlerrate wiefailed, ist aber ein getrennter Zustand, damit Sie empfängerseitige Ablehnungen von providerseitigen trennen können. - Senderstornierung.
cancelledwird nur von Ihnen gemeldet — überPOST /messages/:id/cancelauf einer noch nicht gesendeten Nachricht. Kein Carrier schreibt es jemals, und als Folge löst es kein Webhook-Ereignis aus; nichts informiert den Abonnenten über die Stornierung. Rufen SieGET /messages/:idab, wenn Sie die Stornierung in Ihrer Oberfläche anzeigen und beobachten müssen. - Sandbox / Testmodus. Testsendungen werden vor jeder Provider-Veröffentlichung zu
test_sentaufgelöst. Sie lösenmessage.sentmitstatus: "test_sent"undmetadata.test_mode: trueaus, daher muss der Abonnent aufmetadata.test_modeverzweigen, um Sandbox-Verkehr aus der Produktionsverarbeitung herauszuhalten.
Wonach verzweigt wird
Integrationen müssen nur auf maschinell lesbare Felder verzweigen, niemals auf angezeigte Beschreibungen:status— der aktuelle Zustand der Nachricht. Dies ist der primäre Verzweigungspunkt. Behandeln Sie die Menge als Ganzes: neben den Glückspfad- und Fehlerzuständen, vergessen Sie nichtcancelled,test_sent,submitted_no_receiptundbounced.metadata.classified_error_code— auf endgültigen Fehlerergebnissen vorhanden; die maschinell definierte, maschinell aktivierte Fehlerkategorie. Kombinieren Sie sie mit dem rohenerror_code/error_messageimmessage.failed-Webhook, wenn Sie die Worte des Carriers wollen.metadata.no_dlr_channel— auf Meta-DM-Datensätzen vorhanden; sagt Ihnen, dasssubmitted_no_receiptder von Meta garantierte Zustellzustand ist, nicht der aus SMPP übersetzte.state_class/is_terminal— auf dem Lebenszyklus-Webhook.is_terminal: true(gepaart mitstate_class: "terminal") bedeutet, dass das Ergebnis endgültig ist;submitted_no_receiptmeldet genau deshalbis_terminal: false, damit Sie das Buch nicht darauf schließen.
Häufige Fehler
message.createdals Annahme behandeln.message.createdfeuert in dem Moment, in dem der Datensatz der Warteschlange zugefügt wird, noch vor jedem Provider-Aufruf. Eine synchrone Ablehnung (4xx beim Senden oder sofortigesrejected/failed) lässt dieses Ereignis trotzdem ausliefern. Kombinieren Sie es mitmessage.sent, bevor Sie schließen, dass die Nachricht unterwegs ist.- Annehmen,
deliveredsei unveränderlich. Carrier auf manchen Routen geben eine Zustellbestätigung aus und korrigieren sie Minuten später — einige indische und brasilianische Carrier tun das. Orbit respektiert das: Ein Datensatz kann vondelivered → undeliveredoder vondelivered → failedübergehen. Wenn Sie Zustände in Ihrem eigenen Datenspeicher spiegeln, wenden Sie Aktualisierungen idempotent per Nachrichten-ID an, statt Transitionen für eine bereits vollendete Nachricht zu verwerfen. - Auf einem Webhook bei
cancelledwarten. Er wird niemals kommen — die Stornierung ist an Ihren API-Aufruf gebunden, nicht an einen Carrier-Aufruf, daher gibt die Plattform dafür kein Ereignis aus. Der Datensatz sitzt einfach incancelled, bis Sie ihn löschen. submitted_no_receiptin den Fehlerstrom werfen. Es kommt aus Klassifizierungsgründen als Ereignistypmessage.failed(keine separate Route), aber branch aufdata.status, nicht auf den Ereignistyp, und begrenzen Sie es von harten Fehlertönen ab.- Ein endgültiges Ereignis pro Nachricht erwarten. Eine Nachricht kann
message.failedmitstatus: "submitted_no_receipt"ausgeben und danachmessage.delivered, wenn die langsame Carrier-Bestätigung schließlich im Nachlauffenster eintrifft. Aktualisieren und deduplizieren Sie über diemessage_id, und lassen Sie das spätere Ereignis gewinnen.