Selling to Teams: Seats, Invoices, and Purchase Orders
The first company that wants to buy ten copies of your app is not a bigger version of your usual customer. It is a different product.
Everything in a normal solo-builder purchase flow assumes one fact: the person who pays is the person who uses the software. Break that assumption and the whole chain falls apart. The card gets charged, the license email fires, and it lands in an accounts payable inbox belonging to someone who will never install your app. The ten people who need the key are still waiting.
Nothing in your code is broken. The wall is procurement, and it is almost always the wall.
The buyer and the user are different people
In a team sale, the person holding the budget and the person launching the app are two different humans, and often three or four. That single split invalidates most of a consumer flow.
Here is what actually happens. A team lead tries your app, likes it, and asks their manager. The manager forwards it to finance. Finance asks procurement to run it. Procurement asks you for a quote, a tax form, and possibly a security questionnaire. Weeks later a purchase order arrives with a billing contact you have never spoken to. Your checkout page collects one email address, so that finance address becomes the license owner. Now the person who evaluated your app has no key, no way to get one, and no admin access to anything.
Three concrete consequences to design around:
The license owner is a role, not a person. Whoever pays should be able to hand administration to someone else without asking you. If your data model has a single customer_email on the license and nothing else, you have a support ticket waiting for you every time a finance team changes.
The delivery email and the billing email are separate fields. Ask for both at purchase. This is a fifteen minute change and it removes an entire category of ticket.
The evaluator needs a path to the keys. The person who championed you internally is your only advocate in that company. If they have to chase finance for a key after the purchase closes, your renewal is already in trouble.
A seat is a person, a device is a machine
A seat entitles one human to use your software. A device activation binds one installation to one machine. These are two separate limits and treating them as one number is the classic mistake in team licensing.
Do the arithmetic. Ten people at a design agency buy your app. Most of them have a work laptop and a studio desktop. That is ten seats and roughly eighteen devices. If you sell them a ten activation license, four of them get locked out in the first week and you spend your Monday resetting activations by hand. The device activation mechanism is the right tool for counting machines. It is the wrong tool for counting people.
So model both, explicitly:
// Seats and devices are separate budgets. Never derive one from the other.
type TeamLicense = {
licenseId: string
organization: string
seatLimit: number // people entitled to use the app
devicesPerSeat: number // machines each person may activate
billingEmail: string // finance. never receives a key.
adminEmail: string // the human who assigns seats.
}
type Seat = {
seatId: string
licenseId: string
assignedEmail: string | null // null means the seat is unassigned
assignedAt: Date | null
devices: string[] // device ids bound to THIS seat
}
function canActivate(license: TeamLicense, seat: Seat): Result {
if (!seat.assignedEmail) return { ok: false, reason: 'seat_unassigned' }
if (seat.devices.length >= license.devicesPerSeat) {
// The person is legitimate. Their machine budget is full.
// This is a self-serve problem, not a sales problem.
return { ok: false, reason: 'device_limit_for_seat' }
}
return { ok: true }
}
The reason codes matter as much as the booleans. seat_unassigned means the admin has work to do. device_limit_for_seat means one person needs to drop an old machine. seat_limit_reached means the company needs to buy more, which is the only one of the three that should ever reach you. Tracking these separately is the same discipline that makes licensing metrics worth reading.
A sane default is two devices per seat. Three if your users own a laptop, a desktop, and a machine at home.
Seat reassignment must not require emailing you
People leave companies. When they do, their seat has to go to their replacement without a support ticket, because you are not going to be awake when a European agency onboards someone on a Tuesday morning.
This is the single highest value thing you can build for team customers, and it is a small feature. An admin needs to unassign a seat, which releases every device bound to it, and assign it to a new email address. That is the whole operation.
async function reassignSeat(seatId: string, newEmail: string) {
const seat = await getSeat(seatId)
// Releasing the seat must release its devices too. A departed
// employee's laptop should stop validating, not linger as a
// phantom activation that eats the new person's budget.
await revokeDevices(seat.devices)
await updateSeat(seatId, {
assignedEmail: newEmail,
assignedAt: new Date(),
devices: [],
})
await sendSeatInvite(newEmail, seat.licenseId)
await recordAudit('seat.reassigned', { seatId, newEmail })
}
Two things people get wrong here. First, they leave the old devices bound, which quietly poisons the device budget until someone complains. Second, they skip the audit record. Companies ask who had access and when, especially the ones with a security questionnaire, and “I do not log that” is a bad answer to give a buyer who is deciding whether to sign.
Do not put a cooldown on reassignment to prevent seat sharing. You will punish real onboarding churn to stop an abuse pattern that barely exists at ten seats. If you want to detect sharing, watch the device tail per seat instead, which is the same signal that shows up in preventing license key sharing.
Procurement will ask for five things you have not built
Companies buy differently from individuals, and the difference is a list of artifacts. None of it is unreasonable. All of it is missing from a typical solo-builder stack.
An invoice instead of a card charge. Above a few thousand dollars, most companies will not put it on a card. They want a document with a PO number on it, and they want to pay it through accounts payable. Stripe handles invoicing directly and that is the right place for it. Your payment processor owns the money side, always. Send the invoice, get paid, then issue the license. If you already use a Stripe integration for consumer checkout, the invoicing path sits alongside it rather than replacing it.
A tax form. US buyers will ask for a W-9. EU buyers will ask for your VAT number and will want theirs on the invoice for reverse charge. Have both ready as files you can send in under a minute.
Net 30 terms. They will pay a month after the invoice date. Plan the cash flow and decide in advance whether you issue licenses on PO receipt or on payment. Issuing on PO receipt is a small credit risk and it makes you dramatically easier to buy from. For a company with a real address and a real procurement department, I issue on the PO.
A quote before the PO. Procurement cannot raise a purchase order against a pricing page. They need a document with your legal entity, the line items, the seat count, the total, a validity date, and a quote number. A one page PDF is fine.
A security questionnaire. Where is data stored, what do you collect, do you have SOC 2. For a ten seat deal it is usually short, and honest answers are acceptable. “No SOC 2 today, here is exactly what we store and where” closes deals. Inventing a compliance posture does not.
Per seat, site licenses, and what to charge
Per seat pricing is right when seat count grows with value and the buyer can count the users. A flat site license is the better sale when they cannot, or when counting is more expensive than the revenue difference.
A site license covers everyone at an organization, or everyone at one location, for one price. It is the correct answer for a fifty person studio where the app gets installed on whatever machine is free, for education and lab environments, and for any buyer whose real objection is “I do not want to keep track of this.” A site license also ends the seat audit conversation permanently, which is worth something to both sides.
On price, two rules.
Per seat pricing for a company buying ten copies should not be your single consumer price times ten. Volume discounting is expected and its absence reads as inexperience. Tiered breaks are enough: full price up to five seats, a discount from six, a bigger one from twenty. The buyer is comparing your total against a competitor total, not your per unit rate against your own pricing page.
And do not build an enterprise tier that is just a device count gate. Charging a person triple because they own four computers is extraction, not pricing, and it is transparent to the buyer. Enterprise pricing should be attached to enterprise work: invoicing and PO handling, seat administration, SSO when it exists, a named support contact, an SLA. Those cost you real time. A fourth Mac costs you nothing. The same logic applies when you are designing licensing tiers generally, and it is why the pricing page here is shaped the way it is.
While we are naming wrong answers: do not build SSO until someone pays you to. SAML and SCIM are weeks of work, they carry permanent maintenance, and they matter at a few hundred seats or when IT owns the purchase rather than the team. Before that, a shared admin login is what your customers actually use. When a named buyer with a real contract says SSO is a blocker, build it then. Not in anticipation.
Do the first deals by hand
Close your first team deals over email with a manual invoice. That is not a stopgap you should feel bad about. It is how you learn what to build.
The first one takes an afternoon. You write a quote, send an invoice, receive the PO, generate ten keys, and email them with a spreadsheet of who has which. Not elegant, and it works. By the fourth deal you will know which parts hurt: probably the seat spreadsheet and the reassignment requests, almost certainly not the invoice. That is your build list, and it will look different from the one you would have guessed.
What you eventually need is an admin surface for the buyer. One place where their admin can see who holds a seat, who has activated, and who left, plus the ability to add and remove people. Everything else can stay manual for a long time. The same self-serve principle that keeps consumer activation support tickets down applies to teams, just with one more layer: the admin fixes their own people, and only pings you when they want to buy more.
Building that admin surface yourself is a real project. Seat records, invitations, device budgets scoped per seat, an audit trail, and a portal login for someone who is not the license owner. It is a few weeks, and then it is yours to maintain. If you would rather not, Keylight covers the seat and device split, self-serve reassignment, and a customer portal where the buyer’s admin manages their own people, with device activations counted per seat rather than per license. Stripe still handles the invoice and the money. Licensing is a separate layer and it stays separate.
Either way, the sequence is the same. Take the deal, do it by hand, then automate the part that hurt.
Frequently asked
What is seat based licensing?+
Seat based licensing entitles a fixed number of people to use your software under one purchase. A ten seat license covers ten named users. It is priced and counted per person, not per installed copy and not per machine.
Is a seat the same as a device activation?+
No, and conflating them is the most common mistake. A seat is a person. A device activation is a machine. One person with a laptop and a desktop is one seat and two devices, so a ten seat license needs a device budget of roughly twenty.
Do I need to build SSO to sell to companies?+
Not for your first team deals. SSO becomes a real requirement somewhere around a few hundred seats or when IT owns the purchase. Build it when a named customer with a signed contract is waiting on it, not before.
How do I handle a purchase order if I only take card payments?+
Send an invoice with net 30 terms through your existing payment processor and issue the license when it is paid, or on receipt of the PO if you trust the buyer. Stripe supports invoicing directly, so this is a process question rather than an engineering one.
Should team pricing be cheaper or more expensive per seat?+
Cheaper per seat than your single copy price, because volume discounting is expected and the buyer is comparing your ten seat total against a competitor total. Charge more for real enterprise work like invoicing, seat administration, and support commitments.
Ready to ship?
Create your account and start licensing your apps in under a minute. Free forever tier included.
Start Free