Bots e integrações
Como um bot Node (Telegram, Discord, WhatsApp) consulta e edita tarefas da Axuz com um token de integração axz_bot_, escopos, rotação e tratamento de erros.
Um bot é um serviço seu (um processo Node ligado ao Telegram, Discord, WhatsApp ou Slack) que conversa com a Axuz por API: lê e edita tarefas e boards de um time, sem usar a senha de nenhuma pessoa. A credencial dele é o token de integração axz_bot_…, emitido por um owner ou admin do time.
Como as peças se encaixam
| Credencial | O que alcança |
|---|---|
| Sessão (cookie ou JWT) de owner/admin do time | Gestão em /teams/{teamId}/integrations/** (criar, pausar, emitir token) |
Token axz_bot_… | Só /v1/integration/self* no axuz_api e as rotas de tarefas/boards do mapa abaixo, no axuz_workspace_api |
Assinatura HMAC (whsec_…) | Só o webhook de entrada POST /integrations/inbound/{webhookId} |
O token nunca gerencia integrações (nem a própria), e nunca alcança IAM, billing, admin, /me, /platform, arquivos, wiki, feeds nem outro time. Com bearer axz_bot_ em qualquer outra rota do axuz_api, a resposta é 403 antes de qualquer handler.
Passo a passo
-
Autentique-se como owner ou admin do time e guarde o JWT em uma variável de ambiente (veja Autenticação). Você também precisa do
teamId. -
Crie a integração.
provideré um decustom_bot,github,slack,discord,telegram,whatsapp,webhook.scopesé obrigatório; peça só o que o bot usa.metadataé livre, mas não-secreta (até 4 KiB; chave com cara de segredo é recusada).
curl -sS -X POST "https://api.axuz.net/teams/$AXUZ_TEAM_ID/integrations" \
-H "Authorization: Bearer $AXUZ_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"provider":"telegram","name":"Bot de tarefas","scopes":["tasks:read","tasks:write","boards:read","comments:write","integrations:read"]}'
- Emita o token.
scopesomitido herda os escopos inteiros da integração; um escopo fora dela é400.expires_in_days(1 a 730) é opcional, mas recomendado.
curl -sS -X POST "https://api.axuz.net/teams/$AXUZ_TEAM_ID/integrations/$INTEGRATION_ID/tokens" \
-H "Authorization: Bearer $AXUZ_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"telegram-prod","expires_in_days":90}'
A resposta 201 traz o campo token (axz_bot_ mais 48 caracteres). Ele aparece uma única vez: a Axuz guarda só o SHA-256. Copie direto para o cofre de segredos do seu ambiente. Listagens mostram apenas prefix (por exemplo axz_bot_AbCd) para você reconhecer qual token é qual.
- Teste o token com a rota “quem sou eu”, que exige o escopo
integrations:read:
curl -sS "https://api.axuz.net/v1/integration/self" \
-H "Authorization: Bearer $AXUZ_BOT_TOKEN"
Devolve integration, team_id e token.scopes (os escopos efetivos).
- Chame as rotas de tarefas no host do workspace, sempre com o
teamIddo token. Veja Tarefas e boards pela API e o exemplo executável emexamples/bot-node/.
Escopos
Os escopos são os de integration_catalog.go. Não existe curinga: o casamento é exato e o que não está na lista não é emitido.
| Escopo | Permite |
|---|---|
tasks:read | Listar, buscar e ler tarefas, subtarefas e responsáveis; listar comentários de tarefa |
tasks:write | Criar, atualizar, mover (reordenar) e atribuir tarefas. Nunca deleta |
boards:read | Ler boards e colunas, inclusive o quadro de um canal |
boards:write | Criar e editar boards e colunas. Nunca deleta |
comments:write | Comentar em tarefas (target_type precisa ser task) |
integrations:read | Ler a própria integração, o estado, os escopos e as entregas |
O escopo efetivo do token é a interseção entre o do token e o da integração: se um admin estreitar scopes na integração, os tokens existentes perdem a permissão na hora.
A tabela de rotas permitidas (fonte única: BotRules) mapeia cada chamada a um escopo, por exemplo GET /teams/{teamId}/boards pede boards:read e PATCH /teams/{teamId}/tasks/{id} pede tasks:write. Verbo HTTP ou rota fora da tabela é negado, e não há DELETE de tarefa, board, coluna ou comentário.
Limites
- Um time por token. O
teamIddo caminho precisa ser o do token; qualquer outro viracross_tenant. - Nunca deleta. Remover é tarefa de uma pessoa, na interface.
- Comentários só em tarefas.
POST /commentscom outrotarget_typeé negado. - Sem acesso a IAM, billing, admin, arquivos, wiki e feeds.
- Metadata da integração e nomes: até 4 KiB e 100 caracteres. Até 10 webhooks por integração.
Rate limit
Não há, no código que lemos, um limite próprio para token de integração nas rotas de tarefas. O que existe e vale para o bot:
- No
axuz_workspace_api, mutações (POST,PATCH,PUT,DELETE) sob/teams/{teamId}têm limite de 60 por minuto por chave, configurável porMUTATION_RATE_LIMIT_PER_MIN. Leituras não contam. Estourou:429com{"error":"rate_limited","retry_after":N}e os headersRetry-AftereX-RateLimit-Limit. A chave hoje é usuário mais time; como o principal de bot entra nessa chave ainda não está documentado. - No webhook de entrada: 120 por minuto por webhook (
429).
Trate 429 sempre como “tente de novo depois de Retry-After”, sem assumir o número exato.
Rotação e revogação
- Rotacionar (
POST …/tokens/{tokenId}/rotate): emite um token novo com os mesmos escopos e encerra o antigo.grace_seconds(0 a 86400, padrão 0) deixa o antigo valer só por essa janela, para o bot trocar sem downtime. Token já revogado ou expirado dá409. - Revogar (
DELETE …/tokens/{tokenId}): idempotente, corte imediato, sem esperar cache. - Pausar a integração (
PATCHcomstate: "paused") corta tokens e entregas na hora;revokedé terminal (umPATCHdepois dá409 integration_revoked). - Remover a integração (
DELETE) é soft: revoga os tokens e desativa os webhooks.
O resolvedor guarda tokens válidos em cache por até 15 segundos, mas revogação e pausa invalidam esse cache na hora.
O que fazer em 401, 403 e 429
| Status | Significado | Ação do bot |
|---|---|---|
401 | Token ausente, malformado, revogado, expirado ou integração pausada/removida. A resposta é uniforme e não diz qual | Não repita. Alerte o dono, pare de usar o token e troque por um novo |
403 | Escopo insuficiente, rota fora do mapa, time diferente ou rota que não aceita token de integração | Não repita. É erro de configuração: peça o escopo certo ou corrija a rota |
404 | O item não existe neste time (não revela existência em outros) | Trate como “não encontrado” |
429 | Limite de requisições | Espere Retry-After e tente de novo com backoff exponencial e jitter |
5xx | Falha do servidor | Repita só GET e PATCH; POST pode ter sido processado |
O corpo de erro é sempre {"error":"<código ou mensagem>"}.
Boas práticas
- Token em cofre ou variável de ambiente do servidor, nunca no código, no repositório, em log, na URL nem em app de navegador ou celular. Token em URL vaza em log e referer; a API só aceita o header
Authorization. - Um token por ambiente e por bot, com
expires_in_dayse o mínimo de escopos. Rotacione em calendário e a cada suspeita de vazamento. - Idempotência é sua.
POST /tasksePOST /commentsnão aceitamIdempotency-Keyhoje (só o convite de canal aceita). Provedores de chat reentregam eventos: guarde o id da mensagem do chat e ignore repetidos, como faz o exemplo. - Retry com backoff e jitter, respeitando
Retry-After; nunca em401/403;POSTsó em429. - Falhe fechado. Se o token sumir da configuração, o bot não deve subir fingindo funcionar.
- Não registre o token. Em log, mostre no máximo o
prefix.
Próximos passos
- Tarefas e boards pela API: rotas, campos e erros reais.
- Exemplo completo em
examples/bot-node/, com cliente HTTP isolado, adaptador de chat fictício e teste contra mock.