# Understanding webhook
The message status webhook allows you to programmatically track the delivery status of messages you send.
To receive the status update notifications in your application, you have to create a webhook configuration using the `webhook` property in the [`send`](/products/sms/enterprise-documentation/developer-documentation/api-references/send) methods.
Each SMS message can be linked to a specific [webhook configuration](/products/sms/enterprise-documentation/developer-documentation/wb/wb-configuration).
Example:
```json
{
"destination": "+1234567890",
"text": "Your verification code is: 123456",
"reference": {
"service": "AUTHENTICATION",
"action": "2FA",
"key": "user-12345"
},
"detailed": true,
"webhook": {
"url": "https://example.com/callback",
"authentication": {
"type": "NONE"
}
}
}
```
Check the [webhook configuration](/products/sms/enterprise-documentation/developer-documentation/wb/wb-configuration) page for more details.
When the message is accepted by the provider, the `send` API returns `200` (`OK`). The message status is immediately changed to `PROVIDER_ACCEPTANCE` and the webhook configuration is created.
No webhook notification is sent for the initial `PROVIDER_ACCEPTANCE` status.
### Status Change Notifications
The system sends a notification via webhook for every change.
```mermaid
sequenceDiagram
participant App as Your Application
participant Gateway as SMS Gateway
participant Provider as Provider
participant Carrier as Carrier
participant Handset as Handset
App->>Gateway: Send an SMS
Gateway->>Provider: Send an SMS
Provider-->>Gateway: PROVIDER_ACCEPTANCE
Gateway-->>App: HTTP Status = 200
Note over Gateway,App: Status = PROVIDER_ACCEPTANCE
Provider->>Carrier: SMS
Carrier->>Handset: SMS
Handset-->>Carrier: Status Callback
Carrier-->>Provider: Status Callback
Provider-->>Gateway: Status Callback
Gateway-->>App: Message Status Webhook
```
The system sends status notifications as HTTP `POST` requests to your configured webhook URL.
Example:
```
{
"id": "2bf9a88a-29f2-438a-89a1-9a13bf03d03f",
"webhookConfigurationId": "2dab9410-d2c8-4b60-bcb0-c5eeb073e71d",
"type": "STATUS_UPDATE",
"createdAt": "2026-02-12T14:51:00Z",
"message": {
"id": "b31b6607-9c55-48ba-b145-3f40b809d2d2",
"providerAcceptanceAt" : "2026-02-12T14:49:00Z",
"statusChangedAt": "2026-02-12T14:50:35Z",
"reference": {
"service": "DIGITALSIGN",
"action": "AUTH",
"key": "webhook_3"
},
"channel": "SMS",
"status": "DELIVERED",
"provider": {
"name": "MITTO",
"id": "ee055245-afa5-4dd0-8d8f-10fec8bf64a3",
"status": "DELIVERED",
"code": "0"
},
"sms": {
"segments": 1
}
}
}
```
The webhook contains the following info:
* **id**: Unique identifier of the notification sent via webhook.
* **webhookConfigurationId** : Webhook configuration identifier
* **type**: Event type (always `STATUS_UPDATE` for status notifications)
* **createdAt**: Date and time in ISO 8601 format (e.g., `2026-02-12T14:51:00Z`)
* **message**: Message information object:
* **id**: Message identifier
* **providerAcceptanceAt**: Timestamp when the message was accepted by the provider (ISO 8601 format, e.g., 2026-02-12T14:51:00Z). Corresponds to the initial PROVIDER_ACCEPTANCE status.
* **statusChangedAt**: Timestamp of the most recent status change (ISO 8601 format, e.g., 2026-02-12T14:51:05Z).
* **reference**: Reference object specified in the send request
* **channel** : Delivery channel. Possible values:
* `SMS`
* `RCS`
* **status**: Current delivery status. Possible values:
* `SENT` : Request sent by the provider
* `DELIVERED` : Message delivered to handset
* `REJECTED`: Request rejected by the provider. Message not sent.
* `UNDELIVERED` : Message failed to deliver
* `READ` : (RCS only) Message delivered and read by recipient
* **provider**: Provider information
* **name** : Provider name
* **id**: Provider's message identifier
* **status**: Provider-specific status
* **code**: Provider status/error code
* **message**: (Optional) Provider error details (e.g. `Number Blocked by Carrier`)
* **sms**: SMS-specific information:
* **segments** : Number of SMS segments used. Messages exceeding 160 characters (GSM-7) or 70 characters (UCS-2) are split into multiple segments.
### Webhook Retry Mechanism
**Expected Response:**
- HTTP status code: `200` (OK)
- Response timeout: 10 seconds
- Response body: Not required (ignored if present)
**Retry Behavior:**
The system retries failed webhook deliveries using exponential backoff:
| Attempt | Wait Time | Cumulative Time |
| --- | --- | --- |
| 1 | 1 second | 1 second |
| 2 | 2 seconds | 3 seconds |
| 3 | 4 seconds | 7 seconds |
| 4 | 8 seconds | 15 seconds |
| ... | ... | ... |
| Final | - | 24 hours max |
**Retry Triggers:**
- HTTP status codes: 4xx (except 400, 401, 403), 5xx
- Network errors (timeout, connection refused, DNS failure)
- No response within 10 seconds
**After 24 Hours:**
- Retries stop permanently
- Notification is marked as failed
- No further attempts are made
**Handling Duplicate Notifications**
The same notification may be delivered multiple times due to retries or network issues.
Use the `id` field to detect and ignore duplicates:
```json
{
"id": "2bf9a88a-29f2-438a-89a1-9a13bf03d03f", // Use this as idempotency key
"webhookConfigurationId": "2dab9410-d2c8-4b60-bcb0-c5eeb073e71d",
...
}
```
### Status Transition Diagram
The diagram below shows the status transitions of the messages for which the SMS Gateway sends a status notification request.
```mermaid
flowchart LR
Start([Send
Message]) --> PA[PROVIDER_ACCEPTANCE]
PA --> D1{Sending
Succeeds?}
D1 -->|YES| SENT[SENT]
D1 -->|NO| REJECTED[REJECTED]
SENT --> D2{Delivery
Succeeds?}
D2 -->|YES| DELIVERED[DELIVERED]
D2 -->|NO| UNDELIVERED[UNDELIVERED]
DELIVERED --> D3{Read
Receipt
available?}
D3 -->|YES| READ[READ]
style PA fill:#87CEEB,stroke:#333,stroke-width:2px
style SENT fill:#87CEEB,stroke:#333,stroke-width:2px
style DELIVERED fill:#87CEEB,stroke:#333,stroke-width:2px
style UNDELIVERED fill:#87CEEB,stroke:#333,stroke-width:2px
style REJECTED fill:#87CEEB,stroke:#333,stroke-width:2px
style READ fill:#87CEEB,stroke:#333,stroke-width:2px
```
**Delivery Confirmation Limitations**.
Status notifications are generally reliable indicators of message delivery. However, they depend on carrier-provided information and are not absolute guarantees. Factors affecting accuracy include:
- Carrier reporting delays
- Network issues
- Handset status (on/off, signal strength)
**RCS Channel Variants**
When sending via RCS, the flow varies based on availability of RCS and the message expiration:
RCS is unavailable when:
- Destination country lacks RCS coverage
- Destination operator doesn't support RCS
- Recipient's device doesn't support RCS
Alternative scenarios:
- RCS unavailable → automatic fallback to SMS
- RCS available but message expires → automatic fallback to SMS
In all these cases, the system automatically falls back to SMS and sends the message via that channel.
```mermaid
flowchart TD
Start[Send RCS Message] --> Check{RCS Available?}
Check -->|Yes| Send[Send via RCS]
Check -->|No| Fallback1[Fallback to SMS]
Send --> Expire{Message
Expires?}
Expire -->|No| Delivered[RCS Delivered]
Expire -->|Yes| Fallback2[Fallback to SMS]
Fallback1 --> SMS[Send via SMS]
Fallback2 --> SMS
style Start fill:#90EE90
style Delivered fill:#90EE90
style SMS fill:#87CEEB
```
Status Notifications:
- The message status webhook sends notifications for the SMS message
- In some cases, a `REJECTED` notification for the `RCS` channel may also be sent
| Scenario | RCS Status | SMS Status | Webhooks Sent |
| --- | --- | --- | --- |
| RCS unavailable | - | DELIVERED | 1 (SMS only) |
| RCS expired | REJECTED | DELIVERED | 2 (RCS + SMS) |
| RCS delivered | DELIVERED | - | 1 (RCS only) |
When RCS expires and fallback occurs, you may receive two webhook notifications:
1. First: RCS channel with `REJECTED` status
2. Second: SMS channel with delivery status
Use the `channel` field to distinguish between them.
Example:
```
{
"id": "87b81d7b-d0d8-4561-8caf-de0d14cbf9d1",
...
"message": {
"id": "3eb93593-4d81-4b9e-ba48-531f66cbcb74",
"channel": "RCS",
"status": "REJECTED"
}
}
```