FullstackPhoenix

Payments Billing Facade for Phoenix

phoenixpaymentsbillingstripesaas

You're about to take your first paying customer. You can wire Stripe directly into a LiveView in an afternoon — but a year from now, when you want to add an alternative provider, run a small experiment with usage-based pricing, or replace the implementation, every call site needs to change. Starting with a thin facade costs almost nothing now and saves real work later.

This is a decision feature. Installing it adds MyApp.Billing — the facade the rest of your application calls — and prompts you to pick a provider implementation. Today, the only provider variant is stripe_subscription, which creates Stripe-hosted Checkout sessions using Req. It is deliberately a starting point, not a full subscription system.

A billing seam, not a billing nightmare

Coupling your application code directly to Stripe's API in random LiveViews is a classic source of refactor pain. A facade is not "premature abstraction" here — it is the one piece of structure that makes payment work survive a change of mind about provider, pricing model, or even what "purchase" means.

What This Feature Adds

  • lib/my_app/billing.ex — the MyApp.Billing facade module that application code calls (MyApp.Billing.create_checkout(...), etc.)
  • A decision prompt at install time asking which provider to install. The only current option is stripe_subscription
  • The selected provider's instructions are run on top of the shared facade install, producing a working implementation behind the facade
  • An expectation that webhook verification and access-granting logic are added by you, not by this install

How It Fits Into Your Phoenix Application

Application code calls MyApp.Billing and never references the provider directly. The provider implementation (today: MyApp.Billing.StripeSubscription) handles the provider-specific work. Swapping providers, or adding a second one for a regional market, is a matter of writing a new module and changing the configuration — not changing every call site.

The "decision" is recorded by the installer so subsequent features that depend on a specific variant can check for it. See stripe_subscription for the details of the provider implementation that ships today.

Installation Notes

  • Hard dependency: authentication. The billing facade assumes there is a user to charge.
  • Install command: mix saaskit.feature.install payments --decision provider=stripe_subscription (or interactively).
  • The current install creates Stripe Checkout sessions and redirects the user there. A successful redirect is not proof of payment. Granting access requires verified webhooks, which this install does not add.
  • After install: set STRIPE_SECRET_KEY and STRIPE_SUBSCRIPTION_PRICE_ID, then plan webhook handling before flipping anything customer-facing on.

Build This With Live SaaS Kit

Install saas_kit, then mix saaskit.feature.install payments --decision provider=stripe_subscription to put a real billing seam in place, with the smallest viable Stripe integration behind it.