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

# Deliveries

> Inspect every attempt Endl made to deliver an event, and retry the ones that failed

A delivery is one attempt to send one event to one subscription. Endl records every one — the request sent, the response received, and each individual attempt. Every endpoint here requires the `webhooks` permission.

<Note>
  Mind the two similar paths: `/api/v0/webhooks/events` is the **delivery log** on this page, while `/api/v0/events` is the [PULL event feed](/webhooks/pull-feed). The `{id}` in these paths is a delivery id, not an event id.
</Note>

## List deliveries

<ParamField path="GET /api/v0/webhooks/events" />

Your deliveries, newest first, with [cursor pagination](/webhooks/pagination). Returns `data.deliveries[]`, `data.count`, and `data.nextCursor`.

### Query parameters

<ParamField query="subscriptionId" type="uuid">Scope results to one subscription.</ParamField>
<ParamField query="status" type="enum">Filter by delivery status. Repeatable — `?status=FAILED&status=EXPIRED`.</ParamField>
<ParamField query="types" type="string">Filter by event type. Repeatable.</ParamField>
<ParamField query="after" type="string">Pagination cursor.</ParamField>
<ParamField query="limit" type="integer" default="25">Page size, maximum 100.</ParamField>

<CodeGroup>
  ```bash Request theme={null}
  curl -G https://qa-api.endl.xyz/api/v0/webhooks/events \
    -H "X-API-KEY: $ENDL_API_KEY" -H "X-API-SECRET: $ENDL_API_SECRET" \
    --data-urlencode "status=FAILED" --data-urlencode "limit=25"
  ```

  ```json 200 OK theme={null}
  {
    "code": 200,
    "message": "Success",
    "status": "SUCCESS",
    "data": {
      "deliveries": [
        {
          "id": "4d2f6a11-8c73-4b90-9e21-5f0a2c8d1e44",
          "eventId": "evt_9f1a4c7b2e08",
          "eventType": "payout.completed",
          "subscriptionId": "2b1e8f40-3c9a-4d21-9f7e-6a1c0b5d2e34",
          "status": "FAILED",
          "attemptCount": 5,
          "attemptBudget": 5,
          "lastStatusCode": 500,
          "lastErrorClass": "HTTP_5XX",
          "createdOn": "2026-09-02T12:34:56.789Z"
        }
      ],
      "count": 1,
      "nextCursor": "eyJ1IjoiREVMSVZFUklFUyJ9.a3f9c1e8d0"
    },
    "errors": []
  }
  ```
</CodeGroup>

<Accordion title="Status codes">
  `200` · `400` bad `limit`, bad cursor, bad parameter, or missing permission · `401` / `503` authentication
</Accordion>

***

## Get a delivery

<ParamField path="GET /api/v0/webhooks/events/{id}" />

The full record of one delivery, including what Endl sent, what your endpoint replied, and every attempt.

<ResponseField name="status" type="enum">Current [delivery status](/webhooks/reference#delivery-status).</ResponseField>
<ResponseField name="attemptCount / attemptBudget" type="integer">Attempts made against attempts allowed. A retry adds three.</ResponseField>
<ResponseField name="lastStatusCode" type="integer | null">HTTP status of the most recent attempt.</ResponseField>
<ResponseField name="lastErrorClass / lastError" type="enum / string">The most recent [failure class](/webhooks/reference#error-classes) and its message.</ResponseField>
<ResponseField name="requestPayload" type="object | null">The payload Endl sent, parsed. Leaf values are strings.</ResponseField>
<ResponseField name="requestTimestamp / requestSignature" type="string | null">The `X-WEBHOOK-TIMESTAMP` and `X-WEBHOOK-SIGNATURE` Endl sent.</ResponseField>
<ResponseField name="responseBody / responseTruncated" type="any / boolean">Your endpoint's reply, parsed if it was JSON, and whether it was truncated.</ResponseField>
<ResponseField name="attempts" type="object[]">Each attempt, as `{attemptNo, statusCode, errorClass, latencyMs, at}`.</ResponseField>
<ResponseField name="deliveredAt / failedAt / expiresAt / nextAttemptAt" type="date-time | null">Lifecycle timestamps.</ResponseField>
<ResponseField name="eventId / eventType / subscriptionId / createdOn" type="mixed">Identity and creation time. `createdOn` is the pagination sort key.</ResponseField>

<CodeGroup>
  ```bash Request theme={null}
  curl https://qa-api.endl.xyz/api/v0/webhooks/events/4d2f6a11-8c73-4b90-9e21-5f0a2c8d1e44 \
    -H "X-API-KEY: $ENDL_API_KEY" -H "X-API-SECRET: $ENDL_API_SECRET"
  ```

  ```json 200 OK theme={null}
  {
    "code": 200,
    "message": "Success",
    "status": "SUCCESS",
    "data": {
      "id": "4d2f6a11-8c73-4b90-9e21-5f0a2c8d1e44",
      "eventId": "evt_9f1a4c7b2e08",
      "eventType": "payout.completed",
      "subscriptionId": "2b1e8f40-3c9a-4d21-9f7e-6a1c0b5d2e34",
      "status": "FAILED",
      "attemptCount": 5,
      "attemptBudget": 5,
      "lastStatusCode": 500,
      "lastErrorClass": "HTTP_5XX",
      "lastError": "HTTP 500",
      "lastLatencyMs": 231,
      "requestTimestamp": "2026-09-02T12:34:56.789Z",
      "requestSignature": "a3f9c1e8b2…",
      "requestPayload": {
        "eventId": "evt_9f1a4c7b2e08",
        "eventType": "payout.completed",
        "eventCreatedAt": "2026-09-02T12:34:55.001Z",
        "version": "1.0",
        "data": {
          "referenceId": "c2608cc2-084b-41d1-8be2-c4f3abd55e5a",
          "referenceType": "TRANSACTION",
          "amount": "1500.00"
        }
      },
      "responseBody": "Internal Server Error",
      "responseTruncated": false,
      "attempts": [
        {
          "attemptNo": 1,
          "statusCode": 500,
          "errorClass": "HTTP_5XX",
          "latencyMs": 240,
          "at": "2026-09-02T12:35:00.000Z"
        }
      ],
      "expiresAt": "2026-09-03T12:34:56.789Z",
      "createdOn": "2026-09-02T12:34:56.789Z"
    },
    "errors": []
  }
  ```
</CodeGroup>

<Tip>
  `requestSignature` and `requestPayload` are the fastest way to debug a signature mismatch: re-run your verifier against the exact timestamp and body Endl recorded here.
</Tip>

<Accordion title="Status codes">
  `200` · `404` not found or not yours · `400` non-UUID id or missing permission · `401` / `503` authentication
</Accordion>

***

## Retry a delivery

<ParamField path="POST /api/v0/webhooks/events/{id}/retry" />

Re-arms one failed or expired delivery. Takes no body. It grants three more attempts and a fresh delivery window, and the status returns to `QUEUED`.

<Warning>
  **Retryable states only.** Retrying a `DELIVERED` delivery returns `409`, because it would double-deliver, and so does one still in flight. Only `FAILED` and `EXPIRED` can be retried.
</Warning>

<CodeGroup>
  ```bash Request theme={null}
  curl -X POST https://qa-api.endl.xyz/api/v0/webhooks/events/4d2f6a11-8c73-4b90-9e21-5f0a2c8d1e44/retry \
    -H "X-API-KEY: $ENDL_API_KEY" -H "X-API-SECRET: $ENDL_API_SECRET"
  ```

  ```json 200 OK theme={null}
  {
    "code": 200,
    "message": "Delivery re-armed",
    "status": "SUCCESS",
    "data": {
      "id": "4d2f6a11-8c73-4b90-9e21-5f0a2c8d1e44",
      "eventId": "evt_9f1a4c7b2e08",
      "eventType": "payout.completed",
      "subscriptionId": "2b1e8f40-3c9a-4d21-9f7e-6a1c0b5d2e34",
      "status": "QUEUED",
      "attemptCount": 5,
      "attemptBudget": 8,
      "nextAttemptAt": "2026-09-02T13:00:00.000Z",
      "expiresAt": "2026-09-03T13:00:00.000Z",
      "createdOn": "2026-09-02T12:34:56.789Z"
    },
    "errors": []
  }
  ```
</CodeGroup>

<Note>
  Notice `attemptBudget` rising from 5 to 8 while `attemptCount` stays at 5 — that is the three extra attempts a retry grants.
</Note>

<Accordion title="Status codes">
  `200` re-armed · `400` retry rate limit, non-UUID id, or missing permission · `404` not found · `409` already delivered or otherwise not retryable · `401` / `503` authentication
</Accordion>
