ProdVerdict
← Blog
BillingJuly 1, 20262 min read

Scheduled Stripe–Postgres reconciliation beats PR-only billing tests

Why Access checks belong on a cron, not every pull request — and how to install nightly billing drift detection in GitHub Actions.

stripe reconciliation jobbilling drift detectionstripe postgres syncnightly reconciliation stripegithub actions billingproduction contract

Your PR checks pass. Stripe and Postgres still disagree in production.

That is normal. The Access contract compares live billing state to live database rows. Drift often does not exist at merge time.

Why PR gates miss billing bugs

ScenarioPR-time checkAfter merge
Refactor drops invoice.payment_failed handlerPass (Stripe mocked)Drift when card fails next month
New price ID, stale plans: mapPass (no customer on new price yet)Drift on first signup

Scheduled vs PR in the docs explains the split: file linters on PR, Access on a schedule.

What practitioners run

Alex Mayhew recommends a daily reconcile. Operational.co runs a daily cron. Same shape: list active Stripe subs, compare to DB access flags, alert on mismatch.

typescript
for await (const sub of stripe.subscriptions.list({ status: 'active' })) {
  const row = await db.query(
    `select has_paid_access from users where stripe_customer_id = $1`,
    [sub.customer]
  );
  if (!row.rows[0]?.has_paid_access) {
    await alert('drift', { customer: sub.customer });
  }
}

Thirty lines. Most teams defer it until support tickets arrive.

Install with ProdVerdict

$
npx prodverdict setup
npx prodverdict scheduled --frequency daily --install

That writes a GitHub Actions workflow. Secrets: read-only STRIPE_SECRET_KEY, read-only DATABASE_URL. Slack alert on FAIL.

Fixture demo (no keys):

$
npx prodverdict demo

What a FAIL looks like

StripeDBVerdict
activehas_paid_access = falseRevenue leak
canceledhas_paid_access = trueWrongful access

Revenue leak locks out paying customers. Wrongful access gives away the product.

Full context: billing drift evidence. AI-specific failure modes: revenue leak from agent refactors.

PR checks still matter

Run config, migration, boundary, and webhook contracts on PR. They catch the handler you are about to ship broken. Scheduled Access catches the handler that broke three Tuesdays ago.

— mattbaconz

Try it in 60 seconds

Run the fixture demo — no Stripe key or database required.

$fixture demo
npx prodverdict@latest check access --config examples/nextjs-stripe/prodverdict.yml --fixtures --fixtures-dir examples/nextjs-stripe/scenarios/fail-revenue-leak

Comments

Guest comments. No account required. Max 300 words.

Loading comments…

0/300 words