Skip to main content

SMPP: the no-delivery receipt window

When a submit_sm from your SMPP bind is terminated on another channel — WhatsApp is the common case — no carrier produces a receipt, so Orbit synthesizes one. A receipt that says “nothing confirmed” is only useful if it arrives at a time you chose: this page covers the receipt_timeout_seconds field on a termination rule’s deliver hop, which sets how long the channel has to confirm delivery before your bind receives a UNDELIV receipt you can fail over on. The model behind the field is defined in Send-side DLR model; this page is the how-to: where to set it, when to change it, and the edge cases.

What the window controls

An accepted absorbed submit arms a deadline at submit time plus the window. If a delivery or read receipt lands before the deadline, it is dispatched to your bind normally and the deadline is consumed. If the deadline expires with no confirmation, the sweep emits a stat:UNDELIV receipt whose reason names the armed window — no delivery within 45 s of acceptance — so your fallback logic both fires and can see which window fired it. The field on the hop: The default of 30 seconds means an untouched rule behaves exactly as it did before the field existed: nothing about your existing receipts changes until you set a value. In the dashboard, Developer → SMPP surfaces a No-delivery receipt window panel that previews the deliver-hop field with the same 10–120 bounds and blank-means-default behavior. The panel is a preview today — pick the value there and Support applies it to your rule while the unified rules editor is finalized. The API body below is the same contract you can write immediately.

When to change it

Tune the window against your own traffic’s confirmation curve, not against the platform default:
  • Raise it (toward 120) when destinations confirm slowly — handsets that wake late, recipients roaming across MNOs, or channels with known receipt lag. A UNDELIV fired at 30 s on a channel that habitually confirms at 40 s trains your fallback to re-send messages that were about to land.
  • Lower it (toward 10) when your fallback is the point — OTP and fraud-alert traffic where a fast re-send over a second channel beats the small hit-rate gain from waiting longer.
  • Leave it at 30 unless you have measured otherwise. Two tenants disagree on the right value by tens of seconds; the default exists as a safe middle, not a recommendation.
Measure before you tune: the message row’s status timeline shows how long confirmations actually take on each channel, which is the curve you are setting the window against.

A worked example — absorb onto WhatsApp with a 45-second window

The rule below absorbs SMPP submit_sm traffic for +91 destinations onto WhatsApp and sets a 45-second window on the deliver hop:
Write it against the rules endpoint:
With the rule enforced:
  1. At t=0 your submit_sm (with registered_delivery requesting a receipt) matches the rule and is absorbed onto WhatsApp. A deadline is armed at t=45 s.
  2. If WhatsApp confirms delivery at t=12, a stat:DELIVRD receipt is dispatched to your bind at t=12 — the deadline never fires.
  3. If nothing confirms by t=45, the sweep emits stat:UNDELIV with the reason no delivery within 45 s of acceptance, and your failover channel kicks in on exactly that signal.
In the dashboard, the No-delivery receipt window panel on Developer → SMPP shows 45 in the field once Support has applied it — the same value the API body carries.

How it interacts with the canonical DLR vocabulary

The window touches exactly one arm of the receipt model: the synthesized failed{provider_error}UNDELIV that fires on deadline expiry. Timing of the timeout arm is all it delays. Everything else is untouched:
  • Receipts that arrive before the window dispatch normally — this is a deadline, not a grace period that holds receipts back.
  • The failure arm still carries the documented err: tokens — 81 (not on destination channel), 88 (re-engagement required), 89 (rate limit), 00 (unspecified provider error) — per Send-side DLR model.
  • The encodings the bind and the webhook leg produce are identical, per SMPP edge model.

API-side notes

  • Optional, default 30. Omitting receipt_timeout_seconds arms the platform default. Sending the field as blank/absent and sending it as 30 are equivalent; there is no way to “unset” a rule into a non-default.
  • Integers only. 25.5 fails validation at rule-write time; whole seconds in the 10–120 range only.
  • Shadow vs. enforce. A shadow-mode rule evaluates and records without moving traffic; the window you set takes effect only once the rule flips to enforce. Rules without a deliver hop (pure absorb chains) have nothing to arm and ignore the field.
  • Receipt requests still govern. The deadline only fires for submissions whose registered_delivery flag asked for a receipt; a submission that requested none is not given a timeout receipt either.
  • Rule-level guard on bind mode. A rule that moves messages off the SMPP ingress can require the credential’s dlrMode to be webhook or both (require_dlr_mode on the rule), so choosing a window never creates a receipt black hole for bind-only credentials.

See also