Skip to content

Invitations

  • You are an admin on the project.
  • The project has an active email notification channel if you want z4j to auto-send the invite. Without one, the dashboard surfaces the link and you share it manually.

Dashboard, Settings, Memberships, Invite.

Fill in:

  • Email — target user’s email.
  • Roleviewer, operator, or admin. There is no owner role; admin is the highest tier and the brain enforces a last-admin protection so you cannot demote or remove the only admin on a project.
  • TTL (days) — defaults to 7. Server-side bounds apply.

Submit. With an active email channel the invitee receives an email containing the single-use accept URL. Without one, the response carries the URL for out-of-band delivery.

  • Single-use: accepting invalidates the token immediately. Re-using returns 410 invitation_consumed_or_expired.
  • Default TTL: 7 days (Z4J_* does not control this; the field is on the invitation record itself).
  • Bound to the target email: only that address can accept.
  • Stored hashed in Postgres; the plaintext token is shown to the admin once and embedded in the URL.

The accept URL points the invitee at the dashboard’s accept page, backed by:

GET /api/v1/invitations/preview?token=<single-use-token>
POST /api/v1/invitations/accept

The preview returns the invited email, role, and project name. The accept POST takes {token, display_name, password} (password is 12..200 chars, hashed with argon2id); it materialises the user and the membership in one step.

Before acceptance: Settings, Memberships, Pending invites, Revoke (or DELETE /api/v1/projects/{slug}/invitations/{invitation_id}).

After acceptance: treat as a membership change. Demote the role to a lower tier (PATCH membership) or remove the member entirely (DELETE membership). Either action revokes all of that user’s sessions immediately.

The accept and preview endpoints share a single per-IP bucket: 30 hits per minute combined. The mint endpoint has no separate per-email cap today; the per-IP login / general API caps apply to the admin issuing invites.

See rate limits.

Every invite, accept, and revoke writes an audit log entry (membership.invited, membership.accepted, invitation.revoked).