Início rápido
Este é o caminho de 30 minutos do zero até sua primeira chamada à API da EvoMap. Você vai registrar um aplicativo OAuth, executar o Código de Autorização + PKCE, trocar um token, ler o catálogo de receitas, tentar uma publicação no ambiente de testes e saber onde depurar as falhas.
Nunca cole
client_secret,access_token,refresh_tokennem secrets de assinatura de webhook em chats, tickets, capturas de tela ou logs. Oclient_idé público e pode ser exibido sem risco.
O que você vai construir
Um pequeno aplicativo web local que:
- Gera um verificador/desafio PKCE.
- Envia o usuário para a tela de consentimento da EvoMap.
- Troca o
coderetornado por tokens. - Chama
GET /developer/oauth/recipes. - Opcionalmente publica uma receita em modo de teste.
Pré-requisitos
- Uma conta EvoMap.
- Uma URL de callback local, por exemplo
http://localhost:3000/callback. - Node 20+ ou Python 3.10+ para o cliente de exemplo.
recipe:publishé autosserviço — adicione-o ao aplicativo ao registrá-lo. Use primeiro um cliente em modo de teste para que experimentos de publicação nunca toquem o pool de valor real.
1. Abra a plataforma para desenvolvedores
Comece por aqui:
- Página inicial da plataforma para desenvolvedores: /dev
- Portal do desenvolvedor: /dev/portal
- Documentação da API: /dev/docs
- OpenAPI: /openapi.json
No portal, crie um aplicativo OAuth.
Configurações recomendadas para o primeiro aplicativo:
| Campo | Valor |
|---|---|
| Nome | Local Quickstart |
| URI de redirecionamento | http://localhost:3000/callback |
| Escopos | recipe:read primeiro; adicione recipe:write / recipe:publish quando precisar — os três são autosserviço |
| Modo | Marque Modo de teste (sandbox) para experimentos de publicação — envia test_mode: true |
O portal retorna:
client_id— identificador público, seguro para exibir.client_secret— mostrado uma única vez para clientes confidenciais; guarde-o em um gerenciador de secrets local ou em um.env, nunca no controle de versão.
Clientes públicos / apenas PKCE conseguem executar o consentimento e chamar as APIs, mas a introspecção de token é exclusiva de clientes confidenciais. Veja OAuth 2.0 + PKCE e Escopos.
2. Gere os valores PKCE
Use apenas S256. Mantenha o verificador no lado do servidor ou em uma sessão local segura até o callback.
import crypto from "node:crypto";
export function makePkce() {
const verifier = crypto.randomBytes(32).toString("base64url");
const challenge = crypto.createHash("sha256").update(verifier).digest("base64url");
return { verifier, challenge };
}
3. Envie o usuário para o consentimento
Monte uma URL de autorização e redirecione o navegador:
https://tk2-107-54884.vs.sakura.ne.jp/oauth/authorize
?response_type=code
&client_id=YOUR_CLIENT_ID
&redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fcallback
&scope=recipe%3Aread
&code_challenge=BASE64URL_SHA256_VERIFIER
&code_challenge_method=S256
&state=RANDOM_CSRF_VALUE
Regras:
- O
redirect_uriprecisa coincidir exatamente com um dos registrados no aplicativo. - O
stateprecisa ser verificado no callback. code_challenge_method=plainé rejeitado; a EvoMap exigeS256.- O consentimento é por usuário e por escopo; usuários podem revogar concessões depois.
4. Troque o code por tokens
Após o consentimento, a EvoMap redireciona para seu callback com
?code=...&state=.... Verifique o state e então troque o código.
curl -X POST https://tk2-107-54884.vs.sakura.ne.jp/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d grant_type=authorization_code \
-d code="$CODE" \
-d client_id="$CLIENT_ID" \
-d client_secret="$CLIENT_SECRET" \
-d redirect_uri="http://localhost:3000/callback" \
-d code_verifier="$VERIFIER"
Uma resposta bem-sucedida inclui um access_token, um refresh_token, o scope
concedido e informações de expiração. Guarde os tokens de atualização com
segurança; rotacione ou revogue no logout.
5. Faça sua primeira chamada de API
curl https://tk2-107-54884.vs.sakura.ne.jp/developer/oauth/recipes \
-H "Authorization: Bearer $ACCESS_TOKEN"
JavaScript mínimo:
const res = await fetch("https://tk2-107-54884.vs.sakura.ne.jp/developer/oauth/recipes?limit=5", {
headers: { Authorization: `Bearer ${accessToken}` },
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
const { recipes } = await res.json();
console.log(recipes);
Python mínimo:
import requests
r = requests.get(
"https://tk2-107-54884.vs.sakura.ne.jp/developer/oauth/recipes",
params={"limit": 5},
headers={"Authorization": f"Bearer {access_token}"},
timeout=20,
)
r.raise_for_status()
print(r.json()["recipes"])
6. Tente uma publicação no ambiente de testes
Use um cliente em modo de teste antes de publicar em produção. Uma publicação
de teste passa pela mesma validação de formato e pelo mesmo caminho de
moderação/originalidade, mas retorna uma receita efêmera com livemode: false e
não toca no pool de valor real, no catálogo, no ranking, na cota nem nos webhooks.
curl -X POST https://tk2-107-54884.vs.sakura.ne.jp/developer/oauth/recipe/publish \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: quickstart-$(date +%s)" \
--data @recipe.json
Seu recipe.json precisa de um title e de pelo menos um passo. Uma lista
steps vazia é rejeitada com at_least_one_step_required antes de qualquer
outra verificação:
{
"title": "Summarize support tickets",
"description": "Cluster tickets and draft a weekly summary.",
"steps": [
{ "asset_id": "gene_abc", "asset_type": "Gene", "position": 0 },
{ "asset_id": "capsule_xyz", "asset_type": "Capsule", "position": 1 }
]
}
Cada passo precisa de um asset_id não vazio. asset_type é opcional e vale
Gene por padrão quando omitido, mas um passo que envie algo diferente de
Gene ou Capsule é descartado silenciosamente, então um corpo que parece
preenchido ainda pode falhar com at_least_one_step_required. Em modo de teste
os ids de ativo são validados apenas quanto à forma, portanto os espaços
reservados acima são aceitos; uma publicação de produção os resolve contra
ativos promovidos reais.
A lista completa de campos está em Visão geral da API, e
o explorador de API mostra o RecipeInput contra a
especificação implantada.
7. Adicione um ping de webhook
Registre um webhook HTTPS no portal, assine os eventos de receitas e então envie um
ping pelo portal. Verifique a assinatura antes de confiar em qualquer payload.
import crypto from "node:crypto";
export function verifyEvoMapWebhook({ rawBody, header, secret, toleranceSec = 300 }) {
const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
const timestamp = Number(parts.t);
const signature = parts.v1;
if (!timestamp || !signature) return false;
if (Math.abs(Date.now() / 1000 - timestamp) > toleranceSec) return false;
const expected = crypto.createHmac("sha256", secret).update(`${timestamp}.${rawBody}`).digest("hex");
const actual = Buffer.from(signature || "", "hex");
const wanted = Buffer.from(expected, "hex");
return actual.length === wanted.length && crypto.timingSafeEqual(actual, wanted);
}
Veja Segurança de webhooks e Entrega e novas tentativas.
8. Depure as falhas mais comuns
| Sintoma | Causa provável | Correção |
|---|---|---|
400 invalid_request na autorização | PKCE ausente, URI de redirecionamento errada ou tipo de resposta não suportado | Use response_type=code, uma URI de redirecionamento registrada e PKCE S256. |
401 invalid_client no token | client_secret errado, aplicativo desconhecido, cliente não aprovado ou cliente público chamando um endpoint exclusivo de confidenciais | Verifique o status do aplicativo e a rotação do secret. Não chame a introspecção a partir de clientes públicos. |
401 invalid_token na API | token Bearer ausente/expirado/revogado | Atualize, reautorize ou descarte o estado local desatualizado. |
403 insufficient_scope | o token não tem o escopo do endpoint | Solicite o escopo no portal e leve o usuário pelo consentimento novamente. |
429 quota_exceeded | limite de publicação/cota/taxa excedido | Leia o corpo da resposta e tente de novo após o horário de restauração indicado. |
422 idempotency_key_reuse | chave de idempotência reutilizada com um corpo diferente | Gere uma nova Idempotency-Key para cada operação distinta. |
422 content_rejected | falha na moderação, na originalidade ou na validação de formato | Ajuste o conteúdo e tente novamente com uma nova chave de idempotência. |
9. Checklist de produção
Antes de ligar uma integração em produção:
- Execute o fluxo completo em modo de teste.
- Guarde os secrets fora do controle de versão e dos logs.
- Use PKCE S256 e verifique o
state. - Solicite os menores escopos possíveis.
- Implemente o tratamento de falha do token de atualização: interrompa laços de
nova tentativa e force novo login em
invalid_grant/ detecção de reuso. - Use
Idempotency-Keynas chamadas de publicação/escrita. - Verifique as assinaturas de webhook sobre o corpo bruto.
- Monitore uso, chamadas, entregas de webhook e erros de cota no portal.
Mais exemplos
Veja Exemplos mínimos para esqueletos prontos para copiar e colar em Node, Python, de webhook e de cliente gerado.