Zustellungslebenszyklus
Jede ausgehende Nachricht, die Sie über Orbit senden, trägt einstatus-Feld, das sich weiterbewegt, während die Nachricht von Ihrem API-Aufruf zum Empfängergerät wandert — oder in einen Fehlerzustand endet. Diese Seite erklärt diesen Zustandsautomaten auf Konzeptebene: was die Zustände bedeuten, was jede Transition auslöst und wo die carrierspezifischen Besonderheiten liegen. Lesen Sie sie, bevor Sie Ihren ersten Webhook abonnieren oder Ihre Integration auf Nachrichtenergebnisse verzweigen.
Die Semantik pro Status, die vollständige Transitionstabelle und die Webhook-Ereigniszuordnung stehen in der Referenz zum Nachrichtenstatus-Lebenszyklus; das Antwortschema zum Lesen des aktuellen Zustands einer Nachricht in der Messaging-API-Referenz. Diese Seite verbindet beides auf höherer Ebene.
Der Erfolgspfad
Eine Nachricht, die durchgehend erfolgreich ist, durchläuft:pending → queued → sending → sent → delivered → read
Jede Transition wird von einem anderen Akteur ausgelöst — keine einzelne Partei sieht den gesamten Ablauf:
Zwei Akteure stehen neben diesem Pfad und können einen Eintrag aus ihm herausnehmen:
- Der No-DLR-Scheduler. Wenn ein Carrier nie eine Zustellbestätigung zurückliefert, hebt ein Scheduler den Zustand
sentnach einem kanalspezifischen Zeitfenster aufsubmitted_no_receipt— siehe Carrier-bestätigt vs. Zwischenzustand auf der Leitung. - Sie (der Betreiber). Ein Abbruch einer noch nicht gesendeten geplanten Nachricht setzt sie auf
cancelled, einen Endzustand, den kein Provider-Aufruf und keine DLR je berührt. Sandbox-Sendungen lösen intest_sentauf, einen Endzustand, der vor jeder Provider-Übergabe erreicht wird. Das Löschen eines Eintrags setzt jeden Endzustand aufdeleted, ab dem nichts mehr ihn ändern kann.
scheduled bis zu ihrem Auslösezeitpunkt und tritt dann der Warteschlange bei. Sie kann scheduled nur auf drei Arten verlassen: Hochstufung zu queued zur Auslösezeit, cancelled durch Sie oder expired, wenn ihr Gültigkeitsfenster vor dem Versand abläuft.
Carrier-bestätigt vs. Zwischenzustand auf der Leitung
Die für Reporting und Abgleich wichtigste Unterscheidung ist, ob ein Zustand ein vom Carrier bestätigtes Ergebnis oder ein Zwischenzustand auf der Leitung ist:deliveredundreadsind carrier-bestätigt. Eine echte DLR ist eingegangen; der Carrier selbst hat das Ergebnis behauptet.submitted_no_receiptist ein Zwischenzustand auf der Leitung. Er bedeutet „die Einreichung wurde angenommen, und innerhalb des Zeitfensters kam keine Bestätigung zurück”. Er wird auf jedem Webhook als Zwischenzustand markiert (state_class: "intermediate",is_terminal: false), weil eine echtedelivered-,read- oder Fehler-DLR noch nachträglich eintreffen und ihn überschreiben kann.
submitted_no_receipt als Ergebnis unbekannt, nicht als Zustellung. Ob „unbekannt” eher positiv oder wirklich zweideutig ist, hängt vom Kanal ab — siehe Kanalabhängige Besonderheiten.
expired ist das Gegenstück auf der anderen Seite: Eine DLR ist eingegangen, aber so spät, dass das Bestätigungsfenster bereits geschlossen war. Das Ergebnis ist nicht bestimmbar, und der Eintrag ist abgeschlossen; expired wird den Abonnenten als message.failed-Ereignis gemeldet.
Kanalabhängige Besonderheiten
- Meta-DM-Kanäle (Instagram, Messenger). Metas Send-API gibt nie Zustellbestätigungen aus. Der Versand verlässt Orbit als
sent, wird in den Nachrichtenmetadaten alsno_dlr_channelmarkiert und kippt nach 5 Minuten aufsubmitted_no_receipt. Für einen opt-imierten Empfänger garantiert Meta die Zustellung bei Annahme — auf diesen Kanälen verhält sichsubmitted_no_receiptalso wie ein funktionales Zustellsignal, und die Nachrichtenmetadaten tragenno_dlr_channel: true, damit Sie diesen Fall erkennen. - SMPP-gestützte Kanäle (SMS, MMS, Sprache, Fax, RCS). Das Zeitfenster beträgt 30 Minuten. Hier ist
submitted_no_receiptwirklich zweideutig: Das Gerät kann die Nachricht empfangen haben, ohne dass eine Bestätigung gemeldet wurde, der Carrier sendet auf dieser Route möglicherweise nie Bestätigungen, oder die Bestätigung wurde unterwegs verworfen. Verfolgen Sie diese Rate getrennt von Ihrer Zustellrate — ein steigendersubmitted_no_receipt-Anteil auf einem Ziel deutet auf eine nicht kooperierende Route oder einen defekten Bestätigungspfad hin und ist in jedem Fall untersuchenswert. - E-Mail. Fügt ein Fehlerergebnis hinzu, das anderen Kanälen fehlt:
bounced, wenn der empfangende Mailserver die Nachricht abweist. Bounced zählt wiefailedzu Ihrer Endfehlerrate, ist aber ein eigener Status, damit Sie empfängerseitige von providerseitigen Ablehnungen trennen können. - Betreiberabbruch.
cancelledist nur von Ihnen erreichbar — überPOST /messages/:id/cancelauf einer unversendeten Nachricht. Kein Carrier schreibt ihn je, und dementsprechend löst er kein Webhook-Ereignis aus; nichts benachrichtigt einen Abonnenten von einem Abbruch. Fragen SieGET /messages/:idab, wenn Sie den Abbruch in Ihrer eigenen Oberfläche bereitstellen und beobachten müssen. - Sandbox / Testmodus. Testsendungen lösen in
test_sentauf, bevor irgendeine Provider-Übergabe stattfindet. Sie lösenmessage.sentmitstatus: "test_sent"undmetadata.test_mode: trueaus, sodass ein Abonnent aufmetadata.test_modeverzweigen muss, um Sandbox-Verkehr aus der Produktionsverarbeitung fernzuhalten.
Auf was zu verzweigen ist
Integrationen sollten nur auf maschinenlesbaren Feldern umschalten, nie auf Anzeigenamen:status— der aktuelle Zustand der Nachricht. Dies ist der primäre Verzweigungspunkt. Behandeln Sie die vollständige Menge: neben den Erfolgs- und üblichen Fehlerzuständen vergessen Sie nichtcancelled,test_sent,submitted_no_receiptundbounced.metadata.classified_error_code— bei Endfehlern vorhanden; die normalisierte, maschinenlesbare Fehlerkategorie. Kombinieren Sie sie mit dem rohenerror_code/error_messageaufmessage.failed-Webhooks, wenn Sie den Carrier-eigenen Wortlaut haben möchten.metadata.no_dlr_channel— auf Meta-DM-Einträgen vorhanden; besagt, dass einsubmitted_no_receiptder zustellgarantierte Meta-Fall ist, nicht der zweideutige SMPP-Fall.state_class/is_terminal— auf Lebenszyklus-Webhooks.is_terminal: true(äquivalentstate_class: "terminal") bedeutet, dass das Ergebnis endgültig ist;submitted_no_receiptmeldetis_terminal: falsenur deshalb, damit Sie den Vorgang nicht endgültig abschließen.
Häufige Fallstricke
message.createdals Annahme behandeln.message.createdfeuert in dem Moment, in dem der Eintrags der Warteschlange beitritt, vor jedem Provider-Aufruf. Eine synchrone Ablehnung (ein 4xx beim Versand oder ein sofortigesrejected/failed) lässt dieses Ereignis trotzdem ausgeliefert. Kombinieren Sie es mitmessage.sent, bevor Sie schließen, dass die Nachricht rausging.- Annehmen,
deliveredsei unveränderbar. Carrier auf manchen Routen geben eine Zustellbestätigung aus und dann Minuten später eine Korrektur — manche indische und brasilianische Carrier tun dies. Orbit folgt dem: Der Eintrag kann vondelivered → undeliveredoderdelivered → failedwandern. Wenn Sie Status in Ihren eigenen Datenspeicher spiegeln, wenden Sie Aktualisierungen idempotent über die Nachrichten-ID an, statt Transitionen für eine Nachricht zu ignorieren, die Sie bereits als zugestellt markiert haben. - Auf einen Webhook zu
cancelledwarten. Er wird nie kommen — der Abbruch stammt von Ihrem eigenen API-Aufruf, nicht von einem Carrier-Rückruf, sodass die Plattform dafür kein Ereignis ausgibt. Der Eintrag ruht schlicht aufcancelled, bis Sie ihn löschen. submitted_no_receiptin den Fehler-Eimer werfen. Es trifft zu Transportgründen auf dem Ereignistypmessage.failedein (es gibt kein eigenes Ereignis), aber seinstatusin der Nutzlast istsubmitted_no_receiptmitis_terminal: false. Verzweigen Sie aufdata.status, nicht auf den Ereignistyp, und halten Sie es aus Ihren Hard-Failure-Metriken heraus.- Erwarten, genau ein Endereignis pro Nachricht. Eine Nachricht kann
message.failedmitstatus: "submitted_no_receipt"und spätermessage.deliveredausgeben, wenn eine langsame Carrier-Bestätigung innerhalb des Nachfolgefensters endlich eintrifft. Deduplizieren und rekoncizieren Sie nachmessage_idund lassen Sie das spätere Ereignis gewinnen.