Skip to content

Delivery receipts

GET/messages/sms/{msgId}API v1

Delivery Receipts, also known as DLRs, report the final or intermediate delivery state of an outbound SMS message. Developers can receive them through a webhook callback or query them through the API with GET /messages/sms/{msgId}. Requests are authenticated with a Bearer token and scoped by your servicePlanId.

Terminology

Delivery Receipt, Delivery Report, and DLR all refer to the same thing: the delivery status event for an outbound (MT) SMS message. Strategic Mobile exposes it two ways — pushed to your endpoint as a webhook callback, and pulled on demand from the API.

1. GET delivery receipt

GET /messages/sms/{msgId} · developer → Strategic Mobile API

Returns the current delivery record (the delivery receipt) for a message identified by its msgId. This is the confirmed way to query delivery state on demand. Only messages belonging to the authenticated caller are returned. Authenticate with a Bearer token and pass your servicePlanId as a query parameter to authorize and scope the lookup.

Parameters

FieldTypeDescription
msgIdstring (path)
Server-generated message identifier (UUID) returned by Send SMS.
Required path parameter.
servicePlanIdstring (query)
Service plan that owns the message. Authorizes and scopes the lookup.
Required query parameter.

Responses

StatusDescription
200The current per-message delivery record (the delivery receipt).
400The message identifier is missing or malformed.
401Missing Bearer token, malformed Authorization header, or invalid token.
403Token is valid but not authorized for the requested account/servicePlan mapping.
404No message with the given identifier exists for this caller.

A 404 means no message with that identifier exists for the authenticated caller; it does not by itself indicate a delivery failure. Request samples (cURL, JavaScript, Python) are shown in the panel.

Newly accepted messages: a delivery receipt may not be queryable immediately after the message is accepted. If GET returns 404 right after a successful 202 response, retry after a short delay. The receipt becomes available once the message record is ready for status retrieval.

Delivery status semantics

The public status field is a simplified five-value enum. Internal carrier lifecycle states are mapped onto these values.

StatusMeaning
QUEUEDMessage accepted and queued for delivery to the carrier; no delivery confirmation yet. Non-terminal.
SENTMessage handed off toward the carrier; awaiting a final delivery receipt. Non-terminal.
DELIVEREDDelivered. Carrier confirmed delivery to the handset. Final state.
FAILEDFailed. Message could not be delivered. See errorCode / errorMessage for the reason. Final state.
UNKNOWNUnknown. A reliable carrier/provider delivery status is not available. Final or indeterminate state.

2. Delivery receipt webhook

Strategic Mobile → your endpoint

When a message status changes, a delivery receipt is POSTed to your DLR callback URL — either the per-message callbackUrl supplied on submission or the default DLR URL configured on your account. This is a webhook receiver example: it shows the HTTP POST your endpoint receives, not a request you send. Your endpoint must accept an HTTPS POST with Content-Type: application/json and acknowledge with 200. Required fields are msgId and status.

POST https://client.example.com/sms/status
Content-Type: application/json

{
  "accountId": "111111111111111111111111",
  "servicePlanId": "222222222222222222222222",
  "msgId": "019ee2da-e515-7322-805f-1ac6ce82f20f",
  "channel": "SMS",
  "direction": "MT",
  "from": "+15550001111",
  "to": "+15550002222",
  "body": "Your verification code is 123456",
  "status": "DELIVERED",
  "errorCode": "000",
  "errorMessage": "No error",
  "segments": 1,
  "price": 0.0007,
  "ptf": 0.0065,
  "currency": "USD",
  "mccmnc": "313790",
  "country": "PR",
  "createdAt": "2026-06-20T04:20:40.982Z",
  "sentAt": "2026-06-20T04:20:41.000Z",
  "updatedAt": "2026-06-20T04:20:41.087Z"
}

Delivery receipt payload fields

FieldTypeDescription
accountIdstring | null
Resolved account identifier (business partner) that owns the message.
servicePlanIdstring | null
Service plan that owns the message.
msgIdstring
Server-generated message identifier (UUID) the receipt refers to.
channelstring
Message channel. Enum: SMS.
directionstring
Message direction (for example MT).
fromstring | null
Sender address.
tostring | null
Destination address.
bodystring | null
SMS message text.
statusstring
Simplified public delivery status.
Enum: QUEUED, SENT, DELIVERED, FAILED, UNKNOWN. Internal carrier states are mapped onto this public status model.
errorCodestring
000 on success; otherwise the failure code.
errorMessagestring
Human-readable status/error message.
segmentsinteger | null
Number of SMS segments.
pricenumber | null
Charged price, when available.
ptfnumber | null
Pass-through fee, when available.
currencystring | null
Currency of price/ptf.
mccmncstring | null
Mobile country/network code.
countrystring | null
ISO 3166 country code.
createdAtstring<date-time>
When the record was created.
sentAtstring<date-time> | null
When the message was sent, when available.
updatedAtstring<date-time>
When the record was last updated.

Acknowledge each delivery receipt with a 2xx response after you accept it, and use msgId as your idempotency key because a receipt for the same message may be delivered more than once.

Recommended handling

For delivery receipts, return a fast 200 OK after minimal validation and durable acceptance, then process it asynchronously in the background.

export async function deliveryReceiptHandler(req, res) {
  // Webhook endpoint authentication is customer-controlled. Validate the
  // request using whatever scheme you configured for your own endpoint.

  const dlr = req.body;

  if (!dlr || !dlr.msgId || !dlr.status) {
    return res.status(400).json({ ok: false, error: "invalid payload" });
  }

  // Persist or update your local status record, then acknowledge.
  await upsertMessageStatus(dlr);

  return res.status(200).json({ ok: true });
}
HTTP/1.1 200 OK
Content-Type: application/json

{
  "ok": true
}
  • Acknowledge the webhook quickly with 200 after basic validation, then process it asynchronously in the background.
  • Use msgId as the idempotency key; treat delivery-receipt handling as idempotent, since the same msgId may be received more than once.
  • Required fields on the webhook payload are msgId and status; treat other fields as optional.
  • Use the GET delivery receipt endpoint to confirm the final state if you miss a webhook delivery.
  • Treat the public status as the simplified five-value enum (QUEUED, SENT, DELIVERED, FAILED, UNKNOWN); do not depend on internal carrier states.

Operational notes

  • Query the current delivery state on demand with GET /messages/sms/{msgId}; the response is the same DeliveryReceipt object delivered by the webhook.
  • Make your webhook endpoint idempotent on msgId, since a delivery receipt for the same message may be delivered more than once.
  • The public status is the simplified five-value enum (QUEUED, SENT, DELIVERED, FAILED, UNKNOWN); internal carrier states are mapped onto these values.
  • price and ptf populate as billing data becomes available and may be null on earlier status updates.