Seats and team management
How teams are invited, what a seat is, exactly which actions occupy one, and how machine credentials stay seat-free.
A Voltro seat is one identified natural person. Not a login, not a token, not a machine — a human. Everything on this page follows from that single definition.
This page is the published boundary: what occupies a seat, what does not, and how the product makes both visible before an invoice does.
Membership is not a seat
Two separate things, deliberately:
| What it answers | Cost | |
|---|---|---|
| Membership | May this person act in this org? | Free — invite as many as you like |
| Seat | Does this person consume one of your purchased seats? | Counted |
A seat is occupied by active work. Watching is free: a manager following a deploy, a product owner reading logs, an accountant paying the invoice — all need a membership, none need a seat.
What occupies a seat
The list below is the complete one the server consults. It is an allowlist, which has a consequence worth stating: an endpoint that is not on it is free, so a newly shipped feature can never quietly start costing you money.
Occupies a seat
- Deploy an app · roll a deployment back
- Create or delete a project · create an app · create an environment
- Register a custom domain
- Change environment variables
- Submit or approve a migration plan
- Create a service token · invite a teammate
Free — no seat
- Read logs, view metrics, follow deployment status
- View usage and invoices
- View the team
The same list is rendered inside the dashboard, on the team page, next to your live seat count. There is exactly one list — the server and the UI read the same file — so what you are told and what you are charged for cannot drift apart.
One person, one seat
Occupancy is keyed on (organisation, person) and enforced by a unique constraint in the database, not by application logic. In practice:
- Five machines, three rotated CLI tokens, two browser sessions → one seat.
- A contractor working in five client organisations → five seats, one per client. Whoever works inside an org occupies a seat of that org; there are no cross-org seat pools.
- Activity is recorded coarsely and debounced. Forty deploys in an afternoon are one write, not forty — the ledger records that you worked, not every request.
Inviting people
Invite by personal work email — one address per person.
- An owner or admin sends the invitation. A pending invitation is created and a single-use, expiring link is emailed.
- The invitee opens the link. They can read who invited them, to which organisation, and in which role without signing in — the token is the authorisation for that preview, and it grants nothing else.
- They sign in (or sign up) with the invited address and accept.
The accepting account's email must equal the invited address. This is where "personal accounts" stops being a clause and becomes a check: forwarding a link to a colleague, or into a shared inbox that another account reads, cannot produce a membership. Plus-tagged variants (name+something@) count as a different address — loosening that match is exactly how one invitation would start covering two people.
Two supporting behaviours:
- Shared-looking addresses warn, but are not blocked.
info@,team@,dev@raise an inline warning. They are not refused, becausedev@genuinely is one person at a two-person shop, and address patterns missbuero@andkontakt@anyway. The email match at acceptance is what actually enforces the rule. - Resending rotates the token. The old link stops working. That keeps revocation total and covers the usual reason for a resend — the first link landed somewhere the person no longer reads.
Invitations can be revoked at any time. Revocation is immediate: acceptance requires a pending invitation.
Service tokens — CI without a seat
CI needs a credential. If the only credential were user-bound, every team would paste a human's token into their pipeline — which is precisely the credential sharing the terms forbid. So machines get their own class:
Service token: org-scoped · no seat · individually revocable · automation scopes only
Valid scopes are deploy, build, register and inventory — an automation-only set. Interactive development is not among them and never will be: requesting it is rejected outright. That boundary is what stops the seat model from being bypassed by routing every developer's work through one machine credential.
A token's value is shown once, at creation. Only its hash is stored, so there is no "show it again" and no support path that could reveal it. Revoking is a soft flip: the token stops working immediately, and the record of what it did survives.
Going over your seats
Nothing is blocked. Person 21 on a 20-seat plan starts working immediately; the extra seat appears on the next invoice as the contractual true-up.
Because nothing blocks, the warnings are the safeguard, not a nicety:
| State | What you see |
|---|---|
| Below 80 % | Your seat count, plainly |
| From 80 % | An advance warning on the team page |
| Every seat occupied | The next person to work will be an additional seat |
| Over | How many seats beyond your purchase, and that they will be invoiced |
Suspension exists only for non-payment or abuse, through the contractual process. A developer is never locked out mid-sprint over a seat count.
Where your seat count comes from
Two numbers can define your limit, and the more specific one always wins:
| Situation | Your limit is |
|---|---|
| You have a paid subscription | Its seat quantity — what you bought |
| No subscription | The seats included with your plan |
| Free or Enterprise | Uncapped — Free is gated on projects × apps, Enterprise contractually |
The team page names which of the two applies, so "of 40 on your subscription" and "of 10 included with Team" are never confused. If you buy 40 seats on a plan that includes 10, your limit is 40 — the number you paid for governs.
A cancelled subscription stops granting its quantity and you return to the free tier's limits. A failed payment does not: while a card is being retried your team keeps working, because locking an organisation out over a bank decline is a support incident, not enforcement.
Self-hosted
Seats work the same way when you run Voltro yourself, and self-hosted development is attributed to a person — which is what makes the model measurable rather than aspirational.
Signing in. Voltro Cloud accounts are authenticated by WorkOS — always, in every environment. There is no password, no fixed code, and no local fallback: if WorkOS cannot verify you, you are not signed in.
Getting a personal credential
Generate one from your team page ("Your CLI credential"), then store it:
voltro cloud login --token <token>It is org-scoped and personal. Org-scoped because a contractor working in five client organisations occupies five seats, one per client — so generate one per organisation you work in. Personal because the control plane records who it belongs to, and that link is the whole basis of self-hosted attribution.
What is sent
voltro dev reports a coarse daily heartbeat:
organisation · person · project slug · CLI version · UTC day
Never source, never schema, never data, never file names, never command arguments. That is the complete list, and it is asserted by a test that fails if a field is added — so growing it takes a deliberate decision, not a careless commit. What we do with it, on what legal basis, and for how long is set out in the Privacy Policy under "Developer and usage data".
If you license Voltro for a team, note that you are responsible for informing the people concerned. Administrators see who occupies a seat and the date of last activity — never what anyone did.
Three properties you can rely on:
- Debounced. At most one report per day per project. Restarting your dev server forty times is one heartbeat.
- Offline-tolerant. A failed send is remembered and flushed on a later run. Working on a train is a gap in a chart, not a licence problem.
- It never fails a command. Every error path is swallowed. Telemetry that can break
voltro deveventually will.
Not logged in? Nothing is sent, nothing is warned about, and nothing is slower. That is the normal case for most local development.
Machine credentials are refused
voltro dev requires a personal credential. A service token belongs to no person, so it is rejected with an explanation rather than silently counted:
voltro dev needs a personal login — the stored credential belongs to no user.Without that boundary, a team could route every developer's work through one shared machine token and occupy zero seats. Deploying with a service token stays fine — deploying is not developing.
From activity to an invoice
A nightly job closes the loop, and your team page shows both halves side by side:
| What it is | |
|---|---|
| Live count | Who occupies a seat right now — moves as people work |
| Billing period | The rolled-up figure for the month, including the self-hosted share |
The rollup is idempotent, so a retried job cannot double-count. The two numbers differ between runs by design: one is what your team is doing, the other is what a bill would say, and showing only one of them is how a customer ends up arguing with a dashboard.
Air-gapped and enterprise deployments attest seats contractually instead; no telemetry path is required.
Related
- Voltro Cloud — the control plane these features live in
- Self-hosting — running Voltro yourself