# Receiving DLRs

Delivery reports (DLRs) are POSTed to a webhook URL configured per API token. Each call describes one status transition — sent, delivered, failed, inbound — with a machine-readable status and code.

A DLR (Delivery Receipt) is how carriers tell you what happened to a message after it left Instasent. We aggregate the updates from every hop in the chain and forward each transition to a webhook you control. If two-way messaging is enabled on your account, inbound messages arrive on the same endpoint.

## Configuring the webhook

Webhooks are configured per `api_sms` token in the dashboard. Point it at a public HTTPS endpoint that returns `2xx` quickly — we consider any non-2xx a failure and retry with exponential backoff.

> **Warning**: Respond in under 5 seconds with a `2xx` and process the payload asynchronously. Long-running handlers trigger timeouts, retries and duplicate deliveries.

## Payload shape

Every call is a `POST` with a JSON body:

```json
{
  "id": "sms-id",
  "clientId": "custom-id",
  "status": "delivered",
  "code": 0,
  "eventAt": "2026-04-21T10:15:00Z"
}
```

| Field      | Description                                                                                                      |
| ---------- | ---------------------------------------------------------------------------------------------------------------- |
| `id`       | The Instasent message id. Matches the `id` returned when the SMS was created.                                    |
| `clientId` | The `clientId` you supplied when creating the message, if any — useful for correlation against your own records. |
| `status`   | Machine-readable status. See the list below.                                                                     |
| `code`     | Numeric code that narrows down the reason for `error`/`failed` statuses.                                         |
| `eventAt`  | ISO-8601 timestamp of the event.                                                                                 |

When two-way is enabled on the account, the payload also carries a `message` field with the inbound text.

## Status list

| Status      | Meaning                                                      |
| ----------- | ------------------------------------------------------------ |
| `sent`      | Message was sent to the device.                              |
| `accepted`  | Message was accepted by the carrier.                         |
| `buffered`  | Message is buffered by the carrier, waiting to be delivered. |
| `delivered` | Message was delivered to the handset.                        |
| `error`     | Message could not be sent to the device.                     |
| `failed`    | Message could not be delivered.                              |
| `expired`   | Message expired before delivery was possible.                |
| `canceled`  | Message was canceled.                                        |
| `rejected`  | Message was rejected by the carrier.                         |
| `unknown`   | An unknown error occurred.                                   |
| `stop`      | An opt-out inbound message was received from the handset.    |
| `inbound`   | An inbound message was received (two-way only).              |

## Code list

Codes narrow down the reason for non-delivery. `0` is the happy path; everything else describes a specific failure class.

| Code  | Meaning            |
| ----- | ------------------ |
| `0`   | OK                 |
| `1`   | Unknown            |
| `2`   | Absent temporarily |
| `3`   | Absent permanently |
| `4`   | Blocked subscriber |
| `5`   | Portability error  |
| `6`   | Antispam reject    |
| `7`   | Line busy          |
| `8`   | Network error      |
| `9`   | Illegal number     |
| `10`  | Invalid message    |
| `11`  | Unroutable         |
| `12`  | Unreachable        |
| `13`  | Age restriction    |
| `14`  | Blocked carrier    |
| `15`  | Insufficient funds |
| `16`  | Flooded            |
| `99`  | Unknown error      |
| `100` | Reject             |

## Idempotency

The same message may generate multiple DLRs — typically `sent` → `buffered` → `delivered`. Use `id` as the primary key and treat each DLR as a status transition, not as the final state.

> **Tip**: Persist the latest `status` and `eventAt` per `id` rather than appending every event. If your pipeline needs the full audit trail, log the raw payload to a separate store.

## What's next

- **[Errors](/transactional-api/http/errors)** — for failures that happen before the message even leaves the API.
- **[API Reference](/transactional-api/http/reference)** — retrieve the current status of a message on demand.
