# Teams

A team is a group of workspace members that owns tickets. Its key, such as WEB, starts the IDs of its tickets (WEB-31), and each team has its own ticket statuses and views. Open teams are listed for everyone; private teams only for their members and for owners and admins.

## The Team object

A group of workspace members that owns tickets and numbers them with its key, such as WEB-31.

### Attributes

- `id` (string, required): Unique ID of the team.
- `key` (string, required): 2 to 5 capital letters that start the team's ticket IDs, such as WEB.
- `name` (string, required): The team's display name.
- `visibility` (string, one of: `open`, `private`, required): Who sees the team: open teams are listed for everyone in the workspace, private teams only for their members and for owners and admins.
- `archivedAt` (nullable string, required): When it was archived, as an ISO 8601 timestamp; null while active.
- `members` (array of objects, required): The team's members, sorted by name.
  - `id` (string, required): The person's user ID.
  - `name` (string, required): The person's display name.
  - `email` (string, required): The person's email address.
- `joined` (boolean, required): Whether the caller is a member. Always false for an account API key.
- `createdAt` (string, required): When it was created, as an ISO 8601 timestamp.
- `updatedAt` (string, required): When it last changed, as an ISO 8601 timestamp.

### Example

```json
{
  "id": "Tm6PzN3kWq1J",
  "key": "WEB",
  "name": "Web",
  "visibility": "open",
  "archivedAt": null,
  "members": [
    {
      "id": "Us3NfP8kLq2V",
      "name": "Maya Patel",
      "email": "maya@acme.dev"
    },
    {
      "id": "Us9DcT4wHn6R",
      "name": "Sam Okafor",
      "email": "sam@acme.dev"
    }
  ],
  "joined": true,
  "createdAt": "2026-10-01T16:20:00.000Z",
  "updatedAt": "2026-10-14T09:05:12.000Z"
}
```

## List teams

`GET /v1/workspaces/{slug}/teams`

Returns open teams and the private teams the caller is in; owners, admins and account API keys see every team. Archived teams are left out unless `archived` asks for them.

### Parameters

- `slug` (string, in path, required): The workspace's slug or ID, such as acme.
- `archived` (string, one of: `exclude`, `include`, `only`, in query): Which archived teams to return: exclude (the default), include or only archived ones.

### Returns

Returns an object with these fields. The status is 200.

- `teams` (array of objects, required): The teams, sorted by name. See [the Team object](https://docs.qa.clankership.net/api/teams/object.md).
  - `id` (string, required): Unique ID of the team.
  - `key` (string, required): 2 to 5 capital letters that start the team's ticket IDs, such as WEB.
  - `name` (string, required): The team's display name.
  - `visibility` (string, one of: `open`, `private`, required): Who sees the team: open teams are listed for everyone in the workspace, private teams only for their members and for owners and admins.
  - `archivedAt` (nullable string, required): When it was archived, as an ISO 8601 timestamp; null while active.
  - `members` (array of objects, required): The team's members, sorted by name.
    - `id` (string, required): The person's user ID.
    - `name` (string, required): The person's display name.
    - `email` (string, required): The person's email address.
  - `joined` (boolean, required): Whether the caller is a member. Always false for an account API key.
  - `createdAt` (string, required): When it was created, as an ISO 8601 timestamp.
  - `updatedAt` (string, required): When it last changed, as an ISO 8601 timestamp.

### Request

```bash
curl https://api.qa.clankership.net/v1/workspaces/{slug}/teams \
  -H "Authorization: Bearer $CLANKER_API_KEY"
```

### Response

```json
{
  "teams": [
    {
      "id": "Tm6PzN3kWq1J",
      "key": "WEB",
      "name": "Web",
      "visibility": "open",
      "archivedAt": null,
      "members": [
        {
          "id": "Us3NfP8kLq2V",
          "name": "Maya Patel",
          "email": "maya@acme.dev"
        },
        {
          "id": "Us9DcT4wHn6R",
          "name": "Sam Okafor",
          "email": "sam@acme.dev"
        }
      ],
      "joined": true,
      "createdAt": "2026-10-01T16:20:00.000Z",
      "updatedAt": "2026-10-14T09:05:12.000Z"
    }
  ]
}
```

### Errors

- `400` `InvalidInput`: The request is malformed, or a value is not allowed.
- `401` `Unauthorized`: The request has no valid API key.
- `403` `Forbidden`: The key's user or role may not do this.
- `404` `NotFound`: The workspace or object does not exist, or the caller cannot see it.
- `409` `Conflict`: The change conflicts with current data, such as a slug that is already in use.
- `500` `Internal`: Clanker Ship failed to handle the request. Retry, or report the response's x-request-id.

## Create a team

`POST /v1/workspaces/{slug}/teams`

Owners and admins create teams. The key and name must be unused in the workspace. The team copies the workspace's ticket status template, starts with the default views, and the person who creates it joins it.

### Parameters

- `slug` (string, in path, required): The workspace's slug or ID, such as acme.
- `name` (string, required): The team's display name, up to 80 characters, unique in the workspace.
- `key` (string, required): 2 to 5 letters that start the team's ticket IDs, such as WEB. Stored in capitals.
- `visibility` (string, one of: `open`, `private`): `open` lists the team for everyone in the workspace; `private` only for its members and for owners and admins. Defaults to open.

### Returns

Returns the [Team](https://docs.qa.clankership.net/api/teams/object.md) object. The status is 201.

### Request

```bash
curl -X POST https://api.qa.clankership.net/v1/workspaces/{slug}/teams \
  -H "Authorization: Bearer $CLANKER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Web",
    "key": "WEB",
    "visibility": "open"
  }'
```

### Response

```json
{
  "id": "Tm6PzN3kWq1J",
  "key": "WEB",
  "name": "Web",
  "visibility": "open",
  "archivedAt": null,
  "members": [
    {
      "id": "Us3NfP8kLq2V",
      "name": "Maya Patel",
      "email": "maya@acme.dev"
    },
    {
      "id": "Us9DcT4wHn6R",
      "name": "Sam Okafor",
      "email": "sam@acme.dev"
    }
  ],
  "joined": true,
  "createdAt": "2026-10-01T16:20:00.000Z",
  "updatedAt": "2026-10-14T09:05:12.000Z"
}
```

### Errors

- `400` `InvalidInput`: The request is malformed, or a value is not allowed.
- `401` `Unauthorized`: The request has no valid API key.
- `403` `Forbidden`: The key's user or role may not do this.
- `404` `NotFound`: The workspace or object does not exist, or the caller cannot see it.
- `409` `Conflict`: The change conflicts with current data, such as a slug that is already in use.
- `500` `Internal`: Clanker Ship failed to handle the request. Retry, or report the response's x-request-id.

## Get a team

`GET /v1/workspaces/{slug}/teams/{team}`

Returns one team, archived or not, with its members. A caller who cannot see a private team gets NotFound.

### Parameters

- `slug` (string, in path, required): The workspace's slug or ID, such as acme.
- `team` (string, in path, required): The team's key, such as WEB.

### Returns

Returns the [Team](https://docs.qa.clankership.net/api/teams/object.md) object. The status is 200.

### Request

```bash
curl https://api.qa.clankership.net/v1/workspaces/{slug}/teams/{team} \
  -H "Authorization: Bearer $CLANKER_API_KEY"
```

### Response

```json
{
  "id": "Tm6PzN3kWq1J",
  "key": "WEB",
  "name": "Web",
  "visibility": "open",
  "archivedAt": null,
  "members": [
    {
      "id": "Us3NfP8kLq2V",
      "name": "Maya Patel",
      "email": "maya@acme.dev"
    },
    {
      "id": "Us9DcT4wHn6R",
      "name": "Sam Okafor",
      "email": "sam@acme.dev"
    }
  ],
  "joined": true,
  "createdAt": "2026-10-01T16:20:00.000Z",
  "updatedAt": "2026-10-14T09:05:12.000Z"
}
```

### Errors

- `400` `InvalidInput`: The request is malformed, or a value is not allowed.
- `401` `Unauthorized`: The request has no valid API key.
- `403` `Forbidden`: The key's user or role may not do this.
- `404` `NotFound`: The workspace or object does not exist, or the caller cannot see it.
- `409` `Conflict`: The change conflicts with current data, such as a slug that is already in use.
- `500` `Internal`: Clanker Ship failed to handle the request. Retry, or report the response's x-request-id.

## Update a team

`PATCH /v1/workspaces/{slug}/teams/{team}`

Owners and admins change teams. Only the fields sent change. A new key or name must be unused, and the key changes only while the team has no tickets.

### Parameters

- `slug` (string, in path, required): The workspace's slug or ID, such as acme.
- `team` (string, in path, required): The team's key, such as WEB.
- `name` (string): The team's display name, up to 80 characters, unique in the workspace.
- `key` (string): 2 to 5 letters that start the team's ticket IDs, such as WEB. Changes only while the team has no tickets.
- `visibility` (string, one of: `open`, `private`): `open` lists the team for everyone in the workspace; `private` only for its members and for owners and admins.

### Returns

Returns the [Team](https://docs.qa.clankership.net/api/teams/object.md) object. The status is 200.

### Request

```bash
curl -X PATCH https://api.qa.clankership.net/v1/workspaces/{slug}/teams/{team} \
  -H "Authorization: Bearer $CLANKER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Web platform",
    "visibility": "private"
  }'
```

### Response

```json
{
  "id": "Tm6PzN3kWq1J",
  "key": "WEB",
  "name": "Web",
  "visibility": "open",
  "archivedAt": null,
  "members": [
    {
      "id": "Us3NfP8kLq2V",
      "name": "Maya Patel",
      "email": "maya@acme.dev"
    },
    {
      "id": "Us9DcT4wHn6R",
      "name": "Sam Okafor",
      "email": "sam@acme.dev"
    }
  ],
  "joined": true,
  "createdAt": "2026-10-01T16:20:00.000Z",
  "updatedAt": "2026-10-14T09:05:12.000Z"
}
```

### Errors

- `400` `InvalidInput`: The request is malformed, or a value is not allowed.
- `401` `Unauthorized`: The request has no valid API key.
- `403` `Forbidden`: The key's user or role may not do this.
- `404` `NotFound`: The workspace or object does not exist, or the caller cannot see it.
- `409` `Conflict`: The change conflicts with current data, such as a slug that is already in use.
- `500` `Internal`: Clanker Ship failed to handle the request. Retry, or report the response's x-request-id.

## Delete a team

`DELETE /v1/workspaces/{slug}/teams/{team}`

Owners and admins delete a team that has no tickets. A team with tickets fails with Conflict; archive it instead.

### Parameters

- `slug` (string, in path, required): The workspace's slug or ID, such as acme.
- `team` (string, in path, required): The team's key, such as WEB.

### Returns

Returns no content. The status is 204.

### Request

```bash
curl -X DELETE https://api.qa.clankership.net/v1/workspaces/{slug}/teams/{team} \
  -H "Authorization: Bearer $CLANKER_API_KEY"
```

### Errors

- `400` `InvalidInput`: The request is malformed, or a value is not allowed.
- `401` `Unauthorized`: The request has no valid API key.
- `403` `Forbidden`: The key's user or role may not do this.
- `404` `NotFound`: The workspace or object does not exist, or the caller cannot see it.
- `409` `Conflict`: The change conflicts with current data, such as a slug that is already in use.
- `500` `Internal`: Clanker Ship failed to handle the request. Retry, or report the response's x-request-id.

## Archive a team

`POST /v1/workspaces/{slug}/teams/{team}/archive`

Owners and admins archive teams. The team leaves lists, and its tickets stay readable but take no changes until it is restored. Archiving an archived team changes nothing.

### Parameters

- `slug` (string, in path, required): The workspace's slug or ID, such as acme.
- `team` (string, in path, required): The team's key, such as WEB.

### Returns

Returns the [Team](https://docs.qa.clankership.net/api/teams/object.md) object. The status is 200.

### Request

```bash
curl -X POST https://api.qa.clankership.net/v1/workspaces/{slug}/teams/{team}/archive \
  -H "Authorization: Bearer $CLANKER_API_KEY"
```

### Response

```json
{
  "id": "Tm6PzN3kWq1J",
  "key": "WEB",
  "name": "Web",
  "visibility": "open",
  "archivedAt": null,
  "members": [
    {
      "id": "Us3NfP8kLq2V",
      "name": "Maya Patel",
      "email": "maya@acme.dev"
    },
    {
      "id": "Us9DcT4wHn6R",
      "name": "Sam Okafor",
      "email": "sam@acme.dev"
    }
  ],
  "joined": true,
  "createdAt": "2026-10-01T16:20:00.000Z",
  "updatedAt": "2026-10-14T09:05:12.000Z"
}
```

### Errors

- `400` `InvalidInput`: The request is malformed, or a value is not allowed.
- `401` `Unauthorized`: The request has no valid API key.
- `403` `Forbidden`: The key's user or role may not do this.
- `404` `NotFound`: The workspace or object does not exist, or the caller cannot see it.
- `409` `Conflict`: The change conflicts with current data, such as a slug that is already in use.
- `500` `Internal`: Clanker Ship failed to handle the request. Retry, or report the response's x-request-id.

## Restore a team

`POST /v1/workspaces/{slug}/teams/{team}/restore`

Owners and admins bring an archived team back, so its tickets take changes again. Restoring an active team changes nothing.

### Parameters

- `slug` (string, in path, required): The workspace's slug or ID, such as acme.
- `team` (string, in path, required): The team's key, such as WEB.

### Returns

Returns the [Team](https://docs.qa.clankership.net/api/teams/object.md) object. The status is 200.

### Request

```bash
curl -X POST https://api.qa.clankership.net/v1/workspaces/{slug}/teams/{team}/restore \
  -H "Authorization: Bearer $CLANKER_API_KEY"
```

### Response

```json
{
  "id": "Tm6PzN3kWq1J",
  "key": "WEB",
  "name": "Web",
  "visibility": "open",
  "archivedAt": null,
  "members": [
    {
      "id": "Us3NfP8kLq2V",
      "name": "Maya Patel",
      "email": "maya@acme.dev"
    },
    {
      "id": "Us9DcT4wHn6R",
      "name": "Sam Okafor",
      "email": "sam@acme.dev"
    }
  ],
  "joined": true,
  "createdAt": "2026-10-01T16:20:00.000Z",
  "updatedAt": "2026-10-14T09:05:12.000Z"
}
```

### Errors

- `400` `InvalidInput`: The request is malformed, or a value is not allowed.
- `401` `Unauthorized`: The request has no valid API key.
- `403` `Forbidden`: The key's user or role may not do this.
- `404` `NotFound`: The workspace or object does not exist, or the caller cannot see it.
- `409` `Conflict`: The change conflicts with current data, such as a slug that is already in use.
- `500` `Internal`: Clanker Ship failed to handle the request. Retry, or report the response's x-request-id.

## Join a team

`POST /v1/workspaces/{slug}/teams/{team}/join`

Adds the caller to an open team. Owners and admins can also join private teams, and an account API key cannot join any. Joining a team twice changes nothing.

### Parameters

- `slug` (string, in path, required): The workspace's slug or ID, such as acme.
- `team` (string, in path, required): The team's key, such as WEB.

### Returns

Returns the [Team](https://docs.qa.clankership.net/api/teams/object.md) object. The status is 200.

### Request

```bash
curl -X POST https://api.qa.clankership.net/v1/workspaces/{slug}/teams/{team}/join \
  -H "Authorization: Bearer $CLANKER_API_KEY"
```

### Response

```json
{
  "id": "Tm6PzN3kWq1J",
  "key": "WEB",
  "name": "Web",
  "visibility": "open",
  "archivedAt": null,
  "members": [
    {
      "id": "Us3NfP8kLq2V",
      "name": "Maya Patel",
      "email": "maya@acme.dev"
    },
    {
      "id": "Us9DcT4wHn6R",
      "name": "Sam Okafor",
      "email": "sam@acme.dev"
    }
  ],
  "joined": true,
  "createdAt": "2026-10-01T16:20:00.000Z",
  "updatedAt": "2026-10-14T09:05:12.000Z"
}
```

### Errors

- `400` `InvalidInput`: The request is malformed, or a value is not allowed.
- `401` `Unauthorized`: The request has no valid API key.
- `403` `Forbidden`: The key's user or role may not do this.
- `404` `NotFound`: The workspace or object does not exist, or the caller cannot see it.
- `409` `Conflict`: The change conflicts with current data, such as a slug that is already in use.
- `500` `Internal`: Clanker Ship failed to handle the request. Retry, or report the response's x-request-id.

## Add a team member

`POST /v1/workspaces/{slug}/teams/{team}/members`

Adds a workspace member to the team, which is how private teams grow. The team's members and workspace owners and admins add people; viewers cannot. Adding a member twice changes nothing.

### Parameters

- `slug` (string, in path, required): The workspace's slug or ID, such as acme.
- `team` (string, in path, required): The team's key, such as WEB.
- `person` (string, required): The workspace member to add, by user ID or email address.

### Returns

Returns the [Team](https://docs.qa.clankership.net/api/teams/object.md) object. The status is 200.

### Request

```bash
curl -X POST https://api.qa.clankership.net/v1/workspaces/{slug}/teams/{team}/members \
  -H "Authorization: Bearer $CLANKER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "person": "sam@acme.dev"
  }'
```

### Response

```json
{
  "id": "Tm6PzN3kWq1J",
  "key": "WEB",
  "name": "Web",
  "visibility": "open",
  "archivedAt": null,
  "members": [
    {
      "id": "Us3NfP8kLq2V",
      "name": "Maya Patel",
      "email": "maya@acme.dev"
    },
    {
      "id": "Us9DcT4wHn6R",
      "name": "Sam Okafor",
      "email": "sam@acme.dev"
    }
  ],
  "joined": true,
  "createdAt": "2026-10-01T16:20:00.000Z",
  "updatedAt": "2026-10-14T09:05:12.000Z"
}
```

### Errors

- `400` `InvalidInput`: The request is malformed, or a value is not allowed.
- `401` `Unauthorized`: The request has no valid API key.
- `403` `Forbidden`: The key's user or role may not do this.
- `404` `NotFound`: The workspace or object does not exist, or the caller cannot see it.
- `409` `Conflict`: The change conflicts with current data, such as a slug that is already in use.
- `500` `Internal`: Clanker Ship failed to handle the request. Retry, or report the response's x-request-id.

## Remove a team member

`DELETE /v1/workspaces/{slug}/teams/{team}/members/{person}`

Removes a person from the team. Anyone can leave a team; removing someone else takes a member of the team or a workspace owner or admin, and viewers cannot.

### Parameters

- `slug` (string, in path, required): The workspace's slug or ID, such as acme.
- `team` (string, in path, required): The team's key, such as WEB.
- `person` (string, in path, required): The member's user ID or email address, such as sam@acme.dev.

### Returns

Returns the [Team](https://docs.qa.clankership.net/api/teams/object.md) object. The status is 200.

### Request

```bash
curl -X DELETE https://api.qa.clankership.net/v1/workspaces/{slug}/teams/{team}/members/{person} \
  -H "Authorization: Bearer $CLANKER_API_KEY"
```

### Response

```json
{
  "id": "Tm6PzN3kWq1J",
  "key": "WEB",
  "name": "Web",
  "visibility": "open",
  "archivedAt": null,
  "members": [
    {
      "id": "Us3NfP8kLq2V",
      "name": "Maya Patel",
      "email": "maya@acme.dev"
    },
    {
      "id": "Us9DcT4wHn6R",
      "name": "Sam Okafor",
      "email": "sam@acme.dev"
    }
  ],
  "joined": true,
  "createdAt": "2026-10-01T16:20:00.000Z",
  "updatedAt": "2026-10-14T09:05:12.000Z"
}
```

### Errors

- `400` `InvalidInput`: The request is malformed, or a value is not allowed.
- `401` `Unauthorized`: The request has no valid API key.
- `403` `Forbidden`: The key's user or role may not do this.
- `404` `NotFound`: The workspace or object does not exist, or the caller cannot see it.
- `409` `Conflict`: The change conflicts with current data, such as a slug that is already in use.
- `500` `Internal`: Clanker Ship failed to handle the request. Retry, or report the response's x-request-id.
