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

# Servidor MCP

> Conecte um assistente de IA aos seus dados do UserKit com uma URL e uma chave de API. Lê tudo, escreve em nove lugares, e é restrito ao ambiente da chave.

O UserKit fala [Model Context Protocol](https://modelcontextprotocol.io), então
um assistente compatível com MCP — Claude Desktop, Claude Code, Cursor e
qualquer outro que leia uma configuração MCP — consegue responder perguntas
sobre seus contatos, clientes, assinaturas e preços sem que você saia da
ferramenta em que já estava.

Não há nada para instalar. O servidor é um endpoint da API:

```
https://api.userkit.dev/mcp
```

Ele é autenticado com uma chave de API comum (`uk_sk_live_…` /
`uk_sk_test_…`), e há duas consequências disso que vale conhecer antes de colar
uma chave em algum lugar.

<Note>
  **A chave decide o ambiente, e nada mais decide.** Nenhuma ferramenta aceita um
  argumento de ambiente. Uma chave `uk_sk_test_…` só consegue mostrar dados de
  teste — por isso conectar a chave de teste é a forma segura de experimentar, e
  isso não é uma configuração que alguém consiga convencer o modelo a mudar.
</Note>

<Warning>
  **Uma chave de API é uma credencial de acesso total para todo o resto.** A
  superfície MCP lê tudo e escreve só nos nove lugares listados abaixo, mas a mesma string
  funciona em qualquer endpoint de escrita em `/v1`. Trate o arquivo de configuração como qualquer
  outro lugar onde vive um segredo, e use uma chave criada para isso em vez da que
  seu backend usa — chaves são gratuitas, e uma chave por finalidade é uma chave
  que você revoga sozinha.
</Warning>

## Conectar um cliente

No projeto onde o assistente vai trabalhar:

```bash theme={null}
npx userkit-install
```

Isso escreve a configuração por você — e um `AGENTS.md` com as poucas regras do
UserKit que compilam quando quebradas, escolhidas conforme o que o projeto é. Ele
não escreve chave nenhuma: a configuração nomeia a variável `USERKIT_API_KEY` e lê
do ambiente, então o arquivo pode ser commitado. Rodar de novo não muda nada, e ele
é dono de um bloco delimitado em vez do arquivo — as suas próprias diretrizes e
os seus outros servidores MCP ficam intactos.

Escolha os clientes com `--mcp`: `claude` escreve `.mcp.json`, `cursor` escreve
`.cursor/mcp.json` e `vscode` escreve `.vscode/mcp.json`.

Para fazer à mão, todo cliente guarda os mesmos três fatos: um nome, a URL e o
header. Dois detalhes mudam de um para o outro, e os dois falham em silêncio: o
VS Code guarda os servidores sob `servers` onde os outros usam `mcpServers`, e só
expande a sintaxe dele, `${env:NOME}` — um `${NOME}` puro é escrito literalmente,
e o header carregaria os caracteres em vez da chave.

<CodeGroup>
  ```json Claude Desktop theme={null}
  {
    "mcpServers": {
      "userkit": {
        "type": "http",
        "url": "https://api.userkit.dev/mcp",
        "headers": {
          "Authorization": "Bearer uk_sk_test_…"
        }
      }
    }
  }
  ```

  ```bash Claude Code theme={null}
  claude mcp add --transport http userkit https://api.userkit.dev/mcp \
    --header "Authorization: Bearer uk_sk_test_…"
  ```

  ```json Cursor theme={null}
  {
    "mcpServers": {
      "userkit": {
        "url": "https://api.userkit.dev/mcp",
        "headers": {
          "Authorization": "Bearer uk_sk_test_…"
        }
      }
    }
  }
  ```

  ```json VS Code theme={null}
  {
    "servers": {
      "userkit": {
        "type": "http",
        "url": "https://api.userkit.dev/mcp",
        "headers": {
          "Authorization": "Bearer ${env:USERKIT_API_KEY}"
        }
      }
    }
  }
  ```
</CodeGroup>

Reinicie o cliente e ele vai listar noventa ferramentas. Pergunte alguma coisa —
*"quantos contatos entraram no ambiente de teste?"* — e ele escolhe uma.

## O que ele faz

| Ferramenta                    | Responde                                                                                                 |
| ----------------------------- | -------------------------------------------------------------------------------------------------------- |
| `run_doctor`                  | O que está ligado neste ambiente e o que não está                                                        |
| `search_docs`                 | Esta documentação, como texto e não como link                                                            |
| `list_contacts`               | Os contatos deste ambiente, mais recentes primeiro                                                       |
| `get_contact`                 | Um contato, com suas arestas de identidade e a última nota de pesquisa — sem plano: assinatura é do time |
| `list_segments`               | As audiências deste ambiente, com suas regras e a contagem de membros                                    |
| `active_contacts_usage`       | Contatos que tiveram sessão neste mês, contra o teto do plano                                            |
| `list_customers`              | Os clientes — os times a que os contatos pertencem                                                       |
| `list_subscriptions`          | O que seus clientes pagam a você, espelhado do gateway                                                   |
| `get_subscription`            | Uma assinatura com suas linhas                                                                           |
| `list_invoices`               | O histórico de cobrança, opcionalmente de um cliente                                                     |
| `get_catalogue`               | Os planos, preços e a matriz de recursos que você vende                                                  |
| `list_help_collections`       | As seções em que sua central de ajuda está organizada                                                    |
| `list_help_articles`          | Todos os artigos, rascunhos inclusive                                                                    |
| `get_help_article`            | Um artigo com seu histórico de versões e o texto mais novo                                               |
| `get_help_article_version`    | O texto de uma versão específica                                                                         |
| `list_changelog_posts`        | Todas as notas de versão deste ambiente, rascunhos inclusive                                             |
| `get_changelog_post`          | Um post com o texto inteiro e quantas pessoas abriram                                                    |
| `list_checklists`             | Todo checklist de onboarding deste ambiente, rascunhos incluídos, com os passos                          |
| `get_checklist`               | Um checklist, com os passos em ordem e o que cada um espera                                              |
| `list_funnels`                | Os funis que a sua organização salvou, com os passos e a janela                                          |
| `get_funnel`                  | Um funil, com a lista ordenada de passos                                                                 |
| `list_point_rules`            | As regras de pontos deste ambiente, desligadas inclusive, com quanto cada uma já pagou                   |
| `get_point_rule`              | Uma regra: o que ela espera, quanto paga, o teto e o público                                             |
| `list_point_levels`           | A escada do ambiente, com quantas pessoas estão em cada degrau                                           |
| `list_gamification_metrics`   | As unidades próprias que este ambiente conta ao lado dos pontos                                          |
| `list_achievements`           | As conquistas, secretas inclusive, com quantas pessoas têm cada uma                                      |
| `get_achievement`             | Uma conquista, com a condição e quantas pessoas a têm                                                    |
| `list_legal_documents`        | Os termos que os seus clientes aceitam, com a versão em vigor                                            |
| `get_legal_document`          | Um documento com as versões dele e o estado de cada uma                                                  |
| `get_legal_version`           | O texto de uma versão específica                                                                         |
| `list_message_templates`      | As palavras que o seu produto envia, por canal                                                           |
| `get_message_template`        | Um template com a versão no ar e o histórico                                                             |
| `list_customer_roles`         | Os papéis que as pessoas têm dentro dos seus clientes, com o que cada um concede                         |
| `list_customer_role_versions` | O que um papel concedia antes da última edição                                                           |

`tools/list` é o contrato, e quem responde é o servidor em execução — se alguma
ferramenta aceitar um argumento que esta página não menciona, o cliente já sabe
dele. Cada ferramenta também declara o formato da resposta, então o cliente pode
entregar o resultado a um código em vez de reinterpretá-lo.

## As nove coisas que ele muda

Um assistente escreve em exatamente nove lugares: a sua **central de ajuda**, o
**catálogo** que você vende, os seus **termos**, o seu **changelog**, os seus
**funis**, o seu **onboarding**, os seus **pontos**, os seus **templates de
mensagem** e os **papéis** dentro dos seus clientes. Todo o resto responde
perguntas.

### A central de ajuda

Nove ferramentas: `create_help_collection`, `update_help_collection`,
`delete_help_collection`, `create_help_article`, `save_help_article_version`,
`update_help_article`, `publish_help_article`, `unpublish_help_article` e
`delete_help_article`.

<Note>
  **Escrever um artigo e publicá-lo são chamadas separadas.** Um artigo novo ou
  editado é um **rascunho** — ninguém fora da sua organização consegue ler até que
  `publish_help_article` nomeie uma versão para entrar no ar. Então um assistente
  que escreveu algo errado ainda não disse nada errado aos seus clientes, e a
  revisão é uma etapa de verdade em vez de um combinado.
</Note>

Três coisas decorrem de como a central de ajuda é construída, e o assistente vai
falar das três porque as próprias ferramentas dizem isso nas respostas.

**Todo save é uma versão nova, e nada é sobrescrito.** O histórico é o registro
inteiro do que um artigo já disse, "restaurar" é salvar um corpo antigo de novo,
e mesmo apagar um artigo é um ato diferente de tirá-lo do ar — o
`unpublish_help_article` guarda cada palavra e o `publish_help_article` devolve
todas elas.

**A central de ajuda é da organização, não de um ambiente.** Existe uma só,
compartilhada por live e test — então, diferente de todas as outras ferramentas
daqui, estas respondem `scope: "organization"` e não carregam `environment`. Não
há uma segunda cópia para ir consertar.

**Publicar e despublicar entram na sua trilha de auditoria**, no nome da chave de
API que fez, e não no de uma pessoa. Em `Configurações → Auditoria` a entrada
aparece como `chave de API · <nome da chave>`, e é por isso que vale criar uma
chave para o assistente em vez de emprestar a que seu backend usa: a trilha só
consegue ser tão específica quanto a credencial é.

### O catálogo

Mais nove ferramentas, para os planos, preços e recursos que **você vende** — não
o plano em que você está com a UserKit: `create_catalogue_plan`,
`update_catalogue_plan`, `create_catalogue_price`, `reprice_catalogue_price`,
`archive_catalogue_price`, `create_catalogue_feature`,
`update_catalogue_feature`, `set_catalogue_plan_feature` e
`remove_catalogue_plan_feature`.

<Warning>
  **Isto é a sua página de preços.** Diferente da central de ajuda, estas
  ferramentas mudam o que clientes reais veem cotado — no ambiente a que a sua
  chave pertence, então uma chave de teste só consegue tocar o catálogo de teste.
  Peça ao assistente que leia o `get_catalogue` e diga o que vai fazer antes de
  deixá-lo escrever.
</Warning>

**Um preço nunca é editado, e é isso que torna seguro entregar isso a um
assistente.** Uma assinatura aponta para a linha do preço, e essa linha é o
registro do que alguém concordou em pagar — o banco recusa qualquer alteração
nela. Mudar quanto um plano custa é o `reprice_catalogue_price`, que arquiva a
oferta antiga e cria a nova em um passo só — e **quem já assina não é movido para
o valor novo**. Essas pessoas continuam no preço que aceitaram; mover alguém é
uma troca de plano que ela consente no seu gateway de pagamento.

**Nada é apagado.** Um plano ou um recurso é arquivado, o que tira do que está à
venda e se desfaz com a mesma chamada e `archived: false`. Um preço é arquivado,
e recolocar a oferta é criar uma nova. A única exceção é tirar um recurso de um
plano, que remove aquela célula da matriz — recolocar significa declarar os
termos de novo.

**Duas coisas são permanentes e pedir é recusado em vez de ignorado**: a `key` de
um plano e a de um recurso (a string que o seu próprio código compara) e como um
recurso é medido. Um recurso medido de outro jeito é outro recurso.

**O que ele não alcança é o seu gateway de pagamento.** Nenhuma ferramenta
guarda, lê ou usa a credencial que cobra um cartão — conectar um provedor é só do
owner e vive no painel — e nada aqui cria cobrança, faz reembolso ou mexe na
assinatura de alguém.

Toda escrita no catálogo entra na sua trilha de auditoria no nome da chave,
exatamente como as da central de ajuda.

### Os termos

Cinco ferramentas: `create_legal_document`, `update_legal_document`,
`save_legal_version`, `publish_legal_version` e `delete_legal_document`, mais
`list_legal_documents`, `get_legal_document` e `get_legal_version`.

Escrever e publicar também são atos separados aqui, e a separação pesa mais do
que em qualquer outro ponto desta superfície: um documento novo e todo
`save_legal_version` são **rascunhos**, e nada muda para ninguém até
`publish_legal_version`.

<Warning>
  **Uma versão publicada é congelada no banco e não pode ser editada nem
  retirada.** Publicar é o ato: pode ser datado para a frente, e quem é perguntado
  de novo é decidido pela versão em vigor mais alta que declarou mudança material.
  `delete_legal_document` só funciona enquanto nada foi publicado — depois disso,
  tirar um documento de circulação é arquivá-lo.
</Warning>

Um documento marcado como `required` é reportado como bloqueante onde quer que
os aceites da pessoa sejam lidos, e nada além disso — ele nunca desconecta
ninguém e nunca bloqueia `/v1/contact/token`; o que fazer com isso é decisão do
seu produto. Publicar termos precisa significar "todo mundo é
perguntado", nunca "todo mundo fica trancado do lado de fora".

### O changelog

Quatro ferramentas: `create_changelog_post`, `update_changelog_post`,
`publish_changelog_post` e `delete_changelog_post`, mais as duas leituras da
tabela acima.

**Escrever um post e anunciá-lo são chamadas separadas**, como na central de
ajuda — um post novo é um rascunho que ninguém fora da sua organização vê. O que
é diferente aqui, e é a aresta mais afiada desta superfície inteira:

<Warning>
  **Não existe despublicar.** O `publish_changelog_post` coloca o post na sua
  página pública de changelog — um documento que uma CDN pode guardar —, faz o
  badge de não lidos do widget contar, e entrega `changelog_post.published` para os
  seus webhooks. O único caminho de volta é o `delete_changelog_post`, que não
  desfaz nada disso e ainda leva junto o estado de leitura de todo mundo. Um
  assistente deve publicar porque você pediu que aquele release fosse anunciado,
  nunca para organizar uma lista de rascunhos.
</Warning>

**Um post direcionado não vai para a página pública.** O `segment_id` (ou o
`feedback_post_id`, para quem votou num pedido) estreita a audiência, e um post
estreitado só é alcançável por quem está logado no seu produto — o documento
público não tem leitor para resolver, e responder um por identidade informada
pelo chamador o transformaria num oráculo de quem está em qual segmento. Então um
assistente que mira um post num segmento e depois olha a página pública vai, com
razão, não ver nada lá.

O `list_segments` é de onde esses ids saem, e ele leva a regra de cada segmento
junto com o nome — então o assistente escolhe a audiência pelo que ela significa,
e não pelo nome que ela tem.

Todo o resto desta superfície continua sem mudar nada — veja abaixo.

### Os funis

Três ferramentas: `create_funnel`, `update_funnel` e `delete_funnel`, mais as
duas leituras da tabela acima.

Um funil é uma **pergunta salva** — um nome, uma lista ordenada de nomes de
evento e uma janela em dias — e não uma medição. Ele não guarda número nenhum: a
queda entre um passo e o seguinte é recalculada a partir dos eventos crus toda
vez que alguém abre o gráfico. É por isso que esta é a mais branda das quatro
exceções: um `delete_funnel` errado destrói a pergunta, que você digita de novo,
e nada do que alguém mediu.

Duas coisas valem saber antes de pedir uma edição.

<Note>
  **O funil é da organização, não do ambiente.** Existe um só, live e test
  compartilham a definição, e só os números são por ambiente. Uma chave de teste
  editando um funil está editando o mesmo funil que o live lê — o que é o oposto
  do changelog, onde um post pertence a um ambiente e a chave do outro não o
  alcança.
</Note>

**Mexer nos passos reescreve o passado.** Como não há histórico guardado para
discordar da definição nova, mudar a ordem ou trocar um evento re-responde
também os meses anteriores: um gráfico que alguém printou semana passada não vai
mais reproduzir. O `update_funnel` troca a lista de passos **inteira** em vez de
remendá-la, então leia o funil antes com o `get_funnel`.

Os números em si não estão aqui: eles pedem um intervalo e um ambiente, e são o
gráfico do painel. Nenhuma ferramenta desta superfície calcula um.

### O onboarding

Seis ferramentas: `create_checklist`, `update_checklist`, `delete_checklist`,
`add_checklist_step`, `update_checklist_step` e `delete_checklist_step`, mais as
duas leituras da tabela acima.

Esta é a exceção cuja falha é a mais silenciosa, e as ferramentas são de
propósito mais estreitas que o painel por isso. Um post de changelog escrito
errado está errado numa página que alguém lê; um **passo** escrito errado não
produz nada — um tipo de evento que ninguém publica é um passo que nunca fica
verde, e você descobre semanas depois numa taxa de conclusão que não explica.

<Note>
  **Nada aqui liga um checklist.** O `create_checklist` cria um desligado, e
  nenhuma ferramenta aceita `active`. Ligar é o momento em que a medição começa
  para o público inteiro de uma vez, e isso continua sendo coisa que uma pessoa faz
  no painel, depois de olhar os passos.
</Note>

Um passo `event` nomeia um fato **nosso** e um nome errado é recusado. Um passo
`product_event` nomeia um **seu** — o que o seu produto manda pelo `track()` — e
esse vocabulário é aberto, então nada pode recusar um nome por não existir. O
`list_checklists` traz `sightings` para esses: um zero quer dizer que este
ambiente nunca recebeu aquele evento, o que quase sempre é erro de digitação.

**Passos são adicionados e removidos, nunca reapontados.** O que satisfaz um
passo — o tipo, o evento, a feature — não é editável aqui nem no painel: as
pessoas já têm progresso gravado contra ele, e mudar o que ele significa deixaria
linhas dizendo que alguém fez algo que nunca foi pedido. Um passo esperando o
fato errado se apaga e se cria de novo, o que perde exatamente o progresso que
deve perder.

**E nada satisfaz um passo, tampouco.** Nenhuma ferramenta desta superfície marca
o onboarding de alguém como feito, porque nenhuma existe em lugar nenhum: um
passo é satisfeito por um fato que chega no bus ou por um direito do plano.

O `update_checklist` também carrega o formato do guia — `unlocks_after` põe um
checklist atrás de outro, e `selectable` faz dele uma escolha que a pessoa faz
por si. Dois checklists esperando um pelo outro são recusados: nenhum dos dois
abriria nunca.

O `snooze_days` é quanto tempo um fechar dura: sete por padrão, `0` para o
checklist que é mesmo uma oferta única. Quem dispensa um guia de setup em geral
quer dizer "agora não", então o cartão volta — e mudar o número nunca mexe num
adiamento em curso.

Tanto o checklist quanto o passo aceitam `hint_pending` e `hint_done`: o que a
linha diz no hover antes e depois, porque a mesma linha quer dizer coisas
diferentes nos dois estados. O checklist aceita um terceiro, o `hint_locked` — um
cadeado diz ao leitor qual porta, não por que ela existe. Um passo não tem estado
travado, então não tem o terceiro.

O passo também aceita `action_url`, um caminho do app do inquilino ou uma URL
`http(s)` absoluta, que faz a linha inteira virar link. Pôr um em quase todo
passo é a melhoria mais barata que um guia tem: uma checklist que nomeia o
trabalho e esconde a porta faz o leitor navegar duas vezes.

### Os pontos

Doze ferramentas: `create_point_rule`, `update_point_rule`, `delete_point_rule`,
`create_point_level`, `update_point_level`, `delete_point_level`,
`create_achievement`, `update_achievement`, `delete_achievement`,
`create_gamification_metric`, `update_gamification_metric` e
`delete_gamification_metric`, mais as seis leituras da tabela acima.

Uma **métrica** é uma unidade sua ao lado do saldo de pontos — cursos
concluídos, e-mails enviados —, creditada pelas mesmas regras através do mesmo
extrato. Criar uma não muda nada sozinha: uma métrica que nenhuma regra credita
fica em zero para todo mundo, então a ordem que funciona é métrica, depois regra,
depois nível.

<Warning>
  **Nenhuma delas dá pontos a alguém.** Conceder é o `POST /v1/points`, um ato
  deliberado do seu back-end com uma `request_key` obrigatória. Nenhuma ferramenta
  daqui aceita `contact_id`, `external_id` ou `amount` — configurar o que o produto
  recompensa é um rascunho que alguém revisa; pagar alguém não é.
</Warning>

O `award_limit` é obrigatório e recusado na própria ferramenta, não só no banco.
É a diferença entre esta exceção e as outras oito: "recompense quem usa o app" é
uma frase que parafraseia direto numa regra apontada para o evento mais frequente
do seu produto, e uma regra sem teto escreve uma linha de extrato por
acontecimento, para sempre.

**Regra e conquista nascem desligadas** — mas, ao contrário do checklist, o
`update_point_rule` e o `update_achievement` conseguem ligar. A assimetria é a
retroatividade: ligar um checklist começa a medir um público contra passos que
parte dele já pode ter satisfeito, enquanto uma regra não paga o passado — ligar
começa a contar fatos que ainda não aconteceram, e desligar não tira nada do que
já foi ganho. Um nível não tem interruptor nenhum: ele não dispara, ele é o que um
saldo *quer dizer*.

**O que uma regra escuta e o que uma conquista exige não mudam.** `key`, `kind` e
`event_type` de um lado; `kind`, `rule_id`, `threshold` e `segment_id` do outro —
recusados com uma frase, nunca ignorados em silêncio. As linhas já escritas dizem
"você ganhou isto por X", e a medalha na estante de alguém diz "você fez isto".
Repreçar é permitido e nunca é retroativo.

Os três apagares são diferentes entre si, e cada resposta diz qual é qual.
Apagar uma **regra** guarda o extrato — cada linha carrega o nome que a regra
tinha na hora — e a resposta traz `ledger_kept`; é recusado enquanto uma
conquista contar aquela regra, e o erro diz quantas. Apagar um **nível** só perde
o registro de quem foi parabenizado por alcançá-lo. Apagar uma **conquista** é o
único que tira algo das pessoas: as liberações vão junto, e a resposta traz
`unlocks_removed` com o número — lido antes de apagar, porque depois não há mais
o que contar.

### Os templates de mensagem

Seis ferramentas: `list_message_templates`, `get_message_template`,
`create_message_template`, `update_message_template`,
`restore_message_template_version` e `archive_message_template`.

São as palavras que o seu produto manda — o texto que o cliente lê. Por isso
elas só existem aqui desde que **uma edição virou uma versão**: o que estava no
ar continua guardado, e `restore_message_template_version` traz de volta. Uma
paráfrase infeliz é um `restore` de distância, e não uma frase perdida.

Escrever um template não manda nada. Uma notificação sai quando o seu backend
chama `/v1/notifications` nomeando a `key`; uma campanha sai quando alguém a
arma. Nenhuma ferramenta daqui faz as duas coisas, e essa é a porta que fica
fechada: um assistente que escrevesse o texto e o disparasse colocaria uma
paráfrase na frente de uma audiência.

`update_message_template` substitui o corpo **inteiro**, então leia com
`get_message_template` antes — uma edição feita sem ler descarta o que ela não
sabia que existia. Os campos omitidos vêm da versão em uso, então mudar só o
assunto mantém o corpo.

Não existe apagar. Um template nomeia o que as pessoas receberam, então sair do
seletor é `archive_message_template` e a linha continua resolvendo o histórico.
E os templates da plataforma — a sequência de cobrança — são recusados: aquela
sequência não pode ser pausada, e o texto dela também não é seu para reescrever
por aqui.

### Os papéis dentro dos seus clientes

Seis ferramentas: `list_customer_roles`, `list_customer_role_versions`,
`create_customer_role`, `update_customer_role`,
`restore_customer_role_version` e `delete_customer_role`.

São os papéis que as pessoas dos times dos seus clientes têm, por ambiente.
`owner` e `member` são semeados em todo ambiente e não podem ser apagados nem
renomeados; tudo ao lado deles é vocabulário seu.

A lista de permissões de um papel guarda dois desses vocabulários. Uma permissão
que começa com `$` precisa ser uma das quatro capacidades reservadas que o
UserKit avalia — `$team.manage`, `$billing.manage`, `$keys.manage` e
`$webhooks.manage` — e qualquer outra coisa nesse namespace é recusada em vez de
armazenada. Tudo sem prefixo é seu:
guardado, carregado no JWT do contato, e nunca lido por nós.

<Note>
  **Uma edição é uma versão nova, nunca uma sobrescrita**, que é o que torna isto
  admissível aqui. O `update_customer_role` substitui o conjunto inteiro de
  permissões e move a cabeça do papel para uma versão imutável nova, então o
  conjunto que você substituiu continua em `list_customer_role_versions` e o
  `restore_customer_role_version` o traz de volta numa chamada.
</Note>

Duas edições são recusadas com uma frase. O papel `owner` não pode abrir mão de
`$team.manage` — a guarda que mantém um time administrável roda quando uma
associação muda, então tirar isso aqui deixaria todo time do ambiente sem
ninguém que consiga administrá-lo. E um papel que alguém tem no momento não pode
ser apagado.

A `key` é imutável pelo motivo da key de um plano: é a string que o seu próprio
código compara e a que o JWT carrega, então renomeá-la quebraria o seu portão sem
erro nenhum em lugar nenhum. Renomear para exibição é o `name`, que muda à
vontade.

## Prompts, que são o trabalho e não o dado

O servidor também serve **prompts**: as tarefas que as pessoas de fato trazem
para esta API, escritas uma vez. Clientes que suportam isso desenham cada uma
como algo que você escolhe — o Claude Code mostra como slash command.

| Prompt                  | O que ele manda o assistente fazer                                                            |
| ----------------------- | --------------------------------------------------------------------------------------------- |
| `integrate_userkit`     | Ligar o UserKit ao projeto do diretório atual, no arranjo que couber, e verificar o resultado |
| `diagnose_installation` | Rodar o doctor e explicar o que está quebrado, com a evidência e o conserto                   |
| `plan_go_live`          | Descobrir o que falta antes deste projeto atender clientes de verdade                         |

Eles são renderizados a cada chamada em vez de serem texto fixo, e é essa a razão
de morarem no servidor em vez de num plugin que você instala. O
`integrate_userkit` já sabe quais chaves o ambiente tem e se o segredo de
identidade já foi lido, então o assistente é orientado a ligar um boot assinado
em vez de inventar uma tela de sign-in que esta API não responde. O `plan_go_live` diz
em voz alta se a chave que você conectou consegue enxergar o ambiente sobre o
qual você está perguntando.

Nenhum deles carrega chave, pelo motivo da seção logo abaixo.

## O que ele deliberadamente não faz

**Não muda nada fora dos nove lugares acima.** Nenhuma
ferramenta cria, atualiza, apaga ou funde um contato, um cliente ou uma
assinatura, e nenhuma muda configuração. Isso não é uma etapa do trabalho: quem chama é um
modelo agindo sobre uma frase que alguém digitou, e "dá uma limpada nos contatos
duplicados" está a uma paráfrase de uma fusão que não tem volta. Os atos
continuam todos na API comum, onde uma pessoa escreveu a chamada.

As exceções são admitidas pelo que uma chamada errada consegue destruir. A
central de ajuda toca prosa e um ponteiro: toda edição é uma versão nova em vez
de uma sobrescrita, e o pior resultado alcançável é texto numa página de ajuda. O
catálogo descreve o que você vende sem conseguir reescrevê-lo: preços são
imutáveis, planos e recursos são arquivados em vez de apagados, e o que um
cliente concordou em pagar está fora de alcance por construção. O changelog é
prosa de novo, com o único ato que não tem oposto — e é por isso que publicar diz
isso na própria ferramenta e criar sempre escreve um rascunho. O funil é uma
pergunta salva sobre dados que ele não pode tocar: apagar um custa a definição,
nunca a medição. Os templates de mensagem e os papéis de cliente estão aqui pelo
mesmo motivo um do outro: uma edição escreve uma versão imutável nova e move um
ponteiro, então o que estava no ar fica a um restore de distância em vez de
perdido. Os termos são os mais estritos dos nove, e é publicar que pesa —
escrever é sempre rascunho, uma versão publicada nunca pode ser editada nem
retirada, e a ferramenta diz isso antes de agir.

Todas passam pelo mesmo teste de permissão, que é o que mantém isto
honesto: criar uma chave de API precisa de owner ou admin, e cada uma dessas
escritas já estava ao alcance de quem tem esses papéis. Uma ferramenta que desse
a quem tem chave alguma coisa que a sessão não daria não entra aqui — é
exatamente por isso que a trilha de auditoria, que é só do owner, fica de fora.

**Não manda nada para a caixa de entrada de ninguém.** Publicar uma nota de
versão não envia e-mail para os seus usuários: a página de changelog e o badge do
widget são coisas que eles vêm ler. Nenhuma ferramenta desta superfície envia
e-mail.

**Não move dinheiro.** Nenhuma cobrança, nenhum reembolso, nenhuma troca de plano
na assinatura de alguém e nenhum acesso às credenciais do seu gateway de
pagamento — conectar um provedor é só do owner e fica no painel, onde uma pessoa
colou a chave.

**Não lê a sua trilha de auditoria.** `audit:read` é só do owner — o registro do
que um administrador fez não é do administrador — e uma chave de API não carrega
papel nenhum. Servir a trilha aqui levaria registros exclusivos do owner para
fora através de uma credencial que qualquer pessoa capaz de criar chaves já tem.

**Não responde com credencial.** Nenhuma chave secreta, nenhuma chave
publicável, nenhuma sessão, nenhum token de uso único. Uma conversa com um
assistente é armazenada, resumida e renderizada onde quer que o cliente rode, o
que faz dela o último lugar onde uma credencial deveria ser impressa.

## Lendo as respostas

Três coisas costumam surpreender, e as três são deliberadas.

`search_docs` **responde seções, não páginas, e responde lista vazia quando não
acha nada.** Essa lista vazia é uma resposta de verdade — quer dizer que esta
documentação não cobre a pergunta, o que vale ouvir em vez de ser preenchido pela
memória que o assistente tem da API de auth de outro produto. Ele busca em uma
árvore de idioma por vez (`en` por padrão, `pt-br` sob pedido), e o índice que ele
lê viaja junto com o deploy, então o que ele diz vale para a API com a qual você
está falando.

`run_doctor` **tem um terceiro status, e ele não é aprovação.** Cada verificação
responde `ok`, `attention` ou `unknown`, e `unknown` quer dizer que não deu para
saber — o conjunto de chaves é servido por CDN, então uma busca respondida por um
cache nunca chegou até nós, e "nunca vimos" não é "nunca foi buscado". Uma
verificação que não se aplica a este ambiente fica de fora da lista em vez de
responder `ok`. Assistentes resumem, e o resumo a vigiar é o que transforma
quatro `ok` e dois `unknown` em "está tudo funcionando".

`active_contacts_usage` **responde zero em ambiente de teste**, com
`counted: false` ao lado. Contatos de teste nunca são medidos, então esse zero é
uma afirmação sobre cobrança e não sobre os seus usuários. Aponte o assistente
para uma chave live quando a pergunta for "quantos usuários ativos temos".

**Os valores estão em unidades menores.** Um preço traz `amount_minor` e
`currency_exponent`, então `1000` é R\$10,00 e também ¥1000. O assistente tem os
dois números; peça que ele formate, não que divida por cem.

## Conferindo a conexão sem um cliente

O [MCP Inspector](https://modelcontextprotocol.io/docs/tools/inspector) fala com
o endpoint direto, então ele responde "é meu ou é deles" antes de você ir
procurar no log de um editor:

```bash theme={null}
npx @modelcontextprotocol/inspector
```

Conecte com transporte **Streamable HTTP**, a URL `https://api.userkit.dev/mcp`
e um header `Authorization` de `Bearer uk_sk_test_…`. Se as ferramentas
aparecerem lá e não no seu editor, o problema é o arquivo de configuração do
editor; se não aparecerem em nenhum dos dois, é a chave.

## Quando não funciona

**O cliente conecta e não lista ferramenta nenhuma.** Quase sempre é o header. O
endpoint responde `401` com o envelope de erro de sempre quando a credencial
falta ou não é uma chave `uk_sk_…` — uma chave publicável ou uma sessão do painel
são recusadas aqui, e a mensagem diz qual das duas você mandou.

**Está tudo vazio.** Confira qual chave você colou. Uma resposta vazia vinda de
uma chave de teste é a fronteira de ambiente funcionando, não uma leitura
quebrada; as ferramentas dizem em toda resposta para qual ambiente responderam.

**O assistente diz que bateu no limite.** O endpoint MCP carrega o mesmo limite
por chave do resto da API — 1000 requisições por minuto por chave, com um teto de
3000 por minuto no ambiente inteiro. Um agente percorrendo uma lista grande em
laço é exatamente o chamador que encontra esse limite. Faça uma pergunta mais
estreita, ou dê ao agente uma chave própria para que uma varredura longa não
gaste a cota do seu backend.
