Skip to content

Delivery receipts webhook

POSTWebhook receiveryour callbackUrlAPI v1

Strategic Mobile sends a webhook POST request to your callbackUrl when an outbound SMS message has a delivery status update. The request body follows the DeliveryReceiptWebhook schema and is sent as Content-Type: application/json. Your endpoint should return any 2xx response after it accepts the receipt.

Request

PropertyValue
MethodPOST
TargetThe per-message callbackUrl supplied on submission, or the default delivery receipt URL configured on your account.
Content-Typeapplication/json
PayloadDeliveryReceiptWebhook
Expected responseAny 2xx status code.
Idempotency keymsgId

Webhook endpoint authentication is customer-controlled. If your endpoint requires authentication, configure the required headers or credentials for your account or callbackUrl. Strategic Mobile does not require a fixed API security scheme for this webhook receiver.

Payload fields

The public status field is a simplified five-value enum ( QUEUED, SENT, DELIVERED, FAILED, UNKNOWN). Required fields are msgId and status; treat the rest as optional.

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.
Required. Use as your idempotency key.
channelstring | null
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.
Required. Enum: QUEUED, SENT, DELIVERED, FAILED, UNKNOWN.
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.

Example payload

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"
}

Recommended handling

Return a fast 2xx after minimal validation and durable acceptance, then process the receipt 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 (idempotent on msgId),
  // then acknowledge with a 2xx response.
  await upsertMessageStatus(dlr);

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

{
  "ok": true
}
  • Your endpoint should return a 2xx response after accepting the webhook. Use msgId as your idempotency key because webhook delivery can be retried.
  • Acknowledge quickly after minimal validation and durable acceptance, then process the receipt asynchronously in the background.
  • The webhook payload always includes msgId and status. Additional delivery metadata, such as accountId, servicePlanId, from, to, body, errorCode, errorMessage, segments, country, mccmnc, createdAt, sentAt, and updatedAt, may be included when available.
  • Treat the public status as the simplified five-value enum (QUEUED, SENT, DELIVERED, FAILED, UNKNOWN); do not depend on internal carrier states.
  • If you miss a webhook, query the current state on demand with GET /messages/sms/{msgId}; the response uses the same public status fields as DeliveryReceiptWebhook.

Related

  • Delivery receipts — delivery state semantics and the on-demand GET /messages/sms/{msgId} lookup.