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

# Como criar uma API key

> Crie uma credencial para a Platform API v1, limite seus escopos, use-a com segurança e rotacione sem downtime.

## Antes de criar

A chave pertence à **tribo** em cuja administração você a criar, e a ninguém
mais: não existe chave global de conta, nem chave que enxergue duas tribos. Só
**dono ou administrador** da tribo pode criar, listar ou revogar chaves.

<Warning>
  **O token aparece uma única vez.** A Tryno guarda apenas o hash SHA-256 da
  chave e um prefixo curto para identificação — não há como recuperar o texto
  depois. Tenha o cofre de segredos ou a variável de ambiente prontos para
  receber a chave antes de criá-la.
</Warning>

## Passo a passo

<Frame caption="A aba API do admin da tribo — criação de chaves e configuração de webhooks vivem na mesma tela.">
  <img src="https://mintcdn.com/tryno/Js4__YjMMxSypN-k/images/admin-api-keys.png?fit=max&auto=format&n=Js4__YjMMxSypN-k&q=85&s=a895defe721e5885cd9189c72701fcfe" alt="Tela de administração da tribo com a aba API selecionada, mostrando uma chave criada e o formulário para gerar uma nova" width="2880" height="1800" data-path="images/admin-api-keys.png" />
</Frame>

<Steps>
  <Step title="Abra a administração da tribo">
    Vá a `https://tryno.io/<sua-tribo>/admin` e selecione a aba **API**. Confirme
    que está na tribo certa antes de continuar.
  </Step>

  <Step title="Crie uma nova chave">
    Dê um nome que identifique o consumidor, como `Backend produção`,
    `Automação n8n` ou `Zapier`. O nome é obrigatório e é truncado em
    **60 caracteres**.
  </Step>

  <Step title="Selecione as permissões">
    Marque apenas os escopos que a integração precisa ler. É obrigatório
    escolher **ao menos um** escopo válido.
  </Step>

  <Step title="Copie imediatamente">
    Salve o token no cofre antes de fechar a confirmação. Depois disso ele não
    é exibido de novo.
  </Step>

  <Step title="Valide com GET /v1/me">
    Uma chamada confirma tribo e escopos antes de você construir em cima.
  </Step>
</Steps>

O mesmo fluxo existe em HTTP. O endpoint de criação é autenticado **por
sessão** (você precisa estar logado como admin daquela tribo), não por outra
chave:

```bash theme={"system"}
curl -X POST https://tryno.io/api/communities/sua-tribo/api-keys \
  -H "Content-Type: application/json" \
  --cookie "__session=<sua sessão>" \
  -d '{
        "name": "Integração Zapier",
        "scopes": ["members:read", "posts:read"]
      }'
```

```json 201 Created theme={"system"}
{
  "ok": true,
  "id": "…",
  "name": "Integração Zapier",
  "key": "tryno_sk_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "keyPrefix": "tryno_sk_XXXXXXXX",
  "scopes": ["members:read", "posts:read"]
}
```

<ParamField body="name" type="string" required>
  Rótulo humano, truncado em 60 caracteres. Vazio ⇒ `400 invalid_name`.
</ParamField>

<ParamField body="scopes" type="string[]" required>
  Escopos da chave. Valores desconhecidos são **descartados em silêncio** e
  duplicatas são removidas; se sobrar zero escopo válido, a resposta é
  `400 no_scopes`.
</ParamField>

<Warning>
  Como escopos inválidos são descartados sem erro, um typo (`member:read` no
  lugar de `members:read`) cria uma chave com **menos** poder do que você pediu,
  sem avisar. Confira o campo `scopes` da resposta — ou chame `GET /v1/me` — em
  vez de assumir que o que você enviou foi aceito.
</Warning>

## Quais permissões escolher

Conceda o mínimo necessário — uma chave entregue a um terceiro deve ver só o que
aquele terceiro precisa.

| Objetivo                            | Comece com     |
| ----------------------------------- | -------------- |
| Consultar membros da tribo          | `members:read` |
| Consultar posts públicos publicados | `posts:read`   |
| Consultar eventos e encontros       | `events:read`  |
| Consultar pedidos e valores         | `orders:read`  |

O escopo que cada endpoint exige:

| Escopo         | Libera                                                  |
| -------------- | ------------------------------------------------------- |
| `members:read` | `GET /v1/members`, `GET /v1/members/{username}`         |
| `posts:read`   | `GET /v1/posts`                                         |
| `events:read`  | `GET /v1/events`                                        |
| `orders:read`  | `GET /v1/orders` — **dado sensível**: pedidos e valores |

`GET /v1/me` não exige escopo algum: ele apenas identifica a própria chave.

<Note>
  A lista de escopos selecionáveis também inclui **`community:read`**. Hoje
  nenhum endpoint de `/v1` exige esse escopo — os metadados da tribo já vêm em
  `GET /v1/me`. Ele existe reservado para leituras futuras; conceder ou não
  conceder não muda nada no acesso atual. Dizemos isso em vez de deixar você
  supor que ele libera alguma coisa.
</Note>

<Warning>
  `orders:read` expõe o histórico de compras da tribo (comprador, valor em
  centavos, status). Trate uma chave com esse escopo como credencial financeira:
  ambiente isolado, sem log do valor, sem compartilhamento com ferramenta de
  terceiro que você não audita.
</Warning>

<Tip>
  **Uma chave por consumidor.** Separe produção, testes e automações. Assim você
  revoga uma integração sem interromper as outras, e o `lastUsedAt` diz de fato
  quem está chamando — em vez de conceder permissões amplas "por garantia".
</Tip>

<Accordion title="Escopos não são editáveis depois da criação">
  Não existe endpoint para alterar os escopos de uma chave já criada. Para
  ampliar ou reduzir o acesso de uma integração, crie uma **nova** chave com o
  conjunto correto e revogue a antiga — é o mesmo procedimento da rotação,
  descrito abaixo.

  E um papel administrativo humano **não** amplia os escopos gravados na chave:
  o que vale é exclusivamente o conjunto persistido no momento da criação.
</Accordion>

## Como usar a chave

Envie a chave como **Bearer** no cabeçalho `Authorization`. É o único formato
aceito — não existe `X-API-Key`, nem chave em query string, nem em cookie.
O servidor resolve tribo e escopos a partir da própria credencial, então você
nunca passa o handle da tribo em `/v1`.

```http Cabeçalho HTTP theme={"system"}
Authorization: Bearer tryno_sk_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
```

<CodeGroup>
  ```bash cURL theme={"system"}
  curl https://tryno.io/api/v1/me \
    -H "Authorization: Bearer $TRYNO_API_KEY"
  ```

  ```js Node.js theme={"system"}
  const res = await fetch("https://tryno.io/api/v1/me", {
    headers: { Authorization: `Bearer ${process.env.TRYNO_API_KEY}` },
  });
  if (!res.ok) throw new Error(`Tryno ${res.status}`);
  console.log(await res.json());
  ```

  ```python Python theme={"system"}
  import os
  import requests

  res = requests.get(
      "https://tryno.io/api/v1/me",
      headers={"Authorization": f"Bearer {os.environ['TRYNO_API_KEY']}"},
      timeout=10,
  )
  res.raise_for_status()
  print(res.json())
  ```
</CodeGroup>

```json Resposta theme={"system"}
{
  "object": "api_key",
  "community": { "id": "…", "handle": "sua-tribo", "name": "Sua Tribo" },
  "scopes": ["members:read", "posts:read"]
}
```

<Tip>
  Use `GET /v1/me` como **health check** da sua integração: ele não exige escopo,
  responde `401` se a chave foi revogada e devolve exatamente os escopos ativos.
  É a forma mais barata de descobrir que uma chave morreu antes que o cliente
  descubra.
</Tip>

### Formato da chave

`tryno_sk_` seguido de **43 caracteres base64url**. Os **17 primeiros
caracteres** (`tryno_sk_` + 8) formam o `keyPrefix`: é o que a listagem mostra e
o que identifica a chave sem revelá-la.

O prefixo `tryno_sk_` é o gatilho para scanners de segredo — se você vazar uma
chave num repositório público, ela é detectável, e você deve revogá-la
imediatamente.

<Warning>
  **Chave de API é credencial de servidor.** Nunca a envie ao browser, a um app
  mobile, a logs, a analytics ou a relatórios de erro. Uma chave `tryno_sk_` que
  chega ao navegador é uma chave pública — qualquer pessoa consegue lê-la no
  DevTools. E como `/api/v1` não envia cabeçalhos CORS, chamadas diretas do
  browser em outra origem são bloqueadas de qualquer forma: **chame sempre a
  partir do seu backend**.
</Warning>

## Rotação de chaves

A Tryno **suporta múltiplas chaves ativas por tribo ao mesmo tempo**, e é isso
que torna a rotação sem downtime possível. O que **não** existe é rotação
automática, data de expiração, ou um endpoint de "regenerar chave" que troque o
segredo mantendo o mesmo id — a rotação é sempre *criar nova, migrar, revogar
antiga*.

<Steps>
  <Step title="Crie a nova chave, com os mesmos escopos">
    Nome diferente e datado ajuda: `Backend produção 2026-08`. Nesse momento você
    tem duas chaves válidas simultaneamente — é a **janela de sobreposição**.

    ```bash theme={"system"}
    curl -X POST https://tryno.io/api/communities/sua-tribo/api-keys \
      -H "Content-Type: application/json" \
      --cookie "__session=<sua sessão>" \
      -d '{ "name": "Backend produção 2026-08", "scopes": ["members:read", "orders:read"] }'
    ```
  </Step>

  <Step title="Confira os escopos da nova antes de trocar nada">
    ```bash theme={"system"}
    curl https://tryno.io/api/v1/me -H "Authorization: Bearer <nova chave>"
    ```

    Se `scopes` não bater com o da antiga, pare aqui: houve typo, e a nova chave
    tem menos acesso.
  </Step>

  <Step title="Publique a nova chave nos consumidores">
    Atualize a variável de ambiente / cofre e faça o deploy. Rode a janela de
    sobreposição por tempo suficiente para cobrir **todos** os consumidores —
    inclusive jobs que só rodam de madrugada, semanalmente ou no fechamento do
    mês. Uma janela de 7 dias cobre a maioria dos casos; para automações mensais,
    use 35.
  </Step>

  <Step title="Confirme pelo lastUsedAt que a antiga parou">
    ```bash theme={"system"}
    curl https://tryno.io/api/communities/sua-tribo/api-keys \
      --cookie "__session=<sua sessão>"
    ```

    Procure a linha do `keyPrefix` antigo. Só avance quando o `lastUsedAt` dela
    estiver claramente parado no passado **e** o `lastUsedAt` da nova estiver
    fresco. Este é o passo que impede a rotação de derrubar um consumidor
    esquecido.
  </Step>

  <Step title="Revogue a antiga">
    ```bash theme={"system"}
    curl -X DELETE https://tryno.io/api/communities/sua-tribo/api-keys/<id-antigo> \
      --cookie "__session=<sua sessão>"
    ```

    Efeito **imediato**: a partir da próxima requisição a chave antiga responde
    `401`.
  </Step>
</Steps>

<Warning>
  **A revogação não tem volta.** Ela é suave no banco (a linha fica para
  auditoria), mas não existe "desrevogar": toda autenticação passa a ignorá-la
  para sempre. Se você revogar cedo demais, o conserto é criar uma chave nova e
  redeployar os consumidores.
</Warning>

<Note>
  O `lastUsedAt` é atualizado no máximo **uma vez por minuto** por chave — a
  gravação é deliberadamente estrangulada para não amplificar escrita no caminho
  de autenticação. Consequências práticas: (1) ele é ótimo para responder "esta
  chave ainda está sendo usada?"; (2) ele **não** é um log de auditoria por
  chamada, e uma chave chamada 500 vezes num minuto registra um carimbo só.
  Numa rotação, deixe pelo menos alguns minutos entre a última verificação e a
  revogação.
</Note>

<Accordion title="Rotação de emergência (chave vazada)">
  Quando a chave está publicamente exposta, a ordem se inverte: **revogue
  primeiro**, conserte depois. Uma janela de indisponibilidade da sua integração
  é preferível a uma janela de leitura por terceiros — ainda mais com
  `orders:read`.

  1. `DELETE` na chave comprometida. Efeito imediato.
  2. Crie a substituta e faça o deploy.
  3. Verifique no log da listagem se o `lastUsedAt` da chave revogada indica uso
     em horários que você não reconhece.
  4. Remova o segredo do histórico do repositório, se foi esse o vazamento —
     revogar não apaga o commit.
</Accordion>

## Listar e revogar

```bash Listar (nunca devolve o texto da chave — só o prefixo) theme={"system"}
curl https://tryno.io/api/communities/sua-tribo/api-keys \
  --cookie "__session=<sua sessão>"
```

A listagem devolve, por chave: `id`, `name`, `keyPrefix`, `scopes`,
`lastUsedAt`, `revokedAt` (`null` se ativa), `createdAt` — mais o campo
`availableScopes` com o catálogo completo de escopos válidos. **Nunca** o texto
da chave.

```bash Revogar theme={"system"}
curl -X DELETE https://tryno.io/api/communities/sua-tribo/api-keys/<id> \
  --cookie "__session=<sua sessão>"
```

Chaves revogadas continuam aparecendo na listagem, com `revokedAt` preenchido —
é o registro de auditoria de quem existiu e quando saiu de circulação.

## Quando a autenticação falha

| Status | `error.type`   | Quando                                                              |
| ------ | -------------- | ------------------------------------------------------------------- |
| `401`  | `unauthorized` | Cabeçalho ausente, formato inválido, chave desconhecida ou revogada |
| `403`  | `forbidden`    | Chave válida, mas sem o escopo daquele endpoint                     |
| `429`  | `rate_limited` | Mais de 120 requisições em 60s para a mesma chave                   |

```json 403 theme={"system"}
{ "error": { "type": "forbidden", "message": "This key is missing the 'orders:read' scope." } }
```

O `401` é deliberadamente indistinguível entre "chave inexistente" e "chave
revogada": informar a diferença ajudaria apenas quem está sondando chaves.

<Accordion title="Checklist de depuração para um 401 inesperado">
  * O cabeçalho é literalmente `Authorization: Bearer ` + a chave? Sem `Bearer`,
    a chave é ignorada.
  * Sobrou espaço, quebra de linha ou aspas ao copiar do cofre? Um `\n` no fim
    da variável de ambiente é a causa mais comum.
  * A chave foi truncada? O token completo tem `tryno_sk_` + 43 caracteres.
  * A chave foi revogada por outro administrador? Confira `revokedAt` na
    listagem.
  * Você está chamando `/api/v1/…`? Uma chave `tryno_sk_` **não** autentica a API
    da aplicação (`/api/communities/…`), que usa cookie de sessão.
</Accordion>

O teto de requisições é **por chave**, detalhado em
[Erros e limites](/guides/errors) — inclusive com código pronto de retentativa
com backoff.

<Card title="Próximo passo — configure webhooks →" icon="webhook" href="/guides/webhooks" horizontal>
  Receba `member.joined`, `order.paid` e os demais eventos em vez de consultar
  a API em laço.
</Card>
