
# API de Equipe

Sua equipe é composta por todos que trabalham em sua conta além de você — administradores, agentes e visualizadores com permissão apenas de leitura — além dos convites que você enviou e os departamentos nos quais você os organiza. A API de Equipe é a versão programática de **Configurações → Equipe**: adicione e remova pessoas, defina o que cada uma delas pode ver e fazer, envie e acompanhe convites e gerencie departamentos.

Todos os endpoints abaixo são relativos à URL base `https://api.youraiconnector.com/v1`. Para a versão do painel de tudo nesta página, consulte [Gerenciamento de Equipe](../settings/team-management.md).

---

## Autenticação: estes endpoints exigem uma pessoa conectada

**Esta é a única parte da API que uma chave de API não pode usar.** Cada endpoint `/team`, exceto os de [departamento](#departments), deve ser chamado com um **token de ID do Firebase** de uma sessão conectada:

```
Authorization: Bearer <Firebase ID token>
```

Envie uma chave de API e a solicitação será rejeitada com um `401`:

```json
{
  "success": false,
  "error_code": 401,
  "error": "This endpoint requires a Firebase ID token (Authorization: Bearer <token>)."
}
```

O motivo é que esses endpoints decidem o que fazer com base em **quem está conectado**: sua função, o limite do que você tem permissão para conceder a outra pessoa e se você está trabalhando atualmente dentro de outra conta. Uma chave de API é uma integração, não uma pessoa, portanto, não há ninguém a quem essas regras possam ser aplicadas.

Na prática, isso significa que a API de Equipe é para um aplicativo de primeira parte com um usuário <span data-t="appName">Your AI Connector</span> conectado (consulte [Autenticação → Token de ID do Firebase](authentication.md#4-firebase-id-token-first-party-only)). Uma integração servidor-para-servidor não pode gerenciar membros da equipe — não há como criar um desses tokens de fora do aplicativo.

> **A exceção:** os quatro endpoints de [departamento](#departments) são endpoints de API comuns. Eles aceitam sua chave de API exatamente como o restante da API, bem como uma sessão conectada.

Cada resposta nesta página segue o envelope usual: `success: true` mais os campos do endpoint no nível superior, ou `success: false` com `error` e `error_code` quando algo dá errado.

---

## Funções e permissões

Cada membro da equipe tem uma **função**, que define seu acesso padrão em 12 áreas do aplicativo. Você pode então substituir áreas individuais.

| Função | Valor | Resumo |
|---|---|---|
| Admin | `admin` | Tudo, exceto as ações de nível de faturamento do proprietário. |
| Editor | `editor` | Pode criar e alterar coisas. Exibido como **Agente** no aplicativo. |
| Visualizador | `viewer` | Apenas leitura. |

Cada área é definida como um dos quatro níveis: `none` (oculto), `view` (apenas leitura), `edit` (criar e alterar), `full` (incluindo exclusão).

| Área | Admin | Editor | Visualizador |
|---|---|---|---|
| `campaigns` | full | edit | view |
| `contacts` | full | edit | view |
| `messages` | full | edit | view |
| `appointments` | full | edit | view |
| `settings` | edit | view | none |
| `billing` | edit | none | none |
| `team_management` | edit | none | none |
| `analytics` | full | view | view |
| `phone_numbers` | edit | none | none |
| `integrations` | edit | none | none |
| `faqs` | full | edit | view |
| `daily_summaries` | full | view | view |

Para desviar dos padrões da função, envie `permission_overrides` — uma matriz de objetos `{ "area": ..., "level": ... }`. Cada entrada substitui o padrão da função para aquela área específica; tudo o que você não listar mantém o padrão da função.

```json
"permission_overrides": [
  { "area": "analytics", "level": "full" },
  { "area": "billing", "level": "none" }
]
```

**Quem pode chamar esses endpoints**

- O **proprietário da conta** sempre pode fazer tudo.
- Um membro da equipe precisa de `team_management` em `view` para ler a lista de membros e a lista de convites, e em `edit` para adicionar, alterar, suspender, remover, convidar, cancelar ou reenviar. Administradores têm `edit` por padrão; editores e visualizadores têm `none`, portanto, por padrão, apenas administradores podem gerenciar a equipe.
- **Ninguém pode conceder acesso superior ao seu próprio.** Se você tentar dar a alguém um nível que você mesmo não possui — ou editar, suspender ou remover alguém cujo acesso já seja mais amplo que o seu — a solicitação será recusada com `403` e uma mensagem nomeando a área.

---

## O objeto de membro da equipe

`GET /team/members` retorna um destes por membro:

| Campo | Tipo | Descrição |
|---|---|---|
| `member_uid` | string | O ID de usuário do próprio membro. Este é o `{memberUid}` nos caminhos abaixo. |
| `account_owner_uid` | string | A conta da qual eles são membros. |
| `member_email` | string | O endereço de e-mail deles. |
| `member_display_name` | string | O nome exibido para eles no aplicativo. |
| `role` | string | `admin`, `editor` ou `viewer`. |
| `permission_overrides` | array | Suas exceções por área. `[]` quando eles estão puramente nos padrões da função. |
| `status` | string | `active` ou `suspended`. |
| `auto_assign_enabled` | boolean \| null | Se novos contatos podem ser atribuídos automaticamente a eles. `null` significa nunca alterado, o que se comporta como `true`. |
| `created_by` | string | Quem os adicionou. |
| `created_at` | string \| null | Carimbo de data/hora ISO 8601. |
| `updated_at` | string \| null | Carimbo de data/hora ISO 8601. |

Membros removidos não são retornados — a lista contém apenas membros ativos e suspensos.

> **Limites de visibilidade são apenas de escrita aqui.** `contact_scope`, `contact_scope_axes` e `sub_account_access` (veja [Limitando o que um membro pode ver](#limiting-what-a-member-can-see)) podem ser definidos na criação, atualização e convite, mas este endpoint não os retorna.

---

## Listar membros da equipe

`GET /team/members`

Retorna a lista de membros mais as contagens de assentos do seu plano, para que você possa exibir "3 de 5 assentos" e saber quando um convite está prestes a ser recusado.

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/team/members" \
  -H "Authorization: Bearer FIREBASE_ID_TOKEN"
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/team/members", {
  headers: { Authorization: `Bearer ${idToken}` },
});
const { members, seat_limit, seats_used } = await res.json();
```

**Python**

```python
import requests

res = requests.get(
    "https://api.youraiconnector.com/v1/team/members",
    headers={"Authorization": f"Bearer {id_token}"},
)
data = res.json()
```

**Resposta**

```json
{
  "success": true,
  "members": [
    {
      "account_owner_uid": "owner_uid_123",
      "member_uid": "uid_alice",
      "member_email": "alice@example.com",
      "member_display_name": "Alice Chen",
      "role": "admin",
      "permission_overrides": [],
      "status": "active",
      "auto_assign_enabled": true,
      "created_by": "owner_uid_123",
      "created_at": "2026-05-01T10:00:00.000Z",
      "updated_at": "2026-06-02T09:15:00.000Z"
    }
  ],
  "seat_limit": 5,
  "seats_used": 3
}
```

`seat_limit` é `null` quando seu plano não tem limite de assentos. `seats_used` conta apenas membros **ativos** — suspender ou remover alguém libera seu assento imediatamente.

---

## Adicionar um membro da equipe diretamente

`POST /team/members`

Coloca alguém em sua equipe imediatamente, sem um convite.

> **Isso não envia nenhum e-mail.** Ninguém é avisado de que foi adicionado e, se a pessoa ainda não tiver um login <span data-t="appName">Your AI Connector</span>, a conta criada para ela **não terá senha**, portanto, ela não poderá entrar até que a redefina. Use [Enviar um convite](#send-an-invitation), a menos que você tenha sua própria maneira de avisar a pessoa e ajudá-la a entrar.

**Campos da requisição**

| Campo | Obrigatório | Descrição |
|---|---|---|
| `email` | Sim | O endereço de e-mail do membro da equipe. |
| `display_name` | Sim | O nome exibido para ele no aplicativo. |
| `role` | Sim | `admin`, `editor` ou `viewer`. |
| `permission_overrides` | Não | Exceções por área aos padrões da função. |
| `contact_scope` | Não | `all` ou `assigned` — veja [Limitando o que um membro pode ver](#limiting-what-a-member-can-see). |
| `contact_scope_unassigned` | Não | Com `assigned`, permita também que ele veja contatos que ainda não possuem um proprietário. |
| `contact_scope_axes` | Não | Limite-o a agentes, canais ou departamentos específicos. |
| `sub_account_access` | Não | Apenas agências — quais subcontas de cliente eles podem abrir. |

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/team/members" \
  -H "Authorization: Bearer FIREBASE_ID_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "sam@example.com",
    "display_name": "Sam Rivera",
    "role": "editor"
  }'
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/team/members", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${idToken}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    email: "sam@example.com",
    display_name: "Sam Rivera",
    role: "editor",
  }),
});
const { member_uid } = await res.json();
```

**Resposta** — `201 Created`

```json
{
  "success": true,
  "team_member_id": "owner_uid_123_uid_sam",
  "member_uid": "uid_sam",
  "message": "Team member created successfully."
}
```

| Status | Quando |
|---|---|
| `400` | `email`, `display_name` ou `role` está faltando, a função não é uma das três ou você tentou adicionar a si mesmo. |
| `403` | Você não tem permissão para gerenciar a equipe ou tentou conceder acesso superior ao seu próprio. |
| `409` | Essa pessoa já é um membro ativo da sua equipe. |
| `429` | As vagas da sua equipe no plano estão esgotadas. |

Adicionar alguém que foi anteriormente **suspenso ou removido** o reintegra em vez de falhar.

---

## Atualizar um membro da equipe

`PATCH /team/members/{memberUid}`

Altera a função, permissões, visibilidade, acesso do cliente ou se um membro participa da atribuição automática de contatos. Envie apenas os campos que deseja alterar; tudo o que você omitir manterá seu valor atual.

**Campos da requisição**

| Campo | Descrição |
|---|---|
| `role` | `admin`, `editor` ou `viewer`. |
| `permission_overrides` | Substitui toda a lista de substituições dele. Envie `[]` para colocá-lo de volta nos padrões puros da função. |
| `status` | Apenas `active` é aceito, para trazer de volta um membro suspenso. Para suspender alguém, use o [endpoint de suspensão](#suspend-a-team-member). |
| `auto_assign_enabled` | `true` ou `false`. |
| `contact_scope` | `all` ou `assigned`. |
| `contact_scope_unassigned` | `true` ou `false`. |
| `contact_scope_axes` | Veja [Limitando o que um membro pode ver](#limiting-what-a-member-can-see). |
| `sub_account_access` | Apenas agências. |

> **Este é o único endpoint onde `null` significa "limpar".** Enviar `"contact_scope": null`, `"contact_scope_axes": null` ou `"sub_account_access": null` remove esse limite completamente e faz com que o membro volte a ver tudo. Na criação e no convite, `null` simplesmente significa "não fornecido".

**cURL**

```bash
curl -X PATCH "https://api.youraiconnector.com/v1/team/members/uid_sam" \
  -H "Authorization: Bearer FIREBASE_ID_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "role": "admin",
    "permission_overrides": [{ "area": "billing", "level": "none" }]
  }'
```

**Resposta**

```json
{
  "success": true,
  "message": "Team member updated successfully."
}
```

| Status | Quando |
|---|---|
| `400` | Um valor `status` ou `auto_assign_enabled` inválido, ou você tentou reativar um membro que foi removido (membros removidos devem ser convidados novamente). |
| `403` | Você não tem permissão, ou a alteração editaria ou criaria um acesso mais amplo que o seu. |
| `404` | Esse membro da equipe não existe. |

---

## Suspender um membro da equipe

`POST /team/members/{memberUid}/suspend`

Suspende alguém: a pessoa mantém seu lugar na equipe, mas perde o acesso. Use isso em vez de remover quando a pausa for temporária — traga-a de volta com `PATCH /team/members/{memberUid}` e `{"status": "active"}`.

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/team/members/uid_sam/suspend" \
  -H "Authorization: Bearer FIREBASE_ID_TOKEN"
```

**Resposta**

```json
{
  "success": true,
  "message": "Team member suspended successfully."
}
```

Um membro suspenso **libera sua vaga**, para que você possa convidar outra pessoa em seu lugar. O acesso dele termina quando o token de sessão atual for atualizado, o que pode levar até uma hora — remova-o se precisar que seja imediato.

| Status | Quando |
|---|---|
| `400` | Você tentou suspender o proprietário da conta ou um membro que já está suspenso ou removido. |
| `403` | O acesso dele é mais amplo que o seu. |
| `404` | Esse membro da equipe não existe. |

---

## Remover um membro da equipe

`DELETE /team/members/{memberUid}`

Remove alguém da sua equipe e libera a sua licença. A pessoa é desconectada e perde o acesso à sua conta; o login dela permanece inalterado.

**cURL**

```bash
curl -X DELETE "https://api.youraiconnector.com/v1/team/members/uid_sam" \
  -H "Authorization: Bearer FIREBASE_ID_TOKEN"
```

**Resposta**

```json
{
  "success": true,
  "message": "Team member removed successfully."
}
```

A remoção é permanente do seu lado: um membro removido **não pode ser reativado** com o endpoint de atualização — convide-o novamente se mudar de ideia. O e-mail dele também é removido da lista de notificações da sua conta.

| Status | Quando |
|---|---|
| `400` | Você tentou remover o proprietário da conta. |
| `403` | O acesso dele é mais amplo que o seu. |
| `404` | Esse membro da equipe não existe. |

---

## Limitando o que um membro pode ver

Três campos opcionais, aceitos em [adicionar](#add-a-team-member-directly), [atualizar](#update-a-team-member) e [convidar](#send-an-invitation), determinam quanto da conta uma pessoa pode ver. Eles se acumulam: um membro limitado em mais de um campo é limitado por todos eles.

**`contact_scope`** — `all` (o padrão: todos os contatos e conversas) ou `assigned` (apenas aqueles atribuídos a eles). Com `assigned`, adicione `"contact_scope_unassigned": true` para também permitir que vejam contatos que ainda não possuem proprietário.

**`contact_scope_axes`** — limita-os a agentes, canais ou departamentos nomeados:

| Campo | Tipo | Descrição |
|---|---|---|
| `agents` | string[] | IDs de agentes. Eles só veem chats encaminhados para um desses agentes. Máx. 200. |
| `channels` | string[] | Nomes de canais — `whatsapp`, `whatsapp_web`, `sms`, `instagram`, `instagram_private`, `messenger`, `facebook`, `chat_widget`, `telegram`, `line`, `viber`, `tiktok`, `imessage`, `email`, `linkedin`, `skool`, `custom`, `custom_channel`. Máx. 200. |
| `departments` | string[] | IDs de departamentos (veja [Departamentos](#departments)). Eles só veem leads registrados neles. Máx. 200. |
| `include_unrouted` | boolean | Com `agents` definido, também mostra chats que nenhum agente atende. Desativado por padrão. Ignorado quando `agents` está vazio. |
| `include_undepartmented` | boolean | Com `departments` definido, também mostra chats que não estão em nenhum departamento. Desativado por padrão. Ignorado quando `departments` está vazio. |

Os IDs de agentes e departamentos não são verificados quando você os salva — um ID que não existe simplesmente não corresponde a nada, o que aparece como uma caixa de entrada vazia em vez de um erro. Os nomes dos canais **são** verificados: um nome não reconhecido é rejeitado com `400`.


Nenhum desses três pode ser definido para o proprietário da conta — essa solicitação é recusada com `400`.

---

## Listar convites

`GET /team/invites`

Os convites que você enviou, do mais recente para o mais antigo, para que você possa ver quem ainda não aceitou.

**Parâmetros de consulta**

| Parâmetro | Obrigatório | Descrição |
|---|---|---|
| `status` | Não | Retorna apenas convites neste estado — `pending`, `accepted`, `declined`, `cancelled` ou `expired`. |

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/team/invites?status=pending" \
  -H "Authorization: Bearer FIREBASE_ID_TOKEN"
```

**Resposta**

```json
{
  "success": true,
  "invites": [
    {
      "id": "inv_abc123",
      "account_owner_uid": "owner_uid_123",
      "account_owner_display_name": "Acme Ltd",
      "invitee_email": "sam@example.com",
      "invitee_uid": null,
      "role": "editor",
      "permission_overrides": [],
      "status": "pending",
      "created_by": "owner_uid_123",
      "created_at": "2026-06-10T12:00:00.000Z",
      "expires_at": "2026-06-17T12:00:00.000Z",
      "responded_at": null
    }
  ]
}
```

O token do convite nunca é retornado — ele só existe no e-mail que foi enviado.

---

## Enviar um convite

`POST /team/invites`

Envia por e-mail um convite para alguém entrar na sua equipe. Esta é a maneira usual de adicionar um colega de equipe: ele clica no link, faz login com sua própria conta e aceita. Se ele ainda não tiver uma conta <span data-t="appName">Your AI Connector</span>, uma será criada para ele e o e-mail o guiará na definição de uma senha.

**Campos da requisição**

| Campo | Obrigatório | Descrição |
|---|---|---|
| `email` | Sim | Para onde enviar o convite. |
| `role` | Sim | `admin`, `editor` ou `viewer`. |
| `permission_overrides` | Não | Exceções por área, aplicadas no momento em que aceitam. |
| `contact_scope` | Não | Aplicado quando aceitam. |
| `contact_scope_unassigned` | Não | Aplicado quando aceitam. |
| `contact_scope_axes` | Não | Aplicado quando aceitam. |
| `sub_account_access` | Não | Apenas para agências. Aplicado quando aceitam. |

Configurar as permissões antecipadamente significa que você não precisa editar o membro posteriormente — tudo é copiado para a associação dele quando ele aceita.

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/team/invites" \
  -H "Authorization: Bearer FIREBASE_ID_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "email": "sam@example.com", "role": "editor" }'
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/team/invites", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${idToken}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ email: "sam@example.com", role: "editor" }),
});
const { invite_id } = await res.json();
```

**Resposta** — `201 Created`

```json
{
  "success": true,
  "invite_id": "inv_abc123",
  "message": "Team invite sent successfully."
}
```

**Coisas a planejar**

- **Os convites expiram após 7 dias.** Um convite expirado pode ser reenviado, o que inicia um novo período de 7 dias.
- **Convites pendentes ocupam uma vaga.** Ao contrário de adicionar um membro diretamente, a verificação de vagas aqui conta os membros ativos *mais* os convites pendentes, portanto, uma conta com todas as vagas ocupadas será recusada antes que o e-mail seja enviado.
- **20 convites por dia**, contados por conta, tanto para envio quanto para reenvio.

| Status | Quando |
|---|---|
| `400` | `email` está faltando ou a função é inválida. |
| `403` | Você não tem permissão para gerenciar a equipe, ou tentou conceder acesso superior ao seu. |
| `409` | Já existe um convite pendente para esse e-mail, ou essa pessoa já está na sua equipe. |
| `429` | As vagas da equipe do seu plano estão cheias, ou você atingiu o limite de 20 convites por dia. A mensagem `error` indica qual. |

---

## Cancelar um convite

`DELETE /team/invites/{inviteId}`

Retira um convite antes que ele seja aceito. O link no e-mail para de funcionar.

**cURL**

```bash
curl -X DELETE "https://api.youraiconnector.com/v1/team/invites/inv_abc123" \
  -H "Authorization: Bearer FIREBASE_ID_TOKEN"
```

**Resposta**

```json
{
  "success": true,
  "message": "Team invite cancelled."
}
```

Tanto convites `pending` quanto `expired` podem ser cancelados. Um convite que já foi aceito, recusado ou cancelado retorna `400`; um que não é seu retorna `403`; um ID desconhecido retorna `404`.

---

## Reenviar um convite

`POST /team/invites/{inviteId}/resend`

Envia o e-mail de convite novamente — para quando ele foi perdido ou foi para o spam. Funciona em convites `pending` e `expired`, e redefine a expiração para 7 dias a partir de agora.

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/team/invites/inv_abc123/resend" \
  -H "Authorization: Bearer FIREBASE_ID_TOKEN"
```

**Resposta**

```json
{
  "success": true,
  "message": "Team invite resent successfully."
}
```

O novo e-mail traz um novo link, e **o link antigo continua funcionando também**, para que uma pessoa que encontre o primeiro e-mail mais tarde não fique impedida. O reenvio conta para o mesmo limite de 20 por dia que o envio, e reativar um convite *expirado* verifica novamente suas vagas — um plano completo é recusado com `429`.

---

## Aceitar um convite

`POST /team/invites/accept`

Aceita um convite com o token do e-mail de convite, adicionando a pessoa conectada à equipe daquela conta.

> **Este é um ato da sua própria identidade.** Entre como você mesmo — isso é deliberadamente recusado com `403` enquanto você estiver trabalhando dentro da conta de outra pessoa.

**Campos da requisição**

| Campo | Obrigatório | Descrição |
|---|---|---|
| `invite_token` | Sim | O token do link do e-mail de convite. |

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/team/invites/accept" \
  -H "Authorization: Bearer FIREBASE_ID_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "invite_token": "1f4c…" }'
```

**Resposta**

```json
{
  "success": true,
  "team_member_id": "owner_uid_123_uid_sam",
  "account_owner_uid": "owner_uid_123",
  "message": "Team invite accepted successfully."
}
```

| Status | Quando |
|---|---|
| `400` | `invite_token` está faltando, ou o convite é para sua própria conta. |
| `403` | A sessão está funcionando dentro de outra conta, ou o convite foi enviado para um endereço de e-mail diferente daquele com o qual você está conectado. |
| `404` | O convite não existe ou já foi usado. |
| `429` | As vagas da conta foram preenchidas entre o convite e sua aceitação. |
| `504` | O convite expirou. Peça ao remetente para reenviá-lo. |

---

## Recusar um convite

`POST /team/invites/decline`

Recusa um convite com o token do e-mail. Assim como aceitar, este é um ato da sua própria identidade e é recusado enquanto você estiver trabalhando dentro de outra conta.

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/team/invites/decline" \
  -H "Authorization: Bearer FIREBASE_ID_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "invite_token": "1f4c…" }'
```

**Resposta**

```json
{
  "success": true,
  "message": "Team invite declined."
}
```

---

## Departamentos

Um **departamento** é um grupo nomeado da sua equipe — Vendas, Suporte ao cliente, RH. Ele atribui uma equipe responsável a um lead, pode assumir novas conversas por conta própria e pode ser usado para limitar o que um membro vê.

> **Estes quatro endpoints exigem uma chave de API.** Diferente do restante desta página, eles autenticam como qualquer outro endpoint na API (consulte [Autenticação](authentication.md)). Uma sessão iniciada também funciona: a leitura requer `contacts` em `view`, e criar, alterar ou excluir requer `team_management` em `edit`.

**O objeto departamento**

| Campo | Tipo | Descrição |
|---|---|---|
| `id` | string | O ID do departamento. Use-o em `contact_scope_axes.departments` e nos caminhos abaixo. |
| `name` | string | Como a equipe é chamada. Até 60 caracteres, exclusivo na conta. |
| `color` | string \| null | Cor de destaque como `#rrggbb`, ou `null`. |
| `member_uids` | string[] | Os membros da equipe neste departamento. Pode incluir o proprietário da conta. |
| `auto_assign_enabled` | boolean | Se um lead registrado neste departamento também é encaminhado para alguém nele. `false` significa que o departamento trabalha a partir de uma fila compartilhada. |
| `routing_agents` | string[] | Novas conversas tratadas por esses Agentes de IA são registradas neste departamento automaticamente. Vazio significa sem regra de agente. |
| `routing_channels` | string[] | Novas conversas nestes canais são registradas aqui automaticamente. Vazio significa sem regra de canal. |
| `created_by` | string \| null | Quem o criou. |

Quando `routing_agents` e `routing_channels` estão definidos, uma conversa precisa corresponder a **ambos** para ser registrada aqui — é assim que você dá a uma equipe "o agente de suporte, mas apenas no WhatsApp".

Uma conta pode ter até **50** departamentos.

### Listar departamentos

`GET /team/departments`

```bash
curl "https://api.youraiconnector.com/v1/team/departments?apiKey=YOUR_API_KEY"
```

**Resposta**

```json
{
  "success": true,
  "departments": [
    {
      "id": "dep_abc123",
      "name": "Sales",
      "color": "#2f6fed",
      "member_uids": ["uid_alice", "uid_bob"],
      "auto_assign_enabled": true,
      "routing_agents": [],
      "routing_channels": ["whatsapp"],
      "created_by": "owner_uid_123"
    }
  ]
}
```

### Criar um departamento

`POST /team/departments`

**Campos da requisição**

| Campo | Obrigatório | Descrição |
|---|---|---|
| `name` | Sim | Até 60 caracteres. Não deve corresponder a um departamento existente. |
| `color` | Não | `#rrggbb` hex, ou `null`. |
| `member_uids` | Não | Quem faz parte dele. Cada UID deve ser o proprietário da conta ou um membro da equipe **ativo**. |
| `auto_assign_enabled` | Não | O padrão é `true`. |
| `routing_agents` | Não | IDs de agentes cujos novos chats caem aqui. |
| `routing_channels` | Não | Nomes de canais cujos novos chats caem aqui — mesmo vocabulário de `contact_scope_axes.channels`. |

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/team/departments?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Sales",
    "color": "#2f6fed",
    "member_uids": ["uid_alice", "uid_bob"],
    "routing_channels": ["whatsapp"]
  }'
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/team/departments", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    name: "Sales",
    color: "#2f6fed",
    member_uids: ["uid_alice", "uid_bob"],
    routing_channels: ["whatsapp"],
  }),
});
const { department } = await res.json();
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/team/departments",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "name": "Sales",
        "color": "#2f6fed",
        "member_uids": ["uid_alice", "uid_bob"],
        "routing_channels": ["whatsapp"],
    },
)
department = res.json()["department"]
```

**Resposta** — `201 Created`

```json
{
  "success": true,
  "department": {
    "id": "dep_abc123",
    "name": "Sales",
    "color": "#2f6fed",
    "member_uids": ["uid_alice", "uid_bob"],
    "auto_assign_enabled": true,
    "routing_agents": [],
    "routing_channels": ["whatsapp"],
    "created_by": "owner_uid_123"
  }
}
```

| Status | Quando |
|---|---|
| `400` | `name` está faltando ou é muito longo, `color` não é `#rrggbb`, um nome de canal não é reconhecido, um UID listado não é um membro ativo desta equipe, ou você já tem 50 departamentos. |
| `409` | Um departamento com esse nome já existe. |

### Atualizar um departamento

`PATCH /team/departments/{departmentId}`

Altera um departamento. Apenas os campos que você enviar serão alterados.

```bash
curl -X PATCH "https://api.youraiconnector.com/v1/team/departments/dep_abc123?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "member_uids": ["uid_alice"], "auto_assign_enabled": false }'
```

**Resposta**

```json
{
  "success": true,
  "department": {
    "id": "dep_abc123",
    "name": "Sales",
    "color": "#2f6fed",
    "member_uids": ["uid_alice"],
    "auto_assign_enabled": false,
    "routing_agents": [],
    "routing_channels": ["whatsapp"],
    "created_by": "owner_uid_123"
  }
}
```

O envio de campos não reconhecidos retorna `400`; um departamento desconhecido retorna `404`; um nome que entra em conflito com outro departamento retorna `409`.

### Excluir um departamento

`DELETE /team/departments/{departmentId}`

```bash
curl -X DELETE "https://api.youraiconnector.com/v1/team/departments/dep_abc123?apiKey=YOUR_API_KEY"
```

**Resposta**

```json
{
  "success": true,
  "deleted": "dep_abc123"
}
```

> **A exclusão de um departamento ao qual alguém está limitado é recusada.** A resposta `400` nomeia os membros cuja visibilidade está restrita a ele, para que você possa redefinir o escopo deles primeiro. Isso é intencional: removê-los do limite silenciosamente entregaria a eles toda a sua base de clientes sem que houvesse qualquer indicação de que isso aconteceu.

Os contatos arquivados em um departamento excluído não são reescritos — eles simplesmente param de exibir um departamento, e na próxima vez que você os arquivar, a alteração será aplicada.

---

## Verifique suas próprias permissões

`GET /team/permissions`

Retorna o que a pessoa conectada tem permissão para fazer na conta em que está trabalhando no momento. Use isso para ocultar botões que um membro não pode usar, em vez de permitir que ele descubra o limite por meio de um erro.

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/team/permissions" \
  -H "Authorization: Bearer FIREBASE_ID_TOKEN"
```

**Resposta — o proprietário da conta**

```json
{
  "success": true,
  "role": "owner",
  "is_team_mode": false,
  "permissions": {
    "campaigns": "full",
    "contacts": "full",
    "messages": "full",
    "appointments": "full",
    "settings": "full",
    "billing": "full",
    "team_management": "full",
    "analytics": "full",
    "phone_numbers": "full",
    "integrations": "full",
    "faqs": "full",
    "daily_summaries": "full"
  }
}
```

**Resposta — um membro da equipe trabalhando dentro de uma conta**

```json
{
  "success": true,
  "role": "editor",
  "is_team_mode": true,
  "permissions": { "campaigns": "edit", "billing": "none", "…": "…" },
  "member": {
    "uid": "uid_sam",
    "email": "sam@example.com",
    "display_name": "Sam Rivera",
    "account_owner_uid": "owner_uid_123"
  }
}
```

`role` é `owner` quando a pessoa conectada é o proprietário da conta; caso contrário, é a sua função na equipe. `member` só está presente no modo de equipe e carrega `contact_scope`, `contact_scope_unassigned` e `contact_scope_axes` quando a sua associação os possui.

---

## Tokens de sessão

Cinco endpoints criam um token de login de uso único para alternar entre contas. Todos eles respondem da mesma maneira:

```json
{
  "success": true,
  "customToken": "eyJhbGciOi…"
}
```

O token é trocado por uma sessão com o SDK do cliente Firebase. **Ele não é uma chave de API e não pode ser enviado como tal**, e é por isso que esses endpoints só são úteis dentro de um aplicativo próprio.

| Endpoint | O que faz | Corpo |
|---|---|---|
| `POST /team/tokens/team-member` | Permite que um membro da equipe comece a trabalhar dentro de uma conta à qual pertence. | `account_owner_uid` (obrigatório) |
| `POST /team/tokens/return-from-team` | Leva-o de volta para a sua própria conta. | — |
| `POST /team/tokens/assist` | Permite que a equipe <span data-t="appName">Your AI Connector</span> abra a conta de um cliente para ajudar. Apenas para a equipe. | `customerUid` |
| `POST /team/tokens/return-to-admin` | Encerra uma sessão de assistência e retorna a equipe para a sua própria conta. | — |
| `POST /team/tokens/agency-assist` | Permite que uma agência abra uma de suas subcontas de cliente — ou, se chamada sem uma, retorne para a conta da agência. | `subAccountUid` (opcional) |

Cada um recusa com `403` quando a sessão não tem direito a isso: não é um membro daquela conta, não é da equipe, aquela subconta não está na sua agência ou não foi concedida a você, ou a sessão não está atualmente no modo que o endpoint termina.

---

## Atribuir uma função de plataforma

`POST /team/users/{targetUid}/role`

Define a função de **plataforma** de um usuário — `User`, `Dev`, `Support` ou `Agency`. Isso não é associação de equipe: é que tipo de conta <span data-t="appName">Your AI Connector</span> alguém possui.

Este endpoint é restrito a funcionários <span data-t="appName">Your AI Connector</span>, e o último `Dev` restante não pode ser rebaixado. Listado por completude; não faz parte do gerenciamento da sua própria equipe.

```json
{
  "success": true,
  "targetUid": "uid_sam",
  "role": "Agency",
  "claimUpdated": true
}
```

| Status | Quando |
|---|---|
| `400` | `role` está faltando ou não é um dos quatro, ou isso removeria o último `Dev`. |
| `403` | Você não é funcionário, ou a sessão está funcionando dentro de outra conta. |
| `404` | Usuário inexistente. |

---

## Erros da API de Equipe

Os endpoints de equipe retornam o envelope de erro padrão, sempre com `error_code` junto com o status HTTP:

```json
{
  "success": false,
  "error_code": 403,
  "error": "Cannot grant \"full\" access to \"billing\" — exceeds your own permissions."
}
```

| Status | Quando acontece em um endpoint de equipe |
|---|---|
| `400` | Um campo obrigatório está faltando ou inválido, ou a ação não é permitida neste estado (reativar um membro removido, suspender o proprietário, excluir um departamento ao qual alguém está limitado). |
| `401` | Você enviou uma chave de API para um endpoint que precisa de uma pessoa conectada — veja [Autenticação](#authentication-these-endpoints-need-a-signed-in-person). |
| `403` | Você não tem permissão `team_management`, a alteração excede seu próprio acesso, ou a ação é recusada enquanto trabalha dentro de outra conta. |
| `404` | Membro, convite, departamento ou usuário inexistente. |
| `409` | Já é um membro da equipe, um convite pendente já existe, ou um departamento com esse nome já existe. |
| `429` | As vagas da equipe estão cheias, o limite de 20 convites por dia foi atingido, ou você atingiu o limite de taxa da API. |
| `504` | O convite que você tentou aceitar expirou. |

Os códigos compartilhados que todo endpoint pode retornar — `429` (limite de taxa) e `500` — estão listados com orientações de nova tentativa em [Erros e Paginação](errors-and-pagination.md).

---

## Relacionado

- [Gerenciamento de Equipe](../settings/team-management.md) — os mesmos recursos no painel, com capturas de tela.
- [Autenticação](authentication.md) — como enviar um token de ID do Firebase em vez de uma chave de API.
- [API de Contatos](contacts.md) — os contatos aos quais os limites de visibilidade de um membro se aplicam.

