> ## 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.

# Organizações e membros

> A fronteira de tenancy, o código que a identifica, e quem entra.

Uma **organização** é a fronteira de tenancy. Toda linha que pertence a um cliente
pende de `organization_id`, e toda consulta filtra por ele.

Um usuário chega a uma organização por um **vínculo** (membership), que carrega
exatamente um papel. Um usuário pode ter vínculos em várias organizações; o seletor
do painel é essa lista.

## O código público

Toda organização tem um `public_code` no formato `org_<32 hex>`. É ele que aparece
na URL do painel e viaja no header `X-Organization-Id`.

```
/org_4b1e9c…/settings/members
```

É opaco e imutável de propósito: renomear uma organização nunca pode quebrar um
link. E ele **identifica** sem autorizar — colar o código de outra pessoa na URL
não resolve sessão nenhuma, porque o JOIN do vínculo não casa com nada.

<Note>
  O UUID interno nunca sai da API nas superfícies que o painel usa. Use `public_code`
  em URLs e headers.
</Note>

## Criando uma

O cadastro cria a primeira organização. Um usuário autenticado pode abrir outras,
tornando-se owner de cada uma:

<CodeGroup>
  ```bash cURL theme={null}
  curl -s $API/v1/organizations \
    -H "Authorization: Bearer $UK_SESSION" \
    -H 'Content-Type: application/json' \
    -d '{ "name": "Analytical Engine" }'
  ```

  ```json Resposta — 201 theme={null}
  {
    "organization": {
      "id": "…",
      "name": "Analytical Engine",
      "public_code": "org_4b1e…",
      "onboarded": false
    },
    "active_organization_id": "…",
    "active_organization_code": "org_4b1e…"
  }
  ```
</CodeGroup>

A sessão troca para a nova organização na hora — ninguém cria um workspace para
depois sair procurando por ele.

Três invariantes são estabelecidas nessa mesma transação, e valem por toda a vida
da organização:

* ela sempre tem os três papéis de sistema (`owner`, `admin`, `member`);
* ela sempre tem um owner;
* ela sempre tem um ambiente live e um test, cada um com sua chave publicável.

## Trocando

Trocar é navegação, não um estado que você precise gerenciar. O vínculo é
verificado toda vez, e trocar para uma organização da qual você não faz parte
responde `404` — nunca um vazamento de que ela existe.

```bash theme={null}
curl -s -X PUT $API/v1/session/organization \
  -H "Authorization: Bearer $UK_SESSION" \
  -H 'Content-Type: application/json' \
  -d '{ "organization_id": "…" }'
```

## Convidando pessoas

Um convite é criado contra um papel e enviado por e-mail como link de uso único,
válido por 7 dias. Um convite pendente por endereço, garantido por um índice único
parcial — então um duplo clique não produz dois.

<CodeGroup>
  ```bash Convidar theme={null}
  curl -s $API/v1/organization/members/invitations \
    -H "Authorization: Bearer $UK_SESSION" \
    -H "X-Organization-Id: org_4b1e…" \
    -H 'Content-Type: application/json' \
    -d '{ "email": "grace@example.com", "role_id": "…" }'
  ```

  ```bash Ler (público) theme={null}
  curl -s "$API/v1/invitations?token=uk_inv_…"
  ```

  ```bash Aceitar (público) theme={null}
  curl -s $API/v1/invitations/accept \
    -H 'Content-Type: application/json' \
    -d '{ "token": "uk_inv_…", "name": "Grace Hopper", "password": "Compiler1" }'
  ```
</CodeGroup>

Ler o convite informa à tela de aceite se o endereço já tem conta
(`existing_account`), para ela saber se pede nome e senha. Uma conta existente
entra direto — o convite foi para aquele endereço, e possuir o link já prova o
suficiente.

O convite existe mesmo quando o e-mail se perde. Revogue e convide de novo.

## Sair e remover

Duas ações diferentes, deliberadamente:

| Ação                 | Endpoint                                   | Permissão                  |
| -------------------- | ------------------------------------------ | -------------------------- |
| Remover outra pessoa | `DELETE /v1/organization/members/{userId}` | `members:write`            |
| Sair você mesmo      | `DELETE /v1/organization/members/me`       | nenhuma — todo membro pode |

Sair é um usuário administrando o próprio acesso, então não passa por
`members:write`. Remover a si mesmo pelo primeiro endpoint responde `403` com uma
mensagem apontando para o segundo.

A remoção vale já na próxima requisição da pessoa: o JOIN do vínculo da sessão
deixa de casar.

### A guarda do último owner

Uma organização precisa manter pelo menos um owner. Rebaixar, remover ou sair como
último owner responde:

```json 409 theme={null}
{ "error": { "code": "last_owner", "message": "the organization must keep at least one owner" } }
```

A guarda trava as linhas de owner antes de contar, então dois rebaixamentos
concorrentes de owners diferentes serializam em vez de ambos lerem "2 owners" e
deixarem a organização sem dono.

## Deletando

Só owner (`organization:delete`), e o nome exato precisa ser digitado de volta:

```bash theme={null}
curl -s -X DELETE $API/v1/organization \
  -H "Authorization: Bearer $UK_SESSION" \
  -H "X-Organization-Id: org_4b1e…" \
  -d '{ "name": "Analytical Engine" }'
```

Tudo cai em cascata: vínculos, papéis, chaves, convites, ambientes, contatos e as
sessões presas a ela. Um nome que não bate responde `400 confirmation_mismatch`.
