Axuz Developers

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

CredencialO que alcança
Sessão (cookie ou JWT) de owner/admin do timeGestã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

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

  2. Crie a integração. provider é um de custom_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"]}'
  1. Emita o token. scopes omitido 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.

  1. 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).

  1. Chame as rotas de tarefas no host do workspace, sempre com o teamId do token. Veja Tarefas e boards pela API e o exemplo executável em examples/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.

EscopoPermite
tasks:readListar, buscar e ler tarefas, subtarefas e responsáveis; listar comentários de tarefa
tasks:writeCriar, atualizar, mover (reordenar) e atribuir tarefas. Nunca deleta
boards:readLer boards e colunas, inclusive o quadro de um canal
boards:writeCriar e editar boards e colunas. Nunca deleta
comments:writeComentar em tarefas (target_type precisa ser task)
integrations:readLer 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 teamId do caminho precisa ser o do token; qualquer outro vira cross_tenant.
  • Nunca deleta. Remover é tarefa de uma pessoa, na interface.
  • Comentários só em tarefas. POST /comments com outro target_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 por MUTATION_RATE_LIMIT_PER_MIN. Leituras não contam. Estourou: 429 com {"error":"rate_limited","retry_after":N} e os headers Retry-After e X-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 (PATCH com state: "paused") corta tokens e entregas na hora; revoked é terminal (um PATCH depois 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

StatusSignificadoAção do bot
401Token ausente, malformado, revogado, expirado ou integração pausada/removida. A resposta é uniforme e não diz qualNão repita. Alerte o dono, pare de usar o token e troque por um novo
403Escopo insuficiente, rota fora do mapa, time diferente ou rota que não aceita token de integraçãoNão repita. É erro de configuração: peça o escopo certo ou corrija a rota
404O item não existe neste time (não revela existência em outros)Trate como “não encontrado”
429Limite de requisiçõesEspere Retry-After e tente de novo com backoff exponencial e jitter
5xxFalha do servidorRepita 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_days e o mínimo de escopos. Rotacione em calendário e a cada suspeita de vazamento.
  • Idempotência é sua. POST /tasks e POST /comments não aceitam Idempotency-Key hoje (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 em 401/403; POST só em 429.
  • 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.

Atualizado em