agentsclimarketplace

Conta azul

Skill augustotecnos/claude-skill-conta-azul/conta-azul

Como integrar com a API do ERP Conta Azul (api-v2). Use ao autenticar via OAuth 2.0 (authorization code, refresh token rotativo), ou ao integrar vendas, orçamentos, pessoas (clientes/fornecedores/transportadoras), produtos, contratos recorrentes, notas fiscais e financeiro (contas a pagar/receber, parcelas, categorias, centros de custo, rateio, cobranças). Traz base URLs, o fluxo OAuth completo, validade dos tokens, onde guardar o refresh_token, rate limit, 10 armadilhas, erros comuns, o mapa de endpoints, como buscar payloads na doc-para-IA (llms.txt / .md por endpoint) e o aviso de que a API não tem webhook (exige polling).From its SKILL.md

Install
npx -y skills add augustotecnos/claude-skill-conta-azul --skill conta-azul

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

13.0 KB, ~3.9k tokens by cl100k_base, as published. Nobody here has run it

Conta Azul — API v2

ERP Conta Azul. REST + JSON, autenticação OAuth 2.0 Authorization Code — não é API key.

  • Base URL: https://api-v2.contaazul.com
  • Servidor de autorização: https://auth.contaazul.com
  • Auth nas chamadas: header Authorization: Bearer <access_token>
  • Rate limit: 600 req/min e 10 req/s por conta ERP conectada → estourou, 429.
  • Validades: code 3 min (uso único) · access_token 1 h · refresh_token até 5 anos ou até a próxima renovação
  • Portal do Desenvolvedor: https://developers-portal.contaazul.com — client_id/secret, app de dev com dados fictícios, e o único canal de suporte técnico da API
  • Multi-tenant: cada empresa Conta Azul autoriza individualmente e tem seu próprio par de tokens

OAuth 2.0 — as 3 chamadas que importam

1. Cliente autoriza (abrir no navegador; usar conta do ERP, não a do Portal):

https://auth.contaazul.com/login?response_type=code&client_id=CLIENT_ID&redirect_uri=REDIRECT_URI&state=ALEATORIO&scope=openid+profile+aws.cognito.signin.user.admin

Volta em REDIRECT_URI?code=...&state=... — confira o state (proteção CSRF).

2. Trocar code por tokens (até 3 min depois):

curl -X POST 'https://auth.contaazul.com/oauth2/token' \
  -H 'Authorization: Basic BASE64(CLIENT_ID:CLIENT_SECRET)' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'grant_type=authorization_code' \
  --data-urlencode 'code=CODIGO' \
  --data-urlencode 'redirect_uri=REDIRECT_URI'

3. Renovar (mesma URL e mesmo header, trocando o corpo):

--data-urlencode 'grant_type=refresh_token' --data-urlencode 'refresh_token=REFRESH_TOKEN'

Resposta de 2 e 3: {"access_token":"…","expires_in":3600,"refresh_token":"…","token_type":"Bearer"}

Gerar o Base64:

# Linux / macOS
echo -n "CLIENT_ID:CLIENT_SECRET" | base64
# Windows
[Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes("CLIENT_ID:CLIENT_SECRET"))

⚠️ Dez armadilhas

  1. refresh_token é rotativo. Cada renovação devolve um novo e invalida o anterior. Não gravar o novo = integração morre em 1 h com invalid_grant. Causa nº 1 de "funcionava e parou".
  2. Não existe webhook (confirmado no FAQ oficial). Toda sincronização é polling agendado — desenhe o fluxo assim desde o início, respeitando o rate limit.
  3. Plural × singular é inconsistente e o erro vira 404 silencioso:
    • plural → /v1/pessoas, /v1/produtos, /v1/contratos, /v1/orcamentos, /v1/categorias, /v1/notas-fiscais
    • singular → /v1/venda, /v1/conta-financeira, /v1/centro-de-custo
  4. O verbo da exclusão em lote muda por área: POST /v1/venda/exclusao-lote mas DELETE /v1/orcamentos/exclusao-lote. Inativar/excluir pessoa é POST (/v1/pessoas/inativar, /v1/pessoas/excluir), embora DELETE /v1/pessoas/{id} também exista.
  5. code vale 3 minutos e é de uso único — reutilizar dá invalid_grant.
  6. scope é fixo e literal: openid+profile+aws.cognito.signin.user.admin. Não inventar escopo.
  7. redirect_uri bate byte a byte com a cadastrada no Portal, senão erro de redirecionamento. Usando a extensão Chrome, tem que ser exatamente https://api.contaazul.com/extension/callback.
  8. Renovação é estado compartilhado: grave o novo refresh_token antes de usar o novo access_token, e deixe um único processo renovar por vez. Dois renovando junto = um recebe invalid_grant e a corrente quebra — só volta reautorizando no navegador, na mão.
  9. É id_<coisa>, nunca <coisa>_id. A API usa prefixo: id_categoria, id_centro_custo, id_conta_financeira, id_empresa, id_evento, id_venda, id_vendedor. O único <coisa>_id em toda a documentação é client_id — e esse é do OAuth, não da API. Wrappers de terceiros, exemplos da internet e a memória do modelo tendem à forma invertida (cliente_id, produto_id): ela não existe aqui.
  10. Formato de data diverge entre requisição e resposta. No corpo de entrada a API usa ISO — "data_competencia": "2024-07-15". Na resposta vem DD/MM/AAAA"data_vencimento": "01/01/2030". Mesmo recurso, formato diferente na ida e na volta. Sempre confira o exemplo do endpoint (ver "Buscar payloads e endpoints").

Onde guardar os tokens

O refresh_token rotaciona a cada hora. Isso o torna estado mutável compartilhado, não uma configuração: quem guarda precisa conseguir reescrever o valor, de forma atômica, com um único dono. Variável de ambiente e arquivo .env não servem — não são reescrevíveis com segurança em tempo de execução.

Se quem chama é o n8n → não guarde nada você mesmo. Use a credencial genérica OAuth2 API; o n8n persiste e renova sozinho:

CampoValor
Grant TypeAuthorization Code
Authorization URLhttps://auth.contaazul.com/login
Access Token URLhttps://auth.contaazul.com/oauth2/token
Scopeopenid profile aws.cognito.signin.user.admin
AuthenticationHeader (Basic base64(client_id:client_secret))

Cadastre no Portal a callback do seu próprio n8n (https://SEU-N8N/rest/oauth2-credential/callback) como redirect_uri. ⚠️ Não validado com a Conta Azul — teste deixando o workflow parado >1 h e reexecutando.

Fora do n8n (Python, script, app) → tabela no seu banco:

CREATE TABLE integracao_tokens (
  integracao    TEXT NOT NULL,        -- 'conta_azul'
  id_empresa    TEXT NOT NULL,        -- GET /v1/pessoas/conta-conectada
  access_token  TEXT NOT NULL,
  refresh_token TEXT NOT NULL,
  expira_em     TIMESTAMPTZ NOT NULL,
  atualizado_em TIMESTAMPTZ NOT NULL DEFAULT now(),
  PRIMARY KEY (integracao, id_empresa)
);

Renove dentro de transação com SELECT … FOR UPDATE na linha (ver armadilha 8). Chaveada por id_empresa desde o início: serve para uma conta ou várias, sem migração depois.

Chamada base

Python:

import requests
BASE = "https://api-v2.contaazul.com"
def ca(method, path, token, **kw):
    r = requests.request(method, f"{BASE}{path}",
                         headers={"Authorization": f"Bearer {token}",
                                  "Content-Type": "application/json"},
                         timeout=30, **kw)
    if r.status_code == 401:
        raise RuntimeError("token expirado/inválido — renove antes de repetir")
    r.raise_for_status()
    return r.json()
# ex.: ca("GET", "/v1/pessoas", token)

n8n Code node:

const httpRequest = this.helpers.httpRequest;
async function ca(method, path, token, body) {
  return await httpRequest.call(this, {
    method, url: `https://api-v2.contaazul.com${path}`,
    headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
    body, json: true,
  });
}

No node HTTP Request nativo: Authentication = Generic → OAuth2 API, apontando a credencial descrita acima. É o caminho preferido — evita gerenciar token na mão.

Mapa de endpoints (índice rápido)

ÁreaEndpoints
Pessoas (clientes/fornecedores/transportadoras)GET/POST /v1/pessoas · GET/PUT/DELETE /v1/pessoas/{id} · POST /v1/pessoas/ativar · POST /v1/pessoas/inativar · POST /v1/pessoas/excluir · GET /v1/pessoas/legado/{id} · GET /v1/pessoas/conta-conectada (traz id_empresa)
VendasPOST /v1/venda · GET/PUT /v1/venda/{id} · GET /v1/venda/busca · GET /v1/venda/{id}/imprimir (PDF) · GET /v1/venda/{id_venda}/itens · GET /v1/venda/vendedores · POST /v1/venda/exclusao-lote
OrçamentosPOST /v1/orcamentos · GET /v1/orcamentos/{id} · GET /v1/orcamentos/busca · DELETE /v1/orcamentos/exclusao-lote
FinanceiroGET /v1/categorias · GET /v1/categorias/configuracao-padrao · GET /v1/financeiro/categorias-dre · GET/POST /v1/centro-de-custo · GET /v1/conta-financeira · GET /v1/conta-financeira/{id}/saldo-atual · GET /v1/financeiro/eventos-financeiros/{id_evento}/parcelas · GET /v1/financeiro/eventos-financeiros/parcelas/{id} (rateio, categoria, centro de custo) · POST /v1/financeiro/eventos-financeiros/contas-a-receber/gerar-cobranca
ProdutosGET/POST /v1/produtos · GET/PUT/DELETE /v1/produtos/{id} · GET /v1/produtos/categorias · /ncm · /cest · /unidades-medida · /ecommerce-categorias · /ecommerce-marcas
Notas fiscaisGET /v1/notas-fiscais · GET /v1/notas-fiscais/{chave} · GET /v1/notas-fiscais-servico · POST /v1/notas-fiscais/vinculo-mdfe
Contratos (recorrência)GET/POST /v1/contratos · GET /v1/contratos/proximo-numero
Serviçosárea open-api-service — CRUD de serviços (busque os paths, ver abaixo)
Protocolosárea protocol-apis-openapi — consulta/emissão de protocolos
Baixas · Cobranças · Análisesacquittance-apis-openapi · charge-apis-openapi · open-api-analytics — áreas extras

Este mapa é um índice para achar o endpoint rápido — não é exaustivo. Ex.: Financeiro tem 18 endpoints, não 9 — faltam aqui POST .../contas-a-receber, POST .../contas-a-pagar, os dois /buscar, PATCH .../parcelas/{id}, GET .../alteracoes (ótimo para polling incremental — contorna a falta de webhook), /saldo-inicial e /transferencias. A lista completa e atual de qualquer área sai do llms.txt (ver abaixo).

Regras de validação de contrato (POST /v1/contratos): intervalo_dias entre 1 e 60 · dia_vencimento ≤ 31 · primeira_data_vencimento não pode ser anterior a hoje · data_iniciodata_fim · valor_desconto positivo e ≤ total dos itens.

Erros

ErroCausa provávelAção
invalid_grantcode reutilizado ou expirado (3 min); refresh_token já rotacionado/revogado; redirect_uri ou client_id divergenteRefazer a autorização no navegador; conferir se gravou o último refresh_token
401 Unauthorizedaccess_token ausente, expirado (1 h) ou malformadoRenovar e repetir uma vez — não entrar em loop de retry
429 Too Many RequestsPassou de 600/min ou 10/sBackoff exponencial; ler os headers de limite da resposta
500Erro interno da APIRetry com backoff; persistindo, abrir chamado no Portal do Desenvolvedor

Buscar payloads e endpoints (a doc tem versão para IA)

O portal é Redocly e serve tudo em .md legível por IA — inclusive os corpos de requisição que não estão em references/. Não empacote spec: busque com WebFetch nesta cadeia de 3 níveis, do geral ao específico:

  1. Índice de tudohttps://developers.contaazul.com/llms.txt (~3 KB): lista todas as áreas e páginas.
  2. Uma área — anexe .md à URL da área. Ex.: .../docs/financial-apis-openapi.md (~9 KB): lista os endpoints, cada um com um slug de operação.
  3. Um endpoint.../docs/<area>/v1/<slug>.md (~4 KB): traz ## Request fields com nome, tipo, obrigatoriedade, descrição e exemplo de cada campo. É o payload que faltava.

Exemplo real (POST /v1/financeiro/eventos-financeiros/contas-a-receber → slug createreceivablefinancialevent): data_competencia (string, req, "2024-07-15") · valor (number, req) · contato (string, req, UUID) · conta_financeira (string, req) · rateio[].id_categoria · condicao_pagamento.parcelas[]

Regra de ouro: para qualquer POST/PUT/PATCH, busque o .md do endpoint e use os campos de lá — nunca invente, e desconfie de nomes vindos de wrapper/MCP (ver armadilha 9: a API usa id_<coisa>, e criar pessoa usa cnpj/cpf/codigo, não o perfis:[{tipo_perfil}] que wrappers documentam).

Essa fonte é sempre atual — sem snapshot para envelhecer. references/api-completa.md continua útil como visão geral offline (auth, changelog até 2026-07-10, guias), mas para campo de payload a verdade é o .md do endpoint.

Navegar a referência offline

references/api-completa.md tem ~1.430 linhas — não leia inteiro (use para auth/guias sem rede):

grep -n '^## SEÇÃO' references/api-completa.md      # 8 seções principais
grep -n '^### ' references/api-completa.md          # todos os subtópicos
grep -n '/v1/venda' references/api-completa.md      # onde um endpoint aparece

Depois Read com offset na linha encontrada.

What ships with it: 1 file

69.5 KB alongside SKILL.md

references/

Keep looking

Skills are one crate of 325,949. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.