Reference

Invitations

How team invites work — webhook-only delivery, token flow, and how to add email later.

Invitations are webhook-only — this template does not send emails. When an admin invites someone, the app creates an invitations row and fires an invitation.created webhook to the team's configured webhook_url (set in Settings → General). The webhook payload includes the invite_url, and it is up to the receiving system to deliver it (email, Slack, internal tool, etc.).

If no webhook_url is configured, the invitation is still created and the admin can copy the invite link manually from Settings → Members → Pending invitations → "Copy invite link". Nothing is ever sent automatically.

Flow

  1. Admin opens Settings → Members → Invite, picks an email and role.
  2. POST /api/teams/[teamId]/invitations creates an invitations row with a one-time token and an expiry.
  3. fireWebhook("invitation.created", { ... }) posts the payload to the team's webhook_url. If none is set, the call is a no-op.
  4. The invitee opens invite_url, signs up or logs in, and hits POST /api/invitations/[token]/accept — which validates the token, adds them to team_members with the assigned role, and fires invitation.accepted.
  5. Admin revoking a pending invite hits DELETE /api/teams/[teamId]/invitations/[id] and fires invitation.revoked.

Adding email delivery later

If you want to send invitation emails directly from the app instead of via the webhook, add your provider (Resend, Postmark, etc.) in server/api/teams/[teamId]/invitations/index.post.ts alongside the fireWebhook call. The invite URL is already constructed there — just reuse it.