ShipVeryFastShipVeryFast
Documentation

Team / seat billing

Per-seat billing means the subscription quantity tracks how many people are on a team. ShipVeryFast ships a teams feature flag (off by default) as a placeholder. This recipe outlines the build on top of the existing billing model.

Model teams and membership

Add teams and team_members tables. A user belongs to a team with a role (owner, admin, member). Bill the team, not the user.

create table public.teams (
  id uuid primary key default gen_random_uuid(),
  name text not null,
  stripe_subscription_id text
);
create table public.team_members (
  team_id uuid references public.teams(id),
  user_id uuid references public.users(id),
  role text not null default 'member',
  primary key (team_id, user_id)
);

Use a quantity-based price

Create a per-seat price in Stripe. The subscription quantity is the seat count, so the checkout you already have just sets a quantity.

Sync seats

When you add or remove a member, update the Stripe subscription quantity. The existing webhook keeps the stored status in step, so access checks stay unchanged.

Build on the billing model

The rule from the billing model still holds: the webhook is the source of truth. Seat changes flow through Stripe and back into your database.