uk_sk_live_… /
uk_sk_test_…), e há duas consequências disso que vale conhecer antes de colar
uma chave em algum lugar.
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.Conectar um cliente
No projeto onde o assistente vai trabalhar: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.
O que ele faz
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.
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.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.
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.
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:
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.
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.
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.
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.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.
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.
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.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.
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 fala com o endpoint direto, então ele responde “é meu ou é deles” antes de você ir procurar no log de um editor: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 responde401 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.