Usage Gate

Build

Connect Stripe

Stripe is required. UsageGate does not replace Checkout — you keep collecting money in your Stripe. We listen for paid invoices and subscription updates, refill balances, and set the billing period end (resetAt) from Stripe's current_period_end.

Why Stripe is required

  • Paid plan refills happen on invoice.paid / customer.subscription.updated
  • The billing period clock comes from Stripe — see How billing periods work
  • Cancel / unpaid status zeros entitlements so access stops with the subscription

You still use grant() for free-tier seeds, trials, and admin overrides — but every paid renewal path goes through Stripe.

1. Add a webhook on your Stripe account

code
https://YOUR_USAGEGATE_HOST/api/webhooks/stripe

Events: invoice.paid, customer.subscription.updated. Save the signing secret (whsec_…) on Stripe in UsageGate, or via the SDK:

code
await gate.configureStripe({
  webhookSecret: "whsec_...",
  accountHint: "acct_your_stripe",
});

2. Local testing

terminal
stripe listen --forward-to localhost:43123/api/webhooks/stripe
stripe trigger invoice.paid

3. Bridge paying customers to end users

Put your app’s user id and grant map on the Stripe subscription:

subscription.metadata
{
  "end_user_id": "usr_maya",
  "feature_grants": "{\"ai_credits\":50000,\"export_pdf\":1}"
}

When Maya upgrades or renews: Stripe fires the event → we verify the signature → set balances absolutely → set resetAt to current_period_end → next canAccess succeeds until that period ends. Duplicate events are claimed idempotently.

What you stop doing

  • Parsing invoices in your app to toggle features
  • Storing credit balances in your own DB by hand
  • Debugging “did this webhook already run?” race bugs
  • Building your own month-end reset job