Skip to content

Memberships API

GET /api/v1/projects/{id}/memberships

Role: viewer or above.

POST /api/v1/projects/{id}/memberships/invite

Role: 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.

POST /api/v1/auth/invite-accept

Public 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.

PATCH /api/v1/projects/{id}/memberships/{user_id}

Role: admin (not for ownerowner - that requires owner).

{ "role": "admin" }

Refuses if it would leave zero owners (422 last_owner_protection).

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.

DELETE /api/v1/projects/{id}/memberships/invites/{invite_id}

Role: admin.