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

# Webhooks

> Receive a real-time payload for every recipient after an SMS send is processed.

<Info>
  Webhooks apply to the **V2 OAuth API** only. They are separate from [Delivery Receipts (DLRs)](/guides/delivery-receipts) and [Inbound Messages](/guides/inbound-messages).
</Info>

When you send an SMS via the V2 API, Phonovation sends an HTTP POST to your webhook URL for **each recipient** in the request. If you send to 5 numbers in one API call, you receive 5 webhook payloads — one per mobile number.

This gives you an immediate, per-recipient status report on how the message was processed — including any errors.

## Setup

Provide your webhook URL to [support@phonovation.com](mailto:support@phonovation.com) and we will configure it against your account. The endpoint must:

* Accept `HTTP POST` requests
* Respond with a `200 OK`

## Payload

Each payload is a JSON object sent in the POST body.

<CodeGroup>
  ```json title="Success payload" icon="circle-check" highlight={2,5} wrap theme={"dark"}
  {
    "Status": "MESSAGE_SUCCESS",
    "FinishedAt": "2026-04-09T14:39:40.69257Z",
    "Message": "Your message has been queued.",
    "NotifyId": "order-001"
  }
  ```

  ```json title="Message error payload" icon="circle-xmark" highlight={2,5} wrap theme={"dark"}
  {
    "Status": "MESSAGE_ERROR",
    "FinishedAt": "2025-06-06T17:50:57.675187Z",
    "Message": "Error trying to add a new message. No credits available",
    "NotifyId": "order-001"
  }
  ```

  ```json title="Campaign error payload" icon="triangle-exclamation" highlight={2,4} wrap theme={"dark"}
  {
    "Status": "CAMPAIGN_ERROR",
    "FinishedAt": "2025-06-06T17:55:48.6689654Z",
    "Message": "Sender is not valid"
  }
  ```
</CodeGroup>

### Fields

| Field        | Type   | Description                                                                          |
| ------------ | ------ | ------------------------------------------------------------------------------------ |
| `Status`     | string | Processing outcome — see [Status values](#status-values) below                       |
| `FinishedAt` | string | ISO 8601 timestamp (UTC) of when processing completed                                |
| `Message`    | string | Human-readable description of the outcome                                            |
| `NotifyId`   | string | The `notifyId` you assigned to this recipient when sending — empty string if not set |

## Status values

| Status            | Scope         | Meaning                                                                                 |
| ----------------- | ------------- | --------------------------------------------------------------------------------------- |
| `MESSAGE_SUCCESS` | Per recipient | Message accepted and queued for delivery                                                |
| `MESSAGE_ERROR`   | Per recipient | Message could not be processed for this recipient                                       |
| `CAMPAIGN_ERROR`  | Per recipient | The send was rejected before any messages were queued — one payload fires per recipient |

`CAMPAIGN_ERROR` payloads do not include a `NotifyId` field. The error is campaign-level (e.g. an invalid sender ID), but a payload is still sent for each recipient in the request.

### Common `Message` values

| Message                                                    | Status            | What it means                                                |
| ---------------------------------------------------------- | ----------------- | ------------------------------------------------------------ |
| `Your message has been queued.`                            | `MESSAGE_SUCCESS` | Recipient accepted, message in queue                         |
| `Sender is not valid`                                      | `CAMPAIGN_ERROR`  | The `from` value is not a valid or approved sender ID        |
| `Error trying to add a new message. No credits available`  | `MESSAGE_ERROR`   | Account has insufficient SMS credits                         |
| `null/empty MSISDN`                                        | `MESSAGE_ERROR`   | The recipient number was blank or missing                    |
| `Error trying to add a new message to SMSBroadcastMessage` | `MESSAGE_ERROR`   | Internal processing error — contact support if this persists |

## One payload per recipient

Webhooks fire once for each recipient mobile number in the send request, not once per API call.

| Recipients in request | Webhook payloads received |
| --------------------- | ------------------------- |
| 1                     | 1                         |
| 5                     | 5                         |
| 100                   | 100                       |

## Tracking recipients with notifyId

Set a `notifyId` per recipient when sending and it will be echoed back in the `NotifyId` field of every webhook payload for that recipient. The same value also appears in DLRs and can be used to correlate inbound replies — making it the single identifier that spans your entire send-to-reply flow.

If no `notifyId` is set, the `NotifyId` field will be an empty string.

See [notifyId](/guides/notify-id) for full details, use cases, and end-to-end flow examples.

## Relation to DLRs

Webhooks and DLRs serve different purposes:

```mermaid title="Webhook and DLR timing" theme={"dark"}
sequenceDiagram
  participant App as Developer app
  participant API as Phonovation SMS API
  participant Gateway as Phonovation gateway
  participant Network as Mobile network
  participant Endpoint as Your endpoint

  App->>API: Send campaign
  API->>Gateway: Process recipient
  Gateway->>Endpoint: Webhook after processing
  Gateway->>Network: Submit SMS
  Network-->>Gateway: Delivery result
  Gateway->>Endpoint: DLR after network confirmation
```

|             | Webhook                                               | DLR                              |
| ----------- | ----------------------------------------------------- | -------------------------------- |
| **Trigger** | API message processing complete                       | Network delivery confirmed       |
| **Timing**  | Immediate, after the API call                         | Minutes to hours after sending   |
| **Scope**   | V2 OAuth API only                                     | All send methods                 |
| **Purpose** | Confirms message was accepted/rejected by Phonovation | Confirms delivery to the handset |

Use webhooks to confirm your API call was processed correctly. Use DLRs to confirm the message reached the recipient's device.
