Teams API
Teams allow you to collaborate with other users on monitoring. Team members can view and manage shared monitors based on their assigned role.
All team endpoints require authentication. Include the Authorization: Bearer {token} header with all requests.
Team Roles
| Role | Permissions |
|---|---|
OWNER | Full access, can delete team, change any member's role |
ADMIN | Can invite members, manage monitors, update team settings |
MEMBER | Can view and manage monitors |
VIEWER | Read-only access to monitors and incidents |
List Teams
/api/teamsRetrieve all teams the authenticated user belongs to
Headers:
| Header | Value |
|---|---|
| Authorization | Bearer {access_token} |
Success Response (200 OK):
{
"teams": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Engineering",
"slug": "engineering",
"owner_id": "user-uuid",
"created_at": "2024-01-10T10:00:00Z",
"updated_at": "2024-01-15T14:00:00Z",
"member_count": 5,
"user_role": "OWNER"
},
{
"id": "660e8400-e29b-41d4-a716-446655440001",
"name": "DevOps",
"slug": "devops",
"owner_id": "other-user-uuid",
"created_at": "2024-01-05T08:00:00Z",
"updated_at": "2024-01-12T16:00:00Z",
"member_count": 3,
"user_role": "MEMBER"
}
]
}Create Team
/api/teamsCreate a new team
Headers:
| Header | Value |
|---|---|
| Authorization | Bearer {access_token} |
| Content-Type | application/json |
Request Body:
| Field | Type | Required | Validation |
|---|---|---|---|
name | string | Yes | 1-100 characters |
slug | string | Yes | 1-100 characters, lowercase alphanumeric and hyphens only |
Request Example:
{
"name": "Engineering Team",
"slug": "engineering-team"
}The user creating the team automatically becomes the OWNER and first member.
Success Response (201 Created):
{
"team": {
"id": "770e8400-e29b-41d4-a716-446655440002",
"name": "Engineering Team",
"slug": "engineering-team",
"owner_id": "user-uuid",
"created_at": "2024-01-15T12:00:00Z",
"updated_at": "2024-01-15T12:00:00Z"
}
}Error Responses:
| Status | Error | Description |
|---|---|---|
| 400 | Validation errors | Invalid name or slug format |
| 400 | Team slug already taken | Slug must be unique |
Get Team
/api/teams/:idGet team details including members and pending invites
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
id | UUID | Team ID |
Headers:
| Header | Value |
|---|---|
| Authorization | Bearer {access_token} |
Success Response (200 OK):
{
"team": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Engineering",
"slug": "engineering",
"owner_id": "user-uuid",
"created_at": "2024-01-10T10:00:00Z",
"updated_at": "2024-01-15T14:00:00Z"
},
"members": [
{
"id": "member-uuid-1",
"team_id": "team-uuid",
"user_id": "user-uuid",
"name": "John Doe",
"email": "john@example.com",
"role": "OWNER",
"joined_at": "2024-01-10T10:00:00Z"
},
{
"id": "member-uuid-2",
"team_id": "team-uuid",
"user_id": "user-uuid-2",
"name": "Jane Smith",
"email": "jane@example.com",
"role": "ADMIN",
"joined_at": "2024-01-12T09:00:00Z"
}
],
"pendingInvites": [
{
"id": "invite-uuid",
"team_id": "team-uuid",
"email": "new@example.com",
"role": "MEMBER",
"token": "invite-token",
"invited_by": "user-uuid",
"expires_at": "2024-01-22T10:00:00Z",
"created_at": "2024-01-15T10:00:00Z"
}
],
"userRole": "OWNER"
}Error Responses:
| Status | Error | Description |
|---|---|---|
| 403 | Not a team member | User is not a member of this team |
| 404 | Team not found | Team doesn't exist |
Update Team
/api/teams/:idUpdate team name
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
id | UUID | Team ID |
Headers:
| Header | Value |
|---|---|
| Authorization | Bearer {access_token} |
| Content-Type | application/json |
Request Body:
| Field | Type | Required | Validation |
|---|---|---|---|
name | string | No | 1-100 characters |
Request Example:
{
"name": "Engineering & DevOps"
}Success Response (200 OK):
{
"team": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Engineering & DevOps",
"slug": "engineering",
"owner_id": "user-uuid",
"created_at": "2024-01-10T10:00:00Z",
"updated_at": "2024-01-16T11:00:00Z"
}
}Error Responses:
| Status | Error | Description |
|---|---|---|
| 403 | Not authorized | Only OWNER or ADMIN can update team |
Delete Team
/api/teams/:idPermanently delete a team
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
id | UUID | Team ID |
Headers:
| Header | Value |
|---|---|
| Authorization | Bearer {access_token} |
Success Response (200 OK):
{
"message": "Team deleted"
}Error Responses:
| Status | Error | Description |
|---|---|---|
| 403 | Only owner can delete team | Must be team owner |
| 404 | Team not found | Team doesn't exist |
Deleting a team is permanent and removes all team memberships and pending invites.
Invite Member
/api/teams/:id/inviteSend an invitation to join the team
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
id | UUID | Team ID |
Headers:
| Header | Value |
|---|---|
| Authorization | Bearer {access_token} |
| Content-Type | application/json |
Request Body:
| Field | Type | Required | Validation |
|---|---|---|---|
email | string | Yes | Valid email address |
role | string | Yes | ADMIN, MEMBER, or VIEWER |
Request Example:
{
"email": "newmember@example.com",
"role": "MEMBER"
}Invites expire after 7 days. The invited user must have a PixoMonitor account to accept the invite.
Success Response (201 Created):
{
"invite": {
"id": "invite-uuid",
"team_id": "team-uuid",
"email": "newmember@example.com",
"role": "MEMBER",
"token": "unique-invite-token",
"invited_by": "user-uuid",
"expires_at": "2024-01-22T12:00:00Z",
"created_at": "2024-01-15T12:00:00Z"
}
}Error Responses:
| Status | Error | Description |
|---|---|---|
| 400 | User is already a team member | User already in team |
| 400 | Invite already sent to this email | Pending invite exists |
| 403 | Not authorized to invite | Only OWNER or ADMIN can invite |
Cancel Invite
/api/teams/:id/invite/:inviteIdCancel a pending team invitation
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
id | UUID | Team ID |
inviteId | UUID | Invite ID |
Headers:
| Header | Value |
|---|---|
| Authorization | Bearer {access_token} |
Success Response (200 OK):
{
"message": "Invite cancelled"
}Error Responses:
| Status | Error | Description |
|---|---|---|
| 403 | Not authorized | Only OWNER or ADMIN can cancel invites |
Accept Invite
/api/teams/invites/:token/acceptAccept a team invitation
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
token | string | Invite token from invitation |
Headers:
| Header | Value |
|---|---|
| Authorization | Bearer {access_token} |
The authenticated user's email must match the invitation email.
Success Response (200 OK):
{
"message": "Successfully joined team"
}Error Responses:
| Status | Error | Description |
|---|---|---|
| 400 | No account found with this email. Please sign up first. | User must register first |
| 400 | Already a team member | User already in team |
| 404 | Invalid or expired invite | Token invalid or expired |
Remove Member
/api/teams/:id/members/:memberIdRemove a member from the team
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
id | UUID | Team ID |
memberId | UUID | Team member ID (not user ID) |
Headers:
| Header | Value |
|---|---|
| Authorization | Bearer {access_token} |
Success Response (200 OK):
{
"message": "Member removed"
}Error Responses:
| Status | Error | Description |
|---|---|---|
| 400 | Cannot remove owner | Team owner cannot be removed |
| 403 | Not authorized | Only OWNER or ADMIN can remove members |
| 404 | Member not found | Invalid member ID |
Update Member Role
/api/teams/:id/members/:memberIdChange a team member's role
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
id | UUID | Team ID |
memberId | UUID | Team member ID |
Headers:
| Header | Value |
|---|---|
| Authorization | Bearer {access_token} |
| Content-Type | application/json |
Request Body:
| Field | Type | Required | Validation |
|---|---|---|---|
role | string | Yes | ADMIN, MEMBER, or VIEWER |
Request Example:
{
"role": "ADMIN"
}Success Response (200 OK):
{
"member": {
"id": "member-uuid",
"team_id": "team-uuid",
"user_id": "user-uuid",
"role": "ADMIN",
"joined_at": "2024-01-12T09:00:00Z"
}
}Error Responses:
| Status | Error | Description |
|---|---|---|
| 403 | Only owner can change roles | Must be team owner |
| 404 | Member not found | Invalid member ID |
The OWNER role cannot be assigned via this endpoint. To transfer ownership, the current owner must be changed first.
Team Invitation Flow
1. OWNER/ADMIN sends invite → POST /api/teams/:id/invite
↓
2. Invite email sent with unique token
↓
3. Recipient clicks link / uses token
↓
4. Recipient calls → POST /api/teams/invites/:token/accept
↓
5. User becomes team member with assigned role
Permission Matrix
| Action | OWNER | ADMIN | MEMBER | VIEWER |
|---|---|---|---|---|
| View team | ✓ | ✓ | ✓ | ✓ |
| Update team name | ✓ | ✓ | ✗ | ✗ |
| Delete team | ✓ | ✗ | ✗ | ✗ |
| Invite members | ✓ | ✓ | ✗ | ✗ |
| Cancel invites | ✓ | ✓ | ✗ | ✗ |
| Remove members | ✓ | ✓ | ✗ | ✗ |
| Change member roles | ✓ | ✗ | ✗ | ✗ |
| Manage monitors | ✓ | ✓ | ✓ | ✗ |
| View monitors | ✓ | ✓ | ✓ | ✓ |
Error Responses Summary
| Status | Error | Description |
|---|---|---|
| 400 | Validation errors | Invalid request body |
| 400 | Team slug already taken | Duplicate slug |
| 400 | User is already a team member | Duplicate membership |
| 400 | Invite already sent to this email | Duplicate invite |
| 400 | Cannot remove owner | Owner removal attempted |
| 400 | Already a team member | Accepting invite when already member |
| 403 | Not a team member | Accessing team without membership |
| 403 | Not authorized | Insufficient permissions |
| 403 | Not authorized to invite | Non-admin inviting |
| 403 | Only owner can delete team | Non-owner deleting team |
| 403 | Only owner can change roles | Non-owner changing roles |
| 404 | Team not found | Invalid team ID |
| 404 | Member not found | Invalid member ID |
| 404 | Invalid or expired invite | Bad invite token |
