---
title: "Teams API"
description: "Use when you manage a team library over HTTP: list teams, invite and remove members, manage departments, and share books with the whole team or chosen departments."
url: https://docs.heytrove.ai/reference/api/teams
updated: 2026-10-01
---

# Teams API

> Load this page when: you need to manage team members, departments or shared books over HTTP

## For agents

- Every call needs a teamId from GET /teams. Your role in that team decides what you can do.
- Members can share a book they own read-only with the whole team. Owners and admins manage the rest.
- Team changes share one budget of 20 calls per minute.

A team shares a library. Roles are OWNER, ADMIN and MEMBER. See [Teams](https://docs.heytrove.ai/concepts/teams.md). A `dept` path value is a department slug or id.

## Team errors

| Status | Message | Code | Fix |
| --- | --- | --- | --- |
| 403 | ``You are not a member of this team. Run `trove team list` to see teams you belong to.`` | `NOT_A_TEAM_MEMBER` | Use a team from the list. |
| 403 | `Only OWNER and ADMIN can manage team configuration — your role is MEMBER.` | `FORBIDDEN_ROLE` | Ask an owner or admin. |
| 404 | ``No department '{dept}' in this team — run `trove team departments list` to see available departments.`` | `DEPARTMENT_NOT_FOUND` | Check the slug. |
| 429 | `Too many team changes in a short window — wait a minute and retry.` | `RATE_LIMITED` | Wait for `Retry-After`. |

Routes below add their own errors.

## List teams

`GET https://heytrove.ai/api/v1/teams`

Lists the teams you belong to. It takes no parameters.

```bash
curl https://heytrove.ai/api/v1/teams \
  -H "Authorization: Bearer trove_your_key"
```

```json
{ "teams": [{ "id": "cmteam1", "name": "Platform", "role": "OWNER", "memberCount": 4 }] }
```

**CLI equivalent**: [trove team list](https://docs.heytrove.ai/reference/cli/team.md#trove-team-list).

## List members

`GET https://heytrove.ai/api/v1/teams/{teamId}/members`

Lists members and pending invites. Any member can call it. Plain members see masked emails, with `emailHidden` set.

```json
{ "members": [{ "email": "ada@example.com", "emailHidden": false, "name": "Ada", "role": "ADMIN", "departments": ["engineering"] }], "invites": [] }
```

## Invite a member

`POST https://heytrove.ai/api/v1/teams/{teamId}/members`

Invites a person by email. Only OWNER and ADMIN can call it. The person needs no account yet.

**Parameters**

| Name | In | Type | Required | Constraints | Meaning |
| --- | --- | --- | --- | --- | --- |
| `email` | body | string | yes | an email address | Person to invite. |
| `role` | body | string | no | `MEMBER` or `ADMIN` | Default `MEMBER`. Any other value becomes `MEMBER`. |

```bash
curl https://heytrove.ai/api/v1/teams/cmteam1/members \
  -H "Authorization: Bearer trove_your_key" \
  -H "Content-Type: application/json" \
  -d '{"email":"ada@example.com","role":"ADMIN"}'
```

Status 201 for a new invite, and 200 when it was resent or the person is already a member. The body has `invite`, `member`, `added`, `invited`, `pending`, `resent`, `created` and `alreadyExisted`.

**CLI equivalent**: [trove team invite](https://docs.heytrove.ai/reference/cli/team.md#trove-team-invite).

## Remove a member

`DELETE https://heytrove.ai/api/v1/teams/{teamId}/members`

Removes a member by email, and their access to shared books. Only the team OWNER can call it. The body is `{ "email": "..." }`. The answer is `{ "success": true, "member": { "email": "..." } }`.

| Status | Message | Code | Fix |
| --- | --- | --- | --- |
| 400 | `You can't remove yourself. Delete the team instead, or transfer ownership first.` | `CANNOT_REMOVE_SELF` | Ask another owner. |
| 403 | `Only the team OWNER can do this — your role is {role}.` | `FORBIDDEN_ROLE` | Ask the owner. |

**CLI equivalent**: [trove team remove](https://docs.heytrove.ai/reference/cli/team.md#trove-team-remove).

## List departments

`GET https://heytrove.ai/api/v1/teams/{teamId}/departments`

Lists departments. A plain member sees only their own. The answer is `{ "departments": [{ "id", "name", "slug" }] }`.

## Create a department

`POST https://heytrove.ai/api/v1/teams/{teamId}/departments`

Creates a department. Only OWNER and ADMIN can call it. Creating the same name twice is not an error. Send `{ "name": "Engineering" }`. The answer is status 201 with `{ "department", "created": true }`, or 200 when it existed.

## Rename a department

`PATCH https://heytrove.ai/api/v1/teams/{teamId}/departments/{dept}`

Renames a department. Only OWNER and ADMIN can call it. Send `{ "name": "..." }`. A clash returns 409 `DEPARTMENT_SLUG_TAKEN` with `A department with slug '{slug}' already exists in this team.`

## Delete a department

`DELETE https://heytrove.ai/api/v1/teams/{teamId}/departments/{dept}`

Deletes a department. Members lose the assignment, and books shared only with it are unshared. Only OWNER and ADMIN can call it. The answer is `{ "success": true, "department", "unsharedCount" }`.

## List department members

`GET https://heytrove.ai/api/v1/teams/{teamId}/departments/{dept}/members`

Lists the members of a department. Only OWNER and ADMIN can call it. The answer is `{ "members": [...] }`.

## Add a department member

`POST https://heytrove.ai/api/v1/teams/{teamId}/departments/{dept}/members`

Adds a team member by email. The person must already be on the team. Only OWNER and ADMIN can call it. Send `{ "email": "..." }`. The answer is status 201 with `{ "department", "added": true }`, or 200 when they were there.

| Status | Message | Code | Fix |
| --- | --- | --- | --- |
| 404 | ``No team member with email '{email}' — run `trove team show` to see members, or invite them with `trove team invite {email}`.`` | `MEMBER_NOT_FOUND` | Invite them first. |

## Remove a department member

`DELETE https://heytrove.ai/api/v1/teams/{teamId}/departments/{dept}/members`

Removes a member from a department. Send `{ "email": "..." }`. The answer has `removed` set to true, or false when they were not in it.

## List shared books

`GET https://heytrove.ai/api/v1/teams/{teamId}/items`

Lists the books shared with the team. A plain member sees only their own departments.

```json
{ "items": [{ "itemId": "cmabc123", "title": "Use The Index, Luke", "accessLevel": "READ", "teamWide": true, "departments": [], "sharedAt": "2026-09-01T09:00:00.000Z" }] }
```

## Share a book with the team

`POST https://heytrove.ai/api/v1/teams/{teamId}/items`

Shares a book you own. Without departments it goes to the whole team. OWNER and ADMIN can scope a share and grant write access. A plain member can share only read-only with the whole team.

**Parameters**

| Name | In | Type | Required | Constraints | Meaning |
| --- | --- | --- | --- | --- | --- |
| `itemId` | body | string | yes | a book you own | Book to share. |
| `departmentSlugs` | body | string array | no | up to 50 | Scope to these departments. |
| `departmentSlug` | body | string or null | no | none | Older form with one department. |
| `accessLevel` | body | string | no | `READ` or `WRITE` | Default `READ`. |

```bash
curl https://heytrove.ai/api/v1/teams/cmteam1/items \
  -H "Authorization: Bearer trove_your_key" \
  -H "Content-Type: application/json" \
  -d '{"itemId":"cmabc123","departmentSlugs":["engineering"]}'
```

Status 201 when granted, and 200 when it existed. The body has `item`, `departments`, `teamWide`, `accessLevel`, `granted` and `alreadyExisted`.

| Status | Message | Code | Fix |
| --- | --- | --- | --- |
| 403 | `Item '{id}' not found in your library (you can only share books you own).` | `ITEM_NOT_OWNED` | Share a book you own. |
| 402 | `An active team subscription is required to share books with the team.` | `TEAM_SUBSCRIPTION_REQUIRED` | The team needs a paid plan. |
| 400 | `A book can be shared with at most 50 departments.` | none | Send fewer. |

**CLI equivalent**: [trove team access grant](https://docs.heytrove.ai/reference/cli/team.md#trove-team-access-grant).

## Change how a book is shared

`PATCH https://heytrove.ai/api/v1/teams/{teamId}/items`

Changes the scope, the access level, or both. Only OWNER and ADMIN can call it. Send `itemId` and at least one of `accessLevel` and `departmentSlugs`. An empty `departmentSlugs` means the whole team.

| Status | Message | Code | Fix |
| --- | --- | --- | --- |
| 400 | `Provide accessLevel and/or departmentSlug(s) to update.` | none | Send one of them. |
| 404 | ``Item '{id}' is not shared with this team — grant it first with `trove team access grant {id}`.`` | `TEAM_ITEM_NOT_FOUND` | Share it first. |

**CLI equivalent**: [trove team access scope](https://docs.heytrove.ai/reference/cli/team.md#trove-team-access-scope).

## Stop sharing a book

`DELETE https://heytrove.ai/api/v1/teams/{teamId}/items`

Stops sharing a book for all members. The team OWNER, an admin, or the member who shared it can call it. Send `{ "itemId": "..." }`. The answer is `{ "success": true, "item", "alreadyAbsent" }`. Anyone else gets 403 `FORBIDDEN_REVOKE`.

**CLI equivalent**: [trove team access revoke](https://docs.heytrove.ai/reference/cli/team.md#trove-team-access-revoke).

## Show the access matrix

`GET https://heytrove.ai/api/v1/teams/{teamId}/access-report`

Shows which department can read which book. Only OWNER and ADMIN can call it. It returns the departments with member counts, and the shared books with their scope and access level.

**CLI equivalent**: [trove team access matrix](https://docs.heytrove.ai/reference/cli/team.md#trove-team-access-matrix).
