# Team invitations: from invite email to org member without gaps
Inviting someone to a team is a multi-step workflow across Auth and your membership tables. Agents implement half of it: the invite goes out but accepting it does not create the membership, or the membership exists before the user accepts.
## Checkable procedure
1. Create an `invites` table (email, org_id, role, token, expires_at, accepted_at). The invite is data you can list, revoke, and expire, not just an email.
2. Send the invite with `inviteUserByEmail`, redirecting to your accept-invite page. Store the invite row first so the accept step has something to match.
3. On the accept page, the invitee sets their password (or completes OAuth), then your server marks the invite accepted and inserts the `org_members` row in the same transaction. Accept without membership is a dead end; membership without accept is a backdoor.
4. Expire invites (7 days is typical) and enforce single use. Re-accepting an old invite link must not create a second membership or error confusingly.
5. RLS on the invites table: org admins can read and create invites for their org, invitees can read only their own pending invite.
## Ordering constraints
Invite row before the email. Membership inside the accept transaction, never earlier. Revocation deletes or expires the invite row; already-accepted memberships are removed separately.
## Verification
Invite a test email, accept via the link, and confirm exactly one membership with the right role. Try the link again and confirm it is rejected. Expire an invite manually and confirm acceptance fails.