Skip to content

Replay a failed webhook

When a Lago webhook arrives but the downstream dispatch fails — a Lago customer didn’t update, a subscription change didn’t propagate, an invoice event didn’t reconcile — you can replay the persisted event from the admin console. Replay clones the original event row, attributes the replay to your operator account, and runs the clone through the same dispatch pipeline as the original. Use this runbook when triaging billing discrepancies reported by support, or when a known dispatch bug has been patched and you need to re-process events received during the outage window.

  • You are signed in with an account that has role = "admin". Non-admin sessions are rejected with 403.
  • You know the webhook event ID, or you can locate it in the admin webhook event log by filtering on customer, event type, or failure status.
  • You have confirmed the original failure mode is no longer present. Replaying into the same broken state will just create a second failed event.
  1. Open the webhook event log

    In the admin console sidebar, go to Billing → Webhook events.

  2. Locate the failed event

    Filter by Status: failed and narrow further by Lago customer or event type if needed. Click the event row to open its detail drawer. Confirm:

    • The event_type matches what you expect to replay.
    • The payload and received_at look correct.
    • replayed_from_id is empty. (If it’s already set, this row is itself a replay — find and replay the original instead, or replay this clone knowingly.)
  3. Replay the event

    In the event detail drawer, click Replay.

    The console posts to POST /api/admin/webhook-events/[id]/replay and waits for the dispatch result inline. A 200 response means the clone dispatched successfully; a 502 means the clone was created but dispatch failed again — the response body contains the error string and the newEventId of the clone.

  4. Open the replayed clone

    From the success toast, click View replayed event, or navigate to the event log and open the row with id = newEventId. Confirm:

    • replayed_from_id points to the original event.
    • replayed_by_user_id is your user ID.
    • replayed_at is set to the moment you clicked Replay.
  • The replayed event row exists in Billing → Webhook events with status = success and the replayed_from_id / replayed_by_user_id / replayed_at fields populated.
  • The downstream effect landed. Depending on event_type, check:
    • Lago customer / subscription events — the relevant Lago customer or Lago subscription record in the Polaris admin reflects the change.
    • Invoice events — the invoice appears (or updates) under the customer’s billing tab.
    • Metric events — the relevant Lago metric counters move on the next sync run.
  • The original event row is unchanged. Replay never mutates the source row — it only writes a new clone.

403 Forbidden: admin access required — your session isn’t an admin session. Sign out and back in with an admin account, or ask another operator to perform the replay.

400 Invalid event id — the event ID in the URL isn’t a valid integer. This usually means a malformed link; navigate back to the event log and click into the event row directly.

401 Unauthorized — your session expired mid-action. Re-authenticate and retry.

502 with success: false and an error string — the clone was written but dispatch failed again. The clone’s newEventId is returned in the response so you can inspect it.

Dispatch succeeded but the downstream record didn’t change — the handler may have treated the event as a no-op (for example, an idempotency_key already seen, or a state transition that’s already applied). Compare the payload against the current state of the target record before assuming the replay failed.

Replay is not reversible. The clone runs through the same dispatch pipeline as a fresh inbound webhook, and any side effects it produces (Lago API calls, database writes, notifications) cannot be rolled back from this surface.

What gets logged:

  • A new row in lago_webhook_events with replayed_from_id, replayed_at, and replayed_by_user_id set. This is your audit trail — every replay is attributable to the operator who triggered it.
  • The dispatch pipeline’s own logs and any audit log entries the downstream handlers write.

If a replay produced an incorrect side effect, you will need to correct it through the relevant surface (manual Lago adjustment, customer-facing refund, etc.) rather than by “undoing” the replay.