textbee Logotextbee.dev
Save 44% with yearly billing.View Plans
Documentation

Webhook events reference

Every textbee webhook event with a full JSON payload and field table: received, sent, delivered, failed and unknown state, plus ordering rules.

Updated

textbee sends six event types to webhook subscriptions. Five of them fire today: MESSAGE_RECEIVED, MESSAGE_SENT, MESSAGE_DELIVERED, MESSAGE_FAILED and UNKNOWN_STATE. Each payload is a flat JSON object with the same envelope fields plus fields for that event. To create a subscription and verify signatures, see Webhooks.

Envelope fields

Every event has these six fields.

FieldTypeDescription
smsIdstringID of the stored message. The same ID appears in the messages endpoint as _id.
messagestringMessage text.
deviceIdstringID of the device that received or sent the message.
webhookSubscriptionIdstringID of the subscription that produced this delivery.
webhookEventstringEvent name, for example MESSAGE_RECEIVED.
idempotencyKeystringUnique per delivery. Every retry of one delivery carries the same key.

Switch on webhookEvent to handle each event type.

MESSAGE_RECEIVED

Fires when the phone uploads an incoming SMS to textbee. Receive SMS must be on in the app. See Receiving SMS.

JSON
{
  "smsId": "66f7c1e2a4d5e6f7a8b9c0d1",
  "message": "YES, please confirm my booking",
  "deviceId": "664a9b8cd0e1f2a3b4c5d6e7",
  "webhookSubscriptionId": "664a9b8cd0e1f2a3b4c5d6e8",
  "webhookEvent": "MESSAGE_RECEIVED",
  "idempotencyKey": "8f7e6d5c-4b3a-4c1d-8e9f-8a7b6c5d4e3f",
  "sender": "+12015550123",
  "receivedAt": "2026-09-28T09:14:03.000Z"
}
FieldTypeDescription
senderstringNumber that sent the SMS, as the phone reports it. It can be a short code or a text sender name.
receivedAtstringISO 8601 time when the phone received the SMS.

A phone that was offline uploads its messages later. If the upload is more than 48 hours after receivedAt, textbee stores the message but does not send this event. The messages endpoint still returns it.

MESSAGE_SENT

Fires when the phone reports that it sent the message and the carrier accepted it. It does not confirm delivery to the recipient's handset.

JSON
{
  "smsId": "66f7c3a9b1c2d3e4f5a6b7c8",
  "message": "Your order has shipped.",
  "deviceId": "664a9b8cd0e1f2a3b4c5d6e7",
  "webhookSubscriptionId": "664a9b8cd0e1f2a3b4c5d6e8",
  "webhookEvent": "MESSAGE_SENT",
  "idempotencyKey": "2b4d6f8a-1c3e-4a5b-9d7f-0e2c4a6b8d1f",
  "smsBatchId": "66f7c3a8b1c2d3e4f5a6b7c0",
  "status": "sent",
  "recipient": "+12015550124",
  "sentAt": "2026-09-28T10:02:17.000Z"
}
FieldTypeDescription
smsBatchIdstringBatch ID returned by the send request.
statusstringsent
recipientstringNumber the message was sent to.
sentAtstringISO 8601 time when the phone reported the message as sent.

MESSAGE_DELIVERED

Fires when the carrier sends a delivery report to the phone. Carriers do not always send delivery reports. A message can reach the recipient without this event.

JSON
{
  "smsId": "66f7c3a9b1c2d3e4f5a6b7c8",
  "message": "Your order has shipped.",
  "deviceId": "664a9b8cd0e1f2a3b4c5d6e7",
  "webhookSubscriptionId": "664a9b8cd0e1f2a3b4c5d6e8",
  "webhookEvent": "MESSAGE_DELIVERED",
  "idempotencyKey": "5c7e9a1b-3d5f-4b6c-8e0a-2d4f6a8c0e3b",
  "smsBatchId": "66f7c3a8b1c2d3e4f5a6b7c0",
  "status": "delivered",
  "recipient": "+12015550124",
  "sentAt": "2026-09-28T10:02:17.000Z",
  "deliveredAt": "2026-09-28T10:02:21.000Z"
}
FieldTypeDescription
smsBatchIdstringBatch ID returned by the send request.
statusstringdelivered
recipientstringNumber the message was sent to.
sentAtstringISO 8601 time when the phone reported the message as sent.
deliveredAtstringISO 8601 time when the delivery report arrived.

MESSAGE_FAILED

Fires when a message fails. The phone reports a failure when Android or the carrier rejects the send. textbee also fires this event when it cannot push the message to the phone.

JSON
{
  "smsId": "66f7c4d0e1f2a3b4c5d6e7f8",
  "message": "Your code is 482913",
  "deviceId": "664a9b8cd0e1f2a3b4c5d6e7",
  "webhookSubscriptionId": "664a9b8cd0e1f2a3b4c5d6e8",
  "webhookEvent": "MESSAGE_FAILED",
  "idempotencyKey": "9e1a3c5b-7d9f-4e2a-b4c6-8f0a2c4e6b8d",
  "smsBatchId": "66f7c4cfe1f2a3b4c5d6e7f0",
  "status": "failed",
  "recipient": "+12015550125",
  "errorCode": "4",
  "errorMessage": "No cellular service. Check signal and try again when you have coverage.",
  "failedAt": "2026-09-28T10:05:42.000Z"
}
FieldTypeDescription
smsBatchIdstringBatch ID returned by the send request.
statusstringfailed
recipientstringNumber the message was sent to.
errorCodestringFailure code. For a failure on the phone, this is the Android send result code.
errorMessagestringReason for the failure in plain words, with a suggested fix.
failedAtstringISO 8601 time of the failure.

failed is a final state. textbee does not resend a failed message. To try again, send a new message. Delivery status and message states explains the failure codes, and Messages not sending lists the fixes.

UNKNOWN_STATE

Fires when the phone reports a status that textbee does not map to sent, delivered or failed. The most common case is a delivery report that the carrier cancels or marks as failed. The message can still have reached the recipient.

JSON
{
  "smsId": "66f7c3a9b1c2d3e4f5a6b7c9",
  "message": "Your order has shipped.",
  "deviceId": "664a9b8cd0e1f2a3b4c5d6e7",
  "webhookSubscriptionId": "664a9b8cd0e1f2a3b4c5d6e8",
  "webhookEvent": "UNKNOWN_STATE",
  "idempotencyKey": "4a6c8e0b-2d4f-4a1c-9e3b-5d7f9a1c3e5b",
  "smsBatchId": "66f7c3a8b1c2d3e4f5a6b7c0",
  "status": "delivery_failed",
  "recipient": "+12015550126"
}
FieldTypeDescription
smsBatchIdstringBatch ID returned by the send request.
statusstringThe status the phone reported, in lowercase.
recipientstringNumber the message was sent to.

Log this event and review it by hand. Do not treat it as a failure without a check.

SMS_STATUS_UPDATED

SMS_STATUS_UPDATED is a valid value in a subscription's events list, so the API accepts it. It is reserved: textbee does not emit it today. To track status changes, select MESSAGE_SENT, MESSAGE_DELIVERED, MESSAGE_FAILED and UNKNOWN_STATE.

Ordering and duplicates

textbee does not guarantee the order of events. A retry of one event can arrive after a later event for the same message. For example, MESSAGE_DELIVERED can arrive before MESSAGE_SENT when the first attempt of MESSAGE_SENT failed.

Follow these rules:

  1. Deduplicate on idempotencyKey. Every retry of one delivery carries the same key.
  2. Store the latest known state per smsId. Do not move a message back to an earlier state. delivered and failed are final.
  3. Compare timestamps (sentAt, deliveredAt, failedAt) when two events disagree.
  4. In rare cases the phone reports the same status twice, and textbee sends a second event with a new idempotencyKey. Rule 2 makes this harmless.

To read the current state of one message at any time, call GET /gateway/devices/{id}/sms/{smsId}.

Which events to select

Use caseEvents
Inbox, two-way chat, keyword repliesMESSAGE_RECEIVED
Delivery trackingMESSAGE_SENT, MESSAGE_DELIVERED, MESSAGE_FAILED, UNKNOWN_STATE
Failure alertsMESSAGE_FAILED
Full audit logAll five events that fire today

Each selected event adds deliveries. A bulk send produces one delivery per recipient for each selected status event. Select only what your code uses.

Frequently asked questions

Does every sent message produce MESSAGE_DELIVERED?

No. Carriers do not always send delivery reports. Treat MESSAGE_SENT as "left the phone" and MESSAGE_DELIVERED as a bonus when the carrier confirms.

Does the payload include the device name?

No. The payload has deviceId only. Call GET /gateway/devices/{id} to read the name and other device fields. See Managing devices.

Why is my webhook missing an event that the dashboard shows?

Check that the subscription selects that event, and that the subscription is active. Then check the delivery log under Webhooks > Deliveries for the httpStatusCode your endpoint returned.

Are MESSAGE_SENT and MESSAGE_DELIVERED sent for scheduled messages?

Yes. A scheduled message produces the same events when the phone sends it. See Scheduled messages.

Next steps