Memberships API
List members
Section titled “List members”GET /api/v1/projects/{id}/membershipsRole: viewer or above.
Invite
Section titled “Invite”POST /api/v1/projects/{id}/memberships/inviteRole: admin. Body:
{ "email": "alice@example.com", "role": "operator" }Response:
{ "invite_id": "...", "invite_url": "https://z4j.example.com/invite/<one-shot-token>", "expires_at": "..."}SMTP auto-sends if configured. Otherwise copy invite_url.
Accept
Section titled “Accept”POST /api/v1/auth/invite-acceptPublic endpoint (no auth). Body:
{ "token": "...", "password": "...", "display_name": "Alice" }If the email already has a user account, omit password - the caller must already be authenticated as that user.
Change role
Section titled “Change role”PATCH /api/v1/projects/{id}/memberships/{user_id}Role: admin (not for owner → owner - that requires owner).
{ "role": "admin" }Refuses if it would leave zero owners (422 last_owner_protection).
Remove
Section titled “Remove”DELETE /api/v1/projects/{id}/memberships/{user_id}Role: admin. Cannot remove an owner unless caller is also owner.
Removing revokes all the target user’s sessions immediately.
Revoke pending invite
Section titled “Revoke pending invite”DELETE /api/v1/projects/{id}/memberships/invites/{invite_id}Role: admin.