Invitations
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
- Admin opens Settings → Members → Invite, picks an email and role.
POST /api/teams/[teamId]/invitationscreates aninvitationsrow with a one-time token and an expiry.fireWebhook("invitation.created", { ... })posts the payload to the team'swebhook_url. If none is set, the call is a no-op.- The invitee opens
invite_url, signs up or logs in, and hitsPOST /api/invitations/[token]/accept— which validates the token, adds them toteam_memberswith the assigned role, and firesinvitation.accepted. - Admin revoking a pending invite hits
DELETE /api/teams/[teamId]/invitations/[id]and firesinvitation.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.