This Worker runs alongside the admin-api Worker but has a distinct responsibility. It does not serve operator UI traffic — it serves Stripe webhooks, internal metering events, and scheduled reconciliation jobs.
The 5 existing Stripe Prices are all type=one_time and unsuitable for subscription billing. New Prices must be created:
1 × recurring licensed Price — flat subscription (one Price per plan tier, or unit_amount set per-subscription). Maps to account_plan_sub.sub_rate.
3 × recurring metered graduated Prices — one each for ST, RM, CV impression types. Each Price encodes the tier thresholds from account_plan_usage.
No standing Price for managed services — InvoiceItem created at billing time with the exact job amount.
Existing one-time Prices archived after all customers are migrated off them (B.5 → B.7).
Non-standard arrangements (flag for individualized migration)¶
Confirmed from repo analysis: the mix of pricing models includes custom per-account arrangements handled as manual InvoiceItems in billing_service. These must be inventoried per-customer from the Stripe invoice history and billing_invoice DB before B.6. Each requires a migration note in the cohort runbook (see Chapter 03).
Source: Redshift impression counts, queried by billing_service via Pdo_model
Event shape:{account_id, period (YYYY-MM), usage_type (ST|RM|CV), quantity}
Idempotency key:{account_id}:{period}:{usage_type} — prevents double-counting on retry
Target: Billing Worker POST /usage → Stripe Usage Record API (Meter or legacy create_usage_record)
Frequency: Can be as-accrued (daily push from stats pipeline) or end-of-period summary — either works with metered Prices; daily push reduces cutover risk
Added:stripe (Workers-compatible), handlebars (or a Workers-compatible fork), PDF rendering lib or Cloudflare Browser Rendering binding, mailgun.js or HTTP client.
Removed (end of B.8): legacy rollup job, billing calculation code, PHP PDF renderer, any custom dunning scheduler.
Unit: Vitest for handler logic, signature verification, idempotency keys, RBAC on /admin/* endpoints.
Integration (Stripe test mode): seeded fixture customers + prices; run full invoice lifecycle end-to-end; assert rendered PDF bytes match golden snapshot (≥ tolerance for date fields).
Mail deliverability: Mailgun test mode / sandbox domain before live cutover.
Reconciliation: daily Cron Trigger compares Stripe totals to Acodei / QuickBooks totals; alerts on drift.
Cohort gate: per-cohort dual-run. A cohort is "migrated" only after one full billing cycle with zero reconciliation drift.
Rollback per cohort: cohort can be moved back to legacy rollup until B.8 retires the legacy code. After B.8, rollback is recovery-from-backup only — so B.8 should come with extra scrutiny.