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

# Delivery history

> See what Kit sent to an endpoint, how each attempt went, and debug failed deliveries

Kit keeps a record of every delivery it makes to a webhook endpoint, along with each attempt: when it ran, the HTTP status your endpoint returned, the first part of the response body, and how long it took. Use it to answer "why isn't my endpoint receiving events?", confirm that a [retry](/webhooks/retries) eventually landed, or recover the events from a delivery your handler missed.

> [!NOTE]
>
> Delivery history is kept for 30 days. Older deliveries and their attempts are removed automatically, so store anything you need for longer on your side.

## Matching deliveries to your logs

A delivery's `id` in the history is the same value Kit sends as `delivery_id` in the [envelope](/webhooks/delivery-format) and in the `X-Kit-Delivery` header. Log it when you receive a delivery and you can look up exactly what Kit recorded for it.

## Delivery statuses

| Status | Meaning |
| - | - |
| `pending` | Queued and not attempted yet. |
| `retrying` | At least one attempt failed and another is scheduled on the [retry schedule](/webhooks/retries#retry-schedule). |
| `delivered` | Your endpoint returned a `2xx`. Final. |
| `failed` | Kit has stopped trying. Final. This happens when every attempt failed, your endpoint returned `410 Gone`, the endpoint was disabled when the delivery was due, or the URL resolved to a private or internal address. |

`completed_at` is set when a delivery reaches `delivered` or `failed`, and is `null` until then. `attempt_count` is the number of attempts made so far.

## List an endpoint's deliveries

[List webhook deliveries](/api-reference/webhooks/list-webhook-deliveries) returns an endpoint's deliveries, newest first. Filter by `status` to find the ones that need attention:

```bash theme={null}
curl "https://api.kit.com/v4/webhook_endpoints/42/deliveries?status=failed" \
  -H "X-Kit-Api-Key: <your-api-key>"
```

```json Response theme={null}
{
  "deliveries": [
    {
      "id": 123456,
      "event_type": "subscriber.created",
      "status": "failed",
      "attempt_count": 8,
      "created_at": "2026-07-29T14:32:10Z",
      "completed_at": "2026-07-31T07:49:40Z"
    }
  ],
  "pagination": {
    "has_previous_page": false,
    "has_next_page": false,
    "start_cursor": "WzEyMzQ1Nl0=",
    "end_cursor": "WzEyMzQ1Nl0=",
    "per_page": 500
  }
}
```

You can also filter by `event_type` (any value from the [event types catalog](/webhooks/event-types)) and combine it with `status`. An unrecognized `status` or `event_type` returns `422` naming the bad value, rather than an empty list. Results use [cursor pagination](/api-reference/pagination): pass `end_cursor` as `after` to fetch the next page.

## Inspect a delivery

[Get webhook delivery details](/api-reference/webhooks/get-webhook-delivery-details) returns one delivery with its full attempt history, newest attempt first:

```bash theme={null}
curl "https://api.kit.com/v4/webhook_endpoints/42/deliveries/123456" \
  -H "X-Kit-Api-Key: <your-api-key>"
```

```json Response theme={null}
{
  "delivery": {
    "id": 123456,
    "event_type": "subscriber.created",
    "status": "retrying",
    "attempt_count": 2,
    "created_at": "2026-07-29T14:32:10Z",
    "completed_at": null,
    "attempts": [
      {
        "id": 2,
        "attempt_number": 2,
        "status_code": 500,
        "error_message": null,
        "response_body": "Internal Server Error",
        "duration_ms": 212,
        "attempted_at": "2026-07-29T14:32:41Z"
      },
      {
        "id": 1,
        "attempt_number": 1,
        "status_code": null,
        "error_message": "Connection refused",
        "response_body": null,
        "duration_ms": null,
        "attempted_at": "2026-07-29T14:32:10Z"
      }
    ]
  }
}
```

Each attempt:

| Field | Description |
| - | - |
| `attempt_number` | `1` for the original attempt, counting up with each retry. |
| `status_code` | The HTTP status your endpoint returned. `null` if Kit never got a response. |
| `error_message` | Why Kit couldn't get a response, such as a refused connection, a timeout, or a TLS error. `null` when your endpoint responded. |
| `response_body` | The start of your endpoint's response body, truncated to about 500 characters. `null` if there was no response. |
| `duration_ms` | How long the request took. `null` if Kit never got a response. |
| `attempted_at` | When the attempt ran. |

## Get the events that were sent

The events aren't included by default, because a delivery can carry up to 100 of them. Add `include_payload=true` to get them back as `payload`, the same array your endpoint received as `events`:

```bash theme={null}
curl "https://api.kit.com/v4/webhook_endpoints/42/deliveries/123456?include_payload=true" \
  -H "X-Kit-Api-Key: <your-api-key>"
```

`include_payload` accepts only `true` or `false`; any other value returns `422`.

This is how you recover from a delivery that ended `failed`: once your endpoint is fixed, fetch the payload and pass each event through your handler. Your handler [deduplicates on the event `id`](/webhooks/verifying-signatures#idempotency), so an event that did get processed earlier is skipped safely.

## Diagnosing common failures

| What the attempts show | Likely cause |
| - | - |
| `status_code` `401` or `403` | Something in front of your handler, such as auth middleware, a firewall, or a bot filter, is rejecting Kit's request. Allow the webhook route through and rely on [signature verification](/webhooks/verifying-signatures) instead. |
| `status_code` `404` | The URL path is wrong, or the route was removed. If the endpoint is gone for good, return `410` so Kit stops retrying. |
| `status_code` `5xx` | Your handler is throwing. Check `response_body` and your server logs at `attempted_at`. |
| `error_message` mentions a timeout | Kit couldn't connect within 5 seconds, or your handler took longer than 10 seconds to respond. Return `2xx` first and do the work asynchronously. |
| `error_message` mentions a refused connection, DNS, or SSL | The URL isn't reachable from the public internet, or its TLS certificate is invalid. |
| `error_message` is `endpoint disabled` | The endpoint's `status` was `disabled` when the delivery was due, so Kit recorded it as failed without sending it. |
| No deliveries at all | Check that the endpoint is `active`, that its `events` include the event type you expect, and that the event actually happened in the account. |

## Access

Delivery history follows the same access rules as the endpoint it belongs to. When you authenticate with OAuth, you can read deliveries only for endpoints your app created; any other endpoint returns `404`. An API key can read deliveries for every endpoint on the account. A `delivery_id` that doesn't belong to the endpoint, or that is older than 30 days, also returns `404`.


## Related topics

- [List webhook deliveries](/api-reference/webhooks/list-webhook-deliveries.md)
- [Delivery format](/webhooks/delivery-format.md)
- [Retries](/webhooks/retries.md)
- [Webhooks overview](/webhooks/overview.md)
- [Changelog](/changelog.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.