Stackure

Stackure API Reference

Stackure's HTTP endpoints, with their parameters and responses.

Two APIs. The Sign-in API under /api/public signs people in to your apps. The Management API under /api/internal runs your organization without the web app.

Each region is its own deployment with its own base URL. Use the region where your organization was created.

Bodies are JSON unless an operation says otherwise. Send them with Content-Type: application/json. Parameters such as charset are fine. Each deployment sets the largest JSON body it takes, 1 MB by default. A larger body returns 400 request too large. An empty list is []. User, team, app, organization, signup, support request and AI client connection IDs are UUIDs. An ID that isn't one returns 400. Errors look like {"error": "<message>"}. A method an endpoint doesn't support returns 405 method not allowed.

Paged lists take cursor and limit. The X-Next-Cursor response header holds the cursor for the next page and is absent on the last one.

This page is for https://stackure.com, which takes JSON bodies up to 1 MB. Its OpenAPI 3.1.0 spec is at https://stackure.com/openapi.json.

Sign-in API

Paths start with /api/public.

Authentication

Sign people in to your app, check their sessions and connect AI clients. Each operation lists the credentials it takes:

Exchanging a sign-in token and the MCP endpoints take none. The MCP endpoints follow OAuth 2.1 for public clients: no client secret, PKCE with S256.

The endpoints below refer to credentials by these names:

Endpoints

Apply for an organization

POST /api/public/signup

Applies for a new organization under a parent organization. The parent's approvers and the applicant each get an email.

You get the same 200 when a signup with this email or organization name is already waiting or the email already belongs to a user. The applicant then gets an email saying why it can't go ahead.

Rate limited per email and IP address.

Authentication

Request body

application/json, object.

FieldDescription
parent_id
string (uuid)
The organization to apply under. Leave it out for the top organization of this region.
account_name
string, required
Name of the new organization. Up to 255 characters.
account_country
string, required
Country name, such as Germany. Up to 50 characters.
account_timezone
string, required
IANA time zone, such as Europe/Berlin.
account_type
string, required
What kind of organization it is. Up to 100 characters.
account_plan
string, required
Plan. Any case works. One of free, pilot or premium.
user_first_name
string, required
Up to 100 characters.
user_last_name
string, required
Up to 100 characters.
user_email
string (email), required
The applicant's email. They become the owner when the signup is approved. Up to 255 characters.
user_position
string, required
The applicant's job title. Up to 100 characters.
signup_message
string
A note for the approvers. Up to 1000 characters.

Responses

StatusDescription
200Signup received.
400The request isn't valid. error says why, for example invalid json or invalid input: user_id.
401invalid org secret: X-Org-Secret is missing or doesn't match the parent organization. An unknown parent_id gets the same 401, so the response doesn't reveal which organizations exist.
415unsupported media type: send Content-Type: application/json. Parameters such as charset are fine.
429too many requests, please try again later. Some limits also send Retry-After.
500internal server error: something failed on our side. Try again.

200 body: application/json, object.

FieldDescription
message
string, required
Always We got your signup. We read every one and reply by email.
signup_id
string (uuid)
Only in local development.

429 headers:

HeaderDescription
Retry-After
integer
Seconds to wait before trying again.

Send a sign-in link

POST /api/public/auth/magic-link/send

Emails a sign-in link if the email belongs to a user. The response is the same either way.

With app_id, also send your app's secret in X-App-Secret. The link then signs the person in to your app.

Without app_id, every request gets 200 unless its JSON is invalid, its Content-Type is wrong or it's rate limited.

Authentication

One of these:

Request body

application/json, object.

FieldDescription
user_email
string (email)
app_id
string (uuid)
Your app's ID. Requires X-App-Secret.

Responses

StatusDescription
200Request handled.
400The request isn't valid. error says why, for example invalid json or invalid input: user_id.
401invalid app secret: you sent app_id and X-App-Secret is missing or wrong.
415unsupported media type: send Content-Type: application/json. Parameters such as charset are fine.
429too many requests, please try again later. Some limits also send Retry-After.
500internal server error: something failed on our side. Try again.

200 body: application/json, object.

FieldDescription
message
string, required
token
string
The sign-in link's token. Only in local development.

429 headers:

HeaderDescription
Retry-After
integer
Seconds to wait before trying again.

Exchange a sign-in token

POST /api/public/auth/magic-link/verify

Exchanges the token from a sign-in link for a session token. A link requested without app_id gives a platform session token for the Management API. A link requested with app_id gives a session token for that app.

If the organization's access has expired, a link requested without app_id gives token_scope support_only: the session can only contact support, and redirect_url points to the support page. A link requested with app_id returns 403 forbidden instead.

Links that connect an AI client don't work here.

Authentication

Request body

application/json, object.

FieldDescription
token
string, required
The token query parameter of the sign-in link. Exactly 64 characters.

Responses

StatusDescription
200Signed in.
400The request isn't valid. error says why, for example invalid json or invalid input: user_id.
401token invalid when the token isn't 64 characters. authentication failed when the link is unknown, used, expired or connects an AI client.
403forbidden: the link was for an app the person can't open, or their organization's access has expired.
415unsupported media type: send Content-Type: application/json. Parameters such as charset are fine.
429too many verification attempts from this IP address.
500internal server error: something failed on our side. Try again.

200 headers:

HeaderDescription
Cache-Control
string
Don't cache this response. Always no-store.

200 body: application/json, object.

FieldDescription
session_token
string (uuid), required
The platform session token. When the link was for an app, the app session token.
token_scope
string, required
One of full or support_only.
app_id
string (uuid)
The app the token is for. Only for app links.
redirect_url
string (uri)
The support page. Only when token_scope is support_only.
account_status
string
Only when token_scope is support_only. Always expired.

Check a session

GET /api/public/auth/session/validate

Tells your server who is signed in to your app. Call it from your server on every protected request.

Send your app's secret in X-App-Secret and the person's app session token as Authorization: Bearer <token> or a session cookie. A missing, expired or signed-out token returns authenticated: false with a sign_in_url.

For an MCP endpoint, add mcp and forward the AI client's Authorization: Bearer credential. When the client isn't signed in, the response adds www_authenticate: answer the client with 401 and that value, unchanged, as the WWW-Authenticate header.

Rate limited per app. Failed calls are also limited per app and IP address, 10 a minute by default. Past that, a failed call returns 429 with Retry-After: 60 instead of its error.

Authentication

One of these:

Parameters

NameDescription
app_id
string (uuid) in query, required
Your app's ID.
mcp
string (uri) in query
The public URL of your MCP endpoint the request arrived at, with no query string. When present, the token is checked as an AI client credential for your app.

Responses

StatusDescription
200The session's state.
400app_id required or invalid app_id format.
401invalid app secret: X-App-Secret is missing or wrong.
429too many requests, please try again later. Some limits also send Retry-After.
500internal server error: something failed on our side. Try again.

200 headers:

HeaderDescription
Cache-Control
string
no-store when authenticated is true. Not sent otherwise.

200 body: application/json, object.

FieldDescription
authenticated
boolean, required
user
object
Only when authenticated is true.
user.user_id
string (uuid), required
user.account_id
string (uuid), required
The person's organization.
user.user_email
string (email), required
user.user_first_name
string, required
user.user_last_name
string, required
user.user_is_app_admin
boolean, required
The person is an app admin or the owner in their organization. Your app decides what that means.
user.user_teams
array of objects, required
Teams the person is on in their organization, sorted by name. Empty when none.
user.user_teams[].team_id
string (uuid), required
user.user_teams[].team_name
string, required
sign_in_url
string (uri)
Where to send the person to sign in. Only when authenticated is false.
www_authenticate
string
The WWW-Authenticate value for your 401 to the AI client. Only with mcp and when authenticated is false.

429 headers:

HeaderDescription
Retry-After
integer
Seconds to wait before trying again.

List who can open your app

GET /api/public/directory/users

Lists the users in the signed-in person's organization who can open your app, for pickers and sharing. Sorted by first name, then last name. q matches name, email and job title.

We define no permissions inside your app. You decide what these users and teams may do.

Send X-App-Secret and the person's app session token as Authorization: Bearer <token> or a session cookie. AI client credentials aren't accepted. Rate limited per app. Failed calls are also limited per app and IP address, 10 a minute by default. Past that, a failed call returns 429 with Retry-After: 60 instead of its error.

Authentication

One of these:

Parameters

NameDescription
app_id
string (uuid) in query, required
Your app's ID.
q
string in query
Search text. Every word must match. Up to 256 characters.
cursor
string in query
The X-Next-Cursor value from the previous page.
limit
integer in query
Page size. Values above 200 count as 200. Default 100. At least 1.
id
array of strings (uuid) in query
Only these IDs, for checking or naming people or teams you already have. Repeat it for up to 200. Up to 200 items.

Responses

StatusDescription
200One page of users.
400invalid app_id format when app_id is missing or isn't a UUID, invalid input: q, invalid input: limit, invalid input: cursor or invalid input: id.
401invalid app secret when X-App-Secret is missing or wrong. invalid session when there's no live session for this app.
429too many requests, please try again later. Some limits also send Retry-After.
500internal server error: something failed on our side. Try again.

200 headers:

HeaderDescription
Cache-Control
string
Don't cache this response. Always no-store.
X-Next-Cursor
string
Send it as cursor to get the next page. Absent on the last page.
X-Total-Count
integer
Total matches. Sent on the first page when the total is 10,000 or less.

200 body: application/json, array of objects.

FieldDescription
user_id
string (uuid), required
user_email
string (email), required
user_first_name
string, required
user_last_name
string, required

429 headers:

HeaderDescription
Retry-After
integer
Seconds to wait before trying again.

List teams that have your app

GET /api/public/directory/teams

Lists the teams in the signed-in person's organization that have your app, for pickers and sharing: every team when the app is available to everyone, otherwise the teams it's shared with. Sorted by name. q matches the team name.

We define no permissions inside your app. You decide what these users and teams may do.

Send X-App-Secret and the person's app session token as Authorization: Bearer <token> or a session cookie. AI client credentials aren't accepted. Rate limited per app. Failed calls are also limited per app and IP address, 10 a minute by default. Past that, a failed call returns 429 with Retry-After: 60 instead of its error.

Authentication

One of these:

Parameters

NameDescription
app_id
string (uuid) in query, required
Your app's ID.
q
string in query
Search text. Every word must match. Up to 256 characters.
cursor
string in query
The X-Next-Cursor value from the previous page.
limit
integer in query
Page size. Values above 200 count as 200. Default 100. At least 1.
id
array of strings (uuid) in query
Only these IDs, for checking or naming people or teams you already have. Repeat it for up to 200. Up to 200 items.

Responses

StatusDescription
200One page of teams.
400invalid app_id format when app_id is missing or isn't a UUID, invalid input: q, invalid input: limit, invalid input: cursor or invalid input: id.
401invalid app secret when X-App-Secret is missing or wrong. invalid session when there's no live session for this app.
429too many requests, please try again later. Some limits also send Retry-After.
500internal server error: something failed on our side. Try again.

200 headers:

HeaderDescription
Cache-Control
string
Don't cache this response. Always no-store.
X-Next-Cursor
string
Send it as cursor to get the next page. Absent on the last page.
X-Total-Count
integer
Total matches. Sent on the first page when the total is 10,000 or less.

200 body: application/json, array of objects.

FieldDescription
team_id
string (uuid), required
team_name
string, required

429 headers:

HeaderDescription
Retry-After
integer
Seconds to wait before trying again.

Sign out

POST /api/public/auth/sign-out

Signs the person out everywhere. Every session on every app and device ends. Their AI clients are disconnected.

Send a platform or app session token as Authorization: Bearer <token> or a session cookie. You get 200 even when the token is missing or no longer valid.

Authentication

One of these:

Responses

StatusDescription
200message is signed out successfully.
500internal server error: something failed on our side. Try again.

200 body: application/json, object.

FieldDescription
message
string, required

Get an AI client token

POST /api/public/auth/mcp/token

The OAuth token endpoint for AI clients connecting over MCP, to us or to your app.

The authorize step is GET /mcp/authorize for our MCP server or GET /mcp/{app_id}/authorize for your app. Clients find every OAuth URL at /.well-known/oauth-authorization-server/mcp or /.well-known/oauth-authorization-server/mcp/{app_id}.

Access ends when the person signs out, disconnects the client or loses access. It also ends after a period without use.

Authentication

Request body

application/x-www-form-urlencoded, object.

FieldDescription
grant_type
string, required
One of authorization_code or refresh_token.
code
string
For authorization_code. Exactly 64 characters.
code_verifier
string
For authorization_code. The PKCE verifier. 43 to 128 characters.
redirect_uri
string
For authorization_code. The one used at the authorize step.
resource
string (uri)
For authorization_code. The MCP endpoint URL. Must match the one from the authorize step.
refresh_token
string
For refresh_token. Exactly 64 characters.
client_id
string
Your client_id from registration or the HTTPS URL of your client metadata document.

Responses

StatusDescription
200Tokens issued.
400error is unsupported_grant_type, invalid_grant, invalid_client or invalid_target.
429too many requests, please try again later: the connection holds too many live access tokens.
500internal server error: something failed on our side. Try again.

200 headers:

HeaderDescription
Cache-Control
string
Don't cache this response. Always no-store.

200 body: application/json, object.

FieldDescription
access_token
string (uuid), required
token_type
string, required
Always Bearer.
expires_in
integer, required
Seconds until the access token expires.
refresh_token
string, required
scope
string
Left out for connections to an app. One of stackure.read or stackure.read stackure.write.

Register an AI client

POST /api/public/auth/mcp/register

OAuth dynamic client registration for AI clients. Returns the client_id to use at the authorize and token steps. Rate limited per IP address. This endpoint sets its own body limit, 16 KB by default. A larger body returns 400 invalid_client_metadata.

Each redirect URI must be one of these:

Authentication

Request body

application/json, object.

FieldDescription
redirect_uris
array of strings, required
1 to 10 items.
client_name
string
Shown to people when they connect. Only letters, digits, spaces and hyphens are kept. Defaults to MCP client.

Responses

StatusDescription
201Client registered.
400error is invalid_client_metadata or invalid_redirect_uri.
429too many requests, please try again later. Some limits also send Retry-After.
500internal server error: something failed on our side. Try again.

201 headers:

HeaderDescription
Cache-Control
string
Don't cache this response. Always no-store.

201 body: application/json, object.

FieldDescription
client_id
string (uuid), required
client_id_issued_at
integer, required
Unix time in seconds.
client_name
string, required
redirect_uris
array of strings, required
token_endpoint_auth_method
string, required
Always none.
grant_types
array of strings, required
response_types
array of strings, required

429 headers:

HeaderDescription
Retry-After
integer
Seconds to wait before trying again.

Revoke an AI client token

POST /api/public/auth/mcp/revoke

OAuth token revocation. A live access token or refresh token ends its whole connection. You get 200 and {} whether or not the token was valid.

Authentication

Request body

application/x-www-form-urlencoded, object.

FieldDescription
token
string, required
An access token or refresh token.
client_id
string
When sent, the token must belong to this client.

Responses

StatusDescription
200Done.
500internal server error: something failed on our side. Try again.

200 body: application/json, empty object.

Management API

Paths start with /api/internal.

Authentication

Run your organization without the web app: users, teams, roles, permissions, apps and their secrets, partners, partner signups, AI access, AI clients, support requests and activity. You can also transfer ownership, rotate your organization's secret and see its limits. The signup list shows each organization's name, status and date. GET /api/internal/signup shows one signup in full.

Every call needs a platform session token as Authorization: Bearer <token> or a session cookie. When you send both, the cookie is used. To get a token, request a sign-in link with POST /api/public/auth/magic-link/send without app_id, take the token from the link in the email and exchange it at POST /api/public/auth/magic-link/verify. The token ends when it expires, when you sign out or when you sign in again, since each person has one session at a time. Request a new link when calls return 401 invalid session.

App session tokens and AI client tokens don't work here.

What you can see and change depends on your roles.

The endpoints below refer to credentials by these names:

Endpoints

List users

GET /api/internal/users

Users in your organization you can see, sorted by first name, then last name.

Authentication

One of these:

Parameters

NameDescription
q
string in query
Search text. Every word must match. Up to 256 characters.
cursor
string in query
The X-Next-Cursor value from the previous page.
limit
integer in query
Page size. Values above 200 count as 200. Default 100. At least 1.

Responses

StatusDescription
200One page of users.
400The request isn't valid. error says why, for example invalid json or invalid input: user_id.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
500internal server error: something failed on our side. Try again.

200 headers:

HeaderDescription
X-Next-Cursor
string
Send it as cursor to get the next page. Absent on the last page.
X-Total-Count
integer
Total matches. Sent on the first page when the total is 10,000 or less.

200 body: application/json, array of objects.

FieldDescription
user_id
string (uuid)
account_id
string (uuid)
The user's organization.
user_first_name
string, required
user_last_name
string, required
user_position
string, required
Job title.
user_email
string (email), required
user_settings
object
Stored settings, such as timezone.
user_timezone
string
IANA time zone, such as Europe/Berlin.
user_created
string (date-time), required
user_updated
string (date-time), required
user_created_by
string (uuid)
The user who invited this one.
HasAccess
boolean, required
Always true.

Invite users

POST /api/internal/users

Adds people to your organization. Each new user gets an email with a link to sign in.

201 when at least 1 user was created and none failed. 207 when any failed. 409 when every user already exists. details has one entry per person.

Authentication

One of these:

Request body

application/json, array of objects. At least 1 item.

FieldDescription
user_first_name
string, required
Up to 100 characters.
user_last_name
string, required
Up to 100 characters.
user_email
string (email), required
Up to 255 characters.
user_position
string, required
Job title. Up to 100 characters.
user_settings
object

Responses

StatusDescription
201Users created.
207Some or all failed.
400invalid json when the body isn't a JSON array of users, no users to invite or bulk operation failed, all users must have valid data when no entry is valid.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
409Every user already exists.
415unsupported media type: send Content-Type: application/json. Parameters such as charset are fine.
500internal server error: something failed on our side. Try again.

201, 207 and 409 body: application/json, object.

FieldDescription
message
string, required
One of all users invited successfully, some users invited successfully, some users invited successfully, some failed, all users failed to be invited or all users already exist.
details
array of objects
details[].user_id
string, required
Empty when no user was created.
details[].user_email
string, required
details[].status
string, required
created, duplicate_skipped when the email already exists, or why it failed, such as user_email required or invalid email.

Get a user

GET /api/internal/user

Authentication

One of these:

Parameters

NameDescription
user_id
string (uuid) in query, required
User ID.

Responses

StatusDescription
200The user.
400invalid input: user_id when it's missing or isn't a UUID.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
404It doesn't exist or you can't see it. error says what, for example user not found.
500internal server error: something failed on our side. Try again.

200 body: application/json, object.

FieldDescription
user_id
string (uuid)
account_id
string (uuid)
The user's organization.
user_first_name
string, required
user_last_name
string, required
user_position
string, required
Job title.
user_email
string (email), required
user_settings
object
Stored settings, such as timezone.
user_timezone
string
IANA time zone, such as Europe/Berlin.
user_created
string (date-time), required
user_updated
string (date-time), required
user_created_by
string (uuid)
The user who invited this one.
creator
object, required
The user who invited this one. Email and job title are empty when you can't see them.
creator.user_id
string (uuid)
creator.account_id
string (uuid)
The user's organization.
creator.user_first_name
string, required
creator.user_last_name
string, required
creator.user_position
string, required
Job title.
creator.user_email
string (email), required
creator.user_settings
object
Stored settings, such as timezone.
creator.user_timezone
string
IANA time zone, such as Europe/Berlin.
creator.user_created
string (date-time), required
creator.user_updated
string (date-time), required
creator.user_created_by
string (uuid)
The user who invited this one.
user_is_account_owner
boolean
Present and true when this user owns the organization.
user_app_count
integer
Apps this user can open that you can see. Left out when 0.
user_team_count
integer
Teams this user is on that you can see. Left out when 0.
user_role_count
integer
Roles this user holds. Left out when 0.

Update a user

PUT /api/internal/user

Changes only the fields you send. An empty value leaves that field as it is. You can change user_timezone only for yourself.

Authentication

One of these:

Parameters

NameDescription
user_id
string (uuid) in query, required
User ID.

Request body

application/json, object.

FieldDescription
user_first_name
string
Up to 100 characters.
user_last_name
string
Up to 100 characters.
user_email
string (email)
Up to 255 characters.
user_position
string
Job title. Up to 100 characters.
user_timezone
string
IANA time zone, such as Europe/Berlin. Only for yourself.

Responses

StatusDescription
200message is user updated successfully.
400invalid input: user_id when it's missing or isn't a UUID, invalid json, input too long when user_first_name, user_last_name or user_position is over 100 characters, invalid input: user_first_name, invalid input: user_last_name or invalid input: user_position when that field has a control character such as a line break, invalid email when user_email isn't a valid address of 255 characters or fewer or invalid timezone when user_timezone isn't an IANA time zone.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this, you sent user_timezone for someone else or your organization's access has expired.
404It doesn't exist or you can't see it. error says what, for example user not found.
409email already exists.
415unsupported media type: send Content-Type: application/json. Parameters such as charset are fine.
500internal server error: something failed on our side. Try again.

200 body: application/json, object.

FieldDescription
message
string, required

Delete a user

DELETE /api/internal/user

You can't delete yourself, the owner or a team's last admin.

Authentication

One of these:

Parameters

NameDescription
user_id
string (uuid) in query, required
User ID.

Responses

StatusDescription
200message is user deleted successfully.
400invalid input: user_id when it's missing or isn't a UUID, cannot delete self, cannot delete account owner or cannot delete the last admin of a team.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
404It doesn't exist or you can't see it. error says what, for example user not found.
500internal server error: something failed on our side. Try again.

200 body: application/json, object.

FieldDescription
message
string, required

List a user's apps

GET /api/internal/user/apps

Apps the user can open that you can see, sorted by name. 403 when you can't see apps.

Authentication

One of these:

Parameters

NameDescription
user_id
string (uuid) in query, required
User ID.

Responses

StatusDescription
200The user and their apps. user has only user_id, user_first_name and user_last_name filled in.
400invalid input: user_id when it's missing or isn't a UUID.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
404It doesn't exist or you can't see it. error says what, for example user not found.
500internal server error: something failed on our side. Try again.

200 body: application/json, object.

FieldDescription
user
object, required
A user. Fields an endpoint doesn't load are empty or left out. Dates it doesn't load are 0001-01-01T00:00:00Z.
user.user_id
string (uuid)
user.account_id
string (uuid)
The user's organization.
user.user_first_name
string, required
user.user_last_name
string, required
user.user_position
string, required
Job title.
user.user_email
string (email), required
user.user_settings
object
Stored settings, such as timezone.
user.user_timezone
string
IANA time zone, such as Europe/Berlin.
user.user_created
string (date-time), required
user.user_updated
string (date-time), required
user.user_created_by
string (uuid)
The user who invited this one.
apps
array of objects, required
apps[].app_id
string (uuid)
apps[].account_id
string (uuid)
The organization that registered the app.
apps[].app_name
string
apps[].app_url
string (uri)
apps[].app_logo
string
apps[].app_logo_type
string
apps[].app_created
string (date-time), required
apps[].app_updated
string (date-time), required
apps[].app_created_by
string (uuid)
apps[].share_state
string
How far your organization has distributed the app: pending (not yet), teams (chosen teams) or organization (everyone). One of pending, teams or organization.
apps[].app_mcp_url
string (uri)
The app's MCP endpoint, when set.

List a user's teams

GET /api/internal/user/teams

Teams the user is on that you can see, sorted by name. 403 when you can't see teams.

Authentication

One of these:

Parameters

NameDescription
user_id
string (uuid) in query, required
User ID.

Responses

StatusDescription
200The user and their teams. user has only user_id, user_first_name and user_last_name filled in. teams is [] when there are none.
400invalid input: user_id when it's missing or isn't a UUID.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
404It doesn't exist or you can't see it. error says what, for example user not found.
500internal server error: something failed on our side. Try again.

200 body: application/json, object.

FieldDescription
user
object, required
A user. Fields an endpoint doesn't load are empty or left out. Dates it doesn't load are 0001-01-01T00:00:00Z.
user.user_id
string (uuid)
user.account_id
string (uuid)
The user's organization.
user.user_first_name
string, required
user.user_last_name
string, required
user.user_position
string, required
Job title.
user.user_email
string (email), required
user.user_settings
object
Stored settings, such as timezone.
user.user_timezone
string
IANA time zone, such as Europe/Berlin.
user.user_created
string (date-time), required
user.user_updated
string (date-time), required
user.user_created_by
string (uuid)
The user who invited this one.
teams
array of objects, required
teams[].team_id
string (uuid)
teams[].account_id
string (uuid)
The team's organization.
teams[].team_name
string, required
teams[].team_settings
object
teams[].team_created
string (date-time)
teams[].team_updated
string (date-time)
teams[].team_created_by
string (uuid)

Get a user's roles and permissions

GET /api/internal/user/access

Authentication

One of these:

Parameters

NameDescription
user_id
string (uuid) in query
User ID. Leave it out for yourself.

Responses

StatusDescription
200The user's roles and what each one allows.
400invalid input: user_id.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
404It doesn't exist or you can't see it. error says what, for example user not found.
500internal server error: something failed on our side. Try again.

200 body: application/json, object.

FieldDescription
user_id
string (uuid), required
user_first_name
string, required
user_last_name
string, required
role_actions
object, required
Permission keys by role key. Roles without permissions are left out.
role_actions.{key}
array of strings
roles
array of objects, required
roles[].role_key
string, required
roles[].role_name
string, required
roles[].role_description
string
roles[].role_type
string
One of default or custom.
roles[].account_id
string (uuid)
The organization a custom role belongs to.
roles[].user_count
integer
Users in your organization with this role. Left out when 0.
roles[].can_remove
boolean, required
You can remove this role from the user.
roles[].permissions
array of objects, required
roles[].permissions[].permission_id
string (uuid)
roles[].permissions[].permission_key
string, required
roles[].permissions[].permission_name
string, required
roles[].permissions[].permission_description
string
roles[].permissions[].permission_role_count
integer
Roles with this permission. Left out when 0.
roles[].permissions[].permission_user_count
integer
Users you can see who hold it. Left out when 0.

Give roles to a user

POST /api/internal/user/roles

Gives the user every role in roles. You can't give account_owner: transfer ownership instead.

Authentication

One of these:

Request body

application/json, object.

FieldDescription
user_id
string (uuid)
user_email
string (email)
Up to 255 characters.
roles
array of strings, required
At least 1 item.

Responses

StatusDescription
200message is roles assigned to followed by the user_email you sent, trimmed and lowercased, or else the user_id you sent.
400invalid json, invalid input: user_id when you send neither user_id nor user_email or user_id isn't a UUID, invalid email when user_email isn't a valid address of 255 characters or fewer, role required when roles is empty, or invalid input: roles when a role key isn't 1 to 100 lowercase letters, digits or underscores.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
404user not found for role or role not found: followed by the unknown role keys.
415unsupported media type: send Content-Type: application/json. Parameters such as charset are fine.
500internal server error: something failed on our side. Try again.

200 body: application/json, object.

FieldDescription
message
string, required

Remove a role from a user

DELETE /api/internal/user/roles

Authentication

One of these:

Parameters

NameDescription
user_id
string (uuid) in query, required
User ID.
role_key
string in query, required
Role key, such as user_admin. Up to 100 characters.

Responses

StatusDescription
200message is role revoked from user.
400invalid input: user_id when it's missing or isn't a UUID. invalid input: role_key when it's missing or isn't 1 to 100 lowercase letters, digits or underscores.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
404role not found or user does not hold this role.
500internal server error: something failed on our side. Try again.

200 body: application/json, object.

FieldDescription
message
string, required

List a user's AI clients

GET /api/internal/user/ai-clients

Live AI client connections, newest first. To see another user's connections, you need permission to edit that user.

Authentication

One of these:

Parameters

NameDescription
user_id
string (uuid) in query
User ID. Leave it out for yourself.

Responses

StatusDescription
200The connections.
400invalid input: user_id.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
500internal server error: something failed on our side. Try again.

200 body: application/json, object.

FieldDescription
items
array of objects, required
items[].id
string (uuid), required
Connection ID.
items[].host
string, required
Host of the client's HTTPS client ID. unverified when it has none.
items[].target
string, required
The app the client connects to. For platform connections, our platform's name.
items[].grant
string or null, required
read or write for platform connections. null for app connections. One of read, write or null.
items[].created
string (date-time), required
items[].used
string (date-time), required
items[].expires
string (date-time), required
items[].is_current
boolean, required
Always false here.
items[].untrusted
object, required
items[].untrusted.client
string, required
The name the client gave itself. Not verified.

Disconnect an AI client

POST /api/internal/user/ai-clients

Ends one AI client connection. To end another user's connection, you need permission to edit that user.

Authentication

One of these:

Request body

application/json, object.

FieldDescription
user_id
string (uuid)
Whose connection. Leave it out for yourself.
connection_id
string (uuid), required

Responses

StatusDescription
200Disconnected.
400invalid json, invalid input: user_id or invalid input: connection_id.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
404connection not found, also when you aren't allowed to end it.
415unsupported media type: send Content-Type: application/json. Parameters such as charset are fine.
500internal server error: something failed on our side. Try again.

200 body: application/json, object.

FieldDescription
disconnected
boolean, required
Always true.

List roles

GET /api/internal/roles

Default roles and your organization's custom roles, sorted by name. Needs permission to edit users.

Authentication

One of these:

Responses

StatusDescription
200The roles.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
500internal server error: something failed on our side. Try again.

200 body: application/json, array of objects.

FieldDescription
role_key
string, required
role_name
string, required
role_description
string
role_type
string
One of default or custom.
account_id
string (uuid)
The organization a custom role belongs to.
user_count
integer
Users in your organization with this role. Left out when 0.

Get a role

GET /api/internal/role

Needs permission to edit users.

Authentication

One of these:

Parameters

NameDescription
role_key
string in query, required
Role key, such as user_admin. Up to 100 characters.

Responses

StatusDescription
200The role, with user_count when anyone holds it.
400invalid input: role_key when it's missing or isn't 1 to 100 lowercase letters, digits or underscores.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
404It doesn't exist or you can't see it. error says what, for example user not found.
500internal server error: something failed on our side. Try again.

200 body: application/json, object.

FieldDescription
role_key
string, required
role_name
string, required
role_description
string
role_type
string
One of default or custom.
account_id
string (uuid)
The organization a custom role belongs to.
user_count
integer
Users in your organization with this role. Left out when 0.

Create a role

POST /api/internal/role

Creates a custom role for your organization. Add permissions to it with POST /api/internal/role/permissions.

Authentication

One of these:

Request body

application/json, object.

FieldDescription
role_key
string, required
Matches ^[a-z0-9_]{1,100}$.
role_name
string, required
Up to 100 characters.
role_description
string
Up to 500 characters.

Responses

StatusDescription
200message is custom role created: followed by the role name.
400invalid json, invalid input: role_key when it's missing or isn't 1 to 100 lowercase letters, digits or underscores, role_name required when role_name is missing or blank or input too long when role_name is over 100 characters or role_description is over 500.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
409role already exists.
415unsupported media type: send Content-Type: application/json. Parameters such as charset are fine.
500internal server error: something failed on our side. Try again.

200 body: application/json, object.

FieldDescription
message
string, required

Update a role

PUT /api/internal/role

Renames a custom role or changes its description. Fields you leave out stay as they are.

Authentication

One of these:

Request body

application/json, object.

FieldDescription
role_key
string, required
Up to 100 characters.
role_name
string
Up to 100 characters.
role_description
string
Up to 500 characters.

Responses

StatusDescription
200message is custom role updated successfully.
400invalid json, invalid input: role_key when it's missing or isn't 1 to 100 lowercase letters, digits or underscores, invalid input: nothing to change when neither role_name nor role_description is sent, role_name required when role_name is blank or input too long when role_name is over 100 characters or role_description is over 500.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
404It doesn't exist or you can't see it. error says what, for example user not found.
415unsupported media type: send Content-Type: application/json. Parameters such as charset are fine.
500internal server error: something failed on our side. Try again.

200 body: application/json, object.

FieldDescription
message
string, required

Delete a role

DELETE /api/internal/role

Deletes a custom role. Default roles can't be deleted.

Authentication

One of these:

Parameters

NameDescription
role_key
string in query, required
Role key, such as user_admin. Up to 100 characters.

Responses

StatusDescription
200message is custom role deleted successfully.
400invalid input: role_key when it's missing or isn't 1 to 100 lowercase letters, digits or underscores.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
404It doesn't exist or you can't see it. error says what, for example user not found.
500internal server error: something failed on our side. Try again.

200 body: application/json, object.

FieldDescription
message
string, required

List permissions

GET /api/internal/permissions

Every permission you can put in a role, sorted by name. Needs permission to edit users.

Authentication

One of these:

Responses

StatusDescription
200The permissions. Each has only permission_key and permission_name.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
500internal server error: something failed on our side. Try again.

200 body: application/json, array of objects.

FieldDescription
permission_id
string (uuid)
permission_key
string, required
permission_name
string, required
permission_description
string
permission_role_count
integer
Roles with this permission. Left out when 0.
permission_user_count
integer
Users you can see who hold it. Left out when 0.

Get a permission

GET /api/internal/permission

Needs permission to edit users. Without it you get 404.

Authentication

One of these:

Parameters

NameDescription
permission_key
string in query, required
Permission key, such as view_any_user.

Responses

StatusDescription
200The permission, with how many roles have it and how many users you can see hold it.
400invalid input: permission_key when it's missing or isn't 1 to 100 lowercase letters, digits or underscores.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
404It doesn't exist or you can't see it. error says what, for example user not found.
500internal server error: something failed on our side. Try again.

200 body: application/json, object.

FieldDescription
permission_id
string (uuid)
permission_key
string, required
permission_name
string, required
permission_description
string
permission_role_count
integer
Roles with this permission. Left out when 0.
permission_user_count
integer
Users you can see who hold it. Left out when 0.

List a role's permissions

GET /api/internal/role/permissions

Needs permission to edit users.

Authentication

One of these:

Parameters

NameDescription
role_key
string in query, required
Role key, such as user_admin. Up to 100 characters.

Responses

StatusDescription
200The role's permissions, sorted by name, each with only permission_key and permission_name. [] when the role has none.
400invalid input: role_key when it's missing or isn't 1 to 100 lowercase letters, digits or underscores.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
404It doesn't exist or you can't see it. error says what, for example user not found.
500internal server error: something failed on our side. Try again.

200 body: application/json, array of objects.

FieldDescription
permission_id
string (uuid)
permission_key
string, required
permission_name
string, required
permission_description
string
permission_role_count
integer
Roles with this permission. Left out when 0.
permission_user_count
integer
Users you can see who hold it. Left out when 0.

Add permissions to a role

POST /api/internal/role/permissions

Adds permissions to a custom role, along with any view permissions they need.

Authentication

One of these:

Request body

application/json, object.

FieldDescription
role_key
string, required
Up to 100 characters.
permission_keys
array of strings, required
At least 1 item.

Responses

StatusDescription
200message is permissions added successfully. When view permissions were added too, it goes on with ; also added the view permissions they need: and their keys.
400invalid json, invalid input: role_key when it's missing or isn't 1 to 100 lowercase letters, digits or underscores, permission required when permission_keys is empty or invalid input: permission_keys when one of them isn't 1 to 100 lowercase letters, digits or underscores.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
404role not found or permission not found: followed by the unknown keys.
415unsupported media type: send Content-Type: application/json. Parameters such as charset are fine.
500internal server error: something failed on our side. Try again.

200 body: application/json, object.

FieldDescription
message
string, required

Remove permissions from a role

DELETE /api/internal/role/permissions

Removes permissions from a custom role. This one takes a JSON body.

Authentication

One of these:

Request body

application/json, object.

FieldDescription
role_key
string, required
Up to 100 characters.
permission_keys
array of strings, required
At least 1 item.

Responses

StatusDescription
200message is permissions removed successfully.
400invalid json, invalid input: role_key when it's missing or isn't 1 to 100 lowercase letters, digits or underscores, permission required when permission_keys is empty or invalid input: permission_keys when one of them isn't 1 to 100 lowercase letters, digits or underscores.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
404role not found, permission not found or permission not found: followed by the unknown keys.
409another permission in this role requires it.
415unsupported media type: send Content-Type: application/json. Parameters such as charset are fine.
500internal server error: something failed on our side. Try again.

200 body: application/json, object.

FieldDescription
message
string, required

List users with a role

GET /api/internal/role/users

Users with the role that you can see. Needs permission to edit users.

Authentication

One of these:

Parameters

NameDescription
role_key
string in query, required
Role key, such as user_admin. Up to 100 characters.
q
string in query
Search text. Every word must match. Up to 256 characters.
cursor
string in query
The X-Next-Cursor value from the previous page.
limit
integer in query
Page size. Values above 200 count as 200. Default 100. At least 1.

Responses

StatusDescription
200The role and one page of its users. users is [] when there are none.
400invalid input: role_key when it's missing or isn't 1 to 100 lowercase letters, digits or underscores, invalid input: q, invalid input: limit or invalid input: cursor.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
404It doesn't exist or you can't see it. error says what, for example user not found.
500internal server error: something failed on our side. Try again.

200 headers:

HeaderDescription
X-Next-Cursor
string
Send it as cursor to get the next page. Absent on the last page.
X-Total-Count
integer
Total matches. Sent on the first page when the total is 10,000 or less.

200 body: application/json, object.

FieldDescription
role
object, required
role.role_key
string, required
role.role_name
string, required
role.role_description
string
role.role_type
string
One of default or custom.
role.account_id
string (uuid)
The organization a custom role belongs to.
role.user_count
integer
Users in your organization with this role. Left out when 0.
users
array of objects, required
users[].user_id
string (uuid)
users[].account_id
string (uuid)
The user's organization.
users[].user_first_name
string, required
users[].user_last_name
string, required
users[].user_position
string, required
Job title.
users[].user_email
string (email), required
users[].user_settings
object
Stored settings, such as timezone.
users[].user_timezone
string
IANA time zone, such as Europe/Berlin.
users[].user_created
string (date-time), required
users[].user_updated
string (date-time), required
users[].user_created_by
string (uuid)
The user who invited this one.

List roles with a permission

GET /api/internal/permission/roles

Default roles first, then your custom roles. Needs permission to edit users. You get 404 without it or when no role has the permission.

Authentication

One of these:

Parameters

NameDescription
permission_key
string in query, required
Permission key, such as view_any_user.

Responses

StatusDescription
200The permission and its roles.
400invalid input: permission_key when it's missing or isn't 1 to 100 lowercase letters, digits or underscores.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
404It doesn't exist or you can't see it. error says what, for example user not found.
500internal server error: something failed on our side. Try again.

200 body: application/json, object.

FieldDescription
permission
object, required
permission.permission_id
string (uuid)
permission.permission_key
string, required
permission.permission_name
string, required
permission.permission_description
string
permission.permission_role_count
integer
Roles with this permission. Left out when 0.
permission.permission_user_count
integer
Users you can see who hold it. Left out when 0.
roles
array of objects, required
roles[].role_key
string, required
roles[].role_name
string, required
roles[].role_description
string
roles[].role_type
string
One of default or custom.
roles[].account_id
string (uuid)
The organization a custom role belongs to.
roles[].user_count
integer
Users in your organization with this role. Left out when 0.

List users with a permission

GET /api/internal/permission/users

Users you can see who hold the permission through any role. Needs permission to edit users. Without it you get 404.

Authentication

One of these:

Parameters

NameDescription
permission_key
string in query, required
Permission key, such as view_any_user.
q
string in query
Search text. Every word must match. Up to 256 characters.
cursor
string in query
The X-Next-Cursor value from the previous page.
limit
integer in query
Page size. Values above 200 count as 200. Default 100. At least 1.

Responses

StatusDescription
200The permission and one page of users. users is [] when there are none.
400invalid input: permission_key when it's missing or isn't 1 to 100 lowercase letters, digits or underscores, invalid input: q, invalid input: limit or invalid input: cursor.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
404It doesn't exist or you can't see it. error says what, for example user not found.
500internal server error: something failed on our side. Try again.

200 headers:

HeaderDescription
X-Next-Cursor
string
Send it as cursor to get the next page. Absent on the last page.
X-Total-Count
integer
Total matches. Sent on the first page when the total is 10,000 or less.

200 body: application/json, object.

FieldDescription
permission
object, required
permission.permission_id
string (uuid)
permission.permission_key
string, required
permission.permission_name
string, required
permission.permission_description
string
permission.permission_role_count
integer
Roles with this permission. Left out when 0.
permission.permission_user_count
integer
Users you can see who hold it. Left out when 0.
users
array of objects, required
users[].user_id
string (uuid)
users[].account_id
string (uuid)
The user's organization.
users[].user_first_name
string, required
users[].user_last_name
string, required
users[].user_position
string, required
Job title.
users[].user_email
string (email), required
users[].user_settings
object
Stored settings, such as timezone.
users[].user_timezone
string
IANA time zone, such as Europe/Berlin.
users[].user_created
string (date-time), required
users[].user_updated
string (date-time), required
users[].user_created_by
string (uuid)
The user who invited this one.

List teams

GET /api/internal/teams

Teams you can see, sorted by name. If you can assign partners to teams, you also get every other team by name only.

Authentication

One of these:

Parameters

NameDescription
q
string in query
Search text. Every word must match. Up to 256 characters.
cursor
string in query
The X-Next-Cursor value from the previous page.
limit
integer in query
Page size. Values above 200 count as 200. Default 100. At least 1.
state
string in query
empty lists only teams with at most 1 member that you can add people to. One of empty.

Responses

StatusDescription
200One page of teams.
400The request isn't valid. error says why, for example invalid json or invalid input: user_id.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
500internal server error: something failed on our side. Try again.

200 headers:

HeaderDescription
X-Next-Cursor
string
Send it as cursor to get the next page. Absent on the last page.
X-Total-Count
integer
Total matches. Sent on the first page when the total is 10,000 or less.

200 body: application/json, array of objects.

FieldDescription
team_id
string (uuid)
account_id
string (uuid)
The team's organization.
team_name
string, required
team_settings
object
team_created
string (date-time)
team_updated
string (date-time)
team_created_by
string (uuid)
team_you_are_admin
boolean, required

Get a team

GET /api/internal/team

Returns the team and its counts. For members and what you can do with them, use GET /api/internal/team/members.

Authentication

One of these:

Parameters

NameDescription
team_id
string (uuid) in query, required
Team ID.

Responses

StatusDescription
200The team. team_members is left out.
400invalid input: team_id when it's missing or isn't a UUID.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
404It doesn't exist or you can't see it. error says what, for example user not found.
500internal server error: something failed on our side. Try again.

200 body: application/json, object.

FieldDescription
team_id
string (uuid)
account_id
string (uuid)
The team's organization.
team_name
string, required
team_settings
object
team_created
string (date-time)
team_updated
string (date-time)
team_created_by
string (uuid)
team_member_count
integer
Left out when 0.
team_app_count
integer
Apps shared with the team that you can see. Left out when 0.
team_managed_partner_count
integer
Partners the team manages that you can see. Left out when 0.
team_admin_count
integer, required
team_you_are_admin
boolean, required
user_can_add_users_to_this_team
boolean, required
Whether you can add people to this team.
user_can_manage_admins
boolean, required
Whether you can make and remove this team's admins.
team_members
array of objects
team_members[].user_id
string (uuid)
team_members[].account_id
string (uuid)
The user's organization.
team_members[].user_first_name
string, required
team_members[].user_last_name
string, required
team_members[].user_position
string, required
Job title.
team_members[].user_email
string (email), required
team_members[].user_settings
object
Stored settings, such as timezone.
team_members[].user_timezone
string
IANA time zone, such as Europe/Berlin.
team_members[].user_created
string (date-time), required
team_members[].user_updated
string (date-time), required
team_members[].user_created_by
string (uuid)
The user who invited this one.
team_members[].user_is_team_admin
boolean, required
team_members[].assigned_at
string (date-time), required
When they joined the team.
team_members[].user_can_remove_this_user_from_this_team
boolean, required
team_members[].user_can_make_admin
boolean, required
team_members[].user_can_remove_admin
boolean, required
team_members[].user_can_view
boolean, required
You can open this user's page.

Create a team

POST /api/internal/team

Authentication

One of these:

Request body

application/json, object.

FieldDescription
team_name
string, required
Up to 255 characters.
team_admin_id
string (uuid), required
The team's first admin.
team_settings
object

Responses

StatusDescription
200message is team created successfully.
400invalid json, team_name required, input too long when team_name is over 255 characters, team_admin_id required or team admin invalid when team_admin_id isn't a person in your organization.
401missing authorization header or invalid session.
403forbidden, team quota exceeded or team membership quota exceeded.
409team already exists.
415unsupported media type: send Content-Type: application/json. Parameters such as charset are fine.
500internal server error: something failed on our side. Try again.

200 body: application/json, object.

FieldDescription
message
string, required
team_id
string (uuid), required

Update a team

PUT /api/internal/team

Changes the name or settings. Change admins with PUT /api/internal/team/member.

Authentication

One of these:

Request body

application/json, object.

FieldDescription
team_id
string (uuid), required
team_name
string
Up to 255 characters.
team_settings
object

Responses

StatusDescription
200message is team updated successfully.
400invalid json, invalid input: team_id or input too long when team_name is over 255 characters.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
404team not found.
409team already exists.
415unsupported media type: send Content-Type: application/json. Parameters such as charset are fine.
500internal server error: something failed on our side. Try again.

200 body: application/json, object.

FieldDescription
message
string, required

Delete a team

DELETE /api/internal/team

Authentication

One of these:

Parameters

NameDescription
team_id
string (uuid) in query, required
Team ID.

Responses

StatusDescription
200message is team deleted successfully.
400invalid input: team_id when it's missing or isn't a UUID.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
404It doesn't exist or you can't see it. error says what, for example user not found.
500internal server error: something failed on our side. Try again.

200 body: application/json, object.

FieldDescription
message
string, required

List team members

GET /api/internal/team/members

The team and one page of its members, sorted by first name, then last name.

Authentication

One of these:

Parameters

NameDescription
team_id
string (uuid) in query, required
Team ID.
q
string in query
Search text. Every word must match. Up to 256 characters.
cursor
string in query
The X-Next-Cursor value from the previous page.
limit
integer in query
Page size. Values above 200 count as 200. Default 100. At least 1.

Responses

StatusDescription
200The team with team_members. team_app_count and team_managed_partner_count are left out here. team_members is [] when no member matches.
400invalid input: team_id when it's missing or isn't a UUID, invalid input: q, invalid input: limit or invalid input: cursor.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
404It doesn't exist or you can't see it. error says what, for example user not found.
500internal server error: something failed on our side. Try again.

200 headers:

HeaderDescription
X-Next-Cursor
string
Send it as cursor to get the next page. Absent on the last page.
X-Total-Count
integer
Total matches. Sent on the first page when the total is 10,000 or less.

200 body: application/json, object.

FieldDescription
team_id
string (uuid)
account_id
string (uuid)
The team's organization.
team_name
string, required
team_settings
object
team_created
string (date-time)
team_updated
string (date-time)
team_created_by
string (uuid)
team_member_count
integer
Left out when 0.
team_app_count
integer
Apps shared with the team that you can see. Left out when 0.
team_managed_partner_count
integer
Partners the team manages that you can see. Left out when 0.
team_admin_count
integer, required
team_you_are_admin
boolean, required
user_can_add_users_to_this_team
boolean, required
Whether you can add people to this team.
user_can_manage_admins
boolean, required
Whether you can make and remove this team's admins.
team_members
array of objects
team_members[].user_id
string (uuid)
team_members[].account_id
string (uuid)
The user's organization.
team_members[].user_first_name
string, required
team_members[].user_last_name
string, required
team_members[].user_position
string, required
Job title.
team_members[].user_email
string (email), required
team_members[].user_settings
object
Stored settings, such as timezone.
team_members[].user_timezone
string
IANA time zone, such as Europe/Berlin.
team_members[].user_created
string (date-time), required
team_members[].user_updated
string (date-time), required
team_members[].user_created_by
string (uuid)
The user who invited this one.
team_members[].user_is_team_admin
boolean, required
team_members[].assigned_at
string (date-time), required
When they joined the team.
team_members[].user_can_remove_this_user_from_this_team
boolean, required
team_members[].user_can_make_admin
boolean, required
team_members[].user_can_remove_admin
boolean, required
team_members[].user_can_view
boolean, required
You can open this user's page.

Add team members

POST /api/internal/team/members

Adds people from your organization to the team. 200 when none failed, 207 when any did. details has one entry per ID.

Authentication

One of these:

Request body

application/json, object.

FieldDescription
team_id
string (uuid), required
member_ids
array of strings (uuid), required
User IDs. At least 1 item.

Responses

StatusDescription
200message is team members added successfully.
207Some or all failed.
400invalid json, invalid input: team_id, required parameters missing when member_ids is empty or invalid input: member_ids when one of them isn't a UUID.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
404team not found.
415unsupported media type: send Content-Type: application/json. Parameters such as charset are fine.
500internal server error: something failed on our side. Try again.

200 and 207 body: application/json, object.

FieldDescription
message
string, required
One of team members added successfully, some team members added successfully, some failed or all team members failed to be added.
details
array of objects
details[].user_id
string (uuid), required
details[].status
string, required
assigned, already_member, duplicate_input_skipped, user_not_found or why it failed.

Make or remove a team admin

PUT /api/internal/team/member

Makes a member a team admin or removes their admin role. A team always keeps at least 1 admin.

Authentication

One of these:

Parameters

NameDescription
team_id
string (uuid) in query, required
Team ID.
user_id
string (uuid) in query, required
User ID.

Request body

application/json, object.

FieldDescription
is_admin
boolean, required
true makes the member an admin. false removes their admin role.

Responses

StatusDescription
200message is team admin added or team admin removed.
400invalid input: team_id or invalid input: user_id when that parameter is missing or isn't a UUID. invalid json or cannot remove the last admin of a team.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
404user not found: the user isn't on this team.
409team admin unchanged.
415unsupported media type: send Content-Type: application/json. Parameters such as charset are fine.
500internal server error: something failed on our side. Try again.

200 body: application/json, object.

FieldDescription
message
string, required

Remove a team member

DELETE /api/internal/team/member

Authentication

One of these:

Parameters

NameDescription
team_id
string (uuid) in query, required
Team ID.
user_id
string (uuid) in query, required
User ID.

Responses

StatusDescription
200message is team member removed successfully.
400invalid input: team_id or invalid input: user_id when that parameter is missing or isn't a UUID. cannot remove the last admin of a team.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
404not found or user is not a member of this team.
500internal server error: something failed on our side. Try again.

200 body: application/json, object.

FieldDescription
message
string, required

List a team's apps

GET /api/internal/team/apps

Apps shared with the team that you can see, sorted by name. 403 when you can't see apps.

Authentication

One of these:

Parameters

NameDescription
team_id
string (uuid) in query, required
Team ID.

Responses

StatusDescription
200The team and its apps. team has only team_id and team_name. apps is [] when there are none.
400invalid input: team_id when it's missing or isn't a UUID.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
404It doesn't exist or you can't see it. error says what, for example user not found.
500internal server error: something failed on our side. Try again.

200 body: application/json, object.

FieldDescription
team
object, required
A team. Fields an endpoint doesn't load are left out.
team.team_id
string (uuid)
team.account_id
string (uuid)
The team's organization.
team.team_name
string, required
team.team_settings
object
team.team_created
string (date-time)
team.team_updated
string (date-time)
team.team_created_by
string (uuid)
apps
array of objects, required
apps[].app_id
string (uuid)
apps[].account_id
string (uuid)
The organization that registered the app.
apps[].app_name
string
apps[].app_url
string (uri)
apps[].app_logo
string
apps[].app_logo_type
string
apps[].app_created
string (date-time), required
apps[].app_updated
string (date-time), required
apps[].app_created_by
string (uuid)
apps[].share_state
string
How far your organization has distributed the app: pending (not yet), teams (chosen teams) or organization (everyone). One of pending, teams or organization.
apps[].app_mcp_url
string (uri)
The app's MCP endpoint, when set.

List a team's partners

GET /api/internal/team/partners

Partner organizations the team manages, sorted by name.

Authentication

One of these:

Parameters

NameDescription
team_id
string (uuid) in query, required
Team ID.
q
string in query
Search text. Every word must match. Up to 256 characters.
cursor
string in query
The X-Next-Cursor value from the previous page.
limit
integer in query
Page size. Values above 200 count as 200. Default 100. At least 1.

Responses

StatusDescription
200One page of partners.
400invalid input: team_id when it's missing or isn't a UUID, invalid input: q, invalid input: limit or invalid input: cursor.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
404It doesn't exist or you can't see it. error says what, for example user not found.
500internal server error: something failed on our side. Try again.

200 headers:

HeaderDescription
X-Next-Cursor
string
Send it as cursor to get the next page. Absent on the last page.
X-Total-Count
integer
Total matches. Sent on the first page when the total is 10,000 or less.

200 body: application/json, array of objects.

FieldDescription
account_id
string (uuid)
parent_id
string (uuid)
The organization directly above.
account_name
string, required
account_country
string, required
account_level
string, required
One of root, partner or subpartner.
account_type
string, required
account_plan
string, required
One of free, pilot, premium or root.
account_settings
object
account_created
string (date-time), required
account_updated
string (date-time), required
account_expiry
string (date-time), required
When the organization's access ends.

Assign a partner to a team

POST /api/internal/team/partner

The team then manages that partner organization.

Authentication

One of these:

Request body

application/json, object.

FieldDescription
team_id
string (uuid), required
partner_account_id
string (uuid), required

Responses

StatusDescription
200message is partner assigned to team successfully.
400invalid json, invalid input: team_id or invalid input: partner_account_id.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
404team not found or account not found.
409already exists: the team already manages this partner.
415unsupported media type: send Content-Type: application/json. Parameters such as charset are fine.
500internal server error: something failed on our side. Try again.

200 body: application/json, object.

FieldDescription
message
string, required

Unassign a partner from a team

DELETE /api/internal/team/partner

Authentication

One of these:

Parameters

NameDescription
team_id
string (uuid) in query, required
Team ID.
partner_account_id
string (uuid) in query, required
Partner organization ID.

Responses

StatusDescription
200message is partner unassigned from team successfully.
400invalid input: team_id or invalid input: partner_account_id when that parameter is missing or isn't a UUID.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
404partner not found or team not found.
500internal server error: something failed on our side. Try again.

200 body: application/json, object.

FieldDescription
message
string, required

List apps

GET /api/internal/apps

Apps your organization registered or received that you can see, sorted by name.

Authentication

One of these:

Parameters

NameDescription
q
string in query
Search text. Every word must match. Up to 256 characters.
cursor
string in query
The X-Next-Cursor value from the previous page.
limit
integer in query
Page size. Values above 200 count as 200. Default 100. At least 1.
state
string in query
organization: available to everyone. unassigned or undistributed: not yet available to everyone or any team. received: shared with your organization by another one. One of organization, unassigned, undistributed or received.

Responses

StatusDescription
200One page of apps. Each has app_id, account_id, app_name, app_url, app_logo, app_logo_type and share_state filled in.
400The request isn't valid. error says why, for example invalid json or invalid input: user_id.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
404not found: state=unassigned with no q or cursor found nothing.
500internal server error: something failed on our side. Try again.

200 headers:

HeaderDescription
X-Next-Cursor
string
Send it as cursor to get the next page. Absent on the last page.
X-Total-Count
integer
Total matches. Sent on the first page when the total is 10,000 or less.

200 body: application/json, array of objects.

FieldDescription
app_id
string (uuid)
account_id
string (uuid)
The organization that registered the app.
app_name
string
app_url
string (uri)
app_logo
string
app_logo_type
string
app_created
string (date-time), required
app_updated
string (date-time), required
app_created_by
string (uuid)
share_state
string
How far your organization has distributed the app: pending (not yet), teams (chosen teams) or organization (everyone). One of pending, teams or organization.
app_mcp_url
string (uri)
The app's MCP endpoint, when set.

Get an app

GET /api/internal/app

Authentication

One of these:

Parameters

NameDescription
app_id
string (uuid) in query, required
App ID.

Responses

StatusDescription
200The app and what you can do with it.
400invalid input: app_id when it's missing or isn't a UUID.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
404It doesn't exist or you can't see it. error says what, for example user not found.
500internal server error: something failed on our side. Try again.

200 body: application/json, object.

FieldDescription
app
object, required
app.app_id
string (uuid)
app.account_id
string (uuid)
The organization that registered the app.
app.app_name
string
app.app_url
string (uri)
app.app_logo
string
app.app_logo_type
string
app.app_created
string (date-time), required
app.app_updated
string (date-time), required
app.app_created_by
string (uuid)
app.share_state
string
How far your organization has distributed the app: pending (not yet), teams (chosen teams) or organization (everyone). One of pending, teams or organization.
app.app_mcp_url
string (uri)
The app's MCP endpoint, when set.
app.creator_id
string (uuid)
app.creator_first_name
string
app.creator_last_name
string
app.creator_is_you
boolean, required
app.app_users_count
integer
People in your organization who can open it. Left out when 0.
app.app_teams_count
integer
Teams in your organization it's shared with. Left out when 0.
app.app_partners_count
integer
Partners it's shared with. Left out when 0.
app.user_can_view_this_app
boolean, required
Always true.
app.user_can_edit_this_app
boolean, required
app.user_can_delete_this_app
boolean, required
app.user_can_share_this_app
boolean, required
You can share it with everyone, teams or partners.
app.user_can_share_to_account
boolean, required
You can make it available to everyone.
app.user_can_share_to_teams
boolean, required
app.user_can_share_to_partners
boolean, required
app.user_can_unshare_this_app
boolean, required
app.user_can_view_this_app_users
boolean, required
app.user_can_view_this_app_teams
boolean, required
app.user_can_view_this_app_partners
boolean, required
app.user_can_view_creator
boolean, required
app.is_shared_with_user_account
boolean, required
The app is available to everyone in your organization.
app.is_received
boolean, required
Another organization registered the app and shared it with yours.
app.owner_name
string
Name of the organization that registered the app.

Register an app

POST /api/internal/app

Registers an app for your organization. The response is the only time you see app_secret.

Authentication

One of these:

Request body

application/json, object.

FieldDescription
app_name
string, required
Up to 255 characters.
app_url
string (uri), required
HTTPS URL of the app. Saved in lowercase.
app_logo
string, required
app_logo_type
string, required
app_mcp_url
string (uri)
HTTPS URL of the app's MCP endpoint, if it has one.

Responses

StatusDescription
200message is app registered successfully.
400The request isn't valid. error says why, for example invalid json or invalid input: user_id.
401missing authorization header or invalid session.
403forbidden or app quota exceeded.
409app already exists.
415unsupported media type: send Content-Type: application/json. Parameters such as charset are fine.
500internal server error: something failed on our side. Try again.

200 headers:

HeaderDescription
Cache-Control
string
Don't cache this response. Always no-store.

200 body: application/json, object.

FieldDescription
message
string, required
app_id
string (uuid), required
app_secret
string, required
Shown only here. Store it now. Exactly 64 characters.

Update an app

PUT /api/internal/app

Changes only the fields you send. Send at least 1.

Authentication

One of these:

Parameters

NameDescription
app_id
string (uuid) in query, required
App ID.

Request body

application/json, object.

FieldDescription
app_name
string
Up to 255 characters.
app_url
string (uri)
HTTPS URL of the app.
app_logo
string
app_logo_type
string
app_mcp_url
string
HTTPS URL of the app's MCP endpoint. An empty string removes it.

Responses

StatusDescription
200message is app updated successfully.
400invalid input: app_id when it's missing or isn't a UUID, invalid json, input too long when app_name is over 255 characters, invalid app url, invalid app mcp url or required parameters missing when nothing changes.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
404It doesn't exist or you can't see it. error says what, for example user not found.
409app already exists.
415unsupported media type: send Content-Type: application/json. Parameters such as charset are fine.
500internal server error: something failed on our side. Try again.

200 body: application/json, object.

FieldDescription
message
string, required

Delete an app

DELETE /api/internal/app

Authentication

One of these:

Parameters

NameDescription
app_id
string (uuid) in query, required
App ID.

Responses

StatusDescription
200message is app deleted successfully.
400invalid input: app_id when it's missing or isn't a UUID.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
404It doesn't exist or you can't see it. error says what, for example user not found.
500internal server error: something failed on our side. Try again.

200 body: application/json, object.

FieldDescription
message
string, required

Rotate an app secret

POST /api/internal/app/secret

Creates a new secret for an app your organization registered. The old one stops working at once, so every SDK still using it fails until you update it. The response is the only time you see the new one. Needs permission to edit the app.

Authentication

One of these:

Parameters

NameDescription
app_id
string (uuid) in query, required
App ID.

Responses

StatusDescription
200The new secret.
400invalid input: app_id when it's missing or isn't a UUID.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
404It doesn't exist or you can't see it. error says what, for example user not found.
500internal server error: something failed on our side. Try again.

200 headers:

HeaderDescription
Cache-Control
string
Don't cache this response. Always no-store.

200 body: application/json, object.

FieldDescription
app_secret
string, required
Exactly 64 characters.

List an app's teams

GET /api/internal/app/teams

Teams in your organization the app is shared with, sorted by name.

Authentication

One of these:

Parameters

NameDescription
app_id
string (uuid) in query, required
App ID.
q
string in query
Search text. Every word must match. Up to 256 characters.
cursor
string in query
The X-Next-Cursor value from the previous page.
limit
integer in query
Page size. Values above 200 count as 200. Default 100. At least 1.

Responses

StatusDescription
200The app and one page of teams. app has only app_id and app_name.
400invalid input: app_id when it's missing or isn't a UUID, invalid input: q, invalid input: limit or invalid input: cursor.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
404It doesn't exist or you can't see it. error says what, for example user not found.
500internal server error: something failed on our side. Try again.

200 headers:

HeaderDescription
X-Next-Cursor
string
Send it as cursor to get the next page. Absent on the last page.
X-Total-Count
integer
Total matches. Sent on the first page when the total is 10,000 or less.

200 body: application/json, object.

FieldDescription
app
object, required
An app. Fields an endpoint doesn't load are left out. Dates it doesn't load are 0001-01-01T00:00:00Z.
app.app_id
string (uuid)
app.account_id
string (uuid)
The organization that registered the app.
app.app_name
string
app.app_url
string (uri)
app.app_logo
string
app.app_logo_type
string
app.app_created
string (date-time), required
app.app_updated
string (date-time), required
app.app_created_by
string (uuid)
app.share_state
string
How far your organization has distributed the app: pending (not yet), teams (chosen teams) or organization (everyone). One of pending, teams or organization.
app.app_mcp_url
string (uri)
The app's MCP endpoint, when set.
teams
array of objects, required
teams[].team_id
string (uuid), required
teams[].team_name
string, required
teams[].access_view_this_team
boolean, required
teams[].access_stop_sharing_app_with_this_team
boolean, required

List who can open an app

GET /api/internal/app/users

People you can see who can open an app your organization registered. App admins can open every app. Others get it through a team. users is empty when the app is available to everyone.

Authentication

One of these:

Parameters

NameDescription
app_id
string (uuid) in query, required
App ID.
q
string in query
Search text. Every word must match. Up to 256 characters.
cursor
string in query
The X-Next-Cursor value from the previous page.
limit
integer in query
Page size. Values above 200 count as 200. Default 100. At least 1.

Responses

StatusDescription
200The app and one page of users. app has only app_id and app_name.
400invalid input: app_id when it's missing or isn't a UUID, invalid input: q, invalid input: limit or invalid input: cursor.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
404app not found, also for apps your organization received from another one.
500internal server error: something failed on our side. Try again.

200 headers:

HeaderDescription
X-Next-Cursor
string
Send it as cursor to get the next page. Absent on the last page.
X-Total-Count
integer
Total matches. Sent on the first page when the total is 10,000 or less.

200 body: application/json, object.

FieldDescription
app
object, required
An app. Fields an endpoint doesn't load are left out. Dates it doesn't load are 0001-01-01T00:00:00Z.
app.app_id
string (uuid)
app.account_id
string (uuid)
The organization that registered the app.
app.app_name
string
app.app_url
string (uri)
app.app_logo
string
app.app_logo_type
string
app.app_created
string (date-time), required
app.app_updated
string (date-time), required
app.app_created_by
string (uuid)
app.share_state
string
How far your organization has distributed the app: pending (not yet), teams (chosen teams) or organization (everyone). One of pending, teams or organization.
app.app_mcp_url
string (uri)
The app's MCP endpoint, when set.
users
array of objects, required
users[].user_id
string (uuid), required
users[].user_first_name
string, required
users[].user_last_name
string, required
users[].user_email
string (email), required
users[].user_position
string, required
users[].access_view_this_user
boolean, required
Always true.

List an app's partners

GET /api/internal/app/partners

Partner organizations you can see that an app your organization registered is shared with, sorted by name.

Authentication

One of these:

Parameters

NameDescription
app_id
string (uuid) in query, required
App ID.
q
string in query
Search text. Every word must match. Up to 256 characters.
cursor
string in query
The X-Next-Cursor value from the previous page.
limit
integer in query
Page size. Values above 200 count as 200. Default 100. At least 1.

Responses

StatusDescription
200The app and one page of partners. app has only app_id and app_name.
400invalid input: app_id when it's missing or isn't a UUID, invalid input: q, invalid input: limit or invalid input: cursor.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
404app not found, also for apps your organization received from another one.
500internal server error: something failed on our side. Try again.

200 headers:

HeaderDescription
X-Next-Cursor
string
Send it as cursor to get the next page. Absent on the last page.
X-Total-Count
integer
Total matches. Sent on the first page when the total is 10,000 or less.

200 body: application/json, object.

FieldDescription
app
object, required
An app. Fields an endpoint doesn't load are left out. Dates it doesn't load are 0001-01-01T00:00:00Z.
app.app_id
string (uuid)
app.account_id
string (uuid)
The organization that registered the app.
app.app_name
string
app.app_url
string (uri)
app.app_logo
string
app.app_logo_type
string
app.app_created
string (date-time), required
app.app_updated
string (date-time), required
app.app_created_by
string (uuid)
app.share_state
string
How far your organization has distributed the app: pending (not yet), teams (chosen teams) or organization (everyone). One of pending, teams or organization.
app.app_mcp_url
string (uri)
The app's MCP endpoint, when set.
partners
array of objects, required
partners[].account_id
string (uuid), required
partners[].account_name
string, required
partners[].access_stop_sharing_app_with_this_partner
boolean, required

Make an app available to everyone

POST /api/internal/app/account

Everyone in your organization can then open the app.

Authentication

One of these:

Request body

application/json, object.

FieldDescription
app_id
string (uuid), required
account_id
string (uuid)
Your organization's ID. Any other value returns 400.

Responses

StatusDescription
200message is app shared with account successfully.
400invalid json, invalid input: app_id or invalid input when account_id isn't your organization's ID.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
404app not found.
409app already shared with the organization.
415unsupported media type: send Content-Type: application/json. Parameters such as charset are fine.
500internal server error: something failed on our side. Try again.

200 body: application/json, object.

FieldDescription
message
string, required

Stop sharing an app with everyone

DELETE /api/internal/app/account

Authentication

One of these:

Parameters

NameDescription
app_id
string (uuid) in query, required
App ID.
account_id
string (uuid) in query
Your organization's ID. Any other value returns 400.

Responses

StatusDescription
200message is app unshared from account successfully.
400invalid input: app_id when it's missing or isn't a UUID. invalid input when account_id isn't your organization's ID.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
404app not found or app is not shared there.
500internal server error: something failed on our side. Try again.

200 body: application/json, object.

FieldDescription
message
string, required

Share an app with a team

POST /api/internal/app/team

Members of the team can then open the app.

Authentication

One of these:

Request body

application/json, object.

FieldDescription
app_id
string (uuid), required
team_id
string (uuid), required

Responses

StatusDescription
200message is app shared with team successfully.
400invalid json, invalid input: app_id or invalid input: team_id.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
404app not found or team not found.
415unsupported media type: send Content-Type: application/json. Parameters such as charset are fine.
500internal server error: something failed on our side. Try again.

200 body: application/json, object.

FieldDescription
message
string, required

Stop sharing an app with a team

DELETE /api/internal/app/team

Authentication

One of these:

Parameters

NameDescription
app_id
string (uuid) in query, required
App ID.
team_id
string (uuid) in query, required
Team ID.

Responses

StatusDescription
200message is app unshared from team successfully.
400invalid input: app_id or invalid input: team_id when that parameter is missing or isn't a UUID.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
404app not found or app is not shared there.
500internal server error: something failed on our side. Try again.

200 body: application/json, object.

FieldDescription
message
string, required

Share an app with a partner

POST /api/internal/app/partner

Shares an app your organization registered with a partner organization. Its members see the app only after its app admins distribute it.

Authentication

One of these:

Parameters

NameDescription
app_id
string (uuid) in query, required
App ID.

Request body

application/json, object.

FieldDescription
partner_id
string (uuid), required
Partner organization ID.

Responses

StatusDescription
200message is app shared with account successfully.
400invalid json. invalid input: app_id when it's missing or isn't a UUID. invalid input: partner_id when partner_id is missing, your own organization or not a UUID.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
404app not found or partner not found.
415unsupported media type: send Content-Type: application/json. Parameters such as charset are fine.
500internal server error: something failed on our side. Try again.

200 body: application/json, object.

FieldDescription
message
string, required

Stop sharing an app with a partner

DELETE /api/internal/app/partner

Authentication

One of these:

Parameters

NameDescription
app_id
string (uuid) in query, required
App ID.
partner_account_id
string (uuid) in query, required
Partner organization ID.

Responses

StatusDescription
200message is app unshared from account successfully.
400invalid input: app_id when it's missing or isn't a UUID. invalid input: partner_account_id when it's missing, your own organization or not a UUID.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
404app not found, partner not found or app is not shared there.
500internal server error: something failed on our side. Try again.

200 body: application/json, object.

FieldDescription
message
string, required

List partners

GET /api/internal/partners

Partner organizations directly below yours that you can see.

Authentication

One of these:

Parameters

NameDescription
q
string in query
Search text. Every word must match. Up to 256 characters.
cursor
string in query
The X-Next-Cursor value from the previous page.
limit
integer in query
Page size. Values above 200 count as 200. Default 100. At least 1.
state
string in query
active (the default) sorts by name. expiring lists partners close to expiry, soonest first. closed lists closed partners, most recently closed first. It needs permission to see every partner. One of active, expiring or closed.

Responses

StatusDescription
200One page of partners.
400The request isn't valid. error says why, for example invalid json or invalid input: user_id.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
500internal server error: something failed on our side. Try again.

200 headers:

HeaderDescription
X-Next-Cursor
string
Send it as cursor to get the next page. Absent on the last page.
X-Total-Count
integer
Total matches. Sent on the first page when the total is 10,000 or less.

200 body: application/json, array of objects.

FieldDescription
account_id
string (uuid), required
account_name
string, required
account_expiry
string (date-time), required

Get a partner

GET /api/internal/partner

A partner organization directly below yours, open or closed.

Authentication

One of these:

Parameters

NameDescription
partner_id
string (uuid) in query, required
Partner organization ID.

Responses

StatusDescription
200The partner. total_available_apps counts the apps your organization shared with it that you can see. A closed partner has no owner or totals. Its account_updated is when it closed.
400invalid input: partner_id when it's missing or isn't a UUID.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
404It doesn't exist or you can't see it. error says what, for example user not found.
500internal server error: something failed on our side. Try again.

200 body: application/json, object.

FieldDescription
account_id
string (uuid)
parent_id
string (uuid)
The organization directly above.
account_name
string, required
account_country
string, required
account_level
string, required
One of root, partner or subpartner.
account_type
string, required
account_plan
string, required
One of free, pilot, premium or root.
account_settings
object
account_created
string (date-time), required
account_updated
string (date-time), required
account_expiry
string (date-time), required
When the organization's access ends.
owner_id
string (uuid)
owner_first_name
string
owner_last_name
string
owner_position
string
owner_email
string (email)
total_teams
integer
total_users
integer
total_owned_apps
integer
Apps the organization registered.
total_available_apps
integer
managed_by
array of objects, required
Teams in your organization that manage this partner.
managed_by[].team_id
string (uuid), required
managed_by[].team_name
string, required

Close a partner

POST /api/internal/partner/close

Closes a partner organization and removes everything under it. This is final.

Authentication

One of these:

Parameters

NameDescription
partner_id
string (uuid) in query, required
Partner organization ID.

Responses

StatusDescription
200message is partner closed successfully.
400invalid input: partner_id when it's missing or isn't a UUID.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
404It doesn't exist or you can't see it. error says what, for example user not found.
500internal server error: something failed on our side. Try again.

200 body: application/json, object.

FieldDescription
message
string, required

Extend a partner's expiry

POST /api/internal/partner/expiry

Moves a partner organization's expiry to a later date.

Authentication

One of these:

Parameters

NameDescription
partner_id
string (uuid) in query, required
Partner organization ID.

Request body

application/json, object.

FieldDescription
target_expiry_date
string (date), required
The new expiry date, such as 2026-12-31.

Responses

StatusDescription
200message is partner expiry extended successfully.
400invalid json or invalid input: partner_id when it's missing or isn't a UUID. extension must be between 1 and 3 months when target_expiry_date is missing, isn't YYYY-MM-DD or isn't later than both today and the current expiry. extension would exceed maximum allowed expiry date when it's more than 90 days from now.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
404It doesn't exist or you can't see it. error says what, for example user not found.
409The expiry can't be extended yet.
415unsupported media type: send Content-Type: application/json. Parameters such as charset are fine.
500internal server error: something failed on our side. Try again.

200 body: application/json, object.

FieldDescription
message
string, required

List apps shared with a partner

GET /api/internal/partner/apps

Apps your organization shared with the partner that you can see, sorted by name. share_state shows how far the partner has distributed each one.

Authentication

One of these:

Parameters

NameDescription
partner_id
string (uuid) in query, required
Partner organization ID.

Responses

StatusDescription
200The partner's name and its apps.
400invalid input: partner_id when it's missing or isn't a UUID.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
404It doesn't exist or you can't see it. error says what, for example user not found.
500internal server error: something failed on our side. Try again.

200 body: application/json, object.

FieldDescription
partner_name
string, required
apps
array of objects, required
apps[].app_id
string (uuid)
apps[].account_id
string (uuid)
The organization that registered the app.
apps[].app_name
string
apps[].app_url
string (uri)
apps[].app_logo
string
apps[].app_logo_type
string
apps[].app_created
string (date-time), required
apps[].app_updated
string (date-time), required
apps[].app_created_by
string (uuid)
apps[].share_state
string
How far your organization has distributed the app: pending (not yet), teams (chosen teams) or organization (everyone). One of pending, teams or organization.
apps[].app_mcp_url
string (uri)
The app's MCP endpoint, when set.

Get a partner's limits

GET /api/internal/partner/limits

Authentication

One of these:

Parameters

NameDescription
partner_id
string (uuid) in query, required
Partner organization ID.

Responses

StatusDescription
200The partner's plan, limits and use.
400invalid input: partner_id when it's missing or isn't a UUID.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
404It doesn't exist or you can't see it. error says what, for example user not found.
500internal server error: something failed on our side. Try again.

200 body: application/json, object.

FieldDescription
account_id
string (uuid), required
account_name
string, required
account_plan
string, required
limits
object, required
limits.users
object, required
limits.users.current
integer, required
limits.users.max
integer, required
limits.users.remaining
integer, required
-1 when max is 0 or current is over max.
limits.teams
object, required
limits.teams.current
integer, required
limits.teams.max
integer, required
limits.teams.remaining
integer, required
-1 when max is 0 or current is over max.
limits.apps
object, required
limits.apps.current
integer, required
limits.apps.max
integer, required
limits.apps.remaining
integer, required
-1 when max is 0 or current is over max.
limits.partners
object, required
limits.partners.current
integer, required
limits.partners.max
integer, required
limits.partners.remaining
integer, required
-1 when max is 0 or current is over max.

List teams managing a partner

GET /api/internal/partner/teams

Teams in your organization that manage the partner, sorted by name.

Authentication

One of these:

Parameters

NameDescription
partner_id
string (uuid) in query, required
Partner organization ID.

Responses

StatusDescription
200The teams.
400invalid input: partner_id when it's missing or isn't a UUID.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
404It doesn't exist or you can't see it. error says what, for example user not found.
500internal server error: something failed on our side. Try again.

200 body: application/json, array of objects.

FieldDescription
team_id
string (uuid), required
team_name
string, required

List signups

GET /api/internal/signups

Signups for new organizations under yours, newest first. Needs permission to see signups.

Authentication

One of these:

Parameters

NameDescription
status
string in query
Leave it out or send all for every signup. One of all, pending or rejected.
q
string in query
Search text. Every word must match. Up to 256 characters.
cursor
string in query
The X-Next-Cursor value from the previous page.
limit
integer in query
Page size. Values above 200 count as 200. Default 100. At least 1.

Responses

StatusDescription
200One page of signups.
400The request isn't valid. error says why, for example invalid json or invalid input: user_id.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
500internal server error: something failed on our side. Try again.

200 headers:

HeaderDescription
X-Next-Cursor
string
Send it as cursor to get the next page. Absent on the last page.
X-Total-Count
integer
Total matches. Sent on the first page when the total is 10,000 or less.

200 body: application/json, array of objects.

FieldDescription
signup_id
string (uuid), required
account_name
string, required
signup_status
string, required
One of pending or rejected.
signup_created
string (date-time), required
signup_updated
string (date-time)
account_country
string
account_level
string
account_type
string
account_plan
string
account_timezone
string
user_first_name
string
user_last_name
string
user_email
string
user_position
string

Get a signup

GET /api/internal/signup

One signup for a new organization under yours, with who sent it and what stops its approval. Needs permission to see signups.

Authentication

One of these:

Parameters

NameDescription
signup_id
string (uuid) in query, required
Signup ID.

Responses

StatusDescription
200The signup.
400invalid input: signup_id.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
404signup not found, also when you can't see it.
500internal server error: something failed on our side. Try again.

200 body: application/json, object.

FieldDescription
signup_id
string (uuid), required
account_name
string, required
Name of the new organization.
account_country
string, required
account_type
string, required
What kind of organization it is.
account_plan
string, required
One of free, pilot or premium.
user_first_name
string, required
user_last_name
string, required
user_email
string (email), required
They become the owner when the signup is approved.
user_position
string, required
Job title.
signup_status
string, required
An approved signup becomes the organization and is no longer listed. One of pending or rejected.
signup_message
string, required
The note for the approvers. Empty when there is none.
signup_reviewer_notes
string, required
The reason given when it was rejected. Empty until then.
signup_created
string (date-time), required
signup_updated
string (date-time), required
can_approve
boolean, required
Whether you can approve it now with POST /api/internal/signup/approve. false while approve_blocked is set.
can_reject
boolean, required
Whether you can reject it now with POST /api/internal/signup/reject.
approve_blocked
string or null, required
What stops approval: email_taken when the email already belongs to a user, name_taken when an organization with this name and country exists, partner_limit when you have as many partners as your plan allows. null when nothing does or you can't approve it. One of email_taken, name_taken, partner_limit or null.

Approve a signup

POST /api/internal/signup/approve

Creates the organization and its owner.

Authentication

One of these:

Request body

application/json, object.

FieldDescription
signup_id
string (uuid), required

Responses

StatusDescription
200The new organization and its owner.
400invalid json or invalid input: signup_id when it's missing or isn't a UUID.
401missing authorization header or invalid session.
403forbidden or subaccount quota exceeded.
404It doesn't exist or you can't see it. error says what, for example user not found.
409email already exists.
415unsupported media type: send Content-Type: application/json. Parameters such as charset are fine.
500internal server error: something failed on our side. Try again.

200 body: application/json, object.

FieldDescription
account_id
string (uuid), required
The new organization.
user_id
string (uuid), required
Its owner.

List support requests

GET /api/internal/support-requests

Support requests you sent, newest first. With box set to inbox, the requests that organizations directly below yours sent to your organization. The inbox needs permission to see every partner, in an organization that isn't a subpartner. While your organization's access has expired you can list only your own requests. inbox gets 403.

Authentication

One of these:

Parameters

NameDescription
box
string in query
mine for requests you sent. inbox for requests sent to your organization. One of mine or inbox. Default mine.
status
string in query
Leave it out for every status. One of pending, responded or closed.
type
string in query
Leave it out for every type. One of Account & Billing, Access, Integration, Quota, Bug Report, Feature Request or Other.
q
string in query
Search text. Every word must match the subject, type or organization name. Up to 256 characters.
cursor
string in query
The X-Next-Cursor value from the previous page.
limit
integer in query
Page size. Values above 200 count as 200. Default 100. At least 1.

Responses

StatusDescription
200One page of support requests.
400The request isn't valid. error says why, for example invalid json or invalid input: user_id.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
500internal server error: something failed on our side. Try again.

200 headers:

HeaderDescription
X-Next-Cursor
string
Send it as cursor to get the next page. Absent on the last page.
X-Total-Count
integer
Total matches. Sent on the first page when the total is 10,000 or less.

200 body: application/json, array of objects.

FieldDescription
support_request_id
string (uuid), required
account_id
string (uuid), required
The organization that sent it. Yours in mine.
account_name
string, required
request_type
string, required
One of Account & Billing, Access, Integration, Quota, Bug Report, Feature Request or Other.
subject
string, required
status
string, required
One of pending, responded or closed.
support_request_created
string (date-time), required
support_request_updated
string (date-time), required

Send a support request

POST /api/internal/support-requests

Sends a support request from you to the organization directly above yours. It replies by email. You can send up to 5 in 1 hour. This works while your organization's access has expired.

Authentication

One of these:

Request body

application/json, object.

FieldDescription
request_type
string, required
One of Account & Billing, Access, Integration, Quota, Bug Report, Feature Request or Other.
subject
string, required
3 to 150 characters.
message
string, required
10 to 5000 characters.

Responses

StatusDescription
200The new request.
400invalid json. invalid input when request_type isn't one of the types, subject is under 3 characters or message is under 10. input too long when subject is over 150 characters or message is over 5000.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
415unsupported media type: send Content-Type: application/json. Parameters such as charset are fine.
429too many requests, please try again later: you sent 5 in the last hour.
500internal server error: something failed on our side. Try again.

200 body: application/json, object.

FieldDescription
support_request_id
string (uuid), required
status
string, required
Always pending.

Get a support request

GET /api/internal/support-request

One support request with its message: one you sent, or one in your organization's inbox. The inbox needs permission to see every partner. Replies go by email. To mark a request responded or closed, use POST /api/internal/support-request/status. While your organization's access has expired you can read only requests you sent.

Authentication

One of these:

Parameters

NameDescription
support_request_id
string (uuid) in query, required
Support request ID.

Responses

StatusDescription
200The request.
400invalid input: support_request_id.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
404support request not found, also when you can't see it.
500internal server error: something failed on our side. Try again.

200 body: application/json, object.

FieldDescription
support_request_id
string (uuid), required
account_id
string (uuid), required
The organization that sent it.
account_name
string, required
user_id
string (uuid), required
The person who sent it.
user_first_name
string, required
user_last_name
string, required
user_email
string (email), required
request_type
string, required
One of Account & Billing, Access, Integration, Quota, Bug Report, Feature Request or Other.
subject
string, required
message
string, required
status
string, required
pending can change to responded or closed, and responded to closed. No change can be undone. One of pending, responded or closed.
resolved_at
string (date-time) or null, required
When it was closed. null until then.
support_request_created
string (date-time), required
support_request_updated
string (date-time), required
mine
boolean, required
Whether you sent it.
can_resolve
boolean, required
Whether you can change its status now with POST /api/internal/support-request/status.

Update a support request

POST /api/internal/support-request/status

Marks a support request from an organization below yours as responded or closed.

Authentication

One of these:

Request body

application/json, object.

FieldDescription
support_request_id
string (uuid), required
status
string, required
One of responded or closed.

Responses

StatusDescription
200message is support request marked responded or support request marked closed.
400invalid json, invalid input: support_request_id or status must be responded or closed.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
404It doesn't exist or you can't see it. error says what, for example user not found.
409support request already closed or support request already responded.
415unsupported media type: send Content-Type: application/json. Parameters such as charset are fine.
500internal server error: something failed on our side. Try again.

200 body: application/json, object.

FieldDescription
message
string, required

Reject a signup

POST /api/internal/signup/reject

Authentication

One of these:

Request body

application/json, object.

FieldDescription
signup_id
string (uuid), required
reason
string, required
3 to 500 characters.

Responses

StatusDescription
204Rejected. No body.
400invalid json. invalid input: signup_id when it's missing or isn't a UUID. invalid input when reason is under 3 or over 500 characters.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
404It doesn't exist or you can't see it. error says what, for example user not found.
415unsupported media type: send Content-Type: application/json. Parameters such as charset are fine.
500internal server error: something failed on our side. Try again.

Get your organization

GET /api/internal/account

Needs permission to see the organization.

Authentication

One of these:

Responses

StatusDescription
200Your organization. total_available_apps counts apps available to everyone. The owner's ID, email and job title are left out when you can't see the owner.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
500internal server error: something failed on our side. Try again.

200 body: application/json, object.

FieldDescription
account_id
string (uuid)
parent_id
string (uuid)
The organization directly above.
account_name
string, required
account_country
string, required
account_level
string, required
One of root, partner or subpartner.
account_type
string, required
account_plan
string, required
One of free, pilot, premium or root.
account_settings
object
account_created
string (date-time), required
account_updated
string (date-time), required
account_expiry
string (date-time), required
When the organization's access ends.
owner_id
string (uuid)
owner_first_name
string
owner_last_name
string
owner_position
string
owner_email
string (email)
total_teams
integer
total_users
integer
total_owned_apps
integer
Apps the organization registered.
total_available_apps
integer

Transfer ownership

PUT /api/internal/account/owner

Makes another user in your organization the owner. Only the owner can do this. You keep the role you name.

Authentication

One of these:

Request body

application/json, object.

FieldDescription
new_owner_user_id
string (uuid), required
previous_owner_role_key
string, required
The role you keep, such as user_admin. Not account_owner. Up to 100 characters.

Responses

StatusDescription
200message is ownership transferred successfully.
400invalid json, invalid input: new_owner_user_id when it's missing or isn't a UUID, new owner must be account member when new_owner_user_id isn't another person in your organization, invalid input: previous_owner_role_key when it's missing, account_owner or isn't 1 to 100 lowercase letters, digits or underscores.
401missing authorization header or invalid session.
403only owner can transfer ownership or account expired.
404role not found: previous_owner_role_key isn't a role you can take.
415unsupported media type: send Content-Type: application/json. Parameters such as charset are fine.
500internal server error: something failed on our side. Try again.

200 body: application/json, object.

FieldDescription
message
string, required

Rotate the organization secret

POST /api/internal/account/secret

Creates a new organization secret for X-Org-Secret on POST /api/public/signup. The previous one stops working. The response is the only time you see it.

Authentication

One of these:

Responses

StatusDescription
200The new secret.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
500internal server error: something failed on our side. Try again.

200 headers:

HeaderDescription
Cache-Control
string
Don't cache this response. Always no-store.

200 body: application/json, object.

FieldDescription
org_secret
string, required
Exactly 64 characters.

Get AI access

GET /api/internal/account/ai-access

What AI clients can do in your organization through the platform's MCP server, and which AI client hosts can connect. Only the owner can see this.

Authentication

One of these:

Responses

StatusDescription
200The current settings.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
404not found: this region doesn't offer AI clients.
500internal server error: something failed on our side. Try again.

200 body: application/json, object.

FieldDescription
ai_access
string, required
off: AI clients can't connect. read: view only. write: view and change. One of off, read or write.
ai_clients
array of strings, required
AI client hosts allowed to connect, such as claude.ai, sorted. Empty allows any AI client. Up to 20 items.

Change AI access

PUT /api/internal/account/ai-access

Changes 1 setting per call: send ai_access or ai_clients, not both. Only the owner can do this.

AI clients connected to individual apps stay connected.

Authentication

One of these:

Request body

application/json, object.

FieldDescription
ai_access
string
off: AI clients can't connect. read: view only. write: view and change. One of off, read or write.
ai_clients
array of strings
Host names such as claude.ai, up to 253 characters each. A URL counts as its host. Duplicates are dropped. Empty allows any AI client. Up to 20 items.

Responses

StatusDescription
200The setting you changed and its value before.
400invalid json, invalid input: send ai_access or ai_clients, invalid input: ai_access or invalid input: hosts.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
404not found: this region doesn't offer AI clients.
415unsupported media type: send Content-Type: application/json. Parameters such as charset are fine.
500internal server error: something failed on our side. Try again.

200 body: application/json, object.

FieldDescription
ai_access
string
When you sent ai_access. One of off, read or write.
ai_clients
array of strings
When you sent ai_clients. Sorted, without duplicates.
previous
string or array of strings, required
The value before, in the same form.

Get your organization's limits

GET /api/internal/limits

Needs permission to see limits.

Authentication

One of these:

Responses

StatusDescription
200Your plan, limits and use.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
500internal server error: something failed on our side. Try again.

200 body: application/json, object.

FieldDescription
account_id
string (uuid), required
account_name
string, required
account_plan
string, required
limits
object, required
limits.users
object, required
limits.users.current
integer, required
limits.users.max
integer, required
limits.users.remaining
integer, required
-1 when max is 0 or current is over max.
limits.teams
object, required
limits.teams.current
integer, required
limits.teams.max
integer, required
limits.teams.remaining
integer, required
-1 when max is 0 or current is over max.
limits.apps
object, required
limits.apps.current
integer, required
limits.apps.max
integer, required
limits.apps.remaining
integer, required
-1 when max is 0 or current is over max.
limits.partners
object, required
limits.partners.current
integer, required
limits.partners.max
integer, required
limits.partners.remaining
integer, required
-1 when max is 0 or current is over max.

List activity

GET /api/internal/activity

Your organization's audit log, newest first. You see your own actions and those on things you can see. Emails, changes, IP addresses and user agents appear only for people who can see the whole audit log.

Authentication

One of these:

Parameters

NameDescription
q
string in query
Search text. Every word must match. search works too. Up to 256 characters.
org
string (uuid) in query
A closed organization whose audit log you can still read.
actor
string (uuid) in query
Only events by this user.
thing
string (uuid) in query
Only events about this user, team, app or other thing.
action
string in query
Only this action, such as auth.sign_out. Matches ^[a-z_]+\.[a-z_]+$. Up to 40 characters.
from
string (date) in query
First day to include, in your time zone.
to
string (date) in query
Last day to include, in your time zone.
cursor
integer (int64) in query
The X-Next-Cursor value from the previous page. before works too. At least 1.
limit
integer in query
Page size. Values above 200 count as 200. Default 100. At least 1.

Responses

StatusDescription
200One page of events.
400invalid input or invalid search query.
401missing authorization header or invalid session.
403forbidden: your roles don't allow this or your organization's access has expired.
404partner not found: you can't read the audit log of the organization in org.
500internal server error: something failed on our side. Try again.

200 headers:

HeaderDescription
X-Next-Cursor
string
Send it as cursor to get the next page. Absent on the last page.

200 body: application/json, array of objects.

FieldDescription
event_id
integer (int64), required
occurred_at
string (date-time), required
action
string, required
Such as auth.sign_out.
sentence
string, required
What happened, with {target} and {related} standing for those things.
actor_type
string, required
actor_id
string (uuid)
actor_name
string
actor_email
string (email)
Only for people who can see the whole audit log.
actor_link
string
Path in the web app.
target_type
string, required
target_id
string (uuid)
target_name
string
target_link
string
Path in the web app.
related_type
string
related_id
string (uuid)
related_name
string
related_link
string
Path in the web app.
changes
object
Old and new value by field. Only for people who can see the whole audit log.
changes.{key}
array
Exactly 2 items.
via
string
The AI client that made the change, when one did.
ip
string
Only for people who can see the whole audit log.
user_agent
string
Only for people who can see the whole audit log.