| name | billing |
| description | Use when changing Comp AI billing, Stripe products/prices, subscription checkout, org payment methods, entitlements, usage ledgers, invoices, or billing webhooks. |
| metadata | {"short-description":"Comp AI billing architecture"} |
Billing
Comp AI billing is SKU-first and subscription-ready. Stripe is the payment provider; Comp AI owns catalog definitions, entitlement state, usage gating, and audit history.
Core Rules
- Use
@trycompai/billing for SKU keys, amounts, Stripe product IDs, Stripe price IDs, cadence, and included usage.
- Do not add product-specific nullable fields to
OrganizationBilling.
- Keep org-level billing generic:
stripeCustomerId, stripePaymentMethodId, and paymentMethodUpdatedAt.
- Store per-product state in generic per-SKU tables keyed by
skuKey.
- Gate paid actions from local entitlement/usage state, not directly from Stripe object reads.
- Treat Stripe webhooks as eventually consistent, retryable, and possibly out of order.
- Make webhook and entitlement handling idempotent with Stripe event IDs, invoice IDs, subscription item IDs, and period start/end.
- Archive accidental live/test Stripe objects instead of reusing them blindly.
Current SKU Shape
- Active background-check subscriptions:
background_checks_monthly_3 ($79/mo, 3 checks), background_checks_monthly_10 ($199/mo, 10 checks), and background_checks_monthly_20 ($399/mo, 20 checks).
- Active penetration-test subscriptions:
pentest_monthly_1 ($299/mo, 1 scan), pentest_monthly_3 ($499/mo, 3 scans), and pentest_monthly_5_current ($899/mo, 5 scans).
- Deprecated / legacy SKUs remain in the catalog for historical Stripe records:
background_check_one_time, background_checks_monthly_25, pentest_monthly_4, pentest_monthly_5, and pentest_monthly_10.
Live catalog entries should only be added after deliberate live Stripe object creation.
Implementation Pattern
- Add or update SKU definitions and Stripe IDs in
packages/billing/src/index.ts and packages/billing/src/sku-definitions.ts.
- Store Stripe IDs in the catalog by environment rather than adding new env vars.
- Create subscriptions through Stripe Checkout
mode: subscription.
- Use the shared Stripe customer default payment method unless the product explicitly needs overrides.
- For allowance products, sync local subscription state from Stripe subscription items and period timestamps.
- Record usage in the billing usage ledger with a stable idempotency key.
- Record support-relevant mutations in billing audit events.
Webhooks
Handle these events before launching subscription access:
checkout.session.completed
invoice.paid
invoice.payment_failed
invoice.payment_action_required
customer.subscription.updated
customer.subscription.deleted
Provision or renew allowance only for the matching subscription item and SKU. Do not use generic invoice-level periods for multi-item subscriptions.
Validation
- Run
bun run db:generate after Prisma schema changes.
- Run
bun run check:prisma-schemas to catch stale copied schema fragments.
- Run catalog tests after SKU changes.
- Add webhook tests for duplicate events, out-of-order delivery, payment failure, action required, cancellation, and renewal.