Auth, invites, and roles
How teammates get project access — People settings, invite lifecycle, and owner vs member.
Invite flow (shipped)
- A project owner opens Settings → People and clicks Invite.
POST /api/projects/{slug}/memberscreates a pendinginvitationsrow (requires owner viagetProjectForOwner).- Invite email is sent with an accept URL. On email failure the invite row is deleted.
- The invitee signs in and accepts (
/api/invites/{inviteId}/accept). - Accept fails if the signed-in email does not match the invite email.
- On success they become a
project_membersrow and can open the project.
Invite operations
| Action | HTTP | Who |
|---|---|---|
| Create invite | POST /api/projects/{slug}/members | Owner |
| CSV import invites | POST /api/projects/{slug}/members/import-csv | Owner |
| List people | GET /api/projects/{slug}/members | Project member |
| Resend | POST /api/projects/{slug}/invites/{inviteId} | (UI from People) |
| Revoke | DELETE same invite path | (UI from People) |
| Remove member | DELETE /api/projects/{slug}/members/{userId} | Owner; cannot remove last member |
| Accept | /api/invites/{inviteId}/accept | Invitee (matching email) |
Expiry
- New invites set
expiresAtto now + 14 days. - Rows past expiry are ignored at lookup (
expiresAtnull or future required). - Expired invites show unavailable to the invitee — create or resend from People.
Default invite / membership role when unset: member.
Roles
People UI options:
| Value | Label |
|---|---|
owner | Project owner |
member | Member |
Owner-gated actions (verified)
| Area | Gate |
|---|---|
| Invite / CSV invite / remove members | getProjectForOwner → 403 otherwise |
| Connectors connect/disconnect | isProjectOwner / role === "owner" |
| Creating agents / owner-only agent fields | Owner checks in agents API |
| Some Home / Stripe / project mutation routes | Owner access required messages |
Members can still use most analytics surfaces (Replays, Dashboard, Issues, etc.). Treat owner as required for people administration and connector/agent integration changes.
Not every route’s role check is listed here — use UI disablement and 403 responses as the practical guide.
General access control (People UI)
Settings → People shows General access (Restricted / Anyone with the link / domain). Changing the select updates local React state only in the current frontend; persistence and server enforcement are not verified as wired. Rely on membership + invites for access control.
Wizard approval vs People invites
| Mechanism | Grants |
|---|---|
| People invite | Dashboard membership for a human email |
Wizard device flow (wizard_sessions) | Approved project API key for CLI install |
Approving the wizard does not invite a teammate to the project UI.