# Deliveries

Source: https://docs.pitchpointsolutions.com/api/webhooks/deliveries/

**Beta**

## Query Deliveries

Return a page of delivery summaries for one endpoint, optionally filtered by status and by a creation time range.

`POST /v1/webhooks/deliveries/{endpointId}/query`

```bash
curl -X POST https://api.pointservices.com/riskinsight-services-ws/resources/v1/webhooks/deliveries/4711/query \
  -H "Authorization: Bearer your_access_token_here" \
  -H "Content-Type: application/json" \
  -d '{
    "status": "FAILED",
    "limit": 2
  }'
```

The filter and the pagination cursor travel in the request body rather than in the query string, so this listing is a POST and creates nothing. The body is optional: send `{}`, or no body at all, to request the first page with no filter.

#### Header Properties

| Property | Value | Required? |
|----------|-------|-----------|
| Authorization | Bearer your_access_token_here | true |
| Content-Type | application/json | false |

#### Path Parameters

| Property | Description | Type | Required |
|----------|-------------|------|----------|
| endpointId | The owning endpoint's id. Deliveries are always addressed through their endpoint, because that is where ownership and authorization live. | number | yes |

#### Request Data Properties

Every property is optional, and `since` and `until` accept an explicit `null` as well as being omitted.

| Property | Description | Type | Default |
|----------|-------------|------|---------|
| marker | The pagination cursor: pass back the `nextMarker` from a previous response. Exclusive, so the delivery it names is not sent again, and paging proceeds toward newer deliveries. Must parse as a positive integer. | string | |
| limit | The requested page size. Valid range is 1 to 100. A value outside that range is neither an error nor clamped: it is replaced outright by the default of 100. | number | 100 |
| status | Restricts the result to one delivery status. Omit to return every status. | string | |
| since | The start of the window, as an RFC 3339 date-time. Inclusive. Omit, or send an explicit `null`, to start from the oldest delivery that still exists. | string | |
| until | The end of the window, as an RFC 3339 date-time. Exclusive, so consecutive windows can share a boundary without returning anything twice. Omit, or send an explicit `null`, to run to now. | string | |

> **Warning:** `limit: 0` and `limit: 5000` both yield 100. A request for zero rows returns the largest page, not the smallest and not a 400. If you compute this value, check its range yourself before sending it, and compare the response's own `limit` against what you asked for.

The window is over each delivery's creation time, which is when the event occurred, not when it was last attempted. `marker` is subordinate to the window rather than an alternative to it: when you send both, the two are combined with AND, so paging walks forward through the window and stops at its end.

```bash
curl -X POST https://api.pointservices.com/riskinsight-services-ws/resources/v1/webhooks/deliveries/4711/query \
  -H "Authorization: Bearer your_access_token_here" \
  -H "Content-Type: application/json" \
  -d '{
    "since": "2026-08-01T00:00:00Z",
    "until": "2026-08-28T00:00:00Z",
    "limit": 50
  }'
```

This shape never carries a delivery's `payload` or `lastResponseBody`. Both can be large. Fetch a single delivery to see either.

### Responses

**200**

| Property | Description | Type | Notes |
|----------|-------------|------|-------|
| limit | The page size actually applied, after an absent or out-of-range request was replaced with the default of 100. | number | always emitted |
| marker | The cursor you supplied, echoed back verbatim. Absent when none was supplied. | string | conditional |
| status | The status filter you supplied, echoed back. Absent when none was supplied. | string | conditional |
| count | How many deliveries this page carries. | number | always emitted, including 0 |
| nextMarker | The cursor for the next page, present **only** when this page was full. It is the id of the last delivery actually present in `results`. | string | conditional |
| results | The page of delivery summaries, never the detail shape. | array | always emitted, including `[]` |

> **Warning:** `nextMarker` is present here only when the page was full, so a page that is not full is the last one. This differs from the endpoint listing, where a short or empty page can still carry a cursor and you stop only when it is absent. Do not reuse one paging loop for both.

The examples below use a `limit` of 2 to keep them short, so a full page is two rows. Use a larger page size in practice.

#### Delivery Summary Properties

| Property | Description | Type | Notes |
|----------|-------------|------|-------|
| id | The delivery's id. This is also the value your delivery listing advertises as `nextMarker`. | number | |
| eventId | The stable id of the underlying business event, shared by every delivery of it, including replays. Formatted as `msg_` followed by a UUID. | string | |
| topic | The published topic this delivery carries. | string | |
| url | The URL this delivery was actually sent to, snapshotted when the delivery was created. Editing the URL between retries does not redirect deliveries already under way. | string | |
| status | The delivery's lifecycle state. | string | |
| simulated | Whether this delivery came from the event simulation operation rather than from a business event. | boolean | always emitted |
| nextAttemptDateTime | When the next retry is due. Present exactly when `status` is `PENDING` or `RETRYING`, and ABSENT, not null, otherwise — a terminal row promises no further attempt. | string | conditional |
| deliveredDateTime | When the delivery succeeded. ABSENT, not null, while the delivery is undelivered. | string | conditional |
| lastResponseStatus | The HTTP status your server returned on the last attempt. Emitted as an explicit `null` before any attempt, and when the attempt failed without receiving an HTTP response. | number | always emitted, may be null |
| lastFailureReason | Why the last attempt failed, as a short token: `HTTP_<status>` when your server answered, or `TRANSPORT_` followed by the kind of failure when no HTTP response arrived. Emitted as an explicit `null` on a delivery that has not failed. Meant for your logs and operators, not a stable vocabulary to branch on. | string | always emitted, may be null |

Example, a full page. `count` equals `limit`, so the page was full and carries a cursor:
```json
{
  "limit": 2,
  "status": "FAILED",
  "count": 2,
  "nextMarker": "80514",
  "results": [
    {
      "id": 80512,
      "eventId": "msg_9f1c2e4a-6b73-3d81-a0c5-4e2f7b9d1350",
      "topic": "workflow.updated",
      "url": "https://hooks.example.com/pps/workflows",
      "status": "FAILED",
      "simulated": false,
      "lastResponseStatus": 500,
      "lastFailureReason": "HTTP_500"
    },
    {
      "id": 80514,
      "eventId": "msg_2d7a4c19-8e05-3f62-b431-7c9a0e5d8f26",
      "topic": "workflow.failed",
      "url": "https://hooks.example.com/pps/workflows",
      "status": "FAILED",
      "simulated": false,
      "lastResponseStatus": null,
      "lastFailureReason": "TRANSPORT_SocketTimeoutException"
    }
  ]
}
```

Example, the next page. `count` is less than `limit`, so this page is not full, it carries no `nextMarker`, and it is the last one:
```json
{
  "limit": 2,
  "marker": "80514",
  "status": "FAILED",
  "count": 1,
  "results": [
    {
      "id": 80519,
      "eventId": "msg_0c5a83f7-2b19-4e6d-9a04-7f3e1b8c5d20",
      "topic": "workflow.failed",
      "url": "https://hooks.example.com/pps/workflows",
      "status": "FAILED",
      "simulated": false,
      "lastResponseStatus": 503,
      "lastFailureReason": "HTTP_503"
    }
  ]
}
```

Example, a windowed query. `marker` is absent from the response because none was sent, and 80531 here is the row the [simulate example](https://docs.pitchpointsolutions.com/api/webhooks/events#simulate-an-event) created, which is why it carries `simulated: true`.
```json
{
  "limit": 50,
  "count": 2,
  "results": [
    {
      "id": 80512,
      "eventId": "msg_9f1c2e4a-6b73-3d81-a0c5-4e2f7b9d1350",
      "topic": "workflow.updated",
      "url": "https://hooks.example.com/pps/workflows",
      "status": "FAILED",
      "simulated": false,
      "lastResponseStatus": 500,
      "lastFailureReason": "HTTP_500"
    },
    {
      "id": 80531,
      "eventId": "msg_1d4b7e02-5a93-4c68-b7f1-0e2a9c6d5384",
      "topic": "workflow.updated",
      "url": "https://hooks.example.com/pps/workflows",
      "status": "DELIVERED",
      "simulated": true,
      "deliveredDateTime": "2026-08-28T14:31:22Z",
      "lastResponseStatus": 200,
      "lastFailureReason": null
    }
  ]
}
```

**400**

A `marker` that will not parse as a positive integer.

```json
{
  "type": "about:blank",
  "title": "Bad Request",
  "status": 400,
  "detail": "`marker` carries `80514x`, which does not parse as a positive integer. Pass back the `nextMarker` value unmodified.",
  "instance": "urn:pps:request:b5710e83-9c42-4d06-a7f5-1e3b8c024d97"
}
```

**401**

No credential was presented, or the one presented was rejected.

**404**

No such endpoint, delivery or task is available to this request. This also covers a resource that exists but is not yours, or one you may not act on: the three cases are deliberately indistinguishable so that ids cannot be enumerated, which is why an endpoint that is not yours answers 404 rather than 403. Check the id you sent and the org unit of the credential you sent it with.

See [Errors](https://docs.pitchpointsolutions.com/api/webhooks/index#errors).

---

## Get One Delivery

Return one delivery including its signed `payload` and any captured `lastResponseBody`. This is the one place either is exposed.

`GET /v1/webhooks/deliveries/{endpointId}/{deliveryId}`

```bash
curl -X GET "https://api.pointservices.com/riskinsight-services-ws/resources/v1/webhooks/deliveries/4711/80512" \
  -H "Authorization: Bearer your_access_token_here"
```

A delivery is addressed through its owning endpoint rather than by delivery id alone. The endpoint in the path is what the request is authorized against, and a delivery id that does not belong to that endpoint is a 404.

#### Path Parameters

| Property | Description | Type | Required |
|----------|-------------|------|----------|
| endpointId | The owning endpoint's id. | number | yes |
| deliveryId | The delivery's id. | number | yes |

### Responses

**200**

Everything the summary carries, plus the two large fields exposed only here.

| Property | Description | Type | Notes |
|----------|-------------|------|-------|
| payload | The signed envelope actually sent to your server, embedded as a JSON object rather than as a string of JSON. ABSENT, never null, when this delivery has no retained payload. | object | conditional |
| lastResponseBody | The response body your server returned on the last attempt. Emitted as an explicit `null` for a delivery not yet attempted or whose server returned no body. PPS keeps the first 8,192 characters and discards the rest, with no marker where the cut falls. Untrusted text: it may contain arbitrary content and may stop mid-token. | string | always emitted, may be null |

The null policy differs by property and is part of the contract. `lastResponseStatus`, `lastFailureReason` and `lastResponseBody` are emitted as explicit `null`. `nextAttemptDateTime`, `deliveredDateTime` and `payload` are absent when they have no value.

Example:
```json
{
  "id": 80512,
  "eventId": "msg_9f1c2e4a-6b73-3d81-a0c5-4e2f7b9d1350",
  "topic": "workflow.updated",
  "url": "https://hooks.example.com/pps/workflows",
  "status": "FAILED",
  "simulated": false,
  "lastResponseStatus": 500,
  "lastFailureReason": "HTTP_500",
  "lastResponseBody": "{\"error\":\"internal\"}",
  "payload": {
    "type": "workflow.updated",
    "eventId": "msg_9f1c2e4a-6b73-3d81-a0c5-4e2f7b9d1350",
    "timestamp": "2026-08-28T14:26:03Z",
    "data": {
      "workflowId": "wfpop_7b3f1c9e-2a84-4d16-9f05-c3e8a1b47d92",
      "runId": "wfrunpop_7b3f1c9e-2a84-4d16-9f05-c3e8a1b47d92",
      "correlationId": "9c2e14a7-55d0-4b8e-a731-6f0d2b93e185",
      "serviceName": "ADV",
      "modelName": "ADV-120",
      "status": "ready"
    }
  }
}
```

**401**

No credential was presented, or the one presented was rejected.

**404**

No such endpoint, delivery or task is available to this request. This also covers a resource that exists but is not yours, or one you may not act on: the three cases are deliberately indistinguishable so that ids cannot be enumerated, which is why an endpoint that is not yours answers 404 rather than 403. Check the id you sent and the org unit of the credential you sent it with.

See [Errors](https://docs.pitchpointsolutions.com/api/webhooks/index#errors).

---

## Replay One Delivery

Sign the delivery again and queue it for immediate attempt. This request has no body.

`POST /v1/webhooks/deliveries/{endpointId}/{deliveryId}/replay`

> **Warning:** A 200 from this operation does not mean the replay happened. A delivery in `PENDING` or `RETRYING`, or an endpoint whose circuit is `OPEN`, causes the call to do nothing and still return 200 with the delivery unchanged. There is no 409, no error body, and no field that differs between a replay that was queued and one that was refused.

Predict the refusal rather than detecting it afterwards. Before you replay, read `circuitState` on the endpoint and `status` on the delivery: an `OPEN` circuit, or a delivery already `PENDING` or `RETRYING`, means the call will do nothing. That check is reliable, and the after-the-fact one below is not.

```bash
curl -X POST https://api.pointservices.com/riskinsight-services-ws/resources/v1/webhooks/deliveries/4711/80512/replay \
  -H "Authorization: Bearer your_access_token_here"
```

The delivery keeps its original `eventId`, so a consumer deduplicating on that value recognizes the replay as the same business event rather than as a new one. A replay is a redelivery, not a new event.

A delivery is replayable only while its row still exists. Rows are removed once they fall outside the delivery retention window, which is 90 days.

#### Path Parameters

| Property | Description | Type | Required |
|----------|-------------|------|----------|
| endpointId | The owning endpoint's id. | number | yes |
| deliveryId | The delivery's id. | number | yes |

### Responses

**200**

The delivery in the full detail shape, reporting its state as it stood BEFORE the replay. `status` and `nextAttemptDateTime` hold the values from before, so a delivery that is now `PENDING` is still reported here as `FAILED`. Do not drive your state machine from this body.

Example. This is byte-identical to the GET above, because it is the same state:
```json
{
  "id": 80512,
  "eventId": "msg_9f1c2e4a-6b73-3d81-a0c5-4e2f7b9d1350",
  "topic": "workflow.updated",
  "url": "https://hooks.example.com/pps/workflows",
  "status": "FAILED",
  "simulated": false,
  "lastResponseStatus": 500,
  "lastFailureReason": "HTTP_500",
  "lastResponseBody": "{\"error\":\"internal\"}",
  "payload": {
    "type": "workflow.updated",
    "eventId": "msg_9f1c2e4a-6b73-3d81-a0c5-4e2f7b9d1350",
    "timestamp": "2026-08-28T14:26:03Z",
    "data": {
      "workflowId": "wfpop_7b3f1c9e-2a84-4d16-9f05-c3e8a1b47d92",
      "runId": "wfrunpop_7b3f1c9e-2a84-4d16-9f05-c3e8a1b47d92",
      "correlationId": "9c2e14a7-55d0-4b8e-a731-6f0d2b93e185",
      "serviceName": "ADV",
      "modelName": "ADV-120",
      "status": "ready"
    }
  }
}
```

Fetch the delivery again to see the state after the replay.

```bash
curl -X GET "https://api.pointservices.com/riskinsight-services-ws/resources/v1/webhooks/deliveries/4711/80512" \
  -H "Authorization: Bearer your_access_token_here"
```

A replay that was actually queued changes three fields together: `status` becomes `PENDING`, `nextAttemptDateTime` is set to the instant of the next attempt, and any `deliveredDateTime` is cleared.

> **Warning:** This after-the-fact check cannot tell a queued replay from a refused one on a delivery that was already `PENDING` or `RETRYING`. Being already `PENDING` is itself one of the two refusal conditions, so the delivery reads as `PENDING` either way and the check reports success for a replay that did nothing. It is dependable only for a delivery that was not `PENDING` or `RETRYING` before you called. Check the delivery's status and the endpoint's `circuitState` before replaying instead.

```json
{
  "id": 80512,
  "eventId": "msg_9f1c2e4a-6b73-3d81-a0c5-4e2f7b9d1350",
  "topic": "workflow.updated",
  "url": "https://hooks.example.com/pps/workflows",
  "status": "PENDING",
  "simulated": false,
  "nextAttemptDateTime": "2026-08-28T15:12:40Z",
  "lastResponseStatus": 500,
  "lastFailureReason": "HTTP_500",
  "lastResponseBody": "{\"error\":\"internal\"}",
  "payload": {
    "type": "workflow.updated",
    "eventId": "msg_9f1c2e4a-6b73-3d81-a0c5-4e2f7b9d1350",
    "timestamp": "2026-08-28T14:26:03Z",
    "data": {
      "workflowId": "wfpop_7b3f1c9e-2a84-4d16-9f05-c3e8a1b47d92",
      "runId": "wfrunpop_7b3f1c9e-2a84-4d16-9f05-c3e8a1b47d92",
      "correlationId": "9c2e14a7-55d0-4b8e-a731-6f0d2b93e185",
      "serviceName": "ADV",
      "modelName": "ADV-120",
      "status": "ready"
    }
  }
}
```

**401**

No credential was presented, or the one presented was rejected.

**404**

No such endpoint, delivery or task is available to this request. This also covers a resource that exists but is not yours, or one you may not act on: the three cases are deliberately indistinguishable so that ids cannot be enumerated, which is why an endpoint that is not yours answers 404 rather than 403. Check the id you sent and the org unit of the credential you sent it with.

See [Errors](https://docs.pitchpointsolutions.com/api/webhooks/index#errors). This operation never returns 409.

---

## Replay In Bulk

Select deliveries over a date range, narrowed by an optional `status`, and queue them. The call is asynchronous: it returns 200 with a task handle as soon as the task is accepted, without waiting for the deliveries to be queued.

`POST /v1/webhooks/deliveries/{endpointId}/replay`

```bash
curl -X POST https://api.pointservices.com/riskinsight-services-ws/resources/v1/webhooks/deliveries/4711/replay \
  -H "Authorization: Bearer your_access_token_here" \
  -H "Content-Type: application/json" \
  -d '{
    "since": "2026-08-01T00:00:00Z",
    "until": "2026-08-28T00:00:00Z",
    "status": "FAILED"
  }'
```

#### Header Properties

| Property | Value | Required? |
|----------|-------|-----------|
| Authorization | Bearer your_access_token_here | true |
| Content-Type | application/json | true |

#### Request Data Properties

| Property | Description | Type | Required |
|----------|-------------|------|----------|
| since | The start of the replay window, as an RFC 3339 date-time. Inclusive. Only an absolute instant is accepted; a relative window such as "the last 30 days" is not. | string | yes |
| until | The end of the replay window. Exclusive, so consecutive windows can share a boundary without replaying anything twice. Omit, or send an explicit `null`, to replay everything from `since` up to now. | string | no |
| status | Restricts the replay to one delivery status. Omit to select the two stalled states, `FAILED` plus `PARKED`. | string | no |

The window is the bound on how much one replay queues. There is no per-request ceiling on how many deliveries one replay may queue: narrow the window if you want to queue fewer. The window is over each delivery's creation time, which is when the event occurred, not when it was last attempted.

Four statuses can be replayed: `FAILED`, `PARKED`, `DELIVERED` and `CANCELLED`. Omitting `status` selects `FAILED` plus `PARKED`, which is what recovers a disabled endpoint: enable it again, then run a bulk replay with no `status`.

> **Warning:** A delivery PPS made successfully is `DELIVERED` however your service handled it afterwards, so the default selection does not reach events your own consumer dropped. If your consumer acknowledged deliveries with a 2xx during an outage and then lost them, name `status: "DELIVERED"` and the window your consumer was broken in. This re-sends events your service has already seen, so your handler must tolerate duplicates.

```bash
curl -X POST https://api.pointservices.com/riskinsight-services-ws/resources/v1/webhooks/deliveries/4711/replay \
  -H "Authorization: Bearer your_access_token_here" \
  -H "Content-Type: application/json" \
  -d '{
    "since": "2026-08-01T00:00:00Z",
    "until": "2026-08-28T00:00:00Z",
    "status": "DELIVERED"
  }'
```

Replayed deliveries are spread two seconds apart rather than queued all at once, so a replay of 100 deliveries drains over roughly three and a half minutes. Do not read a slow drain as a failed replay.

> **Warning:** Concurrent bulk replays against the same endpoint are bounded, not prevented. Nothing serializes two replays whose windows overlap, so a delivery selected by both can be reset and enqueued twice. If a replay seems slow, poll the task rather than issuing a second call, which doubles the traffic.

### Responses

**200**

The replay task was accepted. The deliveries are queued after this response returns, so poll the task for progress rather than reading this body as a result.

| Property | Description | Type | Notes |
|----------|-------------|------|-------|
| taskId | The task's handle, formatted as `wrt_` followed by an identifier. Treat it as opaque. | string | always emitted |
| endpointId | The endpoint whose deliveries this task is replaying. | number | always emitted |
| status | `PENDING`, `RUNNING`, `COMPLETED` or `FAILED`. | string | always emitted |
| since | The resolved start of the window, echoed back. Inclusive. | string | always emitted, because it is required on the request |
| until | The resolved end of the window, echoed back. Exclusive. | string | optional; emitted as `null` when the request named none |
| replayed | How many deliveries the task has queued so far. It grows while the task is `RUNNING` and is final once it is `COMPLETED`. | number | always emitted |
| stoppedReason | Why the task stopped before covering the whole window. Present only on a `FAILED` task. Text for a person, not a stable code. | string | conditional |

Example:
```json
{
  "taskId": "wrt_60184",
  "endpointId": 4711,
  "status": "PENDING",
  "since": "2026-08-01T00:00:00Z",
  "until": "2026-08-28T00:00:00Z",
  "replayed": 0
}
```

**400**

Naming `PENDING` or `RETRYING` is rejected, because those rows still have a live delivery task driving them and replaying one would race it.

```json
{
  "type": "about:blank",
  "title": "Bad Request",
  "status": 400,
  "detail": "`status` carries `RETRYING`, which cannot be replayed. Replayable statuses are FAILED, PARKED, DELIVERED and CANCELLED.",
  "instance": "urn:pps:request:47c1e0b9-3f86-4a25-9d70-8b2e5c1a6f34"
}
```

An absent body is equivalent to `{}`, which is rejected with a 400 naming `since`.

```json
{
  "type": "about:blank",
  "title": "Bad Request",
  "status": 400,
  "detail": "`since` is required on a bulk replay and was not supplied. The window is the bound on how much one replay queues.",
  "instance": "urn:pps:request:e28b647a-5d13-4f90-bc36-0a97e4d152b8"
}
```

**409**

A replay into an endpoint whose circuit is currently `OPEN` is refused outright, never silently accepted. A task that completes with `replayed: 0` means "nothing matched the filter", never "the endpoint refused".

```json
{
  "type": "https://pointservices.com/problems/conflict",
  "title": "The resource's current state refuses this request",
  "status": 409,
  "detail": "Endpoint 4711 has an OPEN circuit, so a bulk replay is refused until it closes.",
  "instance": "urn:pps:request:5c2b9e47-0a38-4f15-9d6e-2b7c4a1f8035"
}
```

**401**

No credential was presented, or the one presented was rejected.

**404**

No such endpoint, delivery or task is available to this request. This also covers a resource that exists but is not yours, or one you may not act on: the three cases are deliberately indistinguishable so that ids cannot be enumerated, which is why an endpoint that is not yours answers 404 rather than 403. Check the id you sent and the org unit of the credential you sent it with.

See [Errors](https://docs.pitchpointsolutions.com/api/webhooks/index#errors).

---

## Get A Bulk Replay Task

Report the state of one bulk replay task: whether it is still running, how many deliveries it has queued so far, and the window it resolved.

`GET /v1/webhooks/deliveries/{endpointId}/replay/{taskId}`

```bash
curl -X GET "https://api.pointservices.com/riskinsight-services-ws/resources/v1/webhooks/deliveries/4711/replay/wrt_60184" \
  -H "Authorization: Bearer your_access_token_here"
```

Poll until the task is no longer `PENDING` or `RUNNING`. `replayed` grows while `RUNNING` and is final at `COMPLETED`. `stoppedReason` is present only on a `FAILED` task; branch on `status`, never on that string.

The task is scoped to the endpoint in the path, so a task id belonging to a different endpoint is a 404. Task status is retained for 30 days, after which the task id reads as a 404. Record the outcome you care about rather than relying on the task as a durable record.

#### Path Parameters

| Property | Description | Type | Required |
|----------|-------------|------|----------|
| endpointId | The owning endpoint's id. | number | yes |
| taskId | The handle a bulk replay returned. Treat it as opaque and pass it back unmodified. | string | yes |

### Responses

**200**

The same shape the bulk replay returns.

Example, while the task is running:
```json
{
  "taskId": "wrt_60184",
  "endpointId": 4711,
  "status": "RUNNING",
  "since": "2026-08-01T00:00:00Z",
  "until": "2026-08-28T00:00:00Z",
  "replayed": 1420
}
```

Example, once it has finished the whole window:
```json
{
  "taskId": "wrt_60184",
  "endpointId": 4711,
  "status": "COMPLETED",
  "since": "2026-08-01T00:00:00Z",
  "until": "2026-08-28T00:00:00Z",
  "replayed": 1883
}
```

**401**

No credential was presented, or the one presented was rejected.

**404**

No such endpoint, delivery or task is available to this request. This also covers a resource that exists but is not yours, or one you may not act on: the three cases are deliberately indistinguishable so that ids cannot be enumerated, which is why an endpoint that is not yours answers 404 rather than 403. Check the id you sent and the org unit of the credential you sent it with.

See [Errors](https://docs.pitchpointsolutions.com/api/webhooks/index#errors).

---

## Delivery Statuses

| Status | Meaning | Replayable? |
|---|---|---|
| PENDING | Queued and not yet attempted. | No. A bulk replay naming it is a 400; a single replay returns 200 and does nothing. |
| RETRYING | Has failed at least once and has a further attempt scheduled. | No, on the same terms as `PENDING`. |
| DELIVERED | Succeeded. PPS made the delivery, however your service handled it afterwards. | Yes. Name it explicitly to recover events your own consumer lost. |
| FAILED | Terminal. Either it exhausted its ten attempts, or your endpoint answered `410 Gone` or any other 4xx except `429`, which ends a delivery on the first response. | Yes. Selected by the default when `status` is omitted. |
| PARKED | Held aside because its endpoint was disabled, its destination domain is no longer authorized, or its URL no longer passes destination-safety validation. Not discarded, and no attempt is spent. | Yes. Selected by the default when `status` is omitted. |
| CANCELLED | Terminal: the authorizing grant was revoked, so PPS will not send the delivery again on its own. PPS does not set this status on deliveries; treat it as terminal if you see it. | Yes, when named explicitly. |

Matching is exact and sensitive to case when used as a filter.

> **API Reference:** [Troubleshooting](https://docs.pitchpointsolutions.com/developer_guides/webhooks/troubleshooting) walks through finding a missing delivery and replaying it.
