Skip to content

Replay and Time Machine

Two operations are easy to confuse. Resending a delivery puts the same delivery back on its retry ladder. A replay builds new deliveries from events Railhook already stored. The dashboard calls replay the Time Machine.

Resend a delivery Replay (Time Machine)
Works on One existing delivery Stored events in a time range
Delivery id Kept New
Sequence number Kept New, so it queues behind live traffic
Idempotency-Key Kept <event id>-<endpoint id>
The original delivery Moved again Left untouched
Use it when One delivery failed and the receiver is fixed A receiver lost data, or a new endpoint needs history

POST /api/v1/deliveries/{id}/replay puts the delivery back to PENDING with its attempt count at zero and queues it. It answers 202. A delivery that already succeeded is refused rather than sent twice.

Two query parameters change what it does:

Parameter Effect
dryRun=true Sends nothing. Returns the target URL, the event type, the payload, the Idempotency-Key that would go out, the previous attempts, and a plan: WILL_SEND, SKIP when the delivery already succeeded, or BLOCKED when the endpoint is disabled.
fromAttempt=N Sets the attempt count to N-1, so the next request is attempt N and later waits continue from that point of the ladder. N must be between 1 and the number of attempts already made.

Use fromAttempt when restarting at the one-minute wait is wrong, for example after a receiver was down for hours, or when you want the remaining attempts rather than a fresh set.

To resend many deliveries at once, use POST /api/v1/deliveries/bulk-replay with up to 1000 deliveryIds, or with a projectId plus status and endpointId filters and a limit of up to 5000. The response says how many were replayed, how many were skipped, and whether more matched.

To resend deliveries that were abandoned, you can also retry them from Failed Messages, see Retries and failed messages.

  1. Estimate first. POST /api/v1/projects/{projectId}/replay/estimate takes the same body as the replay and creates nothing. It returns how many events match, how many active subscriptions match, how many deliveries would be created, and a warning when the range is too large.

    Terminal window
    curl -X POST "$RAILHOOK_URL/api/v1/projects/$PROJECT_ID/replay/estimate" \
    -H "X-API-Key: $API_KEY" \
    -H "Content-Type: application/json" \
    -d '{"fromDate":"2026-09-01T00:00:00Z","toDate":"2026-09-02T00:00:00Z","eventType":"order.completed"}'
  2. Start the replay with POST /api/v1/projects/{projectId}/replay and the same body. fromDate and toDate are required; eventType, endpointId and sourceStatus narrow it down. It answers 201 with a session.

  3. Follow the session with GET /api/v1/projects/{projectId}/replay/{sessionId}, or stop it with POST /api/v1/projects/{projectId}/replay/{sessionId}/cancel.

A replay creates one delivery for each stored event and each active subscription that matches. Ordered endpoints get fresh sequence numbers, so replayed deliveries wait behind live ones instead of colliding with them.

Limit Value
Replay sessions running at once, per project 2
Events in one session REPLAY_MAX_EVENTS_PER_SESSION, default 500000

Incoming events can be replayed too, to every destination of their source:

  • One event: POST /api/v1/projects/{projectId}/incoming-events/{id}/replay.
  • Many events: POST /api/v1/projects/{projectId}/incoming-events/bulk-replay with a required sourceId, and either a list of eventIds or a from and to range, optionally filtered by verified and capped by maxEvents.

Each replay creates new forwards that start again from attempt 1.