# Tellagen API Reference

> Generated from the same canonical API contract as the human-readable reference at https://tellagen.com/api-reference.

Documentation contract: `sha256:898ee484330817a84c170e0e87bf24f27e62e5838635ee4c9daf6a7a3d704ce9`. This fingerprint identifies the generated documentation contract, not the API major version.

## Endpoint index

### Teams

[Teams Markdown export](https://tellagen.com/api-reference/teams/markdown)

- [`GET /api/v1/teams`](https://tellagen.com/api-reference/teams#teams-endpoint-get-api-v1-teams) — List teams
- [`POST /api/v1/teams`](https://tellagen.com/api-reference/teams#teams-endpoint-post-api-v1-teams) — Create team
- [`GET /api/v1/teams/{id}`](https://tellagen.com/api-reference/teams#teams-endpoint-get-api-v1-teams-id) — Get team
- [`PATCH /api/v1/teams/{id}`](https://tellagen.com/api-reference/teams#teams-endpoint-patch-api-v1-teams-id) — Update team
- [`DELETE /api/v1/teams/{id}`](https://tellagen.com/api-reference/teams#teams-endpoint-delete-api-v1-teams-id) — Archive team
- [`POST /api/v1/teams/{id}/restore`](https://tellagen.com/api-reference/teams#teams-endpoint-post-api-v1-teams-id-restore) — Restore team
- [`GET /api/v1/teams/{id}/members`](https://tellagen.com/api-reference/teams#teams-endpoint-get-api-v1-teams-id-members) — List team members
- [`POST /api/v1/teams/{id}/members`](https://tellagen.com/api-reference/teams#teams-endpoint-post-api-v1-teams-id-members) — Add team member
- [`PATCH /api/v1/teams/{id}/members/{userId}`](https://tellagen.com/api-reference/teams#teams-endpoint-patch-api-v1-teams-id-members-userid) — Update team member
- [`DELETE /api/v1/teams/{id}/members/{userId}`](https://tellagen.com/api-reference/teams#teams-endpoint-delete-api-v1-teams-id-members-userid) — Remove team member

## Base URL

`https://{company}.api.tellagen.com/api/v1/`

Replace `{company}` with your company subdomain. Requests and JSON responses use `application/json` unless an endpoint documents an empty response.

## Authentication

Create an API token in **Settings > API keys** and send it as a Bearer token:

`Authorization: Bearer tllg_YOUR_TOKEN`

Tokens are shown only once when created. Grant only the scopes the client needs.

## Integration guides

- [Make your first request](https://tellagen.com/api-reference#first-request)
- [Build reliable requests](https://tellagen.com/api-reference#reliable-requests)
- [Filter and paginate collections](https://tellagen.com/api-reference/guides/pagination)
- [Create and move an incident through its workflow](https://tellagen.com/api-reference/guides/workflows)
- [Send custom-field values](https://tellagen.com/api-reference/guides/field-values)

## Versioning

All endpoints in this reference use `/api/v1` and are supported.

**Compatible changes.** Tellagen can add optional response fields or enum values. Ignore response fields that your client does not use.

**Breaking changes.** Tellagen uses a new major version for incompatible changes.

**Deprecated endpoints.** Tellagen marks an endpoint deprecated at least 180 days before removal. Deprecated responses identify the replacement endpoint.

## Scopes

| Scope | Description |
| --- | --- |
| `incidents:read` | List and retrieve incidents, and discover writable workflow statuses and severities |
| `incidents:write` | Create and update incidents and timeline events. Requires an active responder seat for the key owner. |
| `slack_context:read` | Read Slack context collected for incident investigation |
| `services:read` | List and retrieve services, and discover writable service tiers |
| `services:write` | Create, update, and archive services. Requires an active responder seat and the manage_settings role permission. |
| `teams:read` | List and retrieve teams and members |
| `teams:write` | Create, update, and archive teams; manage members. Requires an active responder seat and the manage_teams role permission. |
| `custom_fields:read` | List and retrieve custom field definitions and values |
| `custom_fields:write` | Create, update, and archive custom fields; set incident field values. Definition changes require the manage_settings role permission. Incident value changes require an active responder seat. |

## Prerequisite definitions

- **Active responder seat** (`active_responder`): The API key owner must have an active responder seat.
- **Manage workspace settings** (`manage_settings`): The API key owner must have the manage_settings role permission.
- **Manage teams** (`manage_teams`): The API key owner must have the manage_teams role permission.
- **Incident is not archived** (`mutable_incident`): The incident must not be archived. Workflow-state restrictions are described by each operation.
- **Linked Slack channel** (`slack_channel`): The incident must have a linked Slack channel.

## Errors

Errors always include a stable `code` and a human-readable `message`. They can also include `field`, `details`, and `request_id`.

You can send `X-Request-ID` with a request. If you omit it, the API generates one. The response header and error body return the same value.

### Missing scope (403)

```json
{
  "code": "missing_scope",
  "message": "insufficient scope: incidents:write required",
  "details": {
    "required_scope": "incidents:write"
  },
  "request_id": "01JEXAMPLE8R4N5W6Y7Z"
}
```

### Stale resource version (412)

```json
{
  "code": "precondition_failed",
  "message": "the resource changed; fetch it again and retry with the current resource version",
  "field": "If-Tellagen-Resource-Version",
  "request_id": "01JEXAMPLE8R4N5W6Y7Z"
}
```

### Rate limit (429)

```json
{
  "code": "rate_limited",
  "message": "rate limit exceeded",
  "details": {
    "retry_after_seconds": 1
  },
  "request_id": "01JEXAMPLE8R4N5W6Y7Z"
}
```

When you contact support, include the request ID, method, path, status, and time. Omit tokens and private request bodies.

| Code | Meaning | Next action | Retry |
| --- | --- | --- | --- |
| `authentication_required` | The request has no valid API token or session. | Send an active Bearer token for this workspace. Replace an expired or revoked key. | After correcting authentication. |
| `missing_scope` | The token lacks the scope named in details.required_scope. | Read details.required_scope. Ask a workspace manager for a replacement key with that scope. | After correcting access. |
| `responder_seat_required` | The key owner needs the seat named in details.required_seat. | Ask a workspace manager to review the key owner’s responder seat. | After correcting access. |
| `missing_role_permission` | The key owner lacks details.required_permission or one of details.required_roles. | Ask a workspace manager to review the owner’s role and the permission named in details. | After correcting access. |
| `permission_denied` | Access is denied without exposing private authorization state. | Verify the workspace, key owner, and resource access with a workspace manager. | After correcting access. |
| `invalid_resource_state` | The operation is not valid for the current resource state. | Read the current resource. Restore an archived resource or choose an operation allowed in its current state. | After reconciling state. |
| `invalid_relationship_state` | Restore requires a retained owner or parent relationship to identify an active resource. | Restore the retained parent or owning team before restoring this resource. | After correcting the relationship. |
| `duplicate_slug` | A team already uses the requested slug. | Read the existing team or choose a different slug. | After changing the request. |
| `invalid_json` | The request body is not one valid JSON document. | Send one valid JSON object with Content-Type: application/json. | After correcting the body. |
| `unknown_field` | The request contains an unsupported JSON property named in field. | Remove or correct the property named in field. Use the request schema, not the response schema. | After correcting the body. |
| `request_body_too_large` | The request body is larger than 1 MiB. | Reduce the body to 1 MiB or less. | After reducing the body. |
| `multiple_json_values` | The request body contains more than one JSON document. | Send one JSON document rather than concatenated documents. | After correcting the body. |
| `idempotency_key_reused` | The key was already used with different request content. | Recover the original request for this key. Use a new key only for a different intended operation. | Do not resend changed content with the same key. |
| `idempotency_in_progress` | An equal request with this key is still running. Retry later. | Wait for Retry-After, then resend the identical body with the same key. | After the indicated delay. |
| `idempotency_outcome_unknown` | An earlier request may have completed, but its result could not be stored. Do not retry it automatically. | Read the resource state and contact support with the request ID before deciding whether to create again. | Never retry automatically. |
| `precondition_required` | An API-key PATCH request omitted If-Tellagen-Resource-Version. | Read the resource, then send its Tellagen-Resource-Version as If-Tellagen-Resource-Version. | After adding the current version. |
| `invalid_precondition` | If-Tellagen-Resource-Version is not a positive integer. | Use the positive integer version returned for this resource. Do not use an ETag or a timestamp. | After correcting the header. |
| `precondition_failed` | The resource changed after the client read it. | Read the resource again. Reconcile your intended change with the current state before using its new version. | After reconciling the change. |
| `rate_limited` | Retry after details.retry_after_seconds or the Retry-After header. | Wait for Retry-After or details.retry_after_seconds. Limit concurrency across the workspace. | After the indicated delay, with the original idempotency key where supported. |
| `internal` | The server failed without exposing an internal error. | Keep the request ID. Read current state before retrying a write whose outcome is uncertain. | Retry reads with bounded backoff. Follow operation-specific rules for writes. |
| `invalid_slack_channel_name_request` | The channel-name request is invalid. | Use custom mode with name, or workspace_template mode without name. | After correcting the request. |
| `slack_not_configured` | The workspace has no usable Slack integration. | Ask a workspace manager to connect or repair Slack. | After repairing the integration. |
| `incident_slack_channel_missing` | The incident has no linked Slack channel. | Link a channel through the incident workspace before requesting a rename. | After linking a channel. |
| `slack_channel_not_found` | Slack cannot find the linked channel. | Verify the channel still exists and that the integration can access it. | After repairing channel access. |
| `slack_channel_name_taken` | Another Slack channel uses the requested name. | Choose another custom name or revise the workspace naming template. | After choosing an available name. |
| `invalid_idempotency_key` | The idempotency key has an invalid length or character. | Use 1–128 visible, non-space ASCII characters. A UUID is suitable. | After correcting the key. |

| Status | Meaning |
| --- | --- |
| `400` | Bad Request — invalid input or missing required fields |
| `401` | Unauthorized — missing or invalid token |
| `403` | Forbidden — insufficient scope or responder access |
| `404` | Not Found — resource does not exist |
| `409` | Conflict — resource state prevents the request |
| `412` | Precondition Failed — the supplied resource version is stale |
| `428` | Precondition Required — this operation needs If-Tellagen-Resource-Version |
| `429` | Too Many Requests — rate limit exceeded |
| `500` | Internal Server Error |

Authenticated requests share a workspace limit. Anonymous requests and failed authentication attempts use the trusted client IP. Responses include `X-RateLimit-Limit` and `X-RateLimit-Remaining`. A `429` response also includes `Retry-After`.

## Teams

Creates, lists, reads, updates, archives, and restores teams. This section also manages team memberships.

### `GET /api/v1/teams`

**List teams.** Returns one page sorted by team name and team ID. By default, the response excludes archived teams.

Required scope: `teams:read`

Operation ID: `listTeams`
Contract: `supported`
Retry guidance: This operation is repeat-safe. Respect Retry-After and use bounded retries.
Prerequisites: None

#### Query parameters

Required nested fields apply when their parent object is present. Optional does not imply nullable.

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `limit` | `integer` | No | The maximum number of items in one page. The default is 50, and the maximum is 100. Minimum: 1. Maximum: 100. Default: 50. |
| `cursor` | `string` | No | The next_cursor value from the previous page. Clients treat this value as opaque and do not create, inspect, or change it. Minimum length: 1 characters. Maximum length: 4096 characters. |
| `include_archived` | `boolean` | No | Controls whether the response includes archived teams. The default is false. Default: false. |

#### Example request

Replace `{company}`, `<token>`, and any other placeholders with your values.

```bash
curl --request GET \
  --url 'https://{company}.api.tellagen.com/api/v1/teams' \
  --header 'Authorization: Bearer <token>'
```

#### Success response

Status: `200 OK`

#### Response fields

Returned means the field is present when its parent object is present. A nullable field can contain null.

| Name | Type | Returned | Description |
| --- | --- | --- | --- |
| `teams` | `object[]` | Always | The teams in this page. |
| `teams[].id` | `integer` | Always | The positive numeric ID of the team. Minimum: 1. |
| `teams[].revision` | `integer` | Always | The resource version for concurrency control. Minimum: 1. |
| `teams[].company_id` | `integer` | Always | The ID of the workspace that owns the team. Minimum: 1. |
| `teams[].name` | `string` | Always | The display name of the team. |
| `teams[].slug` | `string` | Always | The permanent key used to identify the team. |
| `teams[].description` | `string` | Optional | The workspace description of the team. |
| `teams[].parent_team_id` | `integer` | Optional | The positive ID of the parent team. This field is absent for a root team. Minimum: 1. |
| `teams[].member_count` | `integer` | Optional | The number of active workspace members in the team. Minimum: 0. |
| `teams[].created_at` | `string (RFC 3339)` | Always | The team creation time. |
| `teams[].updated_at` | `string (RFC 3339)` | Always | The time of the latest team change. |
| `teams[].archived_at` | `string (RFC 3339)` | Optional | The team archive time. This field is absent for an active team. |
| `pagination` | `object` | Always | Pagination details for a collection response. |
| `pagination.limit` | `integer` | Always | The maximum number of items requested for this page. Minimum: 1. Maximum: 100. |
| `pagination.has_more` | `boolean` | Always | Indicates whether another page is available. |
| `pagination.next_cursor` | `string` | Optional | The opaque cursor for the next page. This field is absent on the final page. |

Returns teams and pagination fields.

```json
{
  "teams": [
    {
      "id": 42,
      "revision": 2,
      "company_id": 7,
      "name": "Platform Team",
      "slug": "platform_team",
      "description": "Core platform infrastructure",
      "member_count": 12,
      "created_at": "2025-01-10T09:00:00Z",
      "updated_at": "2025-01-10T09:00:00Z"
    }
  ],
  "pagination": {
    "limit": 50,
    "has_more": true,
    "next_cursor": "opaque-server-cursor"
  }
}
```

#### Endpoint error responses

| Status | Meaning |
| --- | --- |
| `400` | The API rejected the request because its syntax or one of its values is invalid. |
| `401` | The request does not contain valid authentication. |
| `403` | Authentication succeeded, but the caller lacks the required API scope or workspace permission. |
| `404` | The requested resource does not exist or is not available to the caller. |
| `409` | The request conflicts with the current resource state. idempotency_key_reused means that the key belongs to different request content. idempotency_in_progress means that an identical request is still in progress. idempotency_outcome_unknown means that an earlier request may have completed, but its result could not be stored and must not be retried automatically. |
| `429` | The workspace exceeded an active request limit. |
| `500` | An internal server error prevented completion of the request. |

### `POST /api/v1/teams`

**Create team.** Creates a team. If slug is omitted, the API creates it from name. A parent team must be active. If any team already uses the slug, the API returns 409. This includes archived teams.

Required scope: `teams:write`

Operation ID: `createTeam`
Contract: `supported`
Retry guidance: Retry an identical request with the same Idempotency-Key used on the first attempt, within 24 hours. Never retry an unknown outcome automatically.
Prerequisites: Active responder seat, Manage teams

#### Request headers

Required nested fields apply when their parent object is present. Optional does not imply nullable.

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `Idempotency-Key` | `string` | No | A key for safe retries of a create request. It must contain 1–128 visible, non-space ASCII characters. The same key applies only to an identical request. Minimum length: 1 characters. Maximum length: 128 characters. Pattern: ^[\x21-\x7E]+$. |

#### Example request

Replace `{company}`, `<token>`, and any other placeholders with your values.

For `<idempotency-key>`, choose a unique key on the first attempt. Reuse it only when retrying the identical request.

```bash
curl --request POST \
  --url 'https://{company}.api.tellagen.com/api/v1/teams' \
  --header 'Authorization: Bearer <token>' \
  --header 'Idempotency-Key: <idempotency-key>' \
  --header 'Content-Type: application/json' \
  --data '{
  "name": "Platform Team",
  "description": "Core platform infrastructure"
}'
```

#### Request body

Required nested fields apply when their parent object is present. Optional does not imply nullable.

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | `string` | Yes | The team name. The length must be from 1 through 128 characters. Minimum length: 1 characters. Maximum length: 128 characters. |
| `slug` | `string` | No | A permanent team key. It starts with a lowercase letter and contains lowercase letters, digits, or underscores. If slug is omitted, the API creates it from name. |
| `description` | `string` | No | The workspace description of the team. |
| `parent_team_id` | `integer` | No | The positive ID of an active parent team. If the request omits parent_team_id, the API creates a root team. Minimum: 1. |

Request JSON:

```json
{
  "name": "Platform Team",
  "description": "Core platform infrastructure"
}
```

#### Success response

Status: `201 Created`

#### Response fields

Returned means the field is present when its parent object is present. A nullable field can contain null.

| Name | Type | Returned | Description |
| --- | --- | --- | --- |
| `team` | `object` | Always | The complete public record for a team. |
| `team.id` | `integer` | Always | The positive numeric ID of the team. Minimum: 1. |
| `team.revision` | `integer` | Always | The resource version for concurrency control. Minimum: 1. |
| `team.company_id` | `integer` | Always | The ID of the workspace that owns the team. Minimum: 1. |
| `team.name` | `string` | Always | The display name of the team. |
| `team.slug` | `string` | Always | The permanent key used to identify the team. |
| `team.description` | `string` | Optional | The workspace description of the team. |
| `team.parent_team_id` | `integer` | Optional | The positive ID of the parent team. This field is absent for a root team. Minimum: 1. |
| `team.member_count` | `integer` | Optional | The number of active workspace members in the team. Minimum: 0. |
| `team.created_at` | `string (RFC 3339)` | Always | The team creation time. |
| `team.updated_at` | `string (RFC 3339)` | Always | The time of the latest team change. |
| `team.archived_at` | `string (RFC 3339)` | Optional | The team archive time. This field is absent for an active team. |

Returns the created team.

```json
{
  "team": {
    "id": 42,
    "revision": 1,
    "company_id": 7,
    "name": "Platform Team",
    "slug": "platform_team",
    "description": "Core platform infrastructure",
    "created_at": "2025-01-30T12:00:00Z",
    "updated_at": "2025-01-30T12:00:00Z"
  }
}
```

#### Response headers

Returned means the field is present when its parent object is present. A nullable field can contain null.

| Name | Type | Returned | Description |
| --- | --- | --- | --- |
| `Tellagen-Resource-Version` | `integer` | Always | The positive resource version for If-Tellagen-Resource-Version in the next API-key PATCH request. Minimum: 1. |

#### Endpoint error responses

Endpoint-specific codes: `idempotency_key_reused`, `idempotency_in_progress`, `idempotency_outcome_unknown`

| Status | Meaning |
| --- | --- |
| `400` | The API rejected the request because its syntax or one of its values is invalid. |
| `401` | The request does not contain valid authentication. |
| `403` | Authentication succeeded, but the caller lacks the required API scope or workspace permission. |
| `404` | The requested resource does not exist or is not available to the caller. |
| `409` | The request conflicts with the current resource state. idempotency_key_reused means that the key belongs to different request content. idempotency_in_progress means that an identical request is still in progress. idempotency_outcome_unknown means that an earlier request may have completed, but its result could not be stored and must not be retried automatically. |
| `429` | The workspace exceeded an active request limit. |
| `500` | An internal server error prevented completion of the request. |

### `GET /api/v1/teams/{id}`

**Get team.** Returns one team by its positive numeric ID. A team remains available by ID after it is archived.

Required scope: `teams:read`

Operation ID: `getTeam`
Contract: `supported`
Retry guidance: This operation is repeat-safe. Respect Retry-After and use bounded retries.
Prerequisites: None

#### Path parameters

Required nested fields apply when their parent object is present. Optional does not imply nullable.

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | `integer` | Yes | A positive numeric team ID returned by this API. Minimum: 1. |

#### Example request

Replace `{company}`, `<token>`, and any other placeholders with your values.

```bash
curl --request GET \
  --url 'https://{company}.api.tellagen.com/api/v1/teams/{id}' \
  --header 'Authorization: Bearer <token>'
```

#### Success response

Status: `200 OK`

#### Response fields

Returned means the field is present when its parent object is present. A nullable field can contain null.

| Name | Type | Returned | Description |
| --- | --- | --- | --- |
| `team` | `object` | Always | The complete public record for a team. |
| `team.id` | `integer` | Always | The positive numeric ID of the team. Minimum: 1. |
| `team.revision` | `integer` | Always | The resource version for concurrency control. Minimum: 1. |
| `team.company_id` | `integer` | Always | The ID of the workspace that owns the team. Minimum: 1. |
| `team.name` | `string` | Always | The display name of the team. |
| `team.slug` | `string` | Always | The permanent key used to identify the team. |
| `team.description` | `string` | Optional | The workspace description of the team. |
| `team.parent_team_id` | `integer` | Optional | The positive ID of the parent team. This field is absent for a root team. Minimum: 1. |
| `team.member_count` | `integer` | Optional | The number of active workspace members in the team. Minimum: 0. |
| `team.created_at` | `string (RFC 3339)` | Always | The team creation time. |
| `team.updated_at` | `string (RFC 3339)` | Always | The time of the latest team change. |
| `team.archived_at` | `string (RFC 3339)` | Optional | The team archive time. This field is absent for an active team. |

Returns the team.

```json
{
  "team": {
    "id": 42,
    "revision": 2,
    "company_id": 7,
    "name": "Platform Team",
    "slug": "platform_team",
    "description": "Core platform infrastructure",
    "created_at": "2025-01-10T09:00:00Z",
    "updated_at": "2025-01-10T09:00:00Z"
  }
}
```

#### Response headers

Returned means the field is present when its parent object is present. A nullable field can contain null.

| Name | Type | Returned | Description |
| --- | --- | --- | --- |
| `Tellagen-Resource-Version` | `integer` | Always | The positive resource version for If-Tellagen-Resource-Version in the next API-key PATCH request. Minimum: 1. |

#### Endpoint error responses

| Status | Meaning |
| --- | --- |
| `400` | The API rejected the request because its syntax or one of its values is invalid. |
| `401` | The request does not contain valid authentication. |
| `403` | Authentication succeeded, but the caller lacks the required API scope or workspace permission. |
| `404` | The requested resource does not exist or is not available to the caller. |
| `409` | The request conflicts with the current resource state. idempotency_key_reused means that the key belongs to different request content. idempotency_in_progress means that an identical request is still in progress. idempotency_outcome_unknown means that an earlier request may have completed, but its result could not be stored and must not be retried automatically. |
| `429` | The workspace exceeded an active request limit. |
| `500` | An internal server error prevented completion of the request. |

### `PATCH /api/v1/teams/{id}`

**Update team.** Updates an active team. If the request supplies a parent team, that team must be active. The update must not create a hierarchy cycle. Omitted fields stay unchanged.

Required scope: `teams:write`

Operation ID: `updateTeam`
Contract: `supported`
Retry guidance: Read the current resource and reconcile changes before retrying with its current version. A stale version returns 412.
Prerequisites: Active responder seat, Manage teams

#### Path parameters

Required nested fields apply when their parent object is present. Optional does not imply nullable.

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | `integer` | Yes | A positive numeric team ID returned by this API. Minimum: 1. |

#### Request headers

Required nested fields apply when their parent object is present. Optional does not imply nullable.

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `If-Tellagen-Resource-Version` | `integer` | Yes | The current positive resource version from the latest response. API-key PATCH requests must send this value. Minimum: 1. |

#### Example request

Replace `{company}`, `<token>`, and any other placeholders with your values.

Use the Tellagen-Resource-Version header from a GET of this resource for `<resource-version>`.

```bash
curl --request PATCH \
  --url 'https://{company}.api.tellagen.com/api/v1/teams/{id}' \
  --header 'Authorization: Bearer <token>' \
  --header 'If-Tellagen-Resource-Version: <resource-version>' \
  --header 'Content-Type: application/json' \
  --data '{
  "description": "Core platform and infrastructure"
}'
```

#### Request body

Required nested fields apply when their parent object is present. Optional does not imply nullable.

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | `string` | No | The team name. The length must be from 1 through 128 characters. Minimum length: 1 characters. Maximum length: 128 characters. |
| `description` | `string` | No | The replacement team description. |
| `parent_team_id` | `integer \| null` | No | The positive ID of an active parent team. A null value makes this team a root team. |

Request JSON:

```json
{
  "description": "Core platform and infrastructure"
}
```

#### Success response

Status: `200 OK`

#### Response fields

Returned means the field is present when its parent object is present. A nullable field can contain null.

| Name | Type | Returned | Description |
| --- | --- | --- | --- |
| `team` | `object` | Always | The complete public record for a team. |
| `team.id` | `integer` | Always | The positive numeric ID of the team. Minimum: 1. |
| `team.revision` | `integer` | Always | The resource version for concurrency control. Minimum: 1. |
| `team.company_id` | `integer` | Always | The ID of the workspace that owns the team. Minimum: 1. |
| `team.name` | `string` | Always | The display name of the team. |
| `team.slug` | `string` | Always | The permanent key used to identify the team. |
| `team.description` | `string` | Optional | The workspace description of the team. |
| `team.parent_team_id` | `integer` | Optional | The positive ID of the parent team. This field is absent for a root team. Minimum: 1. |
| `team.member_count` | `integer` | Optional | The number of active workspace members in the team. Minimum: 0. |
| `team.created_at` | `string (RFC 3339)` | Always | The team creation time. |
| `team.updated_at` | `string (RFC 3339)` | Always | The time of the latest team change. |
| `team.archived_at` | `string (RFC 3339)` | Optional | The team archive time. This field is absent for an active team. |

Returns the updated team.

```json
{
  "team": {
    "id": 42,
    "revision": 3,
    "company_id": 7,
    "name": "Platform Team",
    "slug": "platform_team",
    "description": "Core platform and infrastructure",
    "created_at": "2025-01-10T09:00:00Z",
    "updated_at": "2025-01-30T12:00:00Z"
  }
}
```

#### Response headers

Returned means the field is present when its parent object is present. A nullable field can contain null.

| Name | Type | Returned | Description |
| --- | --- | --- | --- |
| `Tellagen-Resource-Version` | `integer` | Always | The positive resource version for If-Tellagen-Resource-Version in the next API-key PATCH request. Minimum: 1. |

#### Endpoint error responses

| Status | Meaning |
| --- | --- |
| `400` | The API rejected the request because its syntax or one of its values is invalid. |
| `401` | The request does not contain valid authentication. |
| `403` | Authentication succeeded, but the caller lacks the required API scope or workspace permission. |
| `404` | The requested resource does not exist or is not available to the caller. |
| `409` | The request conflicts with the current resource state. idempotency_key_reused means that the key belongs to different request content. idempotency_in_progress means that an identical request is still in progress. idempotency_outcome_unknown means that an earlier request may have completed, but its result could not be stored and must not be retried automatically. |
| `412` | The resource changed after the client obtained its If-Tellagen-Resource-Version value. |
| `428` | An API-key PATCH request did not include the required If-Tellagen-Resource-Version header. |
| `429` | The workspace exceeded an active request limit. |
| `500` | An internal server error prevented completion of the request. |

### `DELETE /api/v1/teams/{id}`

**Archive team.** Archives a team. A repeated request returns 204 without changing the archive time or resource version. The API retains memberships and child-team relationships. The archived team remains available by ID. It cannot be updated.

Required scope: `teams:write`

Operation ID: `archiveTeam`
Contract: `supported`
Retry guidance: Do not retry automatically after an uncertain outcome. Read the resource state and follow this operation’s recovery guidance.
Prerequisites: Active responder seat, Manage teams

#### Path parameters

Required nested fields apply when their parent object is present. Optional does not imply nullable.

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | `integer` | Yes | A positive numeric team ID returned by this API. Minimum: 1. |

#### Example request

Replace `{company}`, `<token>`, and any other placeholders with your values.

```bash
curl --request DELETE \
  --url 'https://{company}.api.tellagen.com/api/v1/teams/{id}' \
  --header 'Authorization: Bearer <token>'
```

#### Success response

Status: `204 No Content`

No response body.

#### Endpoint error responses

| Status | Meaning |
| --- | --- |
| `400` | The API rejected the request because its syntax or one of its values is invalid. |
| `401` | The request does not contain valid authentication. |
| `403` | Authentication succeeded, but the caller lacks the required API scope or workspace permission. |
| `404` | The requested resource does not exist or is not available to the caller. |
| `409` | The request conflicts with the current resource state. idempotency_key_reused means that the key belongs to different request content. idempotency_in_progress means that an identical request is still in progress. idempotency_outcome_unknown means that an earlier request may have completed, but its result could not be stored and must not be retried automatically. |
| `429` | The workspace exceeded an active request limit. |
| `500` | An internal server error prevented completion of the request. |

### `POST /api/v1/teams/{id}/restore`

**Restore team.** Restores an archived team and returns the active team. A repeated request returns the active team without changing its resource version. If the team has parent_team_id, that parent team must be active. Otherwise, the API returns 409 invalid_relationship_state. The API retains team memberships.

Required scope: `teams:write`

Operation ID: `restoreTeam`
Contract: `supported`
Retry guidance: Do not retry automatically after an uncertain outcome. Read the resource state and follow this operation’s recovery guidance.
Prerequisites: Active responder seat, Manage teams

#### Path parameters

Required nested fields apply when their parent object is present. Optional does not imply nullable.

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | `integer` | Yes | A positive numeric team ID returned by this API. Minimum: 1. |

#### Example request

Replace `{company}`, `<token>`, and any other placeholders with your values.

```bash
curl --request POST \
  --url 'https://{company}.api.tellagen.com/api/v1/teams/{id}/restore' \
  --header 'Authorization: Bearer <token>'
```

#### Success response

Status: `200 OK`

#### Response fields

Returned means the field is present when its parent object is present. A nullable field can contain null.

| Name | Type | Returned | Description |
| --- | --- | --- | --- |
| `team` | `object` | Always | The complete public record for a team. |
| `team.id` | `integer` | Always | The positive numeric ID of the team. Minimum: 1. |
| `team.revision` | `integer` | Always | The resource version for concurrency control. Minimum: 1. |
| `team.company_id` | `integer` | Always | The ID of the workspace that owns the team. Minimum: 1. |
| `team.name` | `string` | Always | The display name of the team. |
| `team.slug` | `string` | Always | The permanent key used to identify the team. |
| `team.description` | `string` | Optional | The workspace description of the team. |
| `team.parent_team_id` | `integer` | Optional | The positive ID of the parent team. This field is absent for a root team. Minimum: 1. |
| `team.member_count` | `integer` | Optional | The number of active workspace members in the team. Minimum: 0. |
| `team.created_at` | `string (RFC 3339)` | Always | The team creation time. |
| `team.updated_at` | `string (RFC 3339)` | Always | The time of the latest team change. |
| `team.archived_at` | `string (RFC 3339)` | Optional | The team archive time. This field is absent for an active team. |

Returns the complete active team.

```json
{
  "team": {
    "id": 42,
    "revision": 3,
    "company_id": 7,
    "name": "Platform Team",
    "slug": "platform_team",
    "description": "Core platform and infrastructure",
    "created_at": "2025-01-10T09:00:00Z",
    "updated_at": "2025-01-30T12:00:00Z"
  }
}
```

#### Response headers

Returned means the field is present when its parent object is present. A nullable field can contain null.

| Name | Type | Returned | Description |
| --- | --- | --- | --- |
| `Tellagen-Resource-Version` | `integer` | Always | The positive resource version for If-Tellagen-Resource-Version in the next API-key PATCH request. Minimum: 1. |

#### Endpoint error responses

Endpoint-specific codes: `invalid_relationship_state`

| Status | Meaning |
| --- | --- |
| `400` | The API rejected the request because its syntax or one of its values is invalid. |
| `401` | The request does not contain valid authentication. |
| `403` | Authentication succeeded, but the caller lacks the required API scope or workspace permission. |
| `404` | The requested resource does not exist or is not available to the caller. |
| `409` | The request conflicts with the current resource state. idempotency_key_reused means that the key belongs to different request content. idempotency_in_progress means that an identical request is still in progress. idempotency_outcome_unknown means that an earlier request may have completed, but its result could not be stored and must not be retried automatically. |
| `429` | The workspace exceeded an active request limit. |
| `500` | An internal server error prevented completion of the request. |

### `GET /api/v1/teams/{id}/members`

**List team members.** Returns one page sorted by membership creation time and user ID. Each entry includes membership and user details.

Required scope: `teams:read`

Operation ID: `listTeamMembers`
Contract: `supported`
Retry guidance: This operation is repeat-safe. Respect Retry-After and use bounded retries.
Prerequisites: None

#### Path parameters

Required nested fields apply when their parent object is present. Optional does not imply nullable.

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | `integer` | Yes | A positive numeric team ID returned by this API. Minimum: 1. |

#### Query parameters

Required nested fields apply when their parent object is present. Optional does not imply nullable.

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `limit` | `integer` | No | The maximum number of items in one page. The default is 50, and the maximum is 100. Minimum: 1. Maximum: 100. Default: 50. |
| `cursor` | `string` | No | The next_cursor value from the previous page. Clients treat this value as opaque and do not create, inspect, or change it. Minimum length: 1 characters. Maximum length: 4096 characters. |

#### Example request

Replace `{company}`, `<token>`, and any other placeholders with your values.

```bash
curl --request GET \
  --url 'https://{company}.api.tellagen.com/api/v1/teams/{id}/members' \
  --header 'Authorization: Bearer <token>'
```

#### Success response

Status: `200 OK`

#### Response fields

Returned means the field is present when its parent object is present. A nullable field can contain null.

| Name | Type | Returned | Description |
| --- | --- | --- | --- |
| `members` | `object[]` | Always | The team memberships in this page. |
| `members[].team_id` | `integer` | Always | The positive numeric ID of the team. |
| `members[].user_id` | `integer` | Always | The positive numeric ID of the workspace member. |
| `members[].role` | `string` | Always | The role in this team. Possible values: `"lead"` \| `"member"` |
| `members[].email` | `string` | Always | The email address of the workspace member. |
| `members[].display_name` | `string` | Optional | The display name of the workspace member. |
| `members[].avatar_url` | `string` | Optional | The avatar URL of the workspace member. |
| `pagination` | `object` | Always | Pagination details for a collection response. |
| `pagination.limit` | `integer` | Always | The maximum number of items requested for this page. Minimum: 1. Maximum: 100. |
| `pagination.has_more` | `boolean` | Always | Indicates whether another page is available. |
| `pagination.next_cursor` | `string` | Optional | The opaque cursor for the next page. This field is absent on the final page. |

Returns team members and pagination fields.

```json
{
  "members": [
    {
      "team_id": 42,
      "user_id": 100,
      "role": "lead",
      "email": "lead@example.com",
      "display_name": "Jane Doe",
      "avatar_url": ""
    }
  ],
  "pagination": {
    "limit": 50,
    "has_more": false
  }
}
```

#### Endpoint error responses

| Status | Meaning |
| --- | --- |
| `400` | The API rejected the request because its syntax or one of its values is invalid. |
| `401` | The request does not contain valid authentication. |
| `403` | Authentication succeeded, but the caller lacks the required API scope or workspace permission. |
| `404` | The requested resource does not exist or is not available to the caller. |
| `409` | The request conflicts with the current resource state. idempotency_key_reused means that the key belongs to different request content. idempotency_in_progress means that an identical request is still in progress. idempotency_outcome_unknown means that an earlier request may have completed, but its result could not be stored and must not be retried automatically. |
| `429` | The workspace exceeded an active request limit. |
| `500` | An internal server error prevented completion of the request. |

### `POST /api/v1/teams/{id}/members`

**Add team member.** Adds an active workspace member to an active team. If the team membership already exists, the API updates its role.

Required scope: `teams:write`

Operation ID: `addTeamMember`
Contract: `supported`
Retry guidance: Do not retry automatically after an uncertain outcome. Read the resource state and follow this operation’s recovery guidance.
Prerequisites: Active responder seat, Manage teams

#### Path parameters

Required nested fields apply when their parent object is present. Optional does not imply nullable.

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | `integer` | Yes | A positive numeric team ID returned by this API. Minimum: 1. |

#### Example request

Replace `{company}`, `<token>`, and any other placeholders with your values.

```bash
curl --request POST \
  --url 'https://{company}.api.tellagen.com/api/v1/teams/{id}/members' \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '{
  "user_id": 100,
  "role": "lead"
}'
```

#### Request body

Required nested fields apply when their parent object is present. Optional does not imply nullable.

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `user_id` | `integer` | Yes | The positive ID of the active workspace member to add. Minimum: 1. |
| `role` | `string` | No | The role in this team. If the request omits role, the API uses member. Default: "member". Allowed values: `"lead"` \| `"member"` |

Request JSON:

```json
{
  "user_id": 100,
  "role": "lead"
}
```

#### Success response

Status: `201 Created`

#### Response fields

Returned means the field is present when its parent object is present. A nullable field can contain null.

| Name | Type | Returned | Description |
| --- | --- | --- | --- |
| `member` | `object` | Always | The team membership returned after a create or update request. |
| `member.team_id` | `integer` | Always | The positive numeric ID of the team. Minimum: 1. |
| `member.user_id` | `integer` | Always | The positive numeric ID of the workspace member. Minimum: 1. |
| `member.role` | `string` | Always | The role in this team. Possible values: `"lead"` \| `"member"` |
| `member.created_at` | `string (RFC 3339)` | Always | The membership creation time. |

Returns the created or updated team membership.

```json
{
  "member": {
    "team_id": 42,
    "user_id": 100,
    "role": "lead",
    "created_at": "2025-01-30T12:00:00Z"
  }
}
```

#### Endpoint error responses

| Status | Meaning |
| --- | --- |
| `400` | The API rejected the request because its syntax or one of its values is invalid. |
| `401` | The request does not contain valid authentication. |
| `403` | Authentication succeeded, but the caller lacks the required API scope or workspace permission. |
| `404` | The requested resource does not exist or is not available to the caller. |
| `409` | The request conflicts with the current resource state. idempotency_key_reused means that the key belongs to different request content. idempotency_in_progress means that an identical request is still in progress. idempotency_outcome_unknown means that an earlier request may have completed, but its result could not be stored and must not be retried automatically. |
| `429` | The workspace exceeded an active request limit. |
| `500` | An internal server error prevented completion of the request. |

### `PATCH /api/v1/teams/{id}/members/{userId}`

**Update team member.** Updates the team role for an active workspace member. If the team membership does not exist, the API returns 404.

Required scope: `teams:write`

Operation ID: `updateTeamMember`
Contract: `supported`
Retry guidance: Do not retry automatically after an uncertain outcome. Read the resource state and follow this operation’s recovery guidance.
Prerequisites: Active responder seat, Manage teams

#### Path parameters

Required nested fields apply when their parent object is present. Optional does not imply nullable.

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | `integer` | Yes | A positive numeric team ID returned by this API. Minimum: 1. |
| `userId` | `integer` | Yes | A positive numeric user ID for an active workspace member. Minimum: 1. |

#### Example request

Replace `{company}`, `<token>`, and any other placeholders with your values.

```bash
curl --request PATCH \
  --url 'https://{company}.api.tellagen.com/api/v1/teams/{id}/members/{userId}' \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '{
  "role": "member"
}'
```

#### Request body

Required nested fields apply when their parent object is present. Optional does not imply nullable.

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `role` | `string` | Yes | The new team role. Allowed values: `"lead"` \| `"member"` |

Request JSON:

```json
{
  "role": "member"
}
```

#### Success response

Status: `200 OK`

#### Response fields

Returned means the field is present when its parent object is present. A nullable field can contain null.

| Name | Type | Returned | Description |
| --- | --- | --- | --- |
| `member` | `object` | Always | The team membership returned after a create or update request. |
| `member.team_id` | `integer` | Always | The positive numeric ID of the team. Minimum: 1. |
| `member.user_id` | `integer` | Always | The positive numeric ID of the workspace member. Minimum: 1. |
| `member.role` | `string` | Always | The role in this team. Possible values: `"lead"` \| `"member"` |
| `member.created_at` | `string (RFC 3339)` | Always | The membership creation time. |

Returns the updated team membership.

```json
{
  "member": {
    "team_id": 42,
    "user_id": 100,
    "role": "member",
    "created_at": "2025-01-10T09:00:00Z"
  }
}
```

#### Endpoint error responses

| Status | Meaning |
| --- | --- |
| `400` | The API rejected the request because its syntax or one of its values is invalid. |
| `401` | The request does not contain valid authentication. |
| `403` | Authentication succeeded, but the caller lacks the required API scope or workspace permission. |
| `404` | The requested resource does not exist or is not available to the caller. |
| `409` | The request conflicts with the current resource state. idempotency_key_reused means that the key belongs to different request content. idempotency_in_progress means that an identical request is still in progress. idempotency_outcome_unknown means that an earlier request may have completed, but its result could not be stored and must not be retried automatically. |
| `429` | The workspace exceeded an active request limit. |
| `500` | An internal server error prevented completion of the request. |

### `DELETE /api/v1/teams/{id}/members/{userId}`

**Remove team member.** Removes one user from the team. The operation does not remove the user from the workspace.

Required scope: `teams:write`

Operation ID: `removeTeamMember`
Contract: `supported`
Retry guidance: Do not retry automatically after an uncertain outcome. Read the resource state and follow this operation’s recovery guidance.
Prerequisites: Active responder seat, Manage teams

#### Path parameters

Required nested fields apply when their parent object is present. Optional does not imply nullable.

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | `integer` | Yes | A positive numeric team ID returned by this API. Minimum: 1. |
| `userId` | `integer` | Yes | A positive numeric user ID for an active workspace member. Minimum: 1. |

#### Example request

Replace `{company}`, `<token>`, and any other placeholders with your values.

```bash
curl --request DELETE \
  --url 'https://{company}.api.tellagen.com/api/v1/teams/{id}/members/{userId}' \
  --header 'Authorization: Bearer <token>'
```

#### Success response

Status: `204 No Content`

No response body.

#### Endpoint error responses

| Status | Meaning |
| --- | --- |
| `400` | The API rejected the request because its syntax or one of its values is invalid. |
| `401` | The request does not contain valid authentication. |
| `403` | Authentication succeeded, but the caller lacks the required API scope or workspace permission. |
| `404` | The requested resource does not exist or is not available to the caller. |
| `409` | The request conflicts with the current resource state. idempotency_key_reused means that the key belongs to different request content. idempotency_in_progress means that an identical request is still in progress. idempotency_outcome_unknown means that an earlier request may have completed, but its result could not be stored and must not be retried automatically. |
| `429` | The workspace exceeded an active request limit. |
| `500` | An internal server error prevented completion of the request. |
