Vulnix
API

Team

List members and pending invites, invite teammates, change roles, and revoke access.

Team endpoints manage who belongs to the organization and what they can do. Because a token's reach is capped by its creator's role, changing someone's role also changes what every token they created can do — immediately.

List members and invites

GET /team · scope members:read · role admin

curl https://api.vulnix.dev/team \
  -H "Authorization: Bearer $VULNIX_TOKEN"
{
  "members": [
    {
      "user_id": "01K5ADMINUSER00000000000A",
      "role": "owner",
      "email": "admin@acme.example.com"
    }
  ],
  "invites": []
}

Prop

Type

Invite a teammate

POST /invites · scope members:write · role admin · returns 201

Prop

Type

curl -X POST https://api.vulnix.dev/invites \
  -H "Authorization: Bearer $VULNIX_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"email": "teammate@acme.example.com", "role": "admin"}'
{
  "id": "01M2NP…",
  "email": "teammate@acme.example.com",
  "role": "admin",
  "status": "pending"
}

`admin` is the only invitable role

analyst and viewer remain valid roles and every role gate still honors them, but they are no longer assignable through an invite — a teammate invited at either could barely see anything, which read as a broken invite rather than a deliberate restriction. Any other value returns 409 signup_rejected.

The invite token is never returned

The response deliberately omits the invite token — it goes out only in the email. There is no endpoint that returns it, so you cannot script around the email step, and a leaked API response cannot be used to join an organization.

Acceptance (POST /invites/{token}/accept) is unauthenticated and issues a session, so it is not token-reachable either.

Rate limit

Invites are capped at 20 per hour per organization, separately from the standard request budget, because each one sends a real outbound email. Exceeding it returns 429 too_many_invites.

Change a member's role

PATCH /team/members/{user_id} · scope members:write · role admin

{ "role": "admin" }
{ "status": "role_updated" }

Prop

Type

Revoke a member

DELETE /team/members/{user_id} · scope members:write · role admin

{ "status": "revoked" }

The organization owner cannot be revoked — 403 insufficient_role.

Revoke a pending invite

DELETE /team/invites/{invite_id} · scope members:write · role admin

{ "status": "revoked" }

What revocation actually does

Revoking or demoting ends that person's sessions everywhere, immediately

Authorization comes from the session JWT's claims, so a database change alone would leave a removed member with working access for the rest of their token's 24-hour life. Both revocation and any privilege-reducing role change stamp a revocation cutoff that invalidates their sessions on the next request.

The cutoff is per user, not per workspace — it ends their sessions in every organization they belong to, not just this one. That is deliberate: for an explicitly security-motivated action, an extra re-login is the right side to err on.

Removing a member also revokes every API token they created. This is the cleanest way to cut off automation belonging to someone who has left — you do not have to find their tokens first.

A role change that reduces privileges also narrows every token that person created, since a token's effective role is the lower of its creation-time role and the creator's live role. Raising a role does not widen existing tokens; those keep the reach they were minted with. See a token never exceeds your own role.

On this page