Single checklist spine for shipping Accrue-backed billing in a real Phoenix SaaS. It does not replace the deep guides — it tells you what to verify and where to read next. Accrue stays Stripe-first and host-owned for auth, tenancy, secrets, and export delivery.
Before you treat billing as “done”
Work through the sections in order the first time you promote to production; later you can skim by risk area.
1. Install pins and upgrades
- [ ]
accrue/accrue_adminuse the same published~>line;mix.lockis the stability boundary for pre-1.0 minors. See First Hour — Install the packages and Upgrade guide.
2. Runtime secrets and config
- [ ]
:stripe_secret_keyand:webhook_signing_secretare read fromconfig/runtime.exs(or equivalent), not compile-time config. See Configuration. - [ ] Optional adapters (
:auth_adapter,:invoice_pdf_adapter,:pdf_adapter,:mailer) match how you run in prod vs dev/test.:invoice_pdf_adapterowns invoice rendering;:pdf_adapterremains the lower-level HTML seam. See Configuration. - [ ] If you ship Braintree,
portal_mount_pathmatches the mountedaccrue_portalroute andportal_base_urlis an absolute host URL in the same runtime environment that generates checkout and billing portal links. See Braintree local portal. - [ ] If you ship Braintree and expose
Accrue.Billing.swap_plan/3or admin-driven plan swaps,:plan_resolveris configured in runtime config and resolves app-facingprice_ids to Braintree plan metadata. See Lifecycle semantics and Braintree local portal.
3. Webhooks (highest ROI failure surface)
- [ ] Raw-body capture runs before
Plug.Parserson the Stripe webhook route. See Webhooks and Webhook gotchas. - [ ] Signing secret(s) match the Stripe Dashboard endpoint(s); you understand test vs live mode boundaries. See Troubleshooting — webhook anchors.
4. Tenancy and billables
- [ ] Billable
owner_type/owner_idand admin queries match your org model; cross-tenant paths are denied at the host boundary. See Organization billing (Sigra and non-Sigra recipes).
5. Tax and pricing rollouts (if enabled)
- [ ] Customer tax location and rollout safety match your Stripe Tax story — no “flip automatic tax” surprises on legacy subscriptions. Cross-check Organization billing and Stripe’s own tax docs via your finance process.
6. Observability and operations
- [ ]
:telemetryhandlers (and optional OpenTelemetry) are wired in the host app for the ops events you need on-call. See Telemetry and Operator runbooks. - [ ] If you explicitly chose
Accrue.InvoiceRenderer.ChromicPDF, the host supervision tree startsChromicPDFand theaccrue_mailersqueue concurrency does not exceed the ChromicPDF pool size. See PDF Rendering. - [ ] Invoice assets and fonts are validated on the renderer you actually run in production, including invoice attachments sent through email. See Branding and PDF Rendering.
- [ ] If you ship Braintree, Hosted Fields and the portal CSP are production-ready before customers can open local checkout. Treat discount preview as provisional UI and final submit as the authoritative subscription result. See Braintree local portal and Telemetry.
7. Testing stance in CI vs live
- [ ] Merge-blocking Fake / host proof path is green (
mix verify/mix verify.fullper your policy). See Testing. - [ ] Stripe test-mode and live lanes are understood as non-merge-blocking unless you explicitly chose otherwise. See repo
guides/testing-live-stripe.md.
8. Finance and compliance boundaries
- [ ] Revenue recognition / accounting stays downstream of Accrue; you use Stripe-native handoff where appropriate. See Finance handoff.
9. Customer portal and hosted surfaces
- [ ] Stripe Billing Portal / Checkout expectations match what you expose to end users. See Portal configuration checklist and Branding for customer-facing polish.
- [ ] Braintree expectations stay provider-honest: checkout and billing portal URLs are mounted local URLs, there is no upstream hosted fallback, and checkout completion is persisted locally after the mounted flow succeeds. See First Hour and Braintree local portal.
- [ ] Braintree admin/operator expectations stay provider-honest: immediate cancel is first-party, plan swap is first-party only when
:plan_resolveris configured, and scheduled-end cancellation plus pause/resume remain host-owned or unsupported. See Lifecycle semantics.
10. Admin access
- [ ]
Accrue.Auth(or Sigra adapter) enforces who may openaccrue_adminroutes in production. See Auth adapters.
Proof vocabulary (local / CI)
For the canonical Fake-backed walkthrough and VERIFY-01 vocabulary, keep using examples/accrue_host/README.md alongside First Hour.
See also
- Maturity and maintenance — maintainer-facing diminishing returns and FRG-01 intake context (monorepo
.planning/pointers).
Explicit non-goals (until a milestone says otherwise)
Second processor (PROC-08), app-owned finance exports (FIN-03), and Stripe Dashboard–only workflows that Accrue does not own — see the package README Stability / deprecation posture and repository RELEASING.md for maintainer boundaries (clone-only planning detail lives under .planning/PROJECT.md in the GitHub repo).