# Webhooks: replay and the event feed

Source: https://help.ruuster.com/api/webhook-replay

> Re-send missed events, poll the event feed instead of receiving webhooks, and use webhooks with Zapier.

**Replay** re-queues a subscription's events from a window with their original ids:

```bash
curl -s -X POST https://api.ruuster.com/v1/webhooks/whk_2c7f9a4e1b/replay \
  -H "x-api-key: $RUUSTER_API_KEY" -H "x-email: you@yourbrokerage.com" \
  -H "Content-Type: application/json" \
  -d '{"from":"2026-09-30T00:00:00Z","to":"2026-10-01T00:00:00Z","onlyFailed":true}'
```

**Event feed.** If you can't host an endpoint, or want to catch up after an outage, read the same
events by polling `GET /events?kinds=…&since=<cursor>&limit=500`. Omit `since` to start 24 hours back,
then pass `meta.nextCursor` each time. Events are kept 30 days and returned oldest first. The feed
needs no subscription and counts against your normal limits.

| Parameter | Default | Description |
|---|---|---|
| `kinds` | every kind | Comma-separated event kinds, or `lead.*` |
| `since` | 24 hours back | The `meta.nextCursor` from your previous call |
| `limit` | 100 | Up to 500 events per call |

`meta.hasMore` is `true` while more events are waiting; keep the last `nextCursor` even when a page
is empty, and poll again later.

**Zapier.** Use *Webhooks by Zapier › Catch Hook* as the trigger and create a subscription with its
URL. Zapier can't verify signatures, so treat the hook URL as a secret and replace it if it leaks.

**Good practice**
- Respond first, process from a queue.
- De-duplicate on `id`; order by `occurredAt`.
- Verify the signature and timestamp on every request.
- Subscribe to the kinds you act on. For alerts, `lead.tour_request`, `lead.contact_agent` and
  `lead.favorite` are usually enough; use the API or the feed for analytics.
- After downtime, replay or read the feed instead of re-pulling everything.
