API reference
Team Accounts API
Public developer Team Accounts API for listing members, creating/revoking invitations, accepting invitations, updating members, removing members, listing roles, and reading audit events.
SoundSync
Workspace membership operations
Never send a developer ID to choose another workspace.
/api/developer/team
Workspace, current access, members, pending invitations, roles
- Auth
- Account Bearer JWT
- Scope
- team.view; workspace and product assignments are resolved server-side.
- Returns
- Workspace, current access, members, pending invitations, roles
- Side effects
- Reads authorized team information.
Request, response and error reference
No request body fields are read by this operation.
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"workspace": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"minimum": 1
},
"ownerUserId": {
"type": "integer",
"minimum": 1
},
"displayName": {
"type": "string"
}
},
"additionalProperties": true
},
"currentAccess": {
"type": "object",
"properties": {
"workspaceId": {
"type": "integer",
"minimum": 1
},
"workspaceOwnerUserId": {
"type": "integer",
"minimum": 1
},
"workspaceDisplayName": {
"type": "string"
},
"membershipId": {
"type": "integer",
"minimum": 1
},
"userId": {
"type": "integer",
"minimum": 1
},
"effectiveDeveloperId": {
"type": "integer",
"minimum": 1
},
"isWorkspaceOwner": {
"type": "boolean"
},
"role": {
"type": "string"
},
"permissions": {
"type": "array",
"items": {
"type": "string"
}
},
"productScopeMode": {
"type": "string"
},
"allowedProductIds": {
"type": [
"array",
"null"
],
"items": {
"type": "integer",
"minimum": 1
}
}
},
"additionalProperties": true
},
"members": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"minimum": 1
},
"userId": {
"type": "integer",
"minimum": 1
},
"email": {
"type": "string",
"format": "email"
},
"role": {
"type": "string"
},
"status": {
"type": "string"
},
"productScopeMode": {
"type": "string",
"enum": [
"all_products",
"selected_products"
]
},
"selectedProductIds": {
"type": "array",
"items": {
"type": "integer",
"minimum": 1
}
}
},
"additionalProperties": true
}
},
"invitations": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"minimum": 1
},
"email": {
"type": "string",
"format": "email"
},
"role": {
"type": "string"
},
"status": {
"type": "string"
},
"expiresAt": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"productScopeMode": {
"type": "string"
},
"selectedProductIds": {
"type": "array",
"items": {
"type": "integer",
"minimum": 1
}
}
},
"additionalProperties": true
}
},
"roles": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": true,
"description": "Operation-specific extension data; do not put credentials or unnecessary personal information here."
}
}
},
"additionalProperties": true
}
Documented failures: 400, 500, 503.
/api/developer/team/members
Team members only
- Auth
- Account Bearer JWT
- Scope
- team.view; workspace and product assignments are resolved server-side.
- Returns
- Team members only
- Side effects
- Reads authorized team information.
Request, response and error reference
No request body fields are read by this operation.
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"members": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"minimum": 1
},
"userId": {
"type": "integer",
"minimum": 1
},
"email": {
"type": "string",
"format": "email"
},
"role": {
"type": "string"
},
"status": {
"type": "string"
},
"productScopeMode": {
"type": "string",
"enum": [
"all_products",
"selected_products"
]
},
"selectedProductIds": {
"type": "array",
"items": {
"type": "integer",
"minimum": 1
}
}
},
"additionalProperties": true
}
},
"workspace": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"minimum": 1
},
"ownerUserId": {
"type": "integer",
"minimum": 1
},
"displayName": {
"type": "string"
}
},
"additionalProperties": true
},
"currentAccess": {
"type": "object",
"properties": {
"workspaceId": {
"type": "integer",
"minimum": 1
},
"workspaceOwnerUserId": {
"type": "integer",
"minimum": 1
},
"workspaceDisplayName": {
"type": "string"
},
"membershipId": {
"type": "integer",
"minimum": 1
},
"userId": {
"type": "integer",
"minimum": 1
},
"effectiveDeveloperId": {
"type": "integer",
"minimum": 1
},
"isWorkspaceOwner": {
"type": "boolean"
},
"role": {
"type": "string"
},
"permissions": {
"type": "array",
"items": {
"type": "string"
}
},
"productScopeMode": {
"type": "string"
},
"allowedProductIds": {
"type": [
"array",
"null"
],
"items": {
"type": "integer",
"minimum": 1
}
}
},
"additionalProperties": true
}
},
"additionalProperties": true
}
Documented failures: 400, 500, 503.
/api/developer/team/invitations
Pending invitations only
- Auth
- Account Bearer JWT
- Scope
- team.view; workspace and product assignments are resolved server-side.
- Returns
- Pending invitations only
- Side effects
- Reads authorized team information.
Request, response and error reference
No request body fields are read by this operation.
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"invitations": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"minimum": 1
},
"email": {
"type": "string",
"format": "email"
},
"role": {
"type": "string"
},
"status": {
"type": "string"
},
"expiresAt": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"productScopeMode": {
"type": "string"
},
"selectedProductIds": {
"type": "array",
"items": {
"type": "integer",
"minimum": 1
}
}
},
"additionalProperties": true
}
},
"workspace": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"minimum": 1
},
"ownerUserId": {
"type": "integer",
"minimum": 1
},
"displayName": {
"type": "string"
}
},
"additionalProperties": true
}
},
"additionalProperties": true
}
Documented failures: 400, 500, 503.
/api/developer/team/invitations
Creates one-time expiring email invitation; stores token hash only
- Auth
- Account Bearer JWT
- Scope
- team.invite; workspace and product assignments are resolved server-side.
- Request fields
- email: string (required)
- role: administrator | product_manager | customer_support | marketing | analyst | billing | engineer (required)
- productScopeMode: all_products | selected_products
- selectedProductIds: array
- Returns
- 201 { invitation, email }. The raw token is sent by transactional email, not returned in this JSON. Inspect the email outcome separately.
- Side effects
- Changes team membership or invitation state and records audit activity.
- Notes
- selected_products requires at least one owned product ID. Creation defaults to all_products. The raw token is emailed, not returned. The invitation expires after seven days; inspect the separate email outcome.
Request, response and error reference
Request (application/json)
{
"type": "object",
"properties": {
"email": {
"type": "string",
"format": "email"
},
"role": {
"type": "string",
"enum": [
"administrator",
"product_manager",
"customer_support",
"marketing",
"analyst",
"billing",
"engineer"
]
},
"productScopeMode": {
"type": "string",
"enum": [
"all_products",
"selected_products"
]
},
"selectedProductIds": {
"type": "array",
"items": {
"type": "integer",
"minimum": 1
}
}
},
"required": [
"email",
"role"
],
"additionalProperties": true
}
HTTP 201 response (application/json)
{
"type": "object",
"properties": {
"invitation": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"minimum": 1
},
"email": {
"type": "string",
"format": "email"
},
"role": {
"type": "string"
},
"status": {
"type": "string"
},
"expiresAt": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"productScopeMode": {
"type": "string"
},
"selectedProductIds": {
"type": "array",
"items": {
"type": "integer",
"minimum": 1
}
}
},
"additionalProperties": true
},
"email": {
"type": "object",
"additionalProperties": true,
"description": "Operation-specific extension data; do not put credentials or unnecessary personal information here."
}
},
"additionalProperties": true
}
Documented failures: 400, 500, 503.
/api/developer/team/invitations/:invitationId
Revokes pending invitation
- Auth
- Account Bearer JWT
- Scope
- team.invite; workspace and product assignments are resolved server-side.
- Returns
- 200 { invitation, revoked: true }. A missing or no-longer-pending invitation returns 404.
- Side effects
- Changes team membership or invitation state and records audit activity.
Request, response and error reference
No request body fields are read by this operation.
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"invitation": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"minimum": 1
},
"email": {
"type": "string",
"format": "email"
},
"role": {
"type": "string"
},
"status": {
"type": "string"
},
"expiresAt": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"productScopeMode": {
"type": "string"
},
"selectedProductIds": {
"type": "array",
"items": {
"type": "integer",
"minimum": 1
}
}
},
"additionalProperties": true
},
"revoked": {
"type": "boolean"
}
},
"additionalProperties": true
}
Documented failures: 400, 500, 503.
/api/developer/team/invitations/accept
Accepts one-time token and creates membership
- Auth
- Account Bearer JWT
- Scope
- authenticated invited email; workspace and product assignments are resolved server-side.
- Request fields
- token: string (required)
- Returns
- 200 { member, workspaceAccess }. Acceptance creates membership; repeated acceptance is rejected.
- Side effects
- Changes team membership or invitation state and records audit activity.
- Notes
- Sign in with the invited email. Used, expired, revoked and superseded invitations cannot grant access.
Request, response and error reference
Request (application/json)
{
"type": "object",
"properties": {
"token": {
"type": "string"
}
},
"required": [
"token"
],
"additionalProperties": true
}
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"member": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"minimum": 1
},
"userId": {
"type": "integer",
"minimum": 1
},
"email": {
"type": "string",
"format": "email"
},
"role": {
"type": "string"
},
"status": {
"type": "string"
},
"productScopeMode": {
"type": "string",
"enum": [
"all_products",
"selected_products"
]
},
"selectedProductIds": {
"type": "array",
"items": {
"type": "integer",
"minimum": 1
}
}
},
"additionalProperties": true
},
"workspaceAccess": {
"type": "object",
"properties": {
"workspaceId": {
"type": "integer",
"minimum": 1
},
"workspaceOwnerUserId": {
"type": "integer",
"minimum": 1
},
"workspaceDisplayName": {
"type": "string"
},
"membershipId": {
"type": "integer",
"minimum": 1
},
"userId": {
"type": "integer",
"minimum": 1
},
"effectiveDeveloperId": {
"type": "integer",
"minimum": 1
},
"isWorkspaceOwner": {
"type": "boolean"
},
"role": {
"type": "string"
},
"permissions": {
"type": "array",
"items": {
"type": "string"
}
},
"productScopeMode": {
"type": "string"
},
"allowedProductIds": {
"type": [
"array",
"null"
],
"items": {
"type": "integer",
"minimum": 1
}
}
},
"additionalProperties": true
}
},
"additionalProperties": true
}
Documented failures: 400, 500, 503.
/api/developer/team/members/:memberId
Changes role and product scope with owner/last-owner protections
- Auth
- Account Bearer JWT
- Scope
- team.manage_roles; workspace and product assignments are resolved server-side.
- Request fields
- role: owner | administrator | product_manager | customer_support | marketing | analyst | billing | engineer
- productScopeMode: all_products | selected_products
- selectedProductIds: array
- Returns
- 200 { member, updated: true }. Existing sessions are revoked; the member may need to sign in again.
- Side effects
- Changes team membership or invitation state and records audit activity.
- Notes
- Send the complete selectedProductIds array for an existing selected_products member, including a role-only update. Owner assignment is owner-only; self-modification and removing the last active owner are prohibited. Existing sessions are revoked.
Request, response and error reference
Request (application/json)
{
"type": "object",
"properties": {
"role": {
"type": "string",
"enum": [
"owner",
"administrator",
"product_manager",
"customer_support",
"marketing",
"analyst",
"billing",
"engineer"
]
},
"productScopeMode": {
"type": "string",
"enum": [
"all_products",
"selected_products"
]
},
"selectedProductIds": {
"type": "array",
"items": {
"type": "integer",
"minimum": 1
}
}
},
"additionalProperties": true
}
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"member": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"minimum": 1
},
"userId": {
"type": "integer",
"minimum": 1
},
"email": {
"type": "string",
"format": "email"
},
"role": {
"type": "string"
},
"status": {
"type": "string"
},
"productScopeMode": {
"type": "string",
"enum": [
"all_products",
"selected_products"
]
},
"selectedProductIds": {
"type": "array",
"items": {
"type": "integer",
"minimum": 1
}
}
},
"additionalProperties": true
},
"updated": {
"type": "boolean"
}
},
"additionalProperties": true
}
Documented failures: 400, 500, 503.
/api/developer/team/members/:memberId
Revokes membership without deleting the user account
- Auth
- Account Bearer JWT
- Scope
- team.remove; workspace and product assignments are resolved server-side.
- Returns
- 200 { member, removed: true }. Removes workspace access, not the user account; sessions are revoked.
- Side effects
- Changes team membership or invitation state and records audit activity.
- Notes
- Removes membership, not the user account; saved sessions are revoked.
Request, response and error reference
No request body fields are read by this operation.
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"member": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"minimum": 1
},
"userId": {
"type": "integer",
"minimum": 1
},
"email": {
"type": "string",
"format": "email"
},
"role": {
"type": "string"
},
"status": {
"type": "string"
},
"productScopeMode": {
"type": "string",
"enum": [
"all_products",
"selected_products"
]
},
"selectedProductIds": {
"type": "array",
"items": {
"type": "integer",
"minimum": 1
}
}
},
"additionalProperties": true
},
"removed": {
"type": "boolean"
}
},
"additionalProperties": true
}
Documented failures: 400, 500, 503.
/api/developer/team/roles
Returns canonical role and permission registry
- Auth
- Account Bearer JWT
- Scope
- authenticated developer; workspace and product assignments are resolved server-side.
- Returns
- 200 { roles, permissions, productScopeModes, sensitivePermissions }.
- Side effects
- Reads authorized team information.
Request, response and error reference
No request body fields are read by this operation.
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"roles": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": true,
"description": "Operation-specific extension data; do not put credentials or unnecessary personal information here."
}
},
"permissions": {
"type": "array",
"items": {
"type": "string"
}
},
"productScopeModes": {
"type": "array",
"items": {
"type": "string"
}
},
"sensitivePermissions": {
"type": "array",
"items": {
"type": "string"
}
}
},
"additionalProperties": true
}
Documented failures: 400, 500, 503.
/api/developer/team/audit
Returns team audit events without sensitive tokens
- Auth
- Account Bearer JWT
- Scope
- team.audit.view; workspace and product assignments are resolved server-side.
- Request fields
- query limit: integer
- Returns
- 200 { audit: [...] }. Treat email addresses and audit identities as private data.
- Side effects
- Reads authorized team information.
Request, response and error reference
Query and header parameters
[
{
"name": "limit",
"in": "query",
"schema": {
"type": "integer",
"minimum": 1,
"maximum": 100,
"default": 50
},
"required": false,
"description": ""
}
]
No request body fields are read by this operation.
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"audit": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"minimum": 1
},
"action": {
"type": "string"
},
"actor_user_id": {
"type": "integer",
"minimum": 1
},
"created_at": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"metadata": {
"type": "object",
"additionalProperties": true,
"description": "Operation-specific extension data; do not put credentials or unnecessary personal information here."
}
},
"additionalProperties": true
}
}
},
"additionalProperties": true
}
Documented failures: 400, 500, 503.
SoundSync
Create a selected-product invitation
Illustrative request; replace the address and product ID with values you are authorized to use. This sends an invitation when executed.
curl --fail-with-body -X POST "$SOUNDSYNC_API_BASE/api/developer/team/invitations" \
-H "Authorization: Bearer $DEVELOPER_TOKEN" \
-H "Content-Type: application/json" \
--data '{"email":"teammate@example.com","role":"product_manager","productScopeMode":"selected_products","selectedProductIds":[23794]}'
SoundSync
Update scope and accept an invitation
{"role":"analyst","productScopeMode":"selected_products","selectedProductIds":[23794]}
{"token":"ONE_TIME_TOKEN_FROM_EMAIL"}
{"code":"developer_team_product_scope_invalid","message":"Selected-product members require at least one product.","field":"selectedProductIds"}
SoundSync
Handle errors without widening access
| Status / code | Recovery |
|---|---|
| 400 / invalid role, email or product scope | Correct the indicated field; selected products must belong to the workspace. |
| 401 / authentication or revoked session | Sign in again. Do not retry with an owner token on behalf of a denied member. |
| 403 / permission, self-modification or invitation email mismatch | Check the signed-in account and allowed role. Do not bypass the denial. |
| 404 / invitation or member not found | Reload the workspace list; IDs are workspace-scoped. |
| 409 / existing member, used invitation or last owner | Refresh current state; retain at least one active owner. |
| 410 / invitation expired or revoked | Ask an authorized member for a new invitation. |
| 429 / rate limit | Wait before retrying. Do not repeatedly submit invitations. |
Rate limits and response evidence
Default mutation limit: 30 requests per minute per user. Invitation acceptance: 20 per 15 minutes per user. Deployments may configure these limits. Fields and examples are traced to the current routes and service; they are not a production invitation test or a guarantee of email delivery.
SoundSync
