agentsclimarketplace

Conta azul

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

Skill do Claude Code para integrar com a API do ERP Conta Azul: OAuth 2.0, 10 armadilhas mapeadas, mapa de ~45 endpoints e referencia completa navegavel.

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.

3 things to look at

  • 14 days oldThe repository was created 14 days ago. New is not bad, but a brand new repository carrying a familiar-sounding name is the shape a typosquat arrives in, and there has been no time for anyone else to find a problem with it.
  • 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.

What its author says it does

Copied from the file, not written here

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

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.

Gives 0 of the 12 instructions most apis services skills give in ~3.9k tokens

Counted across 424 of the 426 authors here whose files we hold, read 2026-08-06

  • use plural nouns for resource namesin 41 of 424, across 32 files
  • use cursor-based pagination for large datasetsin 35 of 424, across 20 files
  • include rate limit headers in responsesin 25 of 424, across 13 files
  • Use kebab-case for multi-word resourcesin 23 of 424, across 13 files
  • version APIs in the URL pathin 19 of 424, across 9 files
  • use semantic HTTP status codesin 18 of 424, across 8 files
  • verify webhook signaturesin 18 of 424, across 11 files
  • use query parameters for filteringin 17 of 424, across 6 files
  • use async database operationsin 14 of 424, across 7 files
  • wrap successful responses in a data fieldin 13 of 424, across 3 files
  • prefix sorting parameters with a hyphen for descending orderin 13 of 424, across 3 files
  • set appropriate HTTP status codesin 13 of 424, across 6 files

Said here and by no other author read

  • authenticate using OAuth 2.0 Authorization Code
  • store new refresh token before using access token
  • use a single process for token renewal
  • implement polling for synchronization
  • respect rate limits of 600 per minute and 10 per second
  • use the exact OAuth scope required

Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.

Keep looking

Skills are one crate of 328,083. 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.