Skip to main content

Delivery receipts

A receipt arrives as deliver_sm on a receiver or transceiver session of your account. One comes for every submit_sm — for every part of a long message — whatever you put in registered_delivery.

What the receipt looks like​

The text of the receipt is in the standard form:

id:4815162342 sub:001 dlvrd:001 submit date:2610301432 done date:2610301433 stat:DELIVRD err:000 text:
FieldWhat it means
id:The message_id from submit_sm_resp
sub:Always 001
dlvrd:001 if the message is delivered, 000 otherwise
submit date:When the message was handed to the operator (for REJECTD — when it was rejected), YYMMDDhhmm
done date:When we recorded the outcome, YYMMDDhhmm
stat:The outcome, see below
err:The error code, see below
text:Always empty

Both dates are in Kyiv time (Europe/Kyiv) and go to the minute.

The same message_id is also in the receipted_message_id field (TLV 0x001E), and the outcome as a number in message_state (TLV 0x0427). Other fields of the PDU:

FieldValue
source_addrThe sender name the message went out under
destination_addrThe recipient's number
esm_class0x04 — a delivery receipt
data_coding0, or 8 if the text cannot be written in GSM 7-bit

The addresses are not swapped: the sender stays in source_addr, the recipient in destination_addr. Many SMSCs put the recipient first, so match receipts to messages by id: or receipted_message_id, not by addresses.

The outcome: stat:​

stat:message_stateWhat happened
DELIVRD2The operator confirmed delivery to the phone
ENROUTE1On its way: the final receipt with the same id: follows
ACCEPTD6Accepted by the operator
EXPIRED3The validity period ran out before the phone came back online, or before the message could be sent
UNDELIV5The operator did not deliver it
REJECTD8The message was not accepted for sending — the reason is in err:
DELETED4The message was cancelled
UNKNOWN7The operator reported no outcome

If the operator never reports an outcome, no receipt comes. A message that runs out of validity while still waiting on our side gets EXPIRED, and the money for it is returned.

Why a message was rejected: err:​

For REJECTD the code says what to fix:

err:ReasonWhat to do
001Not enough money on the balanceTop up and send again
002The recipient: the number is invalid, blocked, or its operator is not servedCheck the number
003The sender name is not allowed for this accountUse an approved name, or ask support
004The text: empty, too long, or a flash message longer than one partShorten or fix the text
005The route does not carry this kind of messageAsk support
006Sending is temporarily switched off on our sideSend again later
000Another reasonAsk support, with the id:

On receipts that come from the operator (DELIVRD, UNDELIV and the rest), err: is the operator's own code, passed on as is.

Acknowledging receipts​

Answer every receipt with deliver_sm_resp. Up to twenty receipts are in flight at once, and the next ones follow as soon as you acknowledge the ones already sent.

Any answer removes the receipt for good — a non-zero command_status included. If your side could not process a receipt, do not expect it again after answering with an error: keep it and process it later instead.

A receipt you have not acknowledged is kept for ten days and comes over your next session.

Several sessions​

A receipt goes to one of the receiver and transceiver sessions of the account, not necessarily the one the message was sent through. Now and then the same receipt can reach two sessions — de-duplicate by id:.

Receipts exist only for messages sent over SMPP. For messages sent through the HTTP API the outcome comes to your notification URL. Incoming messages are not delivered over SMPP.