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

# Deliveries and endpoints

> Inspect webhook payloads, where each delivery went, and the runs it started or resumed.

export const PrivateBeta = ({children}) => <Warning>
    <strong>Private beta.</strong> This feature is only available to some organizations right now.
    {children}
  </Warning>;

<PrivateBeta flag="hasWebhooksAccess">
  [Request access](https://trigger.dev/webhooks-beta) and we'll turn webhooks on for your
  organization and send you the prerelease packages. Webhooks are open source, so they work
  self-hosted too. APIs may change before general availability.
</PrivateBeta>

**A delivery records a verified webhook event and what happened to it at each subscriber.** Find deliveries on an endpoint's **Deliveries** tab. A run that a delivery triggered links back to it, and to its endpoint, from the run's **Detail** tab.

## Endpoints

The environment's **Webhooks** page lists its endpoints with their URL, whether the signing secret is set, the last 24 hours of activity, and the last delivery. Open an endpoint for its tabs:

| Tab | Shows |
| - | - |
| **Deliveries** | The endpoint's deliveries, filterable by status and time. |
| **Subscribers** | Every task, agent session and channel subscribed to the endpoint, with each one's filter. |
| **Waiters** | Runs currently [waiting](/docs/webhooks/waiters) on the endpoint. |
| **Test** | Sends a sample event through the endpoint. |

The endpoint's details show its URL, source, verification scheme and signing secret actions. See [Connect a provider](/docs/webhooks/connect).

### Disable an endpoint

Disable an endpoint to stop accepting its deliveries without removing it from your code. Its status becomes `inactive` and its URL responds with `404`, so the provider records failed deliveries and retries them on its own schedule:

```bash theme={"theme":"css-variables"}
curl -X POST "https://api.trigger.dev/api/v1/webhooks/endpoints/stripe/disable" \
  -H "Authorization: Bearer $TRIGGER_SECRET_KEY"
```

[Enable](/docs/management/webhooks/enable-endpoint) it again with `POST /api/v1/webhooks/endpoints/{endpointId}/enable`. An endpoint that is no longer in the environment's current deployment is also `inactive`.

## Delivery status

| Status | Meaning |
| - | - |
| `PENDING` | Waiting to be routed, including after a retryable error at a subscriber. |
| `PROCESSING` | Being routed. A delivery that resumes many waiting runs stays here until they have all been resumed. |
| `SUCCEEDED` | At least one subscriber or waiting run received it, and nothing failed. |
| `FAILED` | A subscriber failed after its retries. The delivery's error names it. |
| `FILTERED` | No subscriber's filter matched, or the endpoint has no subscribers. The reason shows the failed clause. |
| `UNMATCHED` | Runs were waiting on the endpoint, but none matched and no subscriber took it. |

Delivery status tracks routing. Each run it started has its own status and retry history.

## Where a delivery went

Open a delivery to see its payload and headers, and a row per subscriber with its result (`SUCCEEDED`, `FILTERED` with the reason, or `FAILED` with the error) and a link to the run it started. Waiting runs are summarized in one row: how many waiters matched, how many were resumed, and how many failed to resume.

A subscriber that fails transiently is retried on its own; subscribers that already succeeded are not run again.

## Replay

Replaying a delivery routes its event again as a new delivery. Filters are checked again, so the replay reaches the subscribers that would take the event now:

```bash theme={"theme":"css-variables"}
curl -X POST "https://api.trigger.dev/api/v1/webhooks/deliveries/whd_1234/replay" \
  -H "Authorization: Bearer $TRIGGER_SECRET_KEY"
```

Add `?targetId=` to send it to one subscriber regardless of its filter. `targetId` is the subscriber id: a `webhook()` task's id, or `agentId:eventId` for an agent's `chat.event` or channel. A replay never resumes waiting runs.

## From an agent or the API

The [MCP server](/docs/mcp-introduction) has `list_webhook_deliveries` (filter by endpoint, status and time), `get_webhook_delivery` (each subscriber's result, the waiter summary, the event and headers) and `replay_webhook_delivery`. The same data is on the REST API:

| Request | What it does |
| - | - |
| [`GET /api/v1/webhooks/deliveries`](/docs/management/webhooks/list-deliveries) | Lists deliveries, newest first. Filter with `filter[endpoint]` (declared or `wh_` ids), `filter[status]`, and `filter[period]` or `filter[from]`/`filter[to]`. |
| [`GET /api/v1/webhooks/deliveries/{deliveryId}`](/docs/management/webhooks/retrieve-delivery) | Reads a delivery, with a `targets` entry per subscriber and one for waiting runs. |
| [`POST /api/v1/webhooks/deliveries/{deliveryId}/replay`](/docs/management/webhooks/replay-delivery) | Replays it, as above. The key needs permission to trigger every task the replay starts, and to write sessions if it reaches an agent's subscriber. |

## Deduplication

Trigger.dev uses the endpoint and idempotency key to deduplicate incoming events. Delivery records and task runs have separate deduplication windows:

| What is deduplicated | Window |
| - | - |
| Delivery records | Six hours by default. |
| Task runs | Three days for Stripe; one day for other sources. |

A retry after the delivery window expires can create another delivery record. If the task-run idempotency window is still active, routing returns the existing run instead of starting another one.

When the source maps a provider event ID, that ID becomes the key. For example, Stripe uses the event body's `id`, and GitHub uses the `X-GitHub-Delivery` header.

If the source doesn't map an event ID, the key is derived from the raw body, timestamp, and signature. A retry with a different timestamp or signature can therefore produce a different key. For a [custom source](/docs/webhooks/sources#custom-providers), set `idempotencyField` to a stable event identifier when the provider supplies one.

## Verification and recording

Requests must pass the source's verification checks before they are recorded. Timestamp checks apply when configured by the source. A verification failure returns the source's rejected HTTP status (`400` by default) and creates no delivery or run.

Provider handshakes receive their configured response without creating a delivery. Other verified events are checked for duplicates, recorded, and routed. Filtered and unmatched deliveries stay visible, so you can see what arrived and why nothing ran.


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