Agency Stripe Client Billing Model
Purpose
This document defines how Stripe should fit into the agency manager product.
It answers the specific planning question: if agencies bill their own clients through this app, what should the Stripe model actually be?
Product Stance
The app should behave like a domain-aware operational layer on top of Stripe for agency-to-client billing.
It should not try to replace Stripe as the finance system.
Core Billing Relationship
There are three distinct billing relationships in this product:
agency -> this SaaS productManaged by the app's existing Polar-based org billing.agency -> its clientsManaged through the agency's own Stripe account.client -> Stripe-hosted payment experienceExposed through invoices, hosted payment pages, and customer portal flows.
Only the second and third belong to the new agency billing domain.
Recommended Stripe Architecture
Planning recommendation
Use a Stripe Connect-style model where each agency connects its own Stripe account to the app.
The app then performs billing operations on behalf of that connected account.
Why this is the right shape
- agencies keep their existing Stripe relationship
- agencies can still use the Stripe dashboard directly
- the app can become the workflow layer for client-account billing
- Stripe-native customers, invoices, subscriptions, and billing portal features remain usable
Planning note on account type
The likely default fit is an agency connecting an existing Stripe account through a Connect/OAuth-style flow.
If an agency does not already have Stripe, the product can later support creating a Stripe-connected account through onboarding flows.
The important product-level decision is not the exact first API call. It is this:
- the agency owns the Stripe account
- the app acts on behalf of it
What The App Must Know
At minimum the app needs to know:
- which agency has connected Stripe
- the connected Stripe account id
- whether the connection is healthy and usable
- whether onboarding requirements are incomplete
- which client account maps to which Stripe customer
What The App Should Operate
Customer mapping
For each client account, the app should be able to:
- create a Stripe customer in the agency's Stripe account
- link an existing Stripe customer if needed later
- keep rich billing identity and defaults on the client account surface
- keep the internal client-billing mapping synchronized behind that client account
- let the client account control Stripe customer defaults such as invoice prefixes and invoice rendering template selection
Invoice operations
The app should eventually support these actions from the org side:
- create draft invoice
- add line items or use presets
- finalize invoice
- send invoice or invoice link
- view invoice status
- void invoice when necessary
For the portal side:
- view invoices
- open hosted invoice/payment experience
- understand paid, due, overdue, failed, void, and draft states
Subscription operations
The app should eventually support these actions from the org side:
- create recurring subscription/retainer for a client account
- choose or map service/price context
- update or cancel subscription
- view subscription status and renewal state
Planning rule:
- subscriptions are anchored to the client account first
- subscriptions may optionally reference a project or engagement when that adds clarity
- the product should not require project setup before recurring billing can happen
For the portal side:
- view subscription/retainer status
- access billing portal/payment method flows where appropriate
- understand what service the subscription represents
Billing portal operations
The app should be able to create Stripe-hosted billing portal sessions or equivalent customer billing entry points for the client.
This is preferable to rebuilding payment-method management UX from scratch.
What Should Remain Stripe-Native
- payment method storage
- hosted invoice payment flow
- customer billing portal flow
- invoice object truth
- subscription object truth
- charge/payment outcome truth
The app should project this state, not replace it.
What The App Should Mirror
The app should mirror enough Stripe state to power product UX and tenant-safe queries.
Likely mirrored records:
- agency Stripe connection state
- internal client billing mapping
- invoice summary records
- subscription summary records
- billing event history where needed for audit/troubleshooting
Likely mirrored fields on invoice records:
- Stripe invoice id
- Stripe customer id
- client account id
- status
- amount due / amount paid
- currency
- due date
- hosted invoice url when available
- linked subscription id if applicable
- timestamps
Likely mirrored fields on subscription records:
- Stripe subscription id
- Stripe customer id
- client account id
- status
- current period start/end
- cancel-at-period-end state
- mapped service/retainer label
- linked price or plan metadata
- optional engagement id
- optional project id
Webhook Model
Billing sync should be webhook-driven.
Important events likely include:
- invoice finalized
- invoice paid
- invoice payment failed
- invoice voided
- customer subscription created
- customer subscription updated
- customer subscription deleted/canceled
The app may also have repair or manual resync tools later, but webhooks should be the primary synchronization path.
Product Features Implied By This Model
If Stripe is this central, these product features become justified:
- agency Stripe connection management
- service catalog or pricing presets
- invoice workflow UI
- subscription/retainer workflow UI
- billing summaries in org and portal
- client payment entry points through Stripe-hosted experiences
- billing sync health/admin diagnostics
Features The Product Should Not Fake Early
- custom payment method vaulting outside Stripe
- custom subscription engine outside Stripe
- app-only invoice state that can drift away from Stripe
- app-only payment outcome logic that disagrees with Stripe
Route Ownership
Org
The app should eventually expose:
- billing overview
- customer-detail billing tab and invoice/subscription detail routes
- invoice creation and management
- subscription creation and management
- Stripe connection setup and health
Portal
The app should eventually expose:
- invoice history
- subscription/retainer summary
- payment status
- Stripe-hosted payment/billing portal entry points
Settings split
Keep this separation clear:
org/settings/billingagency pays for this apporg/(dashboard)/billingagency bills its own clients through Stripe
Current route rule:
- do not create a separate user-facing billing-profile route when the billing relationship already lives on the client account plus invoice/subscription routes
Final Planning Rule
When deciding whether a billing feature belongs in the app or in Stripe, use this test:
- if it is core finance infrastructure Stripe already solves well, leave it Stripe-native
- if it needs client-account context, agency workflow context, or portal presentation, the app should own that layer