Teams
Shared workspaces where analysts each have their own keys but draw from one quota pool.
Teams let a workspace owner invite analysts to share their Reput.io subscription without creating separate billing accounts. Each team member gets their own login, their own API keys, and their own security settings — but all activity rolls up to one pool of quota and one billing relationship.
Inviting team members is a Team (or Enterprise) plan feature. Pro users can keep any members already invited but can't add new ones without upgrading.
Roles
There's one non-owner role in the MVP:
- Owner — the account that pays for the subscription. Has full admin rights: invite / remove members, manage billing, manage webhooks, mint their own keys.
- Viewer — invited analysts. Can log in, mint their own API keys, run lookups, see dashboard / usage / audit log. Cannot change billing, manage webhooks, or invite other members.
How the invitation flow works
Owner Reput.io Invitee
│ │ │
├──── POST /team/invite {email} ──────┤
│ │ │
│ ◄── token + email sent ─────────┤
│ │ │
│ ├──── Email with link ──►│
│ │ │
│ │ ◄── GET /team/accept?token=… ─┤
│ │ │
│ ◄── GET /team/members (member now listed) ────────┤
- Owner enters an email →
POST /team/invite - Backend stores a 64-hex token, 7-day TTL, and emails the link to the invitee
- Invitee opens the link. If they don't have a Reput.io account yet, they must create one with that email first (we don't auto-provision)
- Once signed in, they click Accept invitation →
POST /team/accept { token } - A row is inserted in
team_members; their API keys and sessions immediately resolve to the owner's workspace
The link is the capability
We don't strictly enforce that the accepting user's email matches the invited email — whoever clicks the link accepts. This matches the pattern used by Linear, Notion, and Resend. If you need stricter matching, tell us and we'll add it.
Shared quota
All requests from the owner and all members count against one daily budget (the owner's plan limit) and one burst cap. A team of 4 analysts on Team plan shares the 100,000/day + 300/min budget however they actually use it — no fair-share enforcement.
Usage is attributed per member on the backend: each row in user_usage records who actually made the request. That's why the dashboard can show you "Alice used 5,231 today / 47,002 this month" — the pool is shared, but the breakdown is fair.
Per-member keys
Every user — owner or viewer — has their own API keys:
- Keys show up on the key-owner's dashboard only
- Owner never sees the viewer's full key value (not even once — that's revealed to the viewer on creation)
- When a viewer validates a request, we resolve their key to the owner's workspace (shared quota, shared plan) but attribute usage back to the viewer
- Each person's per-plan key limit applies to them individually
Removing a member
When the owner clicks Remove in /settings/team:
- The
team_membersrow is deleted - The viewer's cached API-key entries in Redis are invalidated
- Their keys keep working — but on the next request they resolve as the viewer's personal account, typically Free tier (500/day)
- The viewer loses access to the dashboard's team views (member list, breakdown, owner's billing)
This means Remove is an immediate budget-control action — it stops further drain on your team pool without revoking keys the analyst may have deployed to production. The analyst gets one week of grace at Free quotas to either accept a new Team invitation elsewhere or wind down.
Endpoints
/team/usage response (owner)
{
"role_of_current_user": "owner",
"team_usage_today": 2387,
"team_usage_month": 41298,
"breakdown": [
{
"user_id": "…",
"email": "alice@acme.com",
"role": "owner",
"usage_today": 412,
"usage_month": 8021,
"active_keys": 2,
"is_me": true
},
{
"user_id": "…",
"email": "bob@acme.com",
"role": "viewer",
"usage_today": 1975,
"usage_month": 33277,
"active_keys": 1,
"is_me": false
}
]
}
Viewers get the same response shape but with only their own row in breakdown — they see their personal usage and the team total, not the breakdown of other members.
Limits
- Up to 10 total (members + pending invites) per workspace
- A user can be a viewer of at most one workspace at a time
- Invites expire after 7 days
- A workspace owner cannot be a viewer anywhere simultaneously
What viewers can NOT do
For clarity, here's the explicit deny list. Attempting any of these as a viewer returns 403 Forbidden:
- Invite new members
- Remove members / revoke invites
- Change the subscription plan
- Create or revoke webhooks
- Call
/internal/update-subscription - Change MFA settings for the owner (their own MFA works fine)
- Delete the owner's account (their own delete works fine — it just cleanly removes them from the team)