> For the complete documentation index, see [llms.txt](https://docs.meganova.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.meganova.ai/api-reference/platform-api/teams.md).

# Teams

Team workspaces — members, invitations, permissions, and team-scoped API keys.

Teams let multiple users share billing, API keys, and resources under a single workspace. Every authenticated user sees these endpoints.

* **Base URL:** `https://api.meganova.ai/api/v1`
* **Auth:** Bearer JWT or API key (same as other Platform API calls)

## Endpoint map

### Team CRUD

| Method   | Path                         | Purpose                                                 |
| -------- | ---------------------------- | ------------------------------------------------------- |
| `POST`   | `/teams`                     | Create a team (caller becomes the owner)                |
| `GET`    | `/teams?name=...`            | List teams the caller belongs to (optional name filter) |
| `GET`    | `/teams/{team_id}/`          | Get a single team's details                             |
| `PUT`    | `/teams/{team_id}`           | Update team name/description                            |
| `DELETE` | `/teams/{team_id}`           | Delete a team (owner only)                              |
| `PUT`    | `/teams/{team_id}/ownership` | Transfer ownership to another member                    |
| `GET`    | `/users/teams`               | List teams on the caller's profile (convenience alias)  |

### Members

| Method   | Path                                   | Purpose                                                                       |
| -------- | -------------------------------------- | ----------------------------------------------------------------------------- |
| `POST`   | `/teams/{team_id}/members`             | Invite a user by email (creates an invitation if they aren't on the platform) |
| `GET`    | `/teams/{team_id}/members`             | List members of a team                                                        |
| `PUT`    | `/teams/{team_id}/members/{member_id}` | Update a member's role or permissions                                         |
| `DELETE` | `/teams/{team_id}/members/{member_id}` | Remove a member                                                               |

### Invitations

| Method   | Path                           | Purpose                             |
| -------- | ------------------------------ | ----------------------------------- |
| `GET`    | `/teams/{team_id}/invitations` | List pending invitations for a team |
| `GET`    | `/teams/invitations/{token}`   | Look up invitation details by token |
| `POST`   | `/teams/invitations/{token}`   | Accept an invitation                |
| `DELETE` | `/teams/invitations/{token}`   | Cancel/decline an invitation        |

### Permissions

| Method   | Path                                               | Purpose                                    |
| -------- | -------------------------------------------------- | ------------------------------------------ |
| `GET`    | `/teams/permissions`                               | List every permission the platform defines |
| `GET`    | `/teams/permissions/{permission_id}`               | Detail for a single permission             |
| `GET`    | `/teams/{team_id}/permissions`                     | Permissions currently bound to the team    |
| `GET`    | `/teams/{team_id}/members/{member_id}/permissions` | Permissions granted to a specific member   |
| `POST`   | `/teams/{team_id}/members/{member_id}/permissions` | Grant permissions to a member              |
| `PUT`    | `/teams/{team_id}/members/{member_id}/permissions` | Replace the member's permission set        |
| `DELETE` | `/teams/{team_id}/members/{member_id}/permissions` | Revoke permissions from a member           |

### Team API keys

Team keys authenticate as the team (shared credits, shared rate limits) instead of a single user.

| Method   | Path                             | Purpose                                                         |
| -------- | -------------------------------- | --------------------------------------------------------------- |
| `GET`    | `/teams/{team_id}/keys`          | List team keys                                                  |
| `POST`   | `/keys`                          | Create a key — pass `team_id` in the body to make it a team key |
| `PUT`    | `/teams/{team_id}/keys/{key_id}` | Update key name, description, or status                         |
| `DELETE` | `/teams/{team_id}/keys/{key_id}` | Revoke a team key                                               |

### Team resources

| Method | Path                         | Purpose                                     |
| ------ | ---------------------------- | ------------------------------------------- |
| `GET`  | `/teams/{team_id}/instances` | Compute instances attached to the team      |
| `GET`  | `/teams/{team_id}/storages`  | Object-storage buckets attached to the team |

## Create a team

### Request body

```json
{
  "name": "My Team",
  "description": "Optional description"
}
```

### Response

```json
{
  "data": {
    "id": 42,
    "name": "My Team",
    "description": "Optional description"
  },
  "message": "Team created successfully",
  "status": "success"
}
```

The caller becomes the team owner automatically. Owner role is `1`; admins are `2`; members are `3`.

### Example

```bash
curl -X POST '{API_URL}/teams' \
  -H 'Authorization: Bearer {TOKEN/KEY}' \
  -H 'Content-Type: application/json' \
  -d '{"name":"MyTeam","description":"engineering org"}'
```

## List teams

`GET /teams` returns every team where the caller is owner, admin, or member.

```json
{
  "data": [
    {
      "id": 42,
      "name": "MyTeam",
      "description": "engineering org",
      "role": 1,
      "permissions": [1, 2, 3],
      "members": 4,
      "created_at": 1745452800,
      "owner": { "id": 12, "name": "Alice", "tier": "EXPERT_TIER_1" }
    }
  ],
  "message": "Teams retrieved successfully",
  "status": "success"
}
```

Filter by name: `GET /teams?name=my`.

## Invite a member

### Request body

```json
{
  "email": "alice@example.com",
  "role": 2,
  "permissions": [1, 5, 7]
}
```

* `role` — 1=owner (not normally assignable here), 2=admin, 3=member. Default `2`.
* `permissions` — permission IDs (see `GET /teams/permissions`). Empty list = no extra perms beyond role defaults.

If the invitee isn't a MegaNova user yet, an invitation email is sent and the invitation lives under `GET /teams/{team_id}/invitations` with a token. The invitee accepts by hitting `POST /teams/invitations/{token}`.

## Transfer ownership

```bash
curl -X PUT '{API_URL}/teams/42/ownership' \
  -H 'Authorization: Bearer {OWNER_TOKEN}' \
  -H 'Content-Type: application/json' \
  -d '{"user_id": 99}'
```

The target user must already be a member of the team. The previous owner is automatically demoted to admin.

## Team API keys — usage note

Team-scoped API keys look identical to user keys (`sk-…` prefix) but billing and rate limits apply to the team, not the individual member. List them via `GET /teams/{team_id}/keys`. To create a team key, call the standard `POST /keys` with `team_id` set in the body.

## Usage summaries (team scope)

For team-level usage aggregates the console uses the shared usage-summary endpoints:

| Path                         | Purpose                             |
| ---------------------------- | ----------------------------------- |
| `/usage/last_summary`        | Last billing period summary         |
| `/usage/time_range`          | Custom time-range summary           |
| `/usage/models`              | Per-model breakdown                 |
| `/usage/instance_summary`    | Instance spend aggregate            |
| `/usage/instance_time_range` | Instance spend over a custom window |
| `/usage/storage_summary`     | Storage usage summary               |

These accept a `team_id` query param to scope to a team.

## Errors

| Status | Reason                                                  |
| ------ | ------------------------------------------------------- |
| `400`  | Validation failure (missing `name`, invalid role, etc.) |
| `403`  | Caller lacks the required team permission               |
| `404`  | Team, member, or invitation token not found             |
| `409`  | Email already invited / already a member                |

## Related

* [Authentication](/api-reference/platform-api/authentication.md)
* [Create API Key](/api-reference/platform-api/create-api-key.md) — pass `team_id` in the body for a team key
* [Usage Records](/api-reference/platform-api/usage/get-usage-records.md)
