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

# Retries, logs and replay

> What happens when a delivery fails, and how to recover.

## Retry schedule

A delivery attempt is one HTTP request. A **2xx** response is success. Anything else is a failure: another status (including 3xx, 4xx, 410 and 429), a timeout after 15 seconds, a TLS, DNS or connection error, or an address refused by the safety checks.

When an event occurs, AllRide first **stores** it with its complete body for every subscribed endpoint, in the same transaction as the change that caused it; the delivery is `PENDING` in your log from that moment. Only then is the send triggered through AllRide's delivery queue (Google Cloud Pub/Sub). The sender acknowledges the queue message only after a 2xx (the delivery becomes `DELIVERED`); after a failed attempt the message is not acknowledged and the queue delivers it again, with an increasing delay from about 30 seconds up to 10 minutes between attempts, for at most **5 delivery attempts** in total. When the fifth attempt fails the delivery becomes `FAILED` and is no longer retried automatically; you can [replay](#replay) it. There is no fixed timetable: treat the delays as approximate.

Every attempt sends the body stored at event time, byte for byte (same `event.id` and `event.timestamp`), signed at send time: `t` and the signatures differ between attempts, the body does not.

**Stored first, so never silently dropped.** If triggering a send fails or is lost, an automatic sweep re-queues the delivery: a delivery that was never attempted after about **10 minutes**, and a delivery whose last attempt was more than **30 minutes** ago and that is still `PENDING`. A delivery that still cannot be sent after **3 re-queues** becomes `FAILED` with `lastErrorCode` `delivery-stalled` (a fault on AllRide's side, which AllRide monitors), and you can [replay](#replay) it. Deliveries can therefore arrive late and out of order: deduplicate on `event.id` and do not rely on order.

## Automatic disabling

Endpoints are never disabled automatically, however often they fail. Failures appear in your delivery log (`filter[status]=FAILED`), and you can pause an endpoint yourself (`:pause`) while you fix your receiver, then resume it and replay what you missed.

Nothing is delivered while your partner or its API access is not `active`; the endpoint's `deliveriesBlockedReason` shows `partner-inactive` or `api-access-inactive`. Events of such periods are not delivered later and cannot be replayed.

## Delivery logs

The delivery log has one **delivery** per stored event and endpoint, kept **30 days**: on the [delivery log page](https://provider-developers.voucher.allride.io/go/webhook-deliveries) and through `GET /partner/v1/webhook-deliveries` (`view-webhook-deliveries`). A delivery is listed as soon as its event is stored, before the first send.

| `status` | Meaning |
| - | - |
| `PENDING` | Stored and queued, or waiting for the next retry; also the state after a replay |
| `DELIVERED` | Your endpoint answered 2xx (`deliveredAt`) |
| `FAILED` | The last of the 5 attempts failed, or no request could be sent (see [`lastErrorCode`](#why-a-delivery-failed-lasterrorcode)); replay it to send it again |

| Field | Meaning |
| - | - |
| `webhookEventId`, `eventType` | The body's `event.id` and `event.type`; identical on every attempt and replay |
| `webhookEndpointId`, `url` | The endpoint and the URL of the latest attempt |
| `status`, `lastStatusCode`, `lastErrorCode`, `deliveredAt` | Where the delivery stands |
| `attemptCount`, `replayCount` | The total number of attempts (the length of `attempts[]`, across replays) and how often you replayed the delivery |
| `payload` | The body as stored at event time (every attempt sends it unchanged), with voucher values and personal data masked (your receiver got the real body) |
| `attempts[]` | One entry per attempt, oldest first: `attemptNo` (1, 2, …; never restarted by a replay), `trigger` (`event`, or `replay` for a send you requested), `signature` (that attempt's `x-signing-signature`, never a secret), `statusCode` (`null` without a response), `responseBody` (first 4 KiB; render it as text), `errorCode` (`timeout`, `connection-refused`, `dns-error`, `tls-error`, `ssrf-blocked`, `http-4xx`, `http-5xx`, `redirect-not-followed` or `internal-error`), `durationMs`, `attemptedAt` |
| `createdAt`, `updatedAt` | When the event was stored and when the delivery last changed |

### Why a delivery failed (`lastErrorCode`)

`lastErrorCode` is the `errorCode` of the last attempt, or one of the delivery-level codes below when no request was sent for it. A `FAILED` delivery can be [replayed](#replay) while it is in the log (30 days), except one whose payload was erased (`subject-erased`), which answers 410 `webhook-event-expired`.

| `lastErrorCode` | Level | Meaning |
| - | - | - |
| `timeout` | attempt | No complete response within 15 seconds |
| `connection-refused` | attempt | The connection was refused or reset |
| `dns-error` | attempt | Your host name did not resolve |
| `tls-error` | attempt | The TLS handshake or certificate check failed |
| `ssrf-blocked` | attempt | Your host resolved to an address AllRide does not call (private or internal ranges) |
| `http-4xx` | attempt | Your endpoint answered `4xx` (including `410` and `429`) |
| `http-5xx` | attempt | Your endpoint answered `5xx` |
| `redirect-not-followed` | attempt | Your endpoint answered `3xx`; redirects are never followed |
| `internal-error` | attempt | A fault on AllRide's side while sending; the attempt is retried |
| `endpoint-disabled` | delivery | The endpoint was paused or deleted when the event was stored or sent |
| `partner-inactive` | delivery | Your partner or its API access was not `active` when the delivery was due |
| `endpoint-unsubscribed` | delivery | The endpoint no longer subscribes to the event type |
| `subject-erased` | delivery | The redemption entity the event describes was erased, so the payload is gone; cannot be replayed (410 `webhook-event-expired`) |
| `delivery-stalled` | delivery | The delivery could not be sent after 3 automatic re-queues (a fault on AllRide's side) |
| `attempt-lost` | delivery | The fifth attempt was started but its result was never recorded (AllRide's sender stopped during it); your endpoint may have received it |

Filter by endpoint, status, event type, last status code, event id and time:

```bash theme={null}
curl -sS -G "$VOUCHER_API_BASE_URL/partner/v1/webhook-deliveries" \
  -H "Authorization: Bearer $VOUCHER_API_KEY" \
  --data-urlencode "filter[webhookEndpointId]=11030" \
  --data-urlencode "filter[status]=FAILED"
```

To keep a copy of the log, page through it with `perPage=100` ([Downloading large lists](https://docs-provider.voucher.allride.io/guides/pagination.md#downloading-large-lists)).

## Replay

**One delivery** (`manage-webhooks`): re-sends the same stored event, with the same body and `event.id` and a fresh `t` and signatures. Answers 202 with the `webhookDeliveryId`; the delivery goes back to `PENDING` and its new attempts are added with `trigger: replay`. A replay starts **five new attempts**. The log keeps counting: `attemptNo` continues after the earlier attempts (a `FAILED` delivery with five attempts that is replayed and then answered `2xx` shows `attemptNo` 1 to 6), `attemptCount` is the total number of attempts (the length of `attempts[]`), and `replayCount` says how often the delivery was replayed.

```bash theme={null}
curl -sS -X POST "$VOUCHER_API_BASE_URL/partner/v1/webhook-deliveries/21030:replay" \
  -H "Authorization: Bearer $VOUCHER_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)"
```

**Everything that failed in a window** (bulk replay): re-queues every stored event of the endpoint in `[since, until)` whose delivery is `FAILED`, oldest first (each keeps its `event.id` and goes back to `PENDING`), at most 10,000 per call. It runs in the background and answers 200 with `replayedCount`, `truncated` and `nextSince`; call again with `since = nextSince` while `truncated` is `true`.

```bash theme={null}
curl -sS -X POST "$VOUCHER_API_BASE_URL/partner/v1/webhook-endpoints/11030:replay-failed" \
  -H "Authorization: Bearer $VOUCHER_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"since": "2026-10-20T00:00:00Z", "eventTypes": ["redemption-created"]}'
```

Rules for both:

* The endpoint must be `active` (paused or deleted → 409 `webhook-endpoint-not-active`); a second bulk replay while one runs → 409 `invalid-state-transition`.
* Deliveries older than 30 days are gone from the log (404 `webhook-delivery-not-found`; `since` older than 30 days → 400 `data-failed-validation`); a delivery whose payload was erased answers 410 `webhook-event-expired`.
* Replays ignore the endpoint's current subscription: they are an explicit request.
* Follow progress in the log with `filter[status]=PENDING`.

## Related

* [Webhooks](https://docs-provider.voucher.allride.io/webhooks/overview.md)
* [Verifying signatures](https://docs-provider.voucher.allride.io/webhooks/verify-signatures.md)
* [Limits](https://docs-provider.voucher.allride.io/guides/limits.md#data-retention)


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