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

# GET /sms/delivery-reports — Track Message Delivery

> GET /sms/delivery-reports returns delivery status for your sent messages. Filter by message_id or batch_id to check individual or campaign delivery.

Check the delivery status of sent SMS messages using this endpoint. You can filter results by a single message, an entire bulk campaign batch, or a specific delivery status. Results are paginated for efficient retrieval.

<Note>
  All requests must include the `Authorization: Bearer YOUR_API_KEY` header. Responses use `Content-Type: application/json`.
</Note>

## Endpoint

```
GET https://api.hany.tools/v1/sms/delivery-reports
```

## Query Parameters

<ParamField query="message_id" type="string">
  Filter results to a specific message. Use the `message_id` returned when you sent the message via [POST /sms/send](/api-reference/sms/send).
</ParamField>

<ParamField query="batch_id" type="string">
  Filter results to all messages belonging to a bulk campaign. Use the `batch_id` returned from [POST /sms/bulk](/api-reference/sms/bulk-send).
</ParamField>

<ParamField query="status" type="string">
  Filter results by delivery status. Accepted values: `delivered`, `failed`, `pending`, `sent`.
</ParamField>

<ParamField query="page" type="integer">
  Page number for paginated results. Defaults to `1`.
</ParamField>

<ParamField query="limit" type="integer">
  Number of results to return per page. Defaults to `50`. Maximum is `200`.
</ParamField>

## Request

```bash theme={null}
curl "https://api.hany.tools/v1/sms/delivery-reports?message_id=msg_abc123xyz" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

## Response

### 200 — Success

```json theme={null}
{
  "status": "success",
  "data": [
    {
      "message_id": "msg_abc123xyz",
      "to": "+233XXXXXXXXX",
      "from": "YourBrand",
      "status": "delivered",
      "delivered_at": "2024-06-01T08:05:23Z",
      "sent_at": "2024-06-01T08:05:10Z"
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 50,
    "total": 1
  }
}
```

## Response Fields

<ResponseField name="status" type="string">
  Indicates the outcome of the request. Either `"success"` or `"error"`.
</ResponseField>

<ResponseField name="data" type="array">
  An array of delivery report objects matching your query.

  <ResponseField name="data[].message_id" type="string">
    The unique identifier of the message. Matches the `message_id` from the send response.
  </ResponseField>

  <ResponseField name="data[].to" type="string">
    The recipient phone number in E.164 format.
  </ResponseField>

  <ResponseField name="data[].from" type="string">
    The Sender ID used to send this message.
  </ResponseField>

  <ResponseField name="data[].status" type="string">
    Current delivery status. One of `pending`, `sent`, `delivered`, or `failed`.
  </ResponseField>

  <ResponseField name="data[].delivered_at" type="string">
    ISO 8601 timestamp of when the message was confirmed delivered to the recipient's handset. `null` if not yet delivered.
  </ResponseField>

  <ResponseField name="data[].sent_at" type="string">
    ISO 8601 timestamp of when the message was dispatched to the carrier network.
  </ResponseField>
</ResponseField>

<ResponseField name="pagination" type="object">
  Metadata about the paginated result set.

  <ResponseField name="pagination.page" type="integer">
    The current page number.
  </ResponseField>

  <ResponseField name="pagination.limit" type="integer">
    The number of results per page as requested.
  </ResponseField>

  <ResponseField name="pagination.total" type="integer">
    The total number of records matching your query across all pages.
  </ResponseField>
</ResponseField>

## Delivery Status Values

| Status      | Description                                                                              |
| ----------- | ---------------------------------------------------------------------------------------- |
| `pending`   | Message is queued but has not yet been dispatched to the carrier network.                |
| `sent`      | Message has been dispatched to the carrier network and is awaiting handset confirmation. |
| `delivered` | Delivery confirmed — the message reached the recipient's handset.                        |
| `failed`    | Delivery failed. The message could not be delivered to the recipient's handset.          |

## Code Examples

<CodeGroup>
  ```javascript JavaScript theme={null}
  // Check delivery for a single message
  const response = await fetch(
    "https://api.hany.tools/v1/sms/delivery-reports?message_id=msg_abc123xyz",
    {
      headers: {
        "Authorization": "Bearer YOUR_API_KEY",
      },
    }
  );
  const data = await response.json();
  const report = data.data[0];
  console.log(report.status);        // "delivered"
  console.log(report.delivered_at);  // "2024-06-01T08:05:23Z"

  // Check delivery for an entire bulk campaign
  const batchResponse = await fetch(
    "https://api.hany.tools/v1/sms/delivery-reports?batch_id=batch_xyz789abc&status=failed&limit=100",
    {
      headers: {
        "Authorization": "Bearer YOUR_API_KEY",
      },
    }
  );
  const batchData = await batchResponse.json();
  console.log(`Failed deliveries: ${batchData.pagination.total}`);
  ```

  ```python Python theme={null}
  import requests

  HEADERS = {"Authorization": "Bearer YOUR_API_KEY"}
  BASE_URL = "https://api.hany.tools/v1"

  # Check delivery for a single message
  response = requests.get(
      f"{BASE_URL}/sms/delivery-reports",
      headers=HEADERS,
      params={"message_id": "msg_abc123xyz"},
  )
  data = response.json()
  report = data["data"][0]
  print(report["status"])        # "delivered"
  print(report["delivered_at"])  # "2024-06-01T08:05:23Z"

  # Check delivery for an entire bulk campaign
  batch_response = requests.get(
      f"{BASE_URL}/sms/delivery-reports",
      headers=HEADERS,
      params={"batch_id": "batch_xyz789abc", "status": "failed", "limit": 100},
  )
  batch_data = batch_response.json()
  print(f"Failed deliveries: {batch_data['pagination']['total']}")
  ```
</CodeGroup>

<Tip>
  Use [webhooks](/api-reference/webhooks) for real-time delivery notifications instead of polling this endpoint. Webhooks push status updates to your `callback_url` the moment a delivery event occurs, reducing API calls and eliminating latency.
</Tip>
