# A monitor that tries again, and a webhook you can ask for again

A monitored list whose run dies is re-checked within the hour instead of waiting out its cadence, and a bulk run's completion webhook can be asked for a second time — from the API or from the dashboard — with the same bytes, signed afresh, delivered from the queue.

Date: 2026-09-10

- **A monitored list whose run dies is checked again within the hour, not next month.** A verification run that loses its worker — a deploy, a restart, a host that goes away — used to leave the schedule where it stood, because the schedule is pushed forward before the run starts so an hourly tick can never run a slow monitor twice and bill you twice. The cost was that a monthly list went unwatched for another month, while the dashboard showed the run *before* it as if nothing had happened.
- A run that dies is now recorded as one, and the list is re-checked about 45 minutes later — the sweep ticks hourly, so in practice between 45 minutes and about an hour and three quarters. **Exactly once:** a list that is broken rather than unlucky waits for its normal cadence instead of burning a run every 45 minutes, and pressing "Run now" while that re-check is pending no longer resets the count, or the row, which used to say "we have stopped trying" while the next run was forty minutes away. A run that stopped for lack of credits is untouched by any of this — it stopped for a reason a timer cannot fix.
- The re-check window is derived rather than picked: it is longer than the longest a run may take, so a re-check can never fall due while the attempt it replaces might still be going. And a monitor row whose run never finished no longer prints a green "all clean" it has no results to stand on — a failed run has no counts, and an absent count was reading as zero.
- **A bulk run's completion webhook can be asked for again.** Press **Send webhook again** beside the run on any Bulk runs tab, or call `POST /api/v1/{email,phone,ip,address,consistency}/bulk/{jobId}/webhook/redeliver`. Until now a 100,000-row run whose endpoint happened to be down for four minutes was finished, billed, on disk — and your pipeline never learned, with polling the only way back.
- The body is byte-for-byte the body the first delivery carried. The signature is stamped afresh, because a receiver refuses anything whose timestamp is more than five minutes old. The delivery is queued rather than made while you wait: one attempt against an endpoint that is down takes half a minute, and that is precisely the endpoint you are asking about — so the call answers `202`, the run reads `webhook_status: "pending"` until a worker has an answer, and then `delivered` or `failed` with what your endpoint said. Free, and capped at ten a minute.
- In the same release, cancelling a run that was still queued now fires its completion webhook with `status: "cancelled"` — which the documentation had always promised and the code had never done, so a redelivery for such a run would have been its *first* delivery while every page called it a repeat.
- **A monitor's `stopped_reason` is documented now**, on all five products: `insufficient_credits` and `key_spend_cap` where a run stopped part-way, `run_failed` where it died, and `run_failed_retrying` where it died and the schedule has been pulled in — with `retry_at` beside it saying when. A summary carrying either failure reason has no counts in it at all, so a missing count means unknown rather than zero.

Reference: https://spaw.co/changelog/2026-09-10-a-monitor-that-retries-and-a-webhook-you-can-ask-for-again
