> For the complete documentation index, see [llms.txt](https://docs.channel360.co.za/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.channel360.co.za/api-usage/using-the-channel360-v1.1-api/webhooks.md).

# Webhooks

***

### Managing Webhooks

{% hint style="warning" %}
**Note:** Webhook triggers can be configured directly from the Channel360 frontend without using the API.
{% endhint %}

{% content-ref url="/pages/rw2bt83dh9k1qR6ffKiw" %}
[Webhooks](/channel360-guide/webhooks.md)
{% endcontent-ref %}

### Webhook Triggers

Webhook triggers define which events will result in a webhook request being sent to your endpoint.\
For example, when a user reads a message, a webhook request is sent containing details about that event

### Webhook Target

The webhook target defines the endpoint where Channel360 will send webhook event payloads.

#### appUserId

Webhook payloads include an `appUserId`, which uniquely identifies a user within the organisation.

The `appUserId` is created automatically when a user first interacts with your channel (for example, when they send a message). It can be used to correlate webhook events and to send notifications to that user.

| Trigger                       | Description                                                                                    |
| ----------------------------- | ---------------------------------------------------------------------------------------------- |
| notification:delivery:channel | Triggered when a notification is successfully delivered to a customer channel.                 |
| notification:delivery:failure | Triggered when a notification fails to be delivered to a customer channel / the user’s device. |
| notification:delivery:user    | Triggered when a notification is successfully delivered to the user’s device.                  |
| conversation:read             | Triggered when a user has read the conversation.                                               |
| message:appUser               | Triggered for inbound messages (from clients).                                                 |
| message:appMaker              | Triggered for outbound messages, which are the messages the user sends in a conversation.      |
| message:delivery:failure      | Triggered for failed outbound messages from the `/reply` endpoint.                             |
| flow:submission               | Triggered for whatsapp flow submissions.                                                       |

### Example payloads

Use these examples to test your webhook handler and map the fields returned for each event.

#### `notification:delivery:channel`

This event is sent when a notification is accepted by the channel (WhatsApp).

```json
{
  "trigger": "notification:delivery:channel",
  "version": "v1.1",
  "app": {
    "_id": "app_example_123456789"
  },
  "timestamp": 1781855992.093,
  "destination": {
    "type": "whatsapp",
    "integrationId": "integration_example_123456",
    "destinationId": "27820000000"
  },
  "isFinalEvent": false,
  "externalMessages": [
    {
      "id": "wamid.EXAMPLE_MESSAGE_ID_1234567890"
    }
  ],
  "notification": {
    "_id": "notification_example_123456"
  },
  "matchResult": {
    "client": {
      "integrationId": "integration_example_123456",
      "externalId": "27820000000",
      "id": "client_example_123456",
      "displayName": "+27 82 000 0000",
      "status": "active",
      "raw": {
        "from": "27820000000",
        "profile": {
          "name": "Example User"
        }
      },
      "lastSeen": "2026-06-18T12:46:11.066Z",
      "linkedAt": "2022-08-11T21:36:21.156Z",
      "_id": "client_record_example_123456",
      "platform": "whatsapp",
      "active": true,
      "blocked": false,
      "primary": true
    },
    "appUser": {
      "_id": "appuser_example_123456",
      "authenticated": false,
      "conversationStarted": true
    },
    "conversation": {
      "_id": "conversation_example_123456"
    }
  }
}
```

#### `notification:delivery:user`

This event is sent when a notification reaches the user's device.

```json
{
  "trigger": "notification:delivery:user",
  "version": "v1.1",
  "app": {
    "_id": "app_example_123456789"
  },
  "timestamp": 1781855997.352,
  "destination": {
    "type": "whatsapp",
    "integrationId": "integration_example_123456",
    "destinationId": "27820000000"
  },
  "isFinalEvent": true,
  "externalMessages": [
    {
      "id": "wamid.EXAMPLE_MESSAGE_ID_1234567890"
    }
  ],
  "notification": {
    "_id": "notification_example_123456"
  },
  "matchResult": {
    "client": {
      "integrationId": "integration_example_123456",
      "externalId": "27820000000",
      "id": "client_example_123456",
      "displayName": "+27 82 000 0000",
      "status": "active",
      "raw": {
        "from": "27820000000",
        "profile": {
          "name": "Example User"
        }
      },
      "lastSeen": "2026-06-18T12:46:11.066Z",
      "linkedAt": "2022-08-11T21:36:21.156Z",
      "_id": "client_record_example_123456",
      "platform": "whatsapp",
      "active": true,
      "blocked": false,
      "primary": true
    },
    "appUser": {
      "_id": "appuser_example_123456",
      "authenticated": false,
      "conversationStarted": true
    },
    "conversation": {
      "_id": "conversation_example_123456"
    }
  }
}
```

#### `conversation:read`

This event is sent when the user reads the conversation.

```json
{
  "trigger": "conversation:read",
  "timestamp": 1781856019.856,
  "version": "v1.1",
  "app": {
    "_id": "app_example_123456789"
  },
  "appUser": {
    "_id": "appuser_example_123456",
    "givenName": "Example User",
    "signedUpAt": "2022-08-11T21:36:21.156Z",
    "properties": {},
    "identities": [],
    "authenticated": false,
    "conversationStarted": true
  },
  "conversation": {
    "_id": "conversation_example_123456"
  },
  "client": {
    "integrationId": "integration_example_123456",
    "externalId": "27820000000",
    "id": "client_example_123456",
    "displayName": "+27 82 000 0000",
    "status": "active",
    "raw": {
      "from": "27820000000",
      "profile": {
        "name": "Example User"
      }
    },
    "lastSeen": "2026-06-18T12:46:11.066Z",
    "linkedAt": "2022-08-11T21:36:21.156Z",
    "_id": "client_record_example_123456",
    "platform": "whatsapp",
    "active": true,
    "blocked": false,
    "primary": true
  },
  "source": {
    "type": "whatsapp",
    "integrationId": "integration_example_123456"
  }
}
```

#### `notification:delivery:failure`

This event is sent when a notification fails to deliver. Use the `error` object to inspect the failure reason returned by the channel.

```json
{
  "trigger": "notification:delivery:failure",
  "version": "v1.1",
  "app": {
    "_id": "app_example_123456789"
  },
  "timestamp": 1781856153.836,
  "destination": {
    "type": "whatsapp",
    "integrationId": "integration_example_123456",
    "destinationId": "27820000000"
  },
  "isFinalEvent": true,
  "notification": {
    "_id": "notification_example_failed_123456"
  },
  "matchResult": {
    "client": {
      "integrationId": "integration_example_123456",
      "externalId": "27820000000",
      "id": "client_example_123456",
      "displayName": "+27 82 000 0000",
      "status": "active",
      "raw": {
        "from": "27820000000",
        "profile": {
          "name": "Example User"
        }
      },
      "lastSeen": "2026-06-18T12:46:11.066Z",
      "linkedAt": "2022-08-11T21:36:21.156Z",
      "_id": "client_record_example_123456",
      "platform": "whatsapp",
      "active": true,
      "blocked": false,
      "primary": true
    },
    "appUser": {
      "_id": "appuser_example_123456",
      "authenticated": false,
      "conversationStarted": true
    },
    "conversation": {
      "_id": "conversation_example_123456"
    }
  },
  "error": {
    "code": "uncategorized_error",
    "underlyingError": {
      "message": "(#132001) Template name does not exist in the translation",
      "code": 132001,
      "type": "OAuthException",
      "error_data": {
        "messaging_product": "whatsapp",
        "details": "template name (example_template_name) does not exist in en"
      },
      "fbtrace_id": "FBTRACE_EXAMPLE_123456"
    }
  }
}
```

#### `message:appUser`

This event is sent when a client sends an inbound message.

The example uses fictional data. It includes one prior notification.

```json
{
  "trigger": "message:appUser",
  "version": "v1.1",
  "app": {
    "_id": "app_example_123456789"
  },
  "appUser": {
    "_id": "appuser_example_123456",
    "givenName": "Example User",
    "signedUpAt": "2026-07-15T13:19:56.559Z",
    "properties": {},
    "identities": [],
    "authenticated": false,
    "conversationStarted": true
  },
  "conversation": {
    "_id": "conversation_example_123456"
  },
  "client": {
    "_id": "client_record_example_123456",
    "integrationId": "integration_example_123456",
    "externalId": "27820000000",
    "id": "client_example_123456",
    "displayName": "+27 82 000 0000",
    "status": "active",
    "raw": {
      "from": "27820000000",
      "profile": {
        "name": "Example User"
      }
    },
    "lastSeen": "2026-07-15T13:19:56.559Z",
    "linkedAt": "2026-07-15T13:19:56.559Z",
    "platform": "whatsapp",
    "active": true,
    "blocked": false,
    "primary": true
  },
  "recentNotifications": [
    {
      "source": {
        "type": "notification",
        "id": "notification_example_123456"
      },
      "role": "appMaker",
      "authorId": "author_example_123456",
      "type": "text",
      "text": "Would you like us to contact you about this offer?",
      "received": 1784121596.587,
      "actions": [
        {
          "type": "reply",
          "text": "Yes please",
          "uri": "",
          "payload": "Yes please",
          "_id": "action_example_123456"
        }
      ],
      "_id": "notification_message_example_123456"
    }
  ],
  "messages": [
    {
      "role": "appUser",
      "source": {
        "type": "whatsapp",
        "id": "client_example_123456",
        "integrationId": "integration_example_123456",
        "originalMessageId": "wamid.EXAMPLE_MESSAGE_ID_1234567890",
        "originalMessageTimestamp": 1784121593
      },
      "authorId": "appuser_example_123456",
      "name": "Example User",
      "_id": "message_example_123456",
      "type": "text",
      "received": 1784121596.587,
      "text": "Hello"
    }
  ]
}
```

`recentNotifications` is optional. It may be absent when the conversation has no earlier messages.

```json
{
  "trigger": "message:appUser",
  "messages": [
    {
      "type": "text",
      "text": "Hello"
    }
  ]
}
```

#### `flow:submission`

This event is sent when a user submits a WhatsApp Flow.

The example uses fictional data. Parse `response_json` to access submitted fields.

```json
{
  "events": [
    {
      "id": "flow_submission_example_123456",
      "createdAt": "2026-07-16T08:05:49.907Z",
      "type": "flow:submission",
      "payload": {
        "conversation": {
          "id": "conversation_example_123456",
          "type": "personal"
        },
        "source": {
          "type": "whatsapp",
          "integrationId": "integration_example_123456"
        },
        "user": {
          "id": "appuser_example_123456",
          "authenticated": false
        },
        "passthroughType": "interactive",
        "passthroughPayload": {
          "from": "27820000000",
          "id": "wamid.EXAMPLE_MESSAGE_ID_1234567890",
          "timestamp": "1784189148",
          "type": "interactive",
          "interactive": {
            "type": "nfm_reply",
            "nfm_reply": {
              "response_json": "{\"monthly_income\":\"25000\",\"living_expenses\":\"12000\",\"preferred_store\":\"Example Store\",\"receive_marketing\":true,\"first_name\":\"Example\",\"surname\":\"User\",\"id_number\":\"9001015009087\",\"cellphone\":\"27820000000\",\"email\":\"example.user@example.com\",\"flow_token\":\"example-flow-token\"}"
            }
          }
        }
      }
    }
  ],
  "trigger": "flow:submission"
}
```

## Create Webhook

<mark style="color:yellow;">`POST`</mark> `https://www.channel360.co.za/v1.1/org/{{orgId}}/webhooks`

```json
{
    "target": "{{targetURL}}",
    "triggers": [
        "notification:delivery:channel",
        "notification:delivery:user",
        "notification:delivery:failure",
        "conversation:read",
        "message:appMaker",
        "message:appUser"
    ]
}
```

## Get Webhooks

<mark style="color:green;">`GET`</mark> `https://www.channel360.co.za/v1.1/org/{{orgId}}/webhooks`

```json
    {
        "organization": "{{yourOrgId}}",
        "target": "{{targetURL}}",
        "triggers": [
            "message:appUser",
            "message:appMaker",
            "notification:delivery:user",
            "message:delivery:failure",
            "conversation:read",
            "notification:delivery:channel",
            "notification:delivery:failure"
        ],
        "createdAt": "2025-11-04T14:59:01.000Z",
        "updatedAt": "2025-11-04T14:59:01.000Z",
        "version": 0,
        "id": "webhook_example_123456"
    }
```

## Delete Webhook

<mark style="color:orange;">`DELETE`</mark> `https://www.channel360.co.za/v1.1/org/{{orgId}}/webhooks/{{webhook-id}}`

### Path Parameters

| Field      | Type                                                                         | Description                      |
| ---------- | ---------------------------------------------------------------------------- | -------------------------------- |
| orgId      | string <sup><mark style="color:red;">required<mark style="color:red;"></sup> | Your Organization ID             |
| webhook-id | string <sup><mark style="color:red;">required<mark style="color:red;"></sup> | Unique identifier of the webhook |

## Retry Policy

A webhook call will be attempted up to 5 times over a 15 minute window. The attempts will happen at an exponentially increasing interval if the target responds with anything but a success (2XX) or a [non-recoverable error](https://docs.smooch.io/rest/#non-recoverable-errors). If no response is received within 20 seconds, the call will be considered a failure and will also be reattempted.

#### Non-recoverable Errors <a href="#non-recoverable-errors" id="non-recoverable-errors"></a>

The following status codes are deemed to be non-recoverable and Channel Mobile will not reattempt a call when receiving a response with them:

* 400: The target exists, but can’t process the payload.
* 401: The target is behind authentication or doesn’t recognize the webhook secret.
* 403: Channel Mobile should not be calling the target.
* 404: The target doesn’t exist.
* 406: The target exists, and rejected the webhook intentionally.
