> ## Documentation Index
> Fetch the complete documentation index at: https://docs.userkit.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Papéis e permissões

> Um catálogo que vive no código e definições de papéis que vivem no seu banco.

Uma **permissão** é uma capacidade granular. Um **papel** é um conjunto nomeado
delas. Um **vínculo** dá a um usuário um papel em uma organização.

A separação que faz isso funcionar: o *catálogo* vive em Go, porque o conjunto de
coisas que o sistema sabe fazer é um fato do código. *Qual papel tem o quê* vive no
banco, então uma organização define os próprios papéis sem esperar deploy.

## O catálogo

<ResponseField name="organization:update" type="permissão">
  Renomear a organização, trocar o logo, encerrar o onboarding, definir o modo de
  auth de um ambiente.
</ResponseField>

<ResponseField name="organization:delete" type="permissão">
  Destruir a organização e tudo abaixo dela.
</ResponseField>

<ResponseField name="members:read" type="permissão">
  Listar membros e convites pendentes.
</ResponseField>

<ResponseField name="members:write" type="permissão">
  Convidar, revogar convites, trocar papéis, remover membros.
</ResponseField>

<ResponseField name="roles:read" type="permissão">
  Listar papéis e ler o catálogo de permissões.
</ResponseField>

<ResponseField name="roles:manage" type="permissão">
  Criar, editar e deletar papéis. **Esta concede qualquer permissão, inclusive ela
  mesma** — quem a tem pode escalar os próprios privilégios, e é por isso que o
  `admin` não a recebe por padrão.
</ResponseField>

<ResponseField name="api_keys:read" type="permissão">
  Listar chaves de API e chaves publicáveis.
</ResponseField>

<ResponseField name="api_keys:write" type="permissão">
  Criar e revogar chaves de API, definir origens permitidas, ler e rotacionar o
  segredo de identidade de um ambiente.
</ResponseField>

<ResponseField name="customers:read" type="permissão">
  Ler contatos no painel.
</ResponseField>

<ResponseField name="customers:write" type="permissão">
  Unir contatos. Separada da leitura porque um merge é destrutivo no sentido de
  "não existe desfazer".
</ResponseField>

Leia da API em vez de fixar no código — é o que o editor de papéis faz:

```bash theme={null}
curl -s $API/v1/organization/roles/permissions \
  -H "Authorization: Bearer $UK_SESSION" \
  -H "X-Organization-Id: org_4b1e…"
```

## Os papéis de sistema

Criados em toda organização no momento em que ela nasce. São marcados `is_system`.

|                       | owner | admin | member |
| --------------------- | :---: | :---: | :----: |
| `organization:update` |   ✓   |   ✓   |        |
| `organization:delete` |   ✓   |       |        |
| `members:read`        |   ✓   |   ✓   |    ✓   |
| `members:write`       |   ✓   |   ✓   |        |
| `roles:read`          |   ✓   |   ✓   |        |
| `roles:manage`        |   ✓   |       |        |
| `api_keys:read`       |   ✓   |   ✓   |    ✓   |
| `api_keys:write`      |   ✓   |   ✓   |        |
| `customers:read`      |   ✓   |   ✓   |    ✓   |
| `customers:write`     |   ✓   |   ✓   |        |

O `admin` toca a operação mas não pode deletar a organização nem gerenciar papéis.
O `member` é somente leitura.

<Note>
  Os nomes dos papéis são armazenados em inglês — `owner`, `admin`, `member` — porque
  a API compara com esses literais: a guarda do último owner e a criação inicial
  ambas batem neles. Traduza apenas para exibição.
</Note>

## Papéis customizados

Papéis customizados nunca são `is_system`, então continuam renomeáveis e
deletáveis.

<CodeGroup>
  ```bash Criar theme={null}
  curl -s $API/v1/organization/roles \
    -H "Authorization: Bearer $UK_SESSION" \
    -H "X-Organization-Id: org_4b1e…" \
    -H 'Content-Type: application/json' \
    -d '{
      "name": "Suporte",
      "permissions": ["members:read", "customers:read", "customers:write"]
    }'
  ```

  ```bash Substituir as permissões theme={null}
  curl -s -X PUT $API/v1/organization/roles/{id} \
    -H "Authorization: Bearer $UK_SESSION" \
    -H "X-Organization-Id: org_4b1e…" \
    -H 'Content-Type: application/json' \
    -d '{ "name": "Suporte", "permissions": ["customers:read"] }'
  ```
</CodeGroup>

Ambos exigem `roles:manage`.

<Warning>
  `PUT` **substitui** o conjunto de permissões, não faz merge. O editor envia o
  conjunto completo toda vez — um merge tornaria impossível remover uma permissão.
</Warning>

Uma permissão desconhecida é recusada com `400 unknown_permission` em vez de
silenciosamente descartada. Guardada como veio, ela ficaria no banco parecendo um
acesso que ninguém concede.

### Editando papéis de sistema

As **permissões** de um papel de sistema podem ser editadas — é assim que uma
organização molda o `admin` a si mesma. O **nome** não: `403 system_role`.

Uma regra é absoluta: o papel `owner` precisa manter `roles:manage`. Remover
responde `403 owner_locked`. Sem ela um owner poderia se editar para fora da gestão
de papéis e deixar a organização sem ninguém capaz de devolvê-la.

### Deletando

Um papel que ainda tem membros é recusado com `409 role_in_use` em vez de cair em
cascata — essas pessoas perderiam toda permissão em silêncio. Mova-as antes.
Papéis de sistema não podem ser deletados de jeito nenhum.

## Como a regra é aplicada

As permissões carregam junto com a sessão, sem ida extra ao banco, e toda rota
protegida as confere antes do handler rodar:

```json 403 theme={null}
{ "error": { "code": "forbidden", "message": "your role does not allow this action" } }
```

Como são resolvidas por requisição a partir do vínculo, **uma mudança de permissão
vale já na próxima requisição daquele usuário**. Ninguém precisa sair e entrar de
novo.

O painel esconde o que um papel não pode fazer. Isso é gentileza com quem está
usando — a API é o que de fato recusa.
