Skip to content

Invite a teammate — owner only

POST
/operator/team
curl --request POST \
--url http://localhost:3000/operator/team \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{ "email": "hello@example.com", "name": "example", "role": "owner" }'

Creates an operator on the caller’s own tenant and returns a one-time invite token. We send no email: the owner copies the link and delivers it however they already talk to their colleague.

role accepts owner or member only. staff is rejected by the schema with a 400 — a tenant owner minting platform staff would escape their own tenant, so it fails at the edge rather than as a constraint violation deep in a repository.

Media typeapplication/json
object
email
required
string format: email
<= 254 characters
name
required
string
>= 1 characters <= 200 characters
role
required
string
Allowed values: owner member

The invited teammate and their one-time token.

Media typeapplication/json

The created teammate plus their one-time invite token. The token is returned EXACTLY ONCE — only its sha256 is stored, the same way the tenant api_secret is handled — so the owner must copy the link before leaving the page.

object
member
required

An operator on the caller’s own tenant. invite_pending is true until they accept their invite and set a password. No password material is ever returned.

object
id
required
string
email
required
string format: email
name
required
string
role
required
string
Allowed values: owner member
status
required
string
Allowed values: active disabled
created_at
required
string format: date-time
invite_pending
required
boolean
invite_token
required
string
invite_expires_at
required
string format: date-time
Example
{
"member": {
"role": "owner",
"status": "active"
}
}

Invalid body — including role: staff, which the schema rejects here rather than letting it reach the database CHECK.

Media typeapplication/json
object
error
required
object
code
required
string
Allowed values: VALIDATION_FAILED UNAUTHENTICATED FORBIDDEN NOT_FOUND CONFLICT RATE_LIMITED INTERNAL
message
required
string
requestId
required
string
fields

Present only for VALIDATION_FAILED.

Array<object>
object
path
string
message
string
Example
{
"error": {
"code": "VALIDATION_FAILED"
}
}

Invalid, expired, revoked, or absent token.

Media typeapplication/json
object
error
required
object
code
required
string
Allowed values: VALIDATION_FAILED UNAUTHENTICATED FORBIDDEN NOT_FOUND CONFLICT RATE_LIMITED INTERNAL
message
required
string
requestId
required
string
fields

Present only for VALIDATION_FAILED.

Array<object>
object
path
string
message
string
Example
{
"error": {
"code": "VALIDATION_FAILED"
}
}

Authenticated but not permitted.

Media typeapplication/json
object
error
required
object
code
required
string
Allowed values: VALIDATION_FAILED UNAUTHENTICATED FORBIDDEN NOT_FOUND CONFLICT RATE_LIMITED INTERNAL
message
required
string
requestId
required
string
fields

Present only for VALIDATION_FAILED.

Array<object>
object
path
string
message
string
Example
{
"error": {
"code": "VALIDATION_FAILED"
}
}

That email already has an operator row. Operator emails are unique across the whole platform, not per tenant — login is email + password and must resolve to one account — so this also fires for an address belonging to a different tenant. The route is rate-limited per tenant for that reason; see the design doc’s known-limit note.

Media typeapplication/json
object
error
required
object
code
required
string
Allowed values: VALIDATION_FAILED UNAUTHENTICATED FORBIDDEN NOT_FOUND CONFLICT RATE_LIMITED INTERNAL
message
required
string
requestId
required
string
fields

Present only for VALIDATION_FAILED.

Array<object>
object
path
string
message
string
Example
{
"error": {
"code": "VALIDATION_FAILED"
}
}

Too many invites from this tenant in the last minute.

Media typeapplication/json
object
error
required
object
code
required
string
Allowed values: VALIDATION_FAILED UNAUTHENTICATED FORBIDDEN NOT_FOUND CONFLICT RATE_LIMITED INTERNAL
message
required
string
requestId
required
string
fields

Present only for VALIDATION_FAILED.

Array<object>
object
path
string
message
string
Example
{
"error": {
"code": "VALIDATION_FAILED"
}
}