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

# Replay missed risk events

> Recover from webhook downtime with the events replay endpoint.

Your webhook endpoint was down for an hour. Your kill-switch missed two depeg starts. You need to backfill those events and decide what to do with positions that should already be flat.

## What you build

A backfill job that pulls every missed event for the affected window and reapplies them through the same handler your live webhook uses.

## 1. Identify the gap

Check the last event you successfully processed. Replay is **cursor-based**, not timestamp-windowed: you walk forward from a known event id. If you have one, keep its ULID as your starting cursor (`since_event_id`). If you don't — or you've lost track — omit `since_event_id` on the first call and the endpoint returns from the oldest event still inside your tier's replay window.

## 2. Replay the window

Call `GET /v2/events/replay`. Each response carries a page of events (oldest-first) and a `next_cursor`. Pass that cursor back as `since_event_id` on the next call and repeat until the response is empty.

<CodeGroup>
  ```python python theme={null}
  from alterscope import AlterscopeClient

  client = AlterscopeClient(api_key="sk_live_...")

  cursor = None  # omit on the first call to start at the oldest event in the window
  while True:
      resp = client.get(
          "/v2/events/replay",
          params={
              "since_event_id": cursor,   # dropped when None
              "limit": 100,
              "type": "peg.depeg.start",  # optional, single-valued
          },
      )
      events = resp["events"]
      if not events:
          break
      for ev in events:  # oldest-first
          handle_event(ev)  # same handler your webhook uses
      cursor = resp["next_cursor"]
  ```

  ```bash curl theme={null}
  # First page: omit since_event_id to start at the oldest event in your window.
  curl -H "Authorization: Bearer $ALTERSCOPE_API_KEY" \
    "https://api.alterscope.org/v2/events/replay?limit=100"

  # Subsequent pages: pass the previous next_cursor as since_event_id until empty.
  curl -H "Authorization: Bearer $ALTERSCOPE_API_KEY" \
    "https://api.alterscope.org/v2/events/replay?since_event_id=01HX...&limit=100"
  ```
</CodeGroup>

To filter, add a single `type` (for example `peg.depeg.start` or `vault.cap.changed`) — `type` is single-valued.

## 3. Idempotency

The replay endpoint returns the same event ids your webhook would have delivered. Make your handler idempotent on `event.id` so replay is a no-op for events that did get through, and a recovery for those that didn't.

## 4. Limits

* The replay window is **tier-scoped**. The Free tier has no replay (`404 REPLAY_NOT_AVAILABLE`); Analyst is 1 day, Team 7 days, Enterprise 30 days, Custom 90 days.
* A cursor that points before your tier's window returns `410 REPLAY_WINDOW_EXPIRED`. Start a fresh walk (omit `since_event_id`) to resume from the oldest event still in range.
* Replay does not consume your webhook quota; it counts against your standard rate limit.

## 5. Troubleshooting

* **Gap still has missing events after replay**: check the rejected events log via `/v2/webhooks/{id}/deliveries?status=failed` and re-emit them through the handler manually.
* **Order matters**: events arrive in chronological order; do not parallelize handlers if your kill-switch is order-sensitive.
