"dlr": "yes" and a dlr_url on the
send.
json — the default
A POST with Content-Type: application/json:
Fields
Null fields are omitted rather than sent as nulls, so a receipt for a message that never reached a
vendor does not arrive full of empty keys.
Every call carries
User-Agent: FireFlo/<version>.
err is new. Receipts sent before it existed carried no such key, so it is additive: nothing
else in this body moved, and a receiver that ignores keys it does not recognise needs no change.What err means, and what it does not
err is the same value the SMPP err: field carries for the same failure, so a customer taking
receipts over a webhook and one taking them over SMPP are told the same thing.
An omitted err means nothing reported a code, not that the code was zero. A delivered message
usually carries none, and neither does a receipt FireFlo raised itself about a message no carrier
ever saw.
The value depends on what your provider has configured, and there are three possibilities:
- A code FireFlo recognises, from its own documented set. This is the useful case: the same number means the same real cause whichever carrier the message went through.
018, unknown. The default for a code your provider has not mapped. It is not a real reason, and it is the reason this field is worth asking them about.- A carrier’s own code, passed through unchanged — only where your provider has enabled that per
carrier. Carriers number their failures privately, so
630from one is unrelated to630from another, but it is far more useful than018because it can be looked up.
err you receive is in the documented set. Treat an unrecognised value
as opaque, log it, and quote it when you raise a query — your provider can tell you what that
carrier means by it, and map it so you get a stable code next time.
kannel — placeholder substitution
A bare GET against the registered URL with two placeholders replaced. Nothing is appended.
smsg.dlr.forward.format, not by you. dlr-method is
accepted on a send but does not select it.
Delivery and retries
Delivery is at least once — make your handler idempotent on
id plus level, not on id
alone, since a message can legitimately produce a level 1 and then a level 2.
Which receipts you get
dlr_level on the send: 1 progress only, 2 the outcome (default), 3 both.
Over SMPP the same choice is the registered_delivery octet — 0x11 is the SMPP spelling of
dlr_level: 3.
Every receipt is recorded
Whether or not it is forwarded. Suppressing a receipt is a decision about what to tell you, never about what to record — so “I never got a receipt” is always answerable by your provider.Related
Delivery receipts
Building against this, with the level trap explained.
Callbacks not arriving
Diagnosing the silence.