> ## Documentation Index
> Fetch the complete documentation index at: https://help.texterchat.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Messages Delivered or Failed

> Receive delivered and failed message events with the Texter message ID

Subscribe to receive a notification when an outgoing message is delivered or fails. This subscription includes only statuses `2`, `4`, and `5`.

The `messageStatus` field contains one of:

| Value | Meaning |
| - | - |
| `2` | **Delivered** - delivered to the recipient's device |
| `4` | **Failed** - failed to deliver (e.g. invalid number) |
| `5` | **Channel Failed** - system/channel level failure |

**Event name:** `messageDeliveredOrFailed`

**Required token scopes:**

* `Create scenarios`
* `Manage scenarios on behalf of user`

see [Authentication](https://help.texterchat.com/api-reference/authentication.md)

## Subscribe

Send the body below to [Import Subscription](https://help.texterchat.com/api-reference/subscribe-to-events/import-subscription-subscribe-to-an-event.md). You only need to change:

* **`url`** *(required)* - Located under `data.actions[0].params.url`. Replace `{{yourWebhookURL}}` with the destination URL that should receive the events.
* **`asStatus`** - Keep `"active"` to enable the subscription immediately, or `"inactive"` to save it as an inactive revision.

```json Import body [expandable] theme={null}
{
  "data": {
    "version": "v1",
    "name": "(SUB) Messages Delivered or Failed",
    "description": "Sends a webhook when an outgoing message is delivered or fails, including its Texter message ID",
    "triggerEvents": [
      "app.message.statusRequest"
    ],
    "loaders": {
      "afterConditions": [
        {
          "name": "chat",
          "alias": "chat",
          "params": {
            "name": "%messageStatusRequest:chat.name%",
            "accountId": "%messageStatusRequest:chat.accountId%",
            "idByChannel": "%messageStatusRequest:chat.id%"
          },
          "confidentialData": false
        },
        {
          "name": "chatMessages",
          "alias": "messages",
          "params": {
            "chatId": "%chat:_id%"
          },
          "confidentialData": false
        },
        {
          "name": "staticData",
          "alias": "messageLookup",
          "params": {
            "data": {
              "externalId": "%messageStatusRequest:ids.0%",
              "messages": "%messages:latest(5,-1,\"out\")%"
            }
          },
          "confidentialData": false
        }
      ]
    },
    "conditions": [
      [
        {
          "name": "arrayIncludes",
          "params": {
            "array": [
              2,
              4,
              5
            ],
            "values": [
              "%messageStatusRequest:status%"
            ],
            "condType": "Includes any"
          },
          "confidentialData": false
        }
      ]
    ],
    "actions": [
      {
        "name": "request",
        "params": {
          "url": "{{yourWebhookURL}}",
          "method": "post",
          "json": true,
          "data": {
            "eventName": "messageDeliveredOrFailed",
            "eventData": {
              "chat": {
                "##provide": {
                  "provider": "chat",
                  "key": "chat",
                  "transform": [
                    {
                      "name": "omit",
                      "args": [
                        "crmData",
                        "previousBotSession"
                      ]
                    }
                  ]
                }
              },
              "messageId": {
                "##provide": {
                  "provider": "messageLookup",
                  "key": "data",
                  "keyArgs": [],
                  "transform": [
                    {
                      "name": "hbTpl",
                      "args": [
                        "[{{#each messages}}{{#if ../externalId}}{{#when channelInfo.id 'eq' ../externalId}}\"{{_id}}\",{{/when}}{{/if}}{{/each}}null]"
                      ]
                    },
                    {
                      "name": "jsonParse",
                      "args": []
                    },
                    {
                      "name": "get",
                      "args": [
                        "0"
                      ]
                    }
                  ]
                }
              },
              "messageStatus": "%messageStatusRequest:status%",
              "error": "%messageStatusRequest:error%",
              "timestamp": "%messageStatusRequest:timestamp%",
              "externalId": "%messageStatusRequest:ids%"
            }
          }
        },
        "confidentialData": false
      }
    ],
    "options": {
      "unorderedActions": false
    }
  },
  "asStatus": "active"
}
```

> [!NOTE]
>
> A `201` response returns your new subscription - save its `_id` to manage it later. You can also add an optional `authorUid` root field (a Texter user UID) to attribute the subscription to a specific user.

## Payload

When the event fires, your URL receives an HTTP `POST` with `eventName: "messageDeliveredOrFailed"` and the following `eventData`:

**chat** `Chat`

The chat associated with the message, excluding `crmData` and `previousBotSession`. See the [Chat object](https://help.texterchat.com/api-reference/objects/chat.md) for the remaining fields.

**messageId** `string | null`

The Texter message `_id` matched to `externalId[0]`. This is the same `messageId` returned by [Send Template Message](https://help.texterchat.com/api-reference/manage-templates/send-template-message.md). Returns `null` when no match is found among the latest 5 outgoing messages.

**messageStatus** `number`

The new status - see the status codes table above.

**error** `string | null`

Error message - only present when status is `4` or `5`, otherwise `null`.

**timestamp** `number`

When the status changed (Unix epoch milliseconds).

**externalId** `string[]`

Unique IDs assigned to the message(s) by the external provider.

```json Example payload theme={null}
{
  "eventName": "messageDeliveredOrFailed",
  "eventData": {
    "chat": {
      "_id": "69072b0233aea8a47f8bad9f",
      "displayName": "Josh Dun",
      "channelInfo": {
        "name": "whatsapp",
        "id": "972521234567"
      },
      "...": "..."
    },
    "messageId": "690883c5962e17ab3033f92f",
    "messageStatus": 2,
    "error": null,
    "timestamp": 1768141074000,
    "externalId": [
      "wamid.HBgMOTcyNTIxMjM0NTY3FQIAERgSMDhGRTVGNEY1MTA0Q0NBMzNEAA=="
    ]
  }
}
```

### How to identify the message

Use `messageId` to match this event to the `messageId` returned by [Send Template Message](https://help.texterchat.com/api-reference/manage-templates/send-template-message.md).

The subscription searches the latest 5 outgoing messages in the chat. It selects the message whose `channelInfo.id` equals the first value in `externalId`. If no match exists, `messageId` is `null`; the status webhook is still sent.

`externalId` keeps all provider IDs from the event. The single `messageId` identifies only `externalId[0]`. For older messages or additional IDs, use [Get Messages of a Chat](https://help.texterchat.com/api-reference/messages/get-messages-of-a-chat.md), page through the results, and match each `channelInfo.id`.

> [!NOTE]
>
> Existing subscriptions keep their saved scenario. Update your subscription to use this template before expecting the `messageId` field and the chat-field omissions.

## Manage this subscription

| Action | Endpoint |
| - | - |
| List subscriptions | [List All Subscriptions](https://help.texterchat.com/api-reference/subscribe-to-events/list-all-subscriptions.md) |
| Pause | [Inactivate Subscription](https://help.texterchat.com/api-reference/subscribe-to-events/inactivate-subscription.md) |
| Resume | [Activate Subscription](https://help.texterchat.com/api-reference/subscribe-to-events/activate-subscription.md) |
| Delete | [Delete Subscription](https://help.texterchat.com/api-reference/subscribe-to-events/delete-subscription.md) |
| Debug executions | [List Scenario Runs](https://help.texterchat.com/api-reference/scenarios-advanced/list-scenario-runs.md) |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.