Billing
Set up and manage billing with Autumn for per-seat pricing
Billing Integration
Billing is already integrated with Autumn for per-seat pricing. Organizations are automatically charged based on the number of members on the Pro plan.
Billing is organization-scoped. Each organization has its own subscription and is billed per user. Autumn can be removed if you don't need billing.
Overview
Unstack Pro uses Autumn for billing:
- Per-seat pricing: Charge per organization member
- Automatic billing: Adding members adjusts billing automatically
- Organization-scoped: Each organization has its own subscription
- Self-service: Users manage billing through Autumn's portal
How It Works
Billing Flow
- User creates an organization
- Organization starts on Free tier (no members allowed)
- Owner upgrades to Pro plan via Autumn
- Pro plan enables adding organization members
- Each member added increases the subscription cost
- Billing is handled automatically by Autumn
Plans
| Plan | Members | Features |
|---|---|---|
| Free | Owner only | Basic organization features |
| Pro | Unlimited | Full member management, teams, custom roles |
Organizations cannot add members until they are on the Pro plan.
Setting Up Autumn
Create an Autumn Account
- Go to useautumn.com
- Sign up for an account
- Create a new project
Get Your API Key
- In Autumn dashboard, go to Settings → API Keys
- Create a new API key
- Copy the key (starts with
am_sk_)
Configure Environment Variables
Set AUTUMN_SECRET_KEY in both environments — the Next.js billing routes read
it at runtime, and the Convex auth hooks read it too:
# Convex deployment
bunx convex env set AUTUMN_SECRET_KEY "am_sk_your_api_key_here"AUTUMN_SECRET_KEY="am_sk_your_api_key_here"Setting AUTUMN_SECRET_KEY in only one environment breaks billing: the checkout /
portal routes 500 in the Next.js runtime, or seat syncing fails in the Convex
hooks. Set it in both.
Push Your Products
Plans are defined as code in autumn.config.ts (a free_plan and a
seat-metered pro plan). Push them to your Autumn account with the Autumn CLI:
bunx atmn login # authenticate the Autumn CLI
bunx atmn push # create the products from autumn.config.tsEdit autumn.config.ts to change the plans, price, or billing interval, then
bunx atmn push again.
Managing Subscriptions
Organization Billing Page
Organization owners and admins can manage billing at /organizations/[slug]/billing:
View Subscription:
- Current plan status
- Number of seats/members
- Price per seat
- Next billing date
- Total monthly cost
Manage Subscription:
- Upgrade to Pro
- Access Autumn billing portal
- View order history
- Download invoices
Autumn Customer Portal
Users are redirected to Autumn's hosted portal for:
- Updating payment method
- Viewing invoices
- Managing subscription
- Canceling subscription
// Example: Redirect to billing portal
const handleManageBilling = async () => {
const portalUrl = await getBillingPortalUrl(organizationId);
window.open(portalUrl, "_blank");
};Per-Seat Billing Logic
Adding Members
When a member is added to an organization:
- System checks organization has Pro plan
- If on Pro, member is added
- Autumn automatically updates seat count
- Next invoice reflects new seat
Removing Members
When a member is removed:
- Member is removed from organization
- Seat count decreases
- Prorated credit applied (depending on Autumn settings)
Example Pricing
| Members | Monthly Cost (at $10/seat) |
|---|---|
| 1 (owner) | $10 |
| 5 | $50 |
| 10 | $100 |
| 50 | $500 |
How It's Wired Up
Billing is integrated through Better Auth organization hooks, not a webhook endpoint. The key pieces:
autumn.config.ts— thefree_plan/proproduct definitions, pushed withbunx atmn push.convex/betterAuth/auth.ts—organizationHookscall into the billing integration:afterCreateOrganizationinitialises the Autumn customer for the org.afterAcceptInvitation/afterRemoveMembersync the seat count.beforeCreateInvitation/beforeAddMember/beforeAcceptInvitationgate on a paid plan and throwAPIError("BAD_REQUEST", …)if the org lacks one.
lib/autumn-server.ts— an SDK-free REST client used from the Convex runtime (theautumn-jsSDK is too large for Convex's 64 MB isolate).lib/autumn.ts— the fullautumn-jsSDK, usable from Node server pages.app/api/autumn/[...all]/route.ts— the Next.js billing route (checkout, portal); it readsAUTUMN_SECRET_KEYat runtime in the Node runtime and is gated to org owners/admins.
Subscriptions are organization-scoped and billing is keyed per URL organization
via the x-organization-slug header. If you add a flow that grows seat count or
invites members, hook it into organizationHooks in convex/betterAuth/auth.ts.
Billing Route
Organization owners and admins manage billing at
/organizations/[organizationSlug]/billing (plan status, seats, upgrade, and the
Autumn portal link).
Removing Billing
If you don't need billing:
Remove Environment Variable
Remove AUTUMN_SECRET_KEY from both the Convex deployment and .env.local.
Update Organization Logic
Modify member addition to not check for Pro plan:
// Remove the plan check in add member logic
export async function addMember(organizationId: string, userId: string) {
// Skip: const canAdd = await canAddMembers(organizationId);
await db.insert("members", {
organizationId,
userId,
role: "member",
createdAt: Date.now(),
});
}Remove Billing UI Components
Remove billing-related components and references from:
- Organization sidebar
- Organization settings
- Dashboard cards
Troubleshooting
Subscription Not Updating
Check:
- Autumn API key is correct
- Webhook endpoint is configured
- Organization ID matches Autumn customer ID
Payment Failed
User should:
- Access billing portal
- Update payment method
- Retry payment
System should:
- Send notification to organization owner
- Gracefully handle expired subscriptions
- Provide clear upgrade path
Can't Add Members
Verify:
- Organization is on Pro plan
- Subscription is active (not canceled)
- No payment failures
Best Practices
- Clear pricing: Show per-seat cost clearly
- Upgrade prompts: Guide users to upgrade when needed
- Graceful degradation: Handle expired subscriptions gracefully
- Email notifications: Notify users of billing events
- Audit trail: Log billing-related actions
- Test in sandbox: Use Autumn's test mode before production