Criando uma Skill para IAs usarem a sua API
Olá meus Unicórnios! 🦄✨
Sabe aquele momento em que você pede uma coisa simples para a IA, ela responde lindamente, e você percebe que ela inventou o endereço do seu endpoint? 😅 Pois é. Ela não tinha como saber. A sua API é sua, mora na sua casa, e nunca apareceu em lugar nenhum que a IA tenha lido.
A solução não é explicar tudo de novo a cada conversa. É escrever uma vez um manual que ela abre sozinha quando o assunto aparece. Esse manual tem nome: é uma skill.
E a melhor parte: não tem código, não tem build, não tem servidor. É uma pasta com um arquivo de texto dentro. 🤯
📁 O que é uma skill, na prática
Uma skill é uma pasta com um arquivo chamado SKILL.md. Ponto. Se você criar a pasta e o arquivo, você já tem uma skill.
A estrutura mínima é esta:
entregas-api/
└── SKILL.md
E o arquivo é Markdown comum, com um cabeçalho especial no topo. Esse cabeçalho se chama frontmatter: são as linhas entre dois ---, escritas em YAML, e é ali que moram os dois únicos campos obrigatórios.
---
name: entregas-api
description: Consulta o status de entregas na API de Entregas. Use quando pedirem para rastrear entrega, ver onde está um pacote, consultar código de rastreio (formato BR seguido de 9 dígitos) ou saber se um pedido já foi entregue.
---
# API de Entregas
Documentação para consultar entregas pela API HTTP.
É só isso mesmo. A partir daqui, tudo o que vamos fazer é escrever bem esses dois campos e o texto que vem embaixo deles. 🙂
🎯 A description é tudo, e é onde quase todo mundo erra
Se você só for ler um pedaço deste artigo, leia este. 🙏
A IA não lê a sua skill inteira o tempo todo. Seria caro e lento ter dezenas de manuais abertos em toda conversa. O que ela enxerga, sempre, é apenas o name e a description. Com esses dois pedacinhos de texto ela decide: abro este manual ou não?
Ou seja: a description não é um resumo bonito. Ela é o gatilho. E gatilho que não bate com o que a pessoa digitou não dispara.
Repare na diferença cruel entre estas duas. A primeira:
description: Documentação da API de Entregas.
Essa aí nunca vai ser aberta. Ninguém digita "documentação da API de Entregas" no chat. A pessoa digita "onde está a minha encomenda BR123456789". Agora compare:
description: Consulta o status de entregas na API de Entregas. Use quando
pedirem para rastrear entrega, ver onde está um pacote, consultar código de
rastreio (formato BR seguido de 9 dígitos) ou saber se um pedido já foi
entregue.
Essa segunda tem as palavras que a pessoa realmente usa: rastrear, pacote, encomenda, código de rastreio, entregue. E tem o formato do código, que é um sinal fortíssimo: quando a IA vê BR123456789 na frase, casa na hora.
A receita que funciona é sempre a mesma:
- O que a skill faz, numa frase.
- "Use quando…" seguido dos termos reais que disparam o assunto.
- Um formato reconhecível, se a sua API tiver um (código, prefixo, número de documento).
O teste é fácil: escreva a frase que você digitaria num dia normal de trabalho. Se nenhuma palavra dela aparece na sua description, a skill está invisível. 😬
📖 O corpo: a documentação que a IA vai seguir
Passado o gatilho, vem o manual. E aqui a regra muda: agora a IA vai ler tudo, então escreva para quem não conhece nada da sua API.
Um corpo que funciona tem quatro partes: o endereço-base, a autenticação, os endpoints com exemplo de chamada, e a tabela de erros. Vamos por partes.
Primeiro o básico, que responde "para onde eu mando e como eu me identifico":
## Endereço-base
https://api.exemplo.com.br/v1
## Autenticação
Toda chamada precisa do cabeçalho `X-API-Key` com a chave da conta.
A chave fica na variável de ambiente `ENTREGAS_API_KEY`. Nunca escreva o
valor dela em arquivo nem repita a chave na resposta ao usuário.
Repare na última frase. Ela parece desnecessária e não é: sem ela, a IA às vezes ecoa a chave no meio de uma explicação. Instrução explícita de não fazer algo vale tanto quanto a de fazer. 🔐
🧪 Exemplo de chamada: o pedaço que a IA copia
Agora o coração da skill. Para cada endpoint, dê um exemplo completo que roda copiando e colando, e logo abaixo a resposta de verdade.
## Consultar uma entrega
GET /v1/entregas?codigo=BR123456789
Exemplo:
```bash
curl -s -H "X-API-Key: $ENTREGAS_API_KEY" \
"https://api.exemplo.com.br/v1/entregas?codigo=BR123456789"
```
Resposta:
```json
{
"codigo": "BR123456789",
"situacao": "em_transito",
"cidade": "Curitiba"
}
```
O campo `situacao` só assume três valores: `postado`, `em_transito`
e `entregue`. Qualquer outro valor é erro de leitura, não situação nova.
Três detalhes desse bloco que valem ouro, e que a maioria das documentações esquece:
- O exemplo usa a variável de ambiente (
$ENTREGAS_API_KEY), não uma chave escrita. Assim a IA copia o padrão certo, e não o errado. - A resposta está formatada, em linhas. JSON grudado numa linha só a IA até lê, mas ela aprende a estrutura muito melhor assim, e você também.
- Os valores possíveis estão listados. Sem essa linha, a IA vê
em_transitouma vez e assume que existeatrasado,extraviadoe o que mais a imaginação der. Enumerar corta a invenção pela raiz.
🚨 A tabela de erros, que ninguém escreve e todo mundo precisa
Essa é a seção que separa uma skill que funciona de uma que funciona só quando dá tudo certo.
Sem a tabela de erros, a IA acerta o caminho feliz e trava no primeiro tropeço, inventando explicação para um número que ela não conhece. Com a tabela, ela sabe o que fazer:
## Erros
| Código | O que aconteceu | O que fazer |
|---|---|---|
| 401 | Chave ausente ou inválida | Conferir a variável `ENTREGAS_API_KEY` |
| 404 | Código de rastreio não existe | Avisar o usuário, não tentar de novo |
| 429 | Passou de 60 consultas por minuto | Esperar 60 segundos e repetir uma vez |
| 500 | Falha na API | Repetir uma vez; se persistir, avisar |
Olhe a coluna da direita com carinho. "O que fazer" é o que evita os dois desastres clássicos: repetir para sempre um erro que nunca vai mudar (o 404) e desistir na primeira de um erro passageiro (o 500). Sem essa coluna, a IA escolhe no chute, e o chute vem caro quando a sua API cobra por chamada. 💸
💻 Quando a API não cabe num curl
Consulta simples resolve com curl. Mas às vezes é preciso tratar o resultado, e aí vale colocar um script pronto na skill.
Este é o consultador completo, num arquivo só, de cima para baixo:
// Consulta uma entrega na API de exemplo.
// Uso: node consultar.js BR123456789
async function consultarEntrega(codigo) {
const chave = process.env.ENTREGAS_API_KEY; // a chave nunca fica escrita no arquivo
if (!chave) {
throw new Error("Falta a variavel de ambiente ENTREGAS_API_KEY.");
}
const endereco = "https://api.exemplo.com.br/v1/entregas?codigo=" + encodeURIComponent(codigo);
const resposta = await fetch(endereco, {
headers: { "X-API-Key": chave }
});
// Sem esta checagem o erro chega como JSON e o programa segue achando que deu certo.
if (!resposta.ok) {
const corpo = await resposta.text();
throw new Error("A API respondeu " + resposta.status + ": " + corpo);
}
return await resposta.json();
}
async function main() {
const codigo = process.argv[2];
if (!codigo) {
console.log("Uso: node consultar.js <codigo>");
return;
}
try {
const entrega = await consultarEntrega(codigo);
console.log("Situacao:", entrega.situacao);
console.log("Cidade: ", entrega.cidade);
} catch (erro) {
console.error("Nao deu para consultar:", erro.message);
}
}
main();
Duas linhas desse arquivo merecem atenção, porque cada uma evita um bug específico.
O if (!resposta.ok) é a mais importante. O fetch não lança erro quando a API responde 401 ou 404: para ele, a resposta chegou, missão cumprida. Sem essa checagem o programa segue em frente, faz resposta.json() num corpo de erro, e imprime Situacao: undefined com ar de quem deu certo. É o pior tipo de bug, porque não parece bug.
O encodeURIComponent é o outro. Ele existe para o caso de o código vir com espaço, acento ou & no meio: sem ele, a URL quebra e a API recebe outra coisa.
E veja a saída, com o servidor no ar e a chave no lugar:
$ node consultar.js BR123456789
Situacao: em_transito
Cidade: Curitiba
$ node consultar.js BR000000000
Nao deu para consultar: A API respondeu 404: {"erro":"entrega nao encontrada"}
$ ENTREGAS_API_KEY=errada node consultar.js BR123456789
Nao deu para consultar: A API respondeu 401: {"erro":"chave ausente ou invalida"}
Repare que os dois caminhos de erro dizem exatamente o que houve, com o código e o corpo da resposta. É isso que a IA vai ler quando rodar o script, e é por isso que a mensagem de erro precisa ser boa: ela é o que a IA usa para decidir o próximo passo. Mensagem vaga ("erro ao consultar") deixa a IA no escuro igual a você. 🔦
Com o script na pasta, a skill fica assim, e o SKILL.md ganha uma linha dizendo que ele existe:
entregas-api/
├── SKILL.md
└── consultar.js
📚 Quando a documentação não cabe num arquivo só
API pequena cabe inteira no SKILL.md. Mas se a sua tem trinta endpoints, colocar tudo lá é um tiro no pé: a IA carrega o manual inteiro para consultar um código de rastreio.
O padrão então é separar. No SKILL.md ficam os dois ou três endpoints do dia a dia, e o resto vai para arquivos citados pelo caminho:
entregas-api/
├── SKILL.md
├── consultar.js
└── referencia/
├── endpoints-completos.md
└── codigos-de-situacao.md
E no corpo do SKILL.md você só aponta:
## Mais endpoints
Os outros 28 endpoints (criação, cancelamento, etiquetas, relatórios)
estão em `referencia/endpoints-completos.md`. Leia esse arquivo quando
o pedido não for uma consulta simples de rastreio.
A frase "leia esse arquivo quando…" faz o trabalho todo: a IA abre o arquivo extra só quando precisa. É a mesma ideia da description, um nível abaixo. 🪆
🧯 Os erros que eu vejo em quase toda skill de API
Junte estes cinco e você já está à frente da maioria:
1. Description escrita como título de manual. Já falamos, mas é o campeão disparado. "Documentação da API X" não dispara nada.
2. A chave escrita dentro do SKILL.md. Tentador, porque funciona na hora. Só que a pasta da skill vai para o git, vai para o colega, vai para o backup. E chave publicada é chave queimada: trocar depois não apaga o que já subiu. O nome da variável entra; o valor, nunca.
3. Nenhum exemplo de resposta. Só o endereço do endpoint. A IA tenta adivinhar os nomes dos campos e erra: seu JSON tem situacao, ela escreve status, e nada funciona.
4. Nenhuma tabela de erros. Funciona lindo até o dia em que não funciona.
5. Endereço de exemplo diferente do real. Documentação que ficou com localhost:3000 de quando você estava testando. A IA copia fielmente o que está escrito, e aí passa meia hora chamando um servidor que não existe na máquina dela. 🙃
✅ O roteiro inteiro, em cinco minutos
Juntando tudo, criar a skill é isto. Primeiro a pasta:
mkdir entregas-api
Crie o SKILL.md dentro dela, com o frontmatter de dois campos e, no corpo, nesta ordem: endereço-base, autenticação, um endpoint com curl e resposta formatada, e a tabela de erros. Se precisar de script, ponha o arquivo ao lado e cite-o no texto.
Depois teste do jeito mais honesto que existe: abra uma conversa nova e peça o que um usuário pediria, com as palavras dele. "Onde está a encomenda BR123456789?" Se a IA abrir a skill e acertar a chamada, você terminou. Se ela ignorar, o problema está na description, e é ali que você volta.
É bonito quando funciona: você escreve um arquivo de texto e a sua API, que era um segredo entre você e o servidor, passa a ser uma coisa que qualquer IA sabe usar. ✨
Por hoje é só, meus unicórnios! 🦄✨
Que a magia do arco-íris continue brilhando em suas vidas! Até mais! 🌈🌟
Perguntas frequentes
O que é exatamente uma skill?
SKILL.md dentro, e nada mais que isso precisa existir. O arquivo começa com um frontmatter YAML de dois campos (name e description) e continua em Markdown comum. Não tem build, não tem instalação, não tem servidor rodando: é documentação em pasta.Por que a minha skill nunca é usada pela IA?
description. Ela é o único texto que a IA lê antes de decidir abrir a skill, e se estiver escrita como título de manual ("Documentação da API interna") não bate com nada que a pessoa digita. Escreva as palavras reais: "rastrear entrega", "código de rastreio", "status do pedido", "BR123456789".Qual a diferença entre uma skill e um servidor MCP?
curl, a skill resolve sem você manter processo nenhum de pé.Posso colocar a chave da API dentro do SKILL.md?
SKILL.md o nome da variável de ambiente e como obter a chave; o valor fica fora, na máquina de quem usa.Preciso quebrar a skill em vários arquivos?
SKILL.md passar de umas 500 linhas. Aí o padrão é deixar no arquivo principal os dois ou três endpoints do dia a dia e mandar o resto para referencia/, citando o caminho no texto. A IA lê o arquivo extra quando precisa, em vez de carregar tudo sempre.O que mais falta numa skill de API?
401, inventando explicação. Liste o código, o que significa na sua API e o que fazer: 401 é chave errada, 404 é código inexistente, 429 é limite por minuto e pede espera.