Workspace invitations carry an email, initial role, inviter, expiration, and acceptance state. The list intentionally returns only pending, unexpired invitations; accepted or expired records do not remain actionable there.
Invitation scope is explicit
The workspace_id path must equal the session's selected workspace. A different workspace returns 404 even when the same user belongs to it; switch workspaces first instead of editing the URL.
Resend refreshes, revoke removes
Resending a still-pending invitation refreshes its seven-day expiry and sends the email again. Revocation deletes the outstanding invitation; neither action changes an already accepted membership.
Before you begin
A signed-in browser session with a selected workspace backed by an active membership is required; an archived workspace remains readable but rejects mutations. Every /api/v1/operator endpoint rejects API credentials and bearer tokens, regardless of their scopes.
Any role on an active membership can list current-workspace invitations. Only owners and admins can create, resend, or revoke them.
Use the current workspace UUID in the route and confirm the email and least-privileged initial role before sending.
How it works
Check for pending work
List invitations for the selected workspace and search by normalized email. Creating an invite for an existing active member is rejected, so check Members before assuming delivery failed.
Close the lifecycle
Resend only a pending, unexpired invitation; create a fresh invitation after expiry. Revoke mistaken invites promptly, and manage accepted users through the membership API.
Examples
These examples are illustrative. Replace the sample values with your own.
Keep credentials in environment variables or a secret manager, never in client-side code.
List outstanding invitations
Paste the UUID of the workspace currently selected in the application; merely belonging to another workspace is not enough for this route.
javascript
const workspaceId = window.prompt("Current workspace UUID");
if (!workspaceId) throw new Error("A workspace UUID is required");
const response = await fetch(`/api/v1/operator/workspaces/${encodeURIComponent(workspaceId)}/invitations`, {
credentials: "same-origin",
headers: {"Accept": "application/json"}
});
const body = await response.json();
if (!response.ok) throw new Error(`${response.status}: ${body.detail}`);
console.log(body);
What to expect
200 OK with {"invitations": []} when no pending unexpired invitations remain. Populated rows include email, role, expiry, inviter, and workspace.
Troubleshooting
The workspace path returns 404
The path workspace must be the session's current workspace, not merely another workspace visible in /operator/me. Switch through the application first.
Resend fails
Only pending, unexpired invitations can be resent. Accepted invitations are membership records; expired ones require a new invitation.
Endpoint reference
Ready to integrate? Open an endpoint for its required permissions, request fields,
response format, and status codes. The examples above explain the workflow;
these details define each individual request.
GET
/api/v1/operator/workspaces/:workspace_id/invitations
Web Session
List workspace invitations
Description
Returns unexpired pending invitations only (`accepted_at` is null and
`expires_at` is in the future). Accepted and expired rows are omitted.
JSON never includes the invite token — that secret is emailed and
shown once on `/app/members`.
`:workspace_id` must be the session workspace. Browser session only; CSRF is not required for this GET. Machine Bearer tokens are 401.
Auth
Web Session
Parameters
Name
In
Type
Required
Description
workspace_id
path
string
Yes
Must be the session's current workspace UUID
Responses
200
Pending unexpired invitations
Returns: InvitationList
Response Body
Field
Type
Required
Description
invitations
array<object>
Yes
Invitation records
invitations[].id
string
Yes
Invitation UUID
invitations[].email
string
Yes
Invitee email
invitations[].role
string (member, admin, auditor)
Yes
Assigned role
invitations[].inserted_at
datetime (ISO 8601)
Yes
Created at
invitations[].updated_at
datetime (ISO 8601)
Yes
Updated at
invitations[].expires_at
datetime (ISO 8601)
Yes
Expiry (default now+7 days; resend refreshes by 7 days)
workspace_id is not the session's current workspace
POST
/api/v1/operator/workspaces/:workspace_id/invitations
Web Session
Create invitation
Description
Invites an email to the current workspace. `role` is optional and
defaults to `member` (`admin` and `auditor` are also valid; `owner`
is not). The row expires 7 days from creation. The one-time token is
not in the JSON — the invitee joins at `/users/register?invite_token=…`
(same URL the email and `/app/members` console copy).
Owner/admin only. Marketplace-linked workspaces refuse invites
(`400` `marketplace_managed_workspace`). Inviting an existing active
member is `409` `already_member`. Sending is throttled per recipient
and per workspace; see `429`.
Auth
Web Session
Request Body
Field
Type
Required
Description
invitation
object
Yes
Invitation attributes
invitation.email
string
Yes
Email address to invite
invitation.role
string (member, admin, auditor)
No
Role to assign. Defaults to member. owner is not assignable.
Parameters
Name
In
Type
Required
Description
workspace_id
path
string
Yes
Must be the session's current workspace UUID
Responses
201
Invitation created. Token is omitted; invitee uses /users/register?invite_token=…
Returns: Invitation
Response Body
Field
Type
Required
Description
id
string
Yes
Invitation UUID
email
string
Yes
Invitee email
role
string (member, admin, auditor)
Yes
Assigned role
inserted_at
datetime (ISO 8601)
Yes
Created at
updated_at
datetime (ISO 8601)
Yes
Updated at
expires_at
datetime (ISO 8601)
Yes
Expiry (default now+7 days; resend refreshes by 7 days)
Marketplace-managed workspace (`marketplace_managed_workspace`) or other atom error
401
No operator browser session
403
Owner or admin membership required
404
workspace_id is not the session's current workspace
409
That email is already an active workspace member
422
Invalid email, invalid role, or a pending invite already exists
429
Invitation email throttle exhausted (5 emails per recipient per workspace per hour, 100 per workspace per 24 hours, shared with resend). Nothing is created; retry after the seconds in the Retry-After header / extra.retry_after_seconds.
PATCH
/api/v1/operator/workspaces/:workspace_id/invitations/:id/resend
Web Session
Resend invitation
Description
Re-delivers the invitation email and refreshes `expires_at` by another
7 days from now. The token is unchanged and is still omitted from JSON.
Refuses expired rows (`400` `expired`) and already-accepted rows
(`400` `already_accepted`). Owner/admin only. Sending is throttled
per recipient and per workspace; see `429`.
Auth
Web Session
Parameters
Name
In
Type
Required
Description
workspace_id
path
string
Yes
Must be the session's current workspace UUID
id
path
string
Yes
Invitation UUID
Responses
200
Invitation resent; expires_at refreshed by 7 days
Returns: Invitation
Response Body
Field
Type
Required
Description
id
string
Yes
Invitation UUID
email
string
Yes
Invitee email
role
string (member, admin, auditor)
Yes
Assigned role
inserted_at
datetime (ISO 8601)
Yes
Created at
updated_at
datetime (ISO 8601)
Yes
Updated at
expires_at
datetime (ISO 8601)
Yes
Expiry (default now+7 days; resend refreshes by 7 days)
Invitation not found, or workspace_id is not the current workspace
429
Invitation email throttle exhausted (5 per recipient per workspace per hour, 100 per workspace per 24 hours, shared with create). Retry-After gives the wait in seconds.
DELETE
/api/v1/operator/workspaces/:workspace_id/invitations/:id
Web Session
Cancel invitation
Description
Deletes a pending invitation. Owner/admin only. `:workspace_id` must be the session workspace.
Auth
Web Session
Parameters
Name
In
Type
Required
Description
workspace_id
path
string
Yes
Must be the session's current workspace UUID
id
path
string
Yes
Invitation UUID
Responses
204
Invitation cancelled
401
No operator browser session
403
Owner or admin membership required
404
Invitation not found, or workspace_id is not the current workspace