Overview

How billing works

The flow#

  1. Your tool call finishes, successfully or not.
  2. Your server posts a usage event with an idempotency key and a status.
  3. The event is written to Postgres unconditionally, before anything touches Stripe.
  4. If the status is billable, the event is reported to Stripe Billing Meters.
  5. If the Stripe call fails, the event stays in the database with syncedAt: null instead of disappearing into a silent catch.

That ordering is the core decision. The index @@index([status, syncedAt]) exists for the retry job that picks up unsynced events. Implementing that job is documented as your responsibility, not something the boilerplate hides from you.

Why write to Postgres first#

Stripe confirmation can arrive after the tool has already executed. If Stripe were the source of truth, a failed API call would erase the fact that work happened. With Postgres first, you always have a complete audit trail, and Stripe is a projection of it.

Next#