Invites
List your organization's pending invitations and revoke the ones you no longer want.
An invite is an offer to join your organization with a role. It never creates a person: the invitee accepts it themselves, by email.
| Endpoint | Scope | Token owner's role |
|---|---|---|
POST /invites | members:write | Admin |
GET /invites | members:read | Admin |
DELETE /invites/{id} | members:write | Admin |
All three routes need an owner who is currently an organization Admin; a
Member's token gets 403 insufficient_scope.
Invitations can be sent from the portal (Settings → Team → Invite Member)
or with POST /invites below; this API also lists and revokes the pending ones.
The invite object
| Field | Type | Notes |
|---|---|---|
id | string | Opaque id. |
email | string | |
role | string | admin or member. |
project_ids | string[] | Initial project access for a member, applied on acceptance. May be empty. |
status | string | Always pending — the list holds pending invites only. |
expires_at | string | When the invitation link stops working. |
created_at | string |
The invitation token itself is never returned.
{
"id": "e2f3a4b5-c6d7-4e8f-9a0b-1c2d3e4f5a6b",
"email": "[email protected]",
"role": "member",
"project_ids": ["5b3e9a41-0c7d-4e2f-8a16-9d4b7c2e1f08"],
"status": "pending",
"expires_at": "2026-10-01T10:15:00Z",
"created_at": "2026-09-24T10:15:00Z"
}Create an invite
POST /api/v1/mgmt/invitesCreates an invitation for email. It runs the same flow as the portal: the
address is normalized, role is member (default) or admin (never
superadmin), and project_ids grants a member project access on acceptance
(every id must be a project of your organization; ignored for admin).
An organization with an active SSO connection only accepts the admin's own email
domain. No interactive re-login or acceptance step is added here — the invitee
accepts by email. Requires Idempotency-Key.
The response carries a status, and its HTTP status code reflects whether a
new invite was actually created:
status | HTTP status | Meaning |
|---|---|---|
created | 201 | A new invitation was sent. |
already_member | 200 | The address already belongs to the organization; no invite is sent (the member's name/is_active are returned). |
already_pending | 200 | A pending invitation already exists; it is returned, never duplicated. |
curl -X POST https://portal.<domain>/api/v1/mgmt/invites \
-H "Authorization: Bearer $TF_PAT" \
-H "Idempotency-Key: 2a3b4c5d-6e7f-4a8b-9c9d-0e1f2a3b4c5d" \
-H "Content-Type: application/json" \
-d '{"email":"[email protected]","role":"member","project_ids":["5b3e9a41-0c7d-4e2f-8a16-9d4b7c2e1f08"]}'{
"status": "created",
"id": "e2f3a4b5-c6d7-4e8f-9a0b-1c2d3e4f5a6b",
"email": "[email protected]",
"role": "member",
"project_ids": ["5b3e9a41-0c7d-4e2f-8a16-9d4b7c2e1f08"],
"expires_at": "2026-10-01T10:15:00Z"
}List invites
GET /api/v1/mgmt/invitesThe organization's pending invites, newest first.
Paginated with limit and cursor; there
are no filters.
curl https://portal.<domain>/api/v1/mgmt/invites \
-H "Authorization: Bearer $TF_PAT"{
"data": [
{
"id": "e2f3a4b5-c6d7-4e8f-9a0b-1c2d3e4f5a6b",
"email": "[email protected]",
"role": "member",
"project_ids": ["5b3e9a41-0c7d-4e2f-8a16-9d4b7c2e1f08"],
"status": "pending",
"expires_at": "2026-10-01T10:15:00Z",
"created_at": "2026-09-24T10:15:00Z"
}
],
"has_more": false,
"next_cursor": null
}Revoke an invite
DELETE /api/v1/mgmt/invites/{id}Immediate: the link stops working and the invite leaves the pending list.
No body. Requires Idempotency-Key. Returns 204 No Content.
curl -X DELETE https://portal.<domain>/api/v1/mgmt/invites/e2f3a4b5-c6d7-4e8f-9a0b-1c2d3e4f5a6b \
-H "Authorization: Bearer $TF_PAT" \
-H "Idempotency-Key: 2a3b4c5d-6e7f-4a8b-9c9d-0e1f2a3b4c5d"Errors specific to invites
| Status | Code | When |
|---|---|---|
| 400 | invalid_request (param email) | email is missing, malformed, or not a single bare address. |
| 400 | invalid_request (param role) | role is not member or admin. |
| 400 | invalid_request (param project_ids) | An id in project_ids is not a project of your organization, or more than 100 ids. |
| 403 | insufficient_scope | Token lacks members:read/members:write, or the owner is not currently an Admin. |
| 404 | not_found | Invite absent, already gone, or in another organization. |
| 409 | conflict | The org has an SSO connection and email is not the admin's own domain. |
| 409 | conflict (param email) | The address cannot be invited to this organization. |
| 422 | unsupported_filter | Any query parameter other than limit and cursor on the list. |