Stripe Billing and customer-invoice payment surfaces, environment variables, Connect setup, webhooks, and go-live checks.
CentraKit uses Stripe for two distinct money flows:
SaaS subscription billing — organization plans, Customer Portal, metered overage. Stripe is the source of truth for subscription status; CentraKit keeps a local read model and usage aggregates.
Customer invoice payments — tenants collect payment on CentraKit invoices via Stripe Connect destination charges. CentraKit invoices remain the accounting source of truth (numbering, PDF, status history). Stripe PaymentIntents collect funds; CentraKit is the merchant of record.
Never collect or store raw card numbers, CVC, bank account details, legacy Tokens, Sources, Charges, or Card Element data. Prefer the Stripe Payment Element. Never persist PaymentIntent client secrets.
Checkout Sessions in subscription mode start new subscriptions and upgrades.
Stripe Customer Portal handles subscription management, payment methods, invoice history, billing details, and tax IDs where Stripe supports the flow.
Verified webhooks update local billing tables. Checkout and Portal return pages are UX hints only.
Subscription invoice PDF access is mediated by CentraKit before redirecting to Stripe invoice_pdf or Hosted Invoice Page URLs.
Metered usage events are sent to Stripe only for overage after subtracting plan-included quantities.
Audit-log retention is a local plan entitlement, not a Stripe meter: Starter 1 day, Pro 7 days,
Business 90 days, and Enterprise 365 days or a platform-managed subscription override. Keep the
seeded billing_plan_features copy aligned with the retention workflow.
Organizations connect a Stripe Express account under /{orgSlug}/payments (organization.payments.manage).
Online invoice send is blocked until the connected account can receive destination transfers (charges_enabled + enabled status).
On send, CentraKit creates or reuses one PaymentIntent for the immutable invoice total with transfer_data.destination and application_fee_amount from the admin platform_settings.invoice_payment_fee row (percentage bps or fixed minor units; default 150 bps = 1.5%).
Customers pay on /{orgSlug}/portal/invoices/[invoiceId] via the embedded Payment Element. Dynamic payment methods (card, iDEAL, etc.) follow Stripe Dashboard + currency/country configuration.
Mapping lives in invoice_payments. Webhooks update payment + invoice status atomically; browser returns only refresh UI.
Manual mark-paid and invoice cancel cancel collectible PaymentIntents. Refunds and disputes are owned by CentraKit as merchant of record and mirrored into invoice_payments status.
Plan price IDs are not environment variables — keep them in Stripe and the platform database.
Use separate test and live products, prices, Portal configuration, Connect settings, and webhook signing secrets. Enable Connect in the Stripe Dashboard and complete platform profile / approval prerequisites before going live with destination charges.
Create Stripe test products and recurring prices for Starter, Pro, and Business monthly/yearly plans; store the mapping in the platform DB (not env).
Create Stripe meters matching the seeded usage event names such as centrakit_ai_input_tokens, centrakit_ai_output_tokens, centrakit_inbox_messages_sent, centrakit_api_requests, and centrakit_mcp_tool_calls.
Ensure Stripe keys come from the Vercel Stripe integration (pnpm env:pull).
Forward webhooks to the CentraKit Stripe webhook route with the Stripe CLI (include payment_intent.*, charge.refunded, charge.dispute.created, and account.updated for invoice payments).
Configure Stripe Customer Portal in test mode for subscription changes, payment method updates, invoice history, billing details, and tax IDs.
Open /{orgSlug}/billing and /{orgSlug}/usage with organization.billing.manage, and /{orgSlug}/payments with organization.payments.manage.
Complete Connect onboarding for a test organization, send an invoice, and pay via the public and portal surfaces.
Confirm /admin/settings invoice payment fee matches the commercial agreement.
Replay sandbox webhooks and test card, iDEAL, SCA, retry, failure, refund, dispute, cancellation, reactivation, and invoice download scenarios for both subscription and customer-invoice flows.
Test usage overage sync idempotency by retrying a period sync and confirming Stripe does not receive duplicate billable quantities.
Confirm no application code path handles raw payment credentials or legacy Stripe APIs.
Confirm all four plans expose audit logs and the daily retention workflow applies their configured
tier, including any Enterprise override.