Technical docs

Invite Acceptance Flow

Overview

Support reference for the public invite page: `/invite/[code]`.

For shared login/session bootstrap behavior outside the invite-specific UX, see auth-and-session.md.

Verified routes

  • `GET /api/invites/{code}`
  • `GET /api/invites/{code}/accept`
  • `GET /api/auth/google`
  • `GET /api/auth/google/callback`

Page states

  • The page waits for auth bootstrap, then loads `GET /api/invites/{code}`.
  • The invite code comes from the route param first and falls back to `?code=...`.
  • Backend returns one of:
  • `ready_to_accept`
  • `already_in_organization`
  • `not_found`
  • The response includes organization `id`, `name`, and `description` when the invite exists.
  • If the route has no code, the frontend shows `Invalid invite code` and redirects to `/login`.

Guest flow

  • A guest with a valid pending invite sees the organization details and `Sign in with Google`.
  • The page sends Google OAuth state as `{"inviteCode":"<code>"}`.
  • The guest view warns that signing in will automatically accept the invite.
  • In the Google callback, if `inviteCode` is present, the backend immediately tries to accept the invite before returning a redirect.
  • Successful invite-based sign-in redirects to `/`.
  • If callback-time acceptance fails, the callback redirects back to `/invite/{code}`.
  • New invited users skip the non-invite onboarding redirect and still land on `/` after acceptance.

Authenticated flow

  • An authenticated user with `ready_to_accept` sees the signed-in account plus `Accept Invite`.
  • `Accept Invite` calls `GET /api/invites/{code}/accept`.
  • On success, the frontend refetches the user and follows the backend `redirectUrl`.
  • The current accept processor returns `/` with message `Invite accepted successfully`.
  • On accept failure, the page shows the backend/frontend error toast and reloads invite state.
  • Accepting an invite can restore a previously deleted membership and switches the user's `current_organization_id` to the invited organization.

Already in organization

  • If the signed-in user already has membership in the invited organization, `GET /api/invites/{code}` returns `already_in_organization`.
  • The page shows `Already a member`, hides the accept button, and offers `Go to Dashboard` and `Log out`.
  • `Go to Dashboard` routes to `/`.

Not found and error behavior

  • The page renders the not-found view when invite status is `not_found`.
  • In current backend logic, `status: not_found` covers invites that exist but are expired, cancelled, or already accepted.
  • A completely unknown invite code returns HTTP 404 from `GET /api/invites/{code}`.
  • The frontend currently handles both `status: not_found` and failed invite lookups by rendering `InviteNotFound`.
  • When the lookup fails at HTTP/request level, the frontend also shows an error toast and schedules a redirect to `/login` after 3 seconds.
  • The accept processor can return these verified errors:
  • `Invite not found`
  • `Invite is not pending`
  • `Invite has expired`
  • `User is already in this organization`

Support notes

  • Invite acceptance currently does not enforce that the signed-in Google email matches the invite email.
  • Invite links can be created either with an email address or as shareable links with `email: null`; both land on the same public `/invite/[code]` page.
  • Invite-based sign-up does not run the normal non-invite onboarding redirect. New users coming through an invite are redirected to `/` after acceptance.
  • For invite creation, resend, cancel, and Staff-area context, see staff.md.

Start building your AI team