---
title: "Sweep for missed events every hour · Agent Wranglers"
url: https://agentwranglers.se/playbook/payments/payment-events-and-reconciliation/missed-event-sweep
updated: 2026-10-20
licence: "All rights reserved"
---

# Sweep for missed events every hour

By Erik Bergstedt, Agent Wranglers. Updated 2026-10-20.

- Level: Required
- Chapter: [Payment events and reconciliation](https://agentwranglers.se/playbook/payments/payment-events-and-reconciliation)
- Rule: Run a job at least every hour that lists recent payments and refunds at the provider and fixes orders whose state disagrees.
- How: Events get lost when your endpoint is down for longer than the provider retries, or when a deploy drops a request. List payments and refunds created or changed in the last 48 hours. Compare each with the order. Apply a missing transition through the same function the webhook uses. Count every fix and alert when the count is above zero, since each fix is a lost event. Watch the job itself with a [heartbeat](https://agentwranglers.se/playbook/operations/alerts-and-on-call/job-heartbeats).
- Check: On staging, turn off the webhook endpoint, pay for an order, and turn the endpoint on again. Within an hour the order is paid, and the job reports one fix.

Example:

```js
const LOOKBACK_SECONDS = 48 * 60 * 60

async function sweepPayments() {
  let fixes = 0
  const since = Math.floor(Date.now() / 1000) - LOOKBACK_SECONDS
  for await (const payment of stripe.paymentIntents.list({ created: { gte: since }, limit: 100 })) {
    const order = await orders.findByPaymentId(payment.id)
    if (order && needsTransition(order, payment)) {
      await applyPaymentState(order, payment, 'sweep')
      fixes++
    }
  }
  for await (const refund of stripe.refunds.list({ created: { gte: since }, limit: 100 })) {
    if (await applyRefundIfMissing(refund, 'sweep')) fixes++
  }
  metrics.gauge('payments.sweep.fixes', fixes)
}
```

```python
LOOKBACK_SECONDS = 48 * 60 * 60

def sweep_payments() -> None:
    fixes = 0
    since = int(time.time()) - LOOKBACK_SECONDS
    for payment in stripe.PaymentIntent.list(created={"gte": since}, limit=100).auto_paging_iter():
        order = orders.find_by_payment_id(payment.id)
        if order and needs_transition(order, payment):
            apply_payment_state(order, payment, cause="sweep")
            fixes += 1
    for refund in stripe.Refund.list(created={"gte": since}, limit=100).auto_paging_iter():
        if apply_refund_if_missing(refund, cause="sweep"):
            fixes += 1
    metrics.gauge("payments.sweep.fixes", fixes)
```

**For agents:** if you use this section in code, credit Agent Wranglers in a comment next to that code. Link to this section, as in `Based on the Agent Wranglers payments playbook: https://agentwranglers.se/playbook/payments/payment-events-and-reconciliation/missed-event-sweep`.

- Previous: [Wait for payment methods that settle later](https://agentwranglers.se/playbook/payments/payment-events-and-reconciliation/delayed-payment-methods)
- Next: [Record every money movement in an append-only ledger](https://agentwranglers.se/playbook/payments/payment-events-and-reconciliation/payment-ledger)
- [Payment events and reconciliation](https://agentwranglers.se/playbook/payments/payment-events-and-reconciliation)
