Skip to main content

Overview

The Teams API enables programmatic management of teams, members, invitations, usage tracking, and access control. Base URL: /api/teams Authentication: All endpoints require session authentication unless otherwise noted. Team Identifiers: Endpoints accept either UUID (550e8400-e29b-xxxx-xxxxx-xxxxx) or numeric ID (123).

Error Response Format

All errors return JSON in this format:
{
  "code": "ERROR_CODE",
  "message": "Human-readable description",
  "details": {},
  "status": 400
}
Common Error Codes:
CodeStatusDescription
UNAUTHORIZED401Session required
FORBIDDEN403Insufficient permissions
NOT_FOUND404Resource not found
CONFLICT409Resource conflict (duplicate, wrong state)
INVALID_INPUT422Validation failed
RATE_LIMITED429Too many requests
INTERNAL_ERROR500Server error

Teams

List Teams

Returns all teams the authenticated user belongs to.
GET /api/teams
Response:
{
  "teams": [
    {
      "uuid": "550e8400-e29b-xxxx-xxxx-xxxxxxxxxxxx",
      "name": "Engineering",
      "status": "active",
      "role": "owner"
    }
  ]
}

Create Team

POST /api/teams
Request Body:
{
  "name": "Engineering"
}
FieldTypeRequiredDescription
namestringYes2-50 characters. Letters, numbers, spaces, hyphens, underscores.
Response:
{
  "team": {
    "uuid": "550e8400-e29b-xxxx-xxxx-xxxxxxxxxxxx",
    "name": "Engineering",
    "status": "active",
    "role": "owner"
  }
}
Errors:
  • 409 CONFLICT: You already have a team with this name

Get Team Details

GET /api/teams/{teamUuid}
Response:
{
  "team": {
    "uuid": "550e8400-e29b-xxxx-xxxx-xxxxxxxxxxxx",
    "name": "Engineering",
    "status": "active",
    "paused_at": null,
    "suspended_at": null,
    "invite_link_enabled": true,
    "invite_link_token": "abc123...",
    "default_member_usage_limit_usd": 100,
    "usage_limit_usd": null,
    "usage_limit_enforced": true,
    "balances": {
      "usd_balance": 250.00,
      "nano_balance": 1500.00
    },
    "role": "owner"
  }
}
Notes:
  • balances shows the team owner’s account balance
  • role is the requesting user’s role in this team

Update Team

PATCH /api/teams/{teamUuid}
Required Role: Owner or Admin Request Body:
{
  "name": "New Team Name",
  "status": "paused"
}
FieldTypeRequiredDescription
namestringNo2-50 characters
statusstringNoactive, paused, or suspended
Response:
{
  "team": {
    "uuid": "550e8400-e29b-xxxx-xxxx-xxxxxxxxxxxx",
    "name": "New Team Name",
    "status": "paused"
  }
}

Delete Team

DELETE /api/teams/{teamUuid}
Required Role: Owner Request Body:
{
  "name": "Engineering"
}
FieldTypeRequiredDescription
namestringYesMust exactly match team name (confirmation)
Response:
{
  "ok": true
}

Members

List Members

GET /api/teams/{teamUuid}/members
Query Parameters:
ParameterTypeDefaultDescription
pagenumber1Page number
limitnumberallResults per page (max 100)
Response (with pagination):
{
  "members": [
    {
      "sessionId": 12345,
      "sessionUUID": "abc-123-def",
      "role": "owner",
      "joinedAt": "2024-01-15T10:30:00Z",
      "member_name": "Alice",
      "displayName": "Alice Smith",
      "email": "[email protected]",
      "usage_limit_usd": 150,
      "usage_limit_enforced": true,
      "usage_usd_monthly": 45.50
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 20,
    "total": 45,
    "totalPages": 3
  }
}

Update Member Role

PATCH /api/teams/{teamUuid}/members
Required Role: Owner or Admin Request Body:
{
  "sessionId": 12345,
  "role": "admin"
}
FieldTypeRequiredDescription
sessionIdnumberYesTarget member’s session ID
rolestringYesadmin or member (cannot set owner)
Response:
{
  "ok": true
}
Errors:
  • 403 FORBIDDEN: Cannot change the owner’s role
  • 400 INVALID_INPUT: Cannot change your own role

Update Member Usage Limits

PATCH /api/teams/{teamUuid}/members
Required Role: Owner or Admin Request Body:
{
  "sessionId": 12345,
  "usage_limit_usd": 200,
  "usage_limit_enforced": true
}
FieldTypeRequiredDescription
sessionIdnumberYesTarget member’s session ID
usage_limit_usdnumber|nullNoMonthly limit in USD, or null to use team default
usage_limit_enforcedbooleanNoHard-enforce the limit (blocks usage when exceeded)
Response:
{
  "ok": true
}

Remove Member

DELETE /api/teams/{teamUuid}/members
Required Role: Owner or Admin Request Body:
{
  "sessionId": 12345
}
Response:
{
  "ok": true
}
Errors:
  • 403 FORBIDDEN: Cannot remove the team owner
  • 400 INVALID_INPUT: Cannot remove yourself (use /leave)

Get Own Preferences

Returns the authenticated user’s preferences for this team.
GET /api/teams/{teamUuid}/members/self
Response:
{
  "bill_to_team": true,
  "name": "Alice",
  "usage_limit_usd": 150,
  "usage_limit_enforced": true,
  "default_member_usage_limit_usd": 100,
  "default_usage_limit_enforced": true,
  "effective_usage_limit_usd": 150,
  "effective_usage_limit_enforced": true
}
Notes:
  • effective_* fields show the resolved limit (member override or team default)

Update Own Preferences

PATCH /api/teams/{teamUuid}/members/self
Request Body:
{
  "bill_to_team": true,
  "name": "Alice Smith"
}
FieldTypeRequiredDescription
bill_to_teambooleanNoBill usage to team or personal account
namestringNoDisplay name (1-100 characters)
Response:
{
  "ok": true,
  "preferences": {
    "bill_to_team": true,
    "name": "Alice Smith",
    "usage_limit_usd": 150,
    "usage_limit_enforced": true
  }
}

Leave Team

POST /api/teams/{teamUuid}/leave
Response:
{
  "ok": true
}
Errors:
  • 403 FORBIDDEN: Owner must transfer ownership before leaving

Invitations

List Pending Invitations

GET /api/teams/{teamUuid}/invitations
Required Role: Owner or Admin Response:
{
  "invitations": [
    {
      "id": "inv-uuid-123",
      "email": "[email protected]",
      "role": "member",
      "status": "pending",
      "token": "abc123...",
      "created_at": "2024-01-15T10:30:00Z",
      "expires_at": "2024-01-22T10:30:00Z"
    }
  ]
}

Send Invitation

POST /api/teams/{teamUuid}/invitations
Required Role: Owner or Admin Request Body:
{
  "email": "[email protected]",
  "role": "member"
}
FieldTypeRequiredDescription
emailstringYesValid email address
rolestringNoadmin or member (default: member)
Response:
{
  "invitation": {
    "id": "inv-uuid-123",
    "email": "[email protected]",
    "role": "member",
    "status": "pending",
    "token": "abc123..."
  }
}

Revoke Invitation

PATCH /api/teams/{teamUuid}/invitations
Required Role: Owner or Admin Request Body:
{
  "action": "revoke",
  "id": "inv-uuid-123"
}
FieldTypeRequiredDescription
actionstringNoMust be revoke (default)
idstringNo*Invitation UUID
tokenstringNo*Invitation token (min 16 chars)
*Provide either id or token Response:
{
  "ok": true
}

Accept Invitation

POST /api/teams/invitations/accept
Request Body:
{
  "token": "abc123def456..."
}
FieldTypeRequiredDescription
tokenstringYesInvitation token (min 16 characters)
Response:
{
  "ok": true
}
Errors:
  • 409 CONFLICT: Invitation is not pending
  • 409 CONFLICT: Invitation has expired

Lookup Invitation

Public endpoint to check invitation details before accepting.
GET /api/teams/invitations/lookup?token=abc123...
Authentication: Not required Response (email invitation):
{
  "type": "invitation",
  "email": "[email protected]",
  "status": "pending",
  "teamName": "Engineering"
}
Response (invite link):
{
  "type": "link",
  "teamName": "Engineering",
  "enabled": true
}

GET /api/teams/{teamUuid}/invite-link
Required Role: Owner or Admin Response:
{
  "enabled": true,
  "token": "abc123def456..."
}

POST /api/teams/{teamUuid}/invite-link
Required Role: Owner or Admin Request Body:
{
  "action": "enable"
}
FieldTypeRequiredDescription
actionstringNoenable (default) or disable
Response:
{
  "enabled": true,
  "token": "abc123def456..."
}

POST /api/teams/{teamUuid}/invite-link/email
Required Role: Owner or Admin Rate Limit: 5 emails per minute Request Body:
FieldTypeRequiredDescription
emailsstring[]Yes1-10 valid email addresses
Response:
{
  "ok": true
}
Errors:
  • 403 FORBIDDEN: Invite link is disabled
  • 429 RATE_LIMITED: Too many emails

POST /api/teams/join
Request Body:
{
  "token": "abc123def456..."
}
Response:
{
  "ok": true
}
Or if already a member:
{
  "ok": true,
  "alreadyMember": true
}

Cancel Join Request

DELETE /api/teams/join
Request Body:
{
  "token": "abc123def456..."
}
Response:
{
  "ok": true
}

Join Requests

List Join Requests

GET /api/teams/{teamUuid}/join-requests
Required Role: Owner or Admin Response:
{
  "requests": [
    {
      "id": "req-uuid-123",
      "user_id": 12345,
      "status": "pending",
      "created_at": "2024-01-15T10:30:00Z",
      "name": "Charlie",
      "email": "[email protected]"
    }
  ]
}

Accept/Reject Join Request

PATCH /api/teams/{teamUuid}/join-requests
Required Role: Owner or Admin Request Body:
{
  "action": "accept",
  "id": "req-uuid-123"
}
FieldTypeRequiredDescription
actionstringNoaccept (default) or reject
idstringYesJoin request UUID
Response:
{
  "ok": true
}

Delete Join Request

Delete a processed (non-pending) join request.
DELETE /api/teams/{teamUuid}/join-requests
Required Role: Owner or Admin Request Body:
{
  "id": "req-uuid-123"
}
Response:
{
  "ok": true
}
Errors:
  • 409 CONFLICT: Cannot delete a pending request (must accept/reject first)

Usage & Billing

Get Team Usage

GET /api/teams/{teamUuid}/usage
Query Parameters:
ParameterTypeDefaultDescription
fromstring-Start date (ISO format)
tostring-End date (ISO format)
Response:
{
  "byActor": [
    {
      "actorSessionId": 12345,
      "displayName": "Alice Smith",
      "totalAmount": 45.50,
      "currency": "USD"
    },
    {
      "actorSessionId": 12346,
      "displayName": "Bob Jones",
      "totalAmount": 32.25,
      "currency": "USD"
    }
  ],
  "totals": [
    {
      "totalAmount": 77.75,
      "currency": "USD"
    }
  ]
}

Settings

Update Team Settings

PATCH /api/teams/{teamUuid}/settings
Required Role: Owner or Admin Request Body:
{
  "default_member_usage_limit_usd": 100,
  "usage_limit_enforced": true
}
FieldTypeRequiredDescription
default_member_usage_limit_usdnumber|nullNoDefault monthly limit for members
team_usage_limit_usdnumber|nullNoTeam-wide spending limit
usage_limit_enforcedbooleanNoHard-enforce limits
Response:
{
  "ok": true
}

Model Access Control

Get Allowed Models

GET /api/teams/{teamUuid}/allowed-models
Response:
{
  "allowed_models": {
    "claude-sonnet-4-5": true,
    "gpt-5-1": true,
    "claude-opus-4-5": false
  },
  "all_allowed": false
}
Or if all models are allowed:
{
  "allowed_models": null,
  "all_allowed": true
}

Update Allowed Models

PATCH /api/teams/{teamUuid}/allowed-models
Required Role: Owner or Admin Request Body:
{
  "allowed_models": {
    "claude-sonnet-4-5": true,
    "gpt-5-1": true,
    "claude-opus-4-5": false
  }
}
To allow all models:
{
  "allowed_models": null
}
FieldTypeRequiredDescription
allowed_modelsobject|nullYesMap of model keys to boolean, or null for all
Response:
{
  "ok": true,
  "allowed_models": {
    "claude-sonnet-4-5": true,
    "gpt-5-1": true,
    "claude-opus-4-5": false
  },
  "all_allowed": false
}
Notes:
  • Models not listed in the map are allowed by default
  • Set a model to false to explicitly restrict it
  • Set allowed_models to null to allow all models

Ownership

Transfer Ownership

POST /api/teams/{teamUuid}/owner
Required Role: Owner Request Body:
{
  "sessionId": 12345
}
FieldTypeRequiredDescription
sessionIdnumberYesNew owner’s session ID
Response:
{
  "ok": true
}
Side Effects:
  • Current owner becomes admin
  • Target member becomes owner
Errors:
  • 409 CONFLICT: Target is already the owner
  • 400 INVALID_INPUT: Cannot transfer ownership to yourself

Role Reference

RoleCreate TeamView TeamManage MembersManage SettingsDelete Team
Owner-YesYesYesYes
Admin-YesYesYesNo
Member-YesNoNoNo

Rate Limits

EndpointLimit
POST /api/teams/{teamUuid}/invite-link/email5 emails per minute

Webhooks (Coming Soon)

Future webhook events:
  • team.member.joined
  • team.member.removed
  • team.usage.limit_reached
  • team.status.changed