Team and API keys¶
Your organization is a team. Each member has a role that gates what they may do: see Authentication for the full permission table.
GET /members¶
Requires member.read (admin or owner).
Member records never contain key or token material.
POST /members/invitations¶
Invite someone. Requires member.invite (admin or owner).
| Field | Type | Required | Notes |
|---|---|---|---|
email |
email, max 320 | yes | Where the invite goes |
name |
string(1–200) | no | |
role |
"admin", "member", "viewer" |
yes | owner is never assignable |
The invite token goes to the invitee, and to nobody else¶
The response tells you a member was created and whether the email went out. It does not contain the invite token, not even for the person who sent the invite. The token is a credential for someone else's account.
emailDelivered: false means the invitation stands but nobody was told. Use the
resend endpoint below.
Privilege escalation is blocked¶
You may only grant a role you are allowed to manage. An admin cannot mint
another admin; only an owner can.
POST /members/:id/invitations¶
Resend an outstanding invitation on a fresh token. The old token dies.
This is not just a convenience. Invite tokens are hashed at rest and shown once, and each email may hold only one invitation. Without a resend path, an invitation whose email bounced would leave a member who can never be onboarded and never be re-invited under that address.
Returns 404 if there is no outstanding invitation for that member.
POST /invitations/accept¶
The one write an un-keyed caller may make: the invite token is the credential.
The apiKey is returned once. It is a personal key scoped to that member's
role, distinct from the organization's root key.
PATCH /members/:id¶
Change a member's role. Requires member.manage.
curl -X PATCH "$JET_API/members/mem_a204" \
-H "Authorization: Bearer $JET_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "role": "admin" }'
The same escalation rule applies: you cannot set a role you may not grant.
DELETE /members/:id¶
Revoke a member, or rescind an invitation that was never accepted.
rescinded: true means the member had not yet accepted and the invitation was
withdrawn. false means an active member was revoked. Either way their
credential stops working.
owner cannot be revoked.
POST /members/me/api-key¶
Rotate your own personal key. Available to any active member.
Calling it with the organization root key returns 409, because the
organization has no personal key to rotate:
{
"error": "member_required",
"message": "A member API key is per-user, and this request is authenticated as the ORGANIZATION…"
}
Use the endpoint below instead.
POST /api-keys/rotate¶
Rotate the organization's root key. Owner only.
Danger
The old key, the one that authenticated this very request, is dead the moment this responds. The new key is shown once and there is no way to read it back. Store it before you do anything else, and deploy it before you rotate if you cannot tolerate a gap.
Two kinds of key, side by side¶
| Organization root key | Member key | |
|---|---|---|
| Identifies | The organization | One person |
| Minted by | Onboarding, then POST /api-keys/rotate |
Accepting an invitation |
| Rotated by | POST /api-keys/rotate (owner only) |
POST /members/me/api-key |
| Role | owner |
The member's assigned role |
Use the root key for server-to-server integration. Use member keys where you want per-person attribution and per-person revocation.