{
    "api": "AccordBI — API por Empresa Contábil",
    "versao": "v1",
    "base_url": "https://api.accordtecnologia.com.br/v1",
    "somente_leitura": true,
    "leia_primeiro": [
        "Esta API é somente leitura e está sempre restrita a UMA Empresa Contábil: a dona do token.",
        "A Empresa Contábil NÃO é parâmetro. Enviar ec_id (ou qualquer variação dele) em qualquer lugar da requisição devolve 403 — não tente descobrir ou trocar de empresa.",
        "Se você é um assistente e ainda não tem o token, PEÇA ao usuário: ele precisa buscá-lo no portal, você não consegue emitir sozinho. Veja \"como_obter_token\"."
    ],
    "autenticacao": {
        "tipo": "Bearer token no header Authorization",
        "exemplo": "Authorization: Bearer acb_live_123_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
        "formato_do_token": "acb_live_<id>_<40 caracteres>",
        "observacao": "O token vale para uma única Empresa Contábil e é exibido uma única vez, no momento em que é gerado no portal."
    },
    "como_obter_token": {
        "quem_faz": "O usuário (humano). Um assistente não consegue emitir o token.",
        "passos": [
            "1. Acesse https://app.accordtecnologia.com.br/accordbi/portal/api e faça login no portal AccordBI.",
            "2. Ao entrar, selecione a unidade de negócio principal do escritório (a que representa a própria empresa contábil). Só nela o menu de API funciona.",
            "3. No menu lateral, vá em \"Minha Conta\" > \"API\".",
            "4. Clique em \"Novo token\", dê um nome (ex: \"Claude do escritório\"), marque as permissões desejadas e confirme.",
            "5. Copie o token na hora — ele não é exibido novamente. Cole-o na sua ferramenta."
        ],
        "se_a_tela_nao_aparecer": "A opção \"Minha Conta > API\" exige a mesma permissão da tela \"Escritório\". Se ela não aparece, peça a liberação ao responsável pelo portal ou à equipe AccordTecnologia."
    },
    "origem_do_acesso": [
        "O endereço de internet (IP) de onde o token é usado fica registrado, e o responsável recebe e-mail quando aparece um endereço novo — uma vez por endereço, não a cada chamada.",
        "Se o token bloqueia ou apenas avisa depende de como o usuário o gerou:",
        "Token de pessoa (padrão, \"meu computador\") — NÃO bloqueia. Trocar de rede, usar de casa ou viajando funciona normalmente; o aviso por e-mail é o que torna um token vazado detectável.",
        "Token de máquina (\"servidor / robô\") — mantém o endereço fixo. Chamada de outro endereço recebe 403 origem_nao_autorizada, e o usuário autoriza o novo endereço em Minha Conta > API.",
        "Em nenhum dos dois casos a origem afeta o isolamento: o token continua vendo apenas a própria empresa contábil."
    ],
    "niveis_de_token": {
        "empresa_contabil": "Alcança toda a empresa contábil (o escritório). Emitido por quem acessa o portal pela unidade principal do escritório.",
        "unidade_negocio": "Restrito a UMA unidade de negócio — normalmente um cliente do escritório. Vê apenas os dados daquela unidade.",
        "como_saber": "GET /v1/me devolve \"nivel\" e, quando for o caso, a unidade.",
        "recurso_indisponivel": "Alguns recursos só existem no nível da empresa contábil: /v1/empresas, /v1/uso-sistema (e /v1/uso-sistema/solicitar), /v1/honorarios, e a criação de grupo de empresa e de unidade de negócio. Com token de unidade eles devolvem 403 recurso_exige_token_de_ec — não é ausência de dados, é nível de token. O motivo é que esses dados não têm como ser recortados por unidade: o log do Domínio e o faturamento são do escritório inteiro. Vale por QUALQUER porta — pedir uso-sistema por POST /v1/contabil/solicitar recebe o mesmo 403."
    },
    "endpoints": [
        {
            "metodo": "GET",
            "caminho": "/v1/me",
            "descricao": "Empresa contábil do token, nível (empresa contábil ou unidade de negócio), unidade quando houver, e permissões concedidas. Comece por aqui.",
            "escopo": null
        },
        {
            "metodo": "GET",
            "caminho": "/v1/grupos-empresas",
            "descricao": "Grupos de empresas do escritório.",
            "escopo": "cadastro.grupos.read"
        },
        {
            "metodo": "GET",
            "caminho": "/v1/skills/{skill}",
            "descricao": "Baixa uma skill pronta, em .zip, para descompactar na pasta de skills do agente. As de PAINEL trazem o esqueleto completo — SKILL.md, referências, o atualizador de dataset e o painel já publicado em produção (HTML, CSS, JS, fontes e ícones) —, para partir de algo que funciona em vez de montar do zero. As de MÉTODO trazem o roteiro de cálculo ou de redação técnica com as tabelas vigentes e a fonte de cada valor. Disponíveis: societario, analisebalancete, analiseextrato, analiselancamento, analisenotas, analiserelatorio, apuracaomei, calculofolha, conciliacaobancaria, conciliacaocartoes, conciliacaoclientes, conciliacaofornecedores, conferenciaecf, conferenciasimples, defesafiscal, dimob, dmed, dregerencial, extratodominio, fechamentomensal, fluxocaixa, ganhocapital, icmsst, imobilizado, irpf, lancamentospadrao, obrigacoesfederais, parecercontabil, piscofinscumulativo, planocontas, reformatributaria, regimetributario, rendavariavel, zeramentodominio, auditafolha, movimentacaofiscal, resultadocontabil, rh. Nome inválido responde 404 listando os disponíveis. A resposta é o binário do .zip, não JSON.",
            "escopo": "painel.read"
        },
        {
            "metodo": "POST",
            "caminho": "/v1/grupos-empresas",
            "descricao": "Cria um grupo de empresas no escritório. O grupo é o que liga uma unidade de negócio ao escritório, então criá-lo exige token de empresa contábil — token de unidade recebe 403. Idempotente: reenviar a mesma descrição devolve 200 com o grupo existente, se foi a API que o criou; descrição igual à de um grupo criado no portal é 409. A comparação ignora maiúsculas. Máximo 45 caracteres.",
            "corpo": "descricao (obrigatória, até 45 caracteres)",
            "escopo": "cadastro.grupos.write"
        },
        {
            "metodo": "GET",
            "caminho": "/v1/empresas",
            "descricao": "Empresas clientes do escritório. Filtros: search, grupo_id, ativo. Traz o REGIME TRIBUTÁRIO em `regime_tributario` (rótulo), `regime_tributario_codigo` (número do ERP) e `optante_simples_nacional` (true/false/null). ⚡ Simples Nacional são DOIS códigos — 2 (Microempresa) e 4 (Empresa de Pequeno Porte); use `optante_simples_nacional` em vez de comparar código, ou você perde parte das empresas do regime. Os três campos vêm NULOS quando a empresa não tem parâmetro fiscal lançado no ERP: isso é \"não informado\", NÃO é \"não optante\" — não conte essas empresas como fora do Simples. Exige token de empresa contábil — não disponível para token de unidade.",
            "escopo": "cadastro.empresas.read"
        },
        {
            "metodo": "GET",
            "caminho": "/v1/unidades-negocio",
            "descricao": "Unidades de negócio usadas para login no portal. Filtros: search, grupo_id, cnpj. ⚡ CONSULTE ANTES DE CRIAR: `?cnpj=` responde se aquele CNPJ já tem unidade neste escritório. É a forma barata de não pedir a criação de algo que já existe — e o POST recusa com 409 se você não conferir.",
            "escopo": "cadastro.unidades.read"
        },
        {
            "metodo": "POST",
            "caminho": "/v1/unidades-negocio",
            "descricao": "Cria uma unidade de negócio dentro de um grupo do escritório. Exige token de empresa contábil — token de unidade recebe 403. O grupo_id precisa ser de um grupo DESTE escritório: id de outro responde 404. CNPJ e nome fantasia são obrigatórios (as mesmas regras da tela do portal). NÃO aceita workspace do Power BI: a unidade nasce sem workspace e a vinculação é feita pela equipe da AccordBI; a data de início é sempre hoje. Idempotente pelo CNPJ dentro do grupo: reenvio devolve 200 com a unidade existente, se foi a API que a criou; unidade criada no portal é 409. 🔴 E RECUSA COM 409 se o CNPJ já tem unidade neste escritório em OUTRO grupo — a resposta diz o id da existente. Confira antes em GET /v1/unidades-negocio?cnpj=<cnpj>. Motivo: a idempotência por grupo não pega o caso real, porque cliente novo chega com grupo novo — e aí a mesma empresa ganha dois lugares de login, cada um com um conteúdo, sem nada na tela dizendo qual é qual.",
            "corpo": "grupo_id (obrigatório), razao_social (obrigatória), nome_fantasia (obrigatório, até 60 caracteres), cnpj (obrigatório, 14 dígitos, com ou sem máscara)",
            "escopo": "cadastro.unidades.write"
        },
        {
            "metodo": "GET",
            "caminho": "/v1/usuarios",
            "descricao": "Usuários do portal ligados ao escritório. Filtro: search.",
            "escopo": "cadastro.usuarios.read"
        },
        {
            "metodo": "POST",
            "caminho": "/v1/mensagens",
            "descricao": "Pergunte à equipe da AccordBI quando algo aqui não fizer sentido — campo ambíguo, número que não fecha, endpoint que falta. NÃO é síncrono: devolve um id e a resposta se busca depois. Prefira isto a supor: uma suposição errada vira painel com número errado.",
            "corpo": "pergunta (obrigatória), assunto, autor, conversa_id, contexto (objeto livre)",
            "escopo": "mensagens.write"
        },
        {
            "metodo": "GET",
            "caminho": "/v1/mensagens",
            "descricao": "As perguntas feitas COM ESTE TOKEN e suas respostas — não as de outro integrador da mesma empresa contábil. Filtros: status=Aberta|Respondida|Encerrada, conversa_id, limite.",
            "escopo": "mensagens.read"
        },
        {
            "metodo": "GET",
            "caminho": "/v1/mensagens/{id}",
            "descricao": "Uma pergunta e sua resposta. É aqui que se busca o retorno do POST — resposta null significa que ainda está na fila.",
            "escopo": "mensagens.read"
        },
        {
            "metodo": "GET",
            "caminho": "/v1/paineis",
            "descricao": "Painéis publicados, com seus datasets, versão no ar e quando cada dado foi atualizado.",
            "escopo": "painel.read"
        },
        {
            "metodo": "GET",
            "caminho": "/v1/contabil",
            "descricao": "Assuntos contábeis disponíveis e o fluxo para obtê-los. COMECE POR AQUI antes de pedir qualquer coisa contábil.",
            "escopo": "contabil.read"
        },
        {
            "metodo": "POST",
            "caminho": "/v1/contabil/solicitar",
            "descricao": "Coloca uma extração na fila. NÃO devolve dado — devolve um protocolo. O ERP fica na máquina do escritório, e é ela que extrai no próximo ciclo (5 min). Idempotente enquanto o pedido está aberto: repetir não enfileira de novo. PARA O ANO INTEIRO: em dre, ebitda e indicadores, OMITA \"mes\" — a extração devolve os 12 meses num arquivo só, em vez de exigir 12 pedidos. Com \"mes\", vem só aquele mês.",
            "corpo": "empresa (codi_emp), assunto, ano, mes (opcional), parametros (opcional)",
            "escopo": "contabil.solicitar"
        },
        {
            "metodo": "GET",
            "caminho": "/v1/contabil/solicitacoes",
            "descricao": "Acompanhamento dos pedidos: Solicitado, Processando, Concluido ou Erro — com a mensagem, quando falha. Pedido ABERTO traz `fila`: `na_frente` (quantos protocolos serão atendidos antes dele) e `previsao_min` (pela vazão medida nas últimas 2h). Status parado com `na_frente` alto é FILA, não falha — repetir o pedido põe uma cópia no fim e atrasa o resto. `mensagem` (só em Erro/Invalido) é escrita para você e diz de quem é a ação: erro do PEDIDO (parâmetro faltando ou mal formado, ano/mês/data inválidos, empresa inválida) diz o que corrigir — corrija e faça um pedido NOVO; ASSUNTO indisponível para o sistema contábil do escritório diz que repetir não resolve; CADASTRO do escritório (conexão com o ERP, máquina de extração, credencial recusada) diz que repetir não resolve e que o responsável pelo portal precisa agir. O que não se encaixa nisso vem como \"Não conseguimos concluir este pedido. O detalhe ficou registrado para a nossa equipe.\" — sem detalhe técnico; não tente interpretar nem contornar, e não peça em laço.",
            "filtros": "protocolo, assunto, empresa, abertas, status (Solicitado|Processando|Concluido|Erro|Invalido)",
            "escopo": "contabil.read"
        },
        {
            "metodo": "GET",
            "caminho": "/v1/contabil/{assunto}",
            "descricao": "Resultado da última extração concluída. Assuntos: saldos, dre, balanco, plano, razao, centros-custo, indicadores, ebitda, docs-nao-integrados, empresa-cadastro. `empresa-cadastro` é o retrato COMPLETO do cadastro para AUDITAR o ERP: razão social, endereço da MATRIZ, inscrições e CNAE de cada empresa. Vem a EC inteira de uma vez — NÃO leva `empresa` — e é cadastro, então o `ano` só carimba o retrato e não filtra. Para o endereço do LOCAL DE TRABALHO (contrato), o assunto é `folha-filiais`, não este. `docs-nao-integrados` responde \"o que falta lançar\": documento fiscal (NF-e, CT-e, NFC-e, serviço, entrada e saída) que ainda NÃO tem vínculo de lançamento contábil no ERP. Não é \"quanto foi lançado\" — é o saldo pendente. Ressalva: lançamento feito por caminho que não grava a tabela auxiliar do ERP continua aparecendo como pendente. Se ainda não houver, o 404 diz se o pedido está na fila ou se você precisa pedir. meta.extraido_em diz QUANDO o dado saiu do ERP — não confunda com a hora da sua consulta. ANTES de montar tela de DRE ou EBITDA, peça `plano`: é lá que a marcação das contas vive, e é assim que você descobre se a empresa está configurada. Sem configuração, `dre` e `ebitda` devolvem vazio — e vazio de configuração é indistinguível de defeito para quem não conferiu antes ⚡ RELEITURA BARATA: a resposta traz `ETag` (e `meta.versao`). Guarde e mande de volta em `If-None-Match` na próxima leitura: se o conteúdo não mudou, você recebe 304 SEM CORPO e não paga a transferência de novo. É como descobrir que algo mudou sem reler o arquivo inteiro.",
            "filtros": "empresa, ano (obrigatórios), mes",
            "escopo": "contabil.read"
        },
        {
            "metodo": "GET",
            "caminho": "/v1/perfis",
            "descricao": "Perfis de acesso da unidade, com quantos usuários e painéis cada um tem.",
            "filtros": "unidade_negocio_id (obrigatório só para token de empresa contábil)",
            "escopo": "perfil.read"
        },
        {
            "metodo": "GET",
            "caminho": "/v1/perfis/{id}",
            "descricao": "Detalhe do perfil: usuários e painéis vinculados. O meta traz \"usuarios_disponiveis\" (logins da unidade) e \"paineis_disponiveis\" (SÓ os painéis que esta API publicou) — consulte antes de vincular, para não chutar id.",
            "escopo": "perfil.read"
        },
        {
            "metodo": "POST",
            "caminho": "/v1/perfis",
            "descricao": "Cria um perfil de acesso. Idempotente por nome: reenviar devolve o mesmo perfil. Nome que já existe COMO PERFIL DO PORTAL devolve 409 — a API só administra os perfis que ela mesma criou.",
            "corpo": "nome (obrigatório)",
            "escopo": "perfil.write"
        },
        {
            "metodo": "POST",
            "caminho": "/v1/perfis/{id}/usuarios",
            "descricao": "Coloca usuários no perfil, por login ou por e-mail. Vincula quem já está NESTA unidade ou na equipe do escritório (unidade matriz) — não alcança usuário de outro cliente da mesma empresa contábil. A API não cria usuário: quem não existe precisa ser criado no portal, por uma pessoa. Quem ficou de fora volta em \"recusados\" (login) ou \"emails_recusados\", sem falhar os demais; \"emails_vinculados\" mostra em que login cada e-mail caiu.",
            "corpo": "um de: login, logins (lista), email, emails (lista)",
            "escopo": "perfil.write"
        },
        {
            "metodo": "DELETE",
            "caminho": "/v1/perfis/{id}/usuarios/{login}",
            "descricao": "Tira o usuário do perfil (revoga o acesso).",
            "escopo": "perfil.write"
        },
        {
            "metodo": "POST",
            "caminho": "/v1/perfis/{id}/paineis",
            "descricao": "Libera um painel para o perfil. Só aceita painel PUBLICADO POR ESTA API (o que aparece em GET /v1/paineis) — relatório montado pela Accord devolve 422 e é liberado no portal, por uma pessoa. \"pode_editar\" permite ao painel gravar parâmetros (metas, classificações).",
            "corpo": "relatorio_id (obrigatório), pode_editar (opcional)",
            "escopo": "perfil.write"
        },
        {
            "metodo": "DELETE",
            "caminho": "/v1/perfis/{id}/paineis/{relatorio}",
            "descricao": "Remove o painel do perfil. Mesma fronteira do POST: só painel publicado por esta API.",
            "escopo": "perfil.write"
        },
        {
            "metodo": "GET",
            "caminho": "/v1/uso-sistema",
            "descricao": "Tempo que cada colaborador gastou em cada empresa cliente, por módulo do Domínio (Contabilidade, Escrita Fiscal, Folha...). Base do painel de custo de atendimento. SERVE ARQUIVO: se o ano ainda não foi extraído, responde 404 com motivo extracao_nao_solicitada — peça em POST /v1/uso-sistema/solicitar e volte. Granularidade sempre DIÁRIA (some para obter mês); os filtros recortam o arquivo, não geram fila. NÃO pagina: devolve a série inteira. Confira meta.extraido_em antes de concluir que um número está errado. Junte com /v1/honorarios pelo campo \"empresa\" para ter a margem.",
            "filtros": "ano (obrigatório), mes, empresa (codi_emp), grupo_id, usuario, modulo",
            "escopo": "custo.uso.read"
        },
        {
            "metodo": "POST",
            "caminho": "/v1/uso-sistema/solicitar",
            "descricao": "Coloca na fila a extração do tempo de uso de um ano inteiro. A máquina do escritório lê o log do Domínio e grava o arquivo; o GET acima passa a servi-lo. Idempotente enquanto o pedido está aberto: chamar de novo devolve o mesmo protocolo. Corpo: {\"ano\": 2026}.",
            "escopo": "custo.uso.solicitar"
        },
        {
            "metodo": "POST",
            "caminho": "/v1/folha/solicitar",
            "descricao": "Departamento Pessoal — enfileira uma extração da folha. Assuntos: folha-resumo (agregado, sem pessoa), folha-detalhe (quadro de pessoal, com cargo, CBO, departamento e centro de custo em NOME, mais endereço, e-mail, serviço com % de INSS patronal/RAT e o FAP da filial), folha-rubricas (cada rubrica de cada pessoa, com a categoria do ERP), folha-encargos (INSS, FGTS, IRRF e PIS RECOLHIDOS, por empresa e competência — NÃO por pessoa), folha-experiencia (contratos de experiência com vencimento calculado), folha-aviso-previo (com o prazo legal de pagamento), folha-encargos-pessoa (bases e alíquotas, para quem precisa ratear), folha-rubricas-cadastro, folha-faltas, folha-ferias, folha-afastamentos e folha-rescisoes. folha-filiais (uma linha por SERVIÇO/local de trabalho, com a filial a que pertence e o ENDEREÇO resolvido — é este o endereço que serve para contrato de trabalho, e NÃO o da matriz que vem em empresa-cadastro; junte com folha-detalhe por codi_emp + i_servicos para ligar pessoa ao local). Corpo igual ao do contábil: {\"empresa\": 10, \"assunto\": \"folha-encargos\", \"ano\": 2026}.",
            "escopo": "folha.solicitar"
        },
        {
            "metodo": "GET",
            "caminho": "/v1/folha/{assunto}",
            "descricao": "Serve a extração da folha já concluída. DADO PESSOAL: nome, cargo, salário e, em folha-rubricas, pensão/consignado/adiantamento por pessoa. Separado do contábil de propósito — quem tem contabil.read NÃO alcança isto, e a recíproca também vale ⚡ RELEITURA BARATA: a resposta traz `ETag` (e `meta.versao`). Guarde e mande de volta em `If-None-Match` na próxima leitura: se o conteúdo não mudou, você recebe 304 SEM CORPO e não paga a transferência de novo. É como descobrir que algo mudou sem reler o arquivo inteiro.",
            "filtros": "empresa (obrigatória), ano (obrigatório), mes",
            "escopo": "folha.read"
        },
        {
            "metodo": "GET",
            "caminho": "/v1/folha/solicitacoes",
            "descricao": "Fila das extrações de folha. Só assuntos de DP aparecem aqui. Pedido ABERTO traz `fila`: `na_frente` (quantos protocolos serão atendidos antes dele) e `previsao_min` (pela vazão medida nas últimas 2h). Status parado com `na_frente` alto é FILA, não falha — repetir o pedido põe uma cópia no fim e atrasa o resto. `mensagem` (só em Erro/Invalido) é escrita para você e diz de quem é a ação: erro do PEDIDO (parâmetro faltando ou mal formado, ano/mês/data inválidos, empresa inválida) diz o que corrigir — corrija e faça um pedido NOVO; ASSUNTO indisponível para o sistema contábil do escritório diz que repetir não resolve; CADASTRO do escritório (conexão com o ERP, máquina de extração, credencial recusada) diz que repetir não resolve e que o responsável pelo portal precisa agir. O que não se encaixa nisso vem como \"Não conseguimos concluir este pedido. O detalhe ficou registrado para a nossa equipe.\" — sem detalhe técnico; não tente interpretar nem contornar, e não peça em laço.",
            "filtros": "protocolo, assunto, empresa, abertas, status (Solicitado|Processando|Concluido|Erro|Invalido)",
            "escopo": "folha.read"
        },
        {
            "metodo": "GET",
            "caminho": "/v1/fiscal",
            "descricao": "Índice dos assuntos fiscais, com as regras do pedido. Saíram de /v1/contabil em 15/08/2026: nota fiscal e cadastro de produto não são contabilidade, e o escritório precisa poder conceder um sem o outro.",
            "escopo": "fiscal.read"
        },
        {
            "metodo": "POST",
            "caminho": "/v1/fiscal/solicitar",
            "descricao": "Enfileira uma extração fiscal. 32 assuntos hoje — consulte GET /v1/fiscal para a lista completa e o `recorte` de cada um (anual, mensal ou cadastro), que muda com frequência. Notas escrituradas: notas-saida, notas-entrada, notas-servico, cupom-fiscal, reducao-z. Item a item: itens-produto, itens-entrada, itens-servico. Item a item já com a competência fechada e o NCM, para quem vai agrupar por mês (exigem `mes`): itens-produto-mensal (competência = EMISSÃO) e itens-entrada-mensal (competência = ESCRITURAÇÃO, o critério do robô de Auditoria Fiscal). Somado por competência: faturamento-fiscal (ValorSaida, ValorServico, ValorOutros; anual, peça SEM `mes`). Cadastro: produtos, empresa, clientes, fornecedores, acumuladores, acumuladores-vigencia, produtos-vigencia. Satélite de notas-entrada, sem data própria: especies-cadastro, info-contribuinte, info-fisco, impostos-cadastro, impostos-entrada, impostos-saida, itens-cupom, impostos-servico. APURADO, não o documento: apuracao-simples (Simples Nacional aberto por anexo e tributo) e apuracao-impostos (saldo de todos os impostos, qualquer regime) — some imposto de nota e você chega perto da guia, nunca no número dela. Satélites da apuração: apuracao-simples-bases (a receita anterior e a folha que EXPLICAM a alíquota efetiva), apuracao-simples-aliquotas (alíquota aberta por tributo), apuracao-simples-base-negativa (devolução que deduz a base) e apuracao-icms-uf (DIFAL e ST devidos a outros estados, regime normal). Corpo igual ao do contábil: {\"empresa\": 22, \"assunto\": \"notas-saida\", \"ano\": 2026}. empresa e ano são obrigatórios em todos.",
            "escopo": "fiscal.solicitar"
        },
        {
            "metodo": "GET",
            "caminho": "/v1/fiscal/reforma-ncm-lc214",
            "descricao": "Base LC 214 por NCM: alíquotas e reduções de CBS e IBS, com o anexo da Lei Complementar que sustenta cada uma, imposto seletivo e base legal. Responde \"quanto este produto paga na reforma, e por quê\". 3.475 NCMs. Leitura direta — não passa pela fila. Filtros: ncm (prefixo, ex. 0101 traz a família), anexo, busca. A base e HIERARQUICA (o mesmo produto em niveis de 2 a 8 digitos): para classificar um produto use ncm_aplicavel=01022110, que devolve a regra MAIS ESPECIFICA existente — se o codigo exato nao estiver na base, cai no nivel acima, que e o que de fato vale. ncm= serve para explorar a familia inteira.",
            "escopo": "fiscal.read"
        },
        {
            "metodo": "GET",
            "caminho": "/v1/fiscal/reforma-ncm-pis-cofins",
            "descricao": "Base PIS/COFINS por NCM (10.585), com convênio de ICMS e vigência. É a MESMA base do /v1/fiscal/tributacao-ncm, em versão mais nova e limpa — prefira esta em integração nova; aquela existe porque já tem consumidor. Filtros: ncm (prefixo), categoria, busca.",
            "escopo": "fiscal.read"
        },
        {
            "metodo": "GET",
            "caminho": "/v1/fiscal/reforma-classtrib",
            "descricao": "Classificação Tributária (cClassTrib) da NF-e do regime novo: 164 códigos, com o CST a que pertencem — resolvido em nome, não só o número — e os indicadores que mudam o cálculo (crédito presumido, estorno, monofásica). Filtre por documento=nfe|nfce|cte|nfse para não oferecer, numa NFC-e, classificação que só vale para CT-e. Filtros: cst, cod_classtrib, documento, busca.",
            "escopo": "fiscal.read"
        },
        {
            "metodo": "GET",
            "caminho": "/v1/paineis/{slug}/atualizacao",
            "descricao": "O que aconteceria se você atualizasse o painel — sem atualizar nada. Diz quantos conjuntos se regeneram sozinhos (`entram`) e quais vêm de upload e ficariam com o dado antigo (`ficam_de_fora`, com o motivo). Leia ANTES de chamar o POST: um painel com 22 conjuntos em que 15 se regeneram não fica atualizado com um clique, fica 15/22 — e conjunto velho não avisa que está velho.",
            "escopo": "painel.read"
        },
        {
            "metodo": "POST",
            "caminho": "/v1/paineis/{slug}/atualizar",
            "descricao": "Atualiza DE UMA VEZ todos os conjuntos do painel que têm `consulta` declarada, pelo mesmo caminho do agendador. Sem corpo. A resposta separa `atualizados`, `falharam` (com a mensagem de cada um) e `sem_consulta` (os de upload, que NÃO foram tocados). Responde 200 mesmo com falha parcial: um conjunto que falha não impede os outros. Conjunto que nunca teve extração concluída faz o pedido entrar na fila e falha esta rodada — a máquina do escritório atende e a chamada seguinte encontra o arquivo.",
            "escopo": "dataset.write"
        },
        {
            "metodo": "GET",
            "caminho": "/v1/fiscal/sitram-selagem",
            "descricao": "Selo do SITRAM (SEFAZ-CE) das notas de ENTRADA INTERESTADUAIS no Ceará, nota a nota. Selo existe porque a mercadoria cruzou a divisa: nota emitida no próprio Ceará (a chave começa com 23) NÃO é selada, e só NF-e (modelo 55, posições 21-22 da chave) entra — das 395.068 notas seladas, 395.068 são modelo 55. `status`: SELADA (tem selo), SEM_SELO (consultada, a SEFAZ não selou), PENDENTE (ainda não consultada), ANULADA (empresa inativa ou não habilitada para SITRAM). É AQUI que se lê o resultado de POST /consultar — aquele é assíncrono.",
            "filtros": "chave, cnpj, competencia (AAAAMM), status, page, per_page",
            "escopo": "fiscal.selagem.read"
        },
        {
            "metodo": "POST",
            "caminho": "/v1/fiscal/sitram-selagem/consultar",
            "descricao": "Pede que a AccordBI consulte o selo na SEFAZ-CE. Corpo: {\"chaves\": [\"35260...\", \"32260...\"]}, até 500 por chamada. Responde 202: o selo NÃO vem nesta resposta — leia em GET /v1/fiscal/sitram-selagem alguns minutos depois. Chave consultada há menos de 15 minutos é ignorada (campo `em_cooldown`): a SEFAZ não muda de resposta nesse intervalo e o endereço com rota até ela é um só. A consulta traz o selo de quem a SEFAZ JÁ selou; ela nunca PEDE selagem — nota que voltar sem selo precisa de pedido, que não se faz por esta API. Chaves não elegíveis voltam em `recusadas`, com o motivo.",
            "escopo": "fiscal.selagem.consultar"
        },
        {
            "metodo": "POST",
            "caminho": "/v1/fiscal/sitram-selagem/resultado",
            "descricao": "Grava o resultado de uma consulta de selagem que VOCÊ fez na SEFAZ. Obrigatório só `chave_acesso` (44 dígitos, sem máscara). Com `selo`, a nota passa a \"Selada\" no painel. SEM `selo` é resultado legítimo (\"consultei e não tem\"): registra a consulta e a nota vira \"Sem selo\" — não se cria linha de nota selada que a SEFAZ não confirmou. Campos aceitos, todos opcionais: emitente_cnpj, emitente_nome, destinatario_cgf, destinatario_nome, cnpj_empresa, numero_nfe, data_emissao (AAAA-MM-DD), valor_nf, situacao, uf_origem, uf_destino, transportadora, numero_acao_fiscal, situacao_acao_fiscal, data_hora_acao_fiscal. Não mande CNPJ_EMITENTE, NOME_EMITENTE, IE_DESTINATARIO, NOME_DESTINATARIO nem AnoMes: o banco os deriva sozinho da chave e dos nomes acima.",
            "escopo": "fiscal.selagem.write"
        },
        {
            "metodo": "GET",
            "caminho": "/v1/fiscal/tributacao-ncm",
            "descricao": "Classificação de PIS/COFINS por NCM. Tabela própria da Accord, nacional e igual para todas as ECs — não é dado do ERP do cliente, por isso é leitura direta (não passa pela fila de /v1/fiscal/solicitar).",
            "filtros": "ncm (prefixo), categoria (busca textual), page, per_page",
            "escopo": "fiscal.read"
        },
        {
            "metodo": "GET",
            "caminho": "/v1/fiscal/{assunto}",
            "descricao": "Serve a extração fiscal já concluída. Quem tem contabil.read NÃO alcança isto, e a recíproca também vale. Em apuracao-simples, filtre a coluna `linha` antes de somar: cada competência tem uma linha `total` e as linhas `detalhe` por anexo, e somar as duas dobra o DAS. Escritório no ERP Fortes: quando o código da sua empresa não é o código dela no ERP, a extração localiza a empresa pelo CNPJ do cadastro e a resposta traz `resolucao_empresa` (`metodo`, `cnpj`, `emp_fortes`, `est_fortes` e, se houver, `fichas_desativadas_mesmo_cnpj`) — sem essa chave, nenhuma tradução foi feita. Ficha desativada listada ali = dado ANTERIOR ao recadastro da empresa no ERP pode estar nela e NÃO vem no arquivo: zero linhas num ano antigo não prova ausência de movimento. ⚡ RELEITURA BARATA: a resposta traz `ETag` (e `meta.versao`). Guarde e mande de volta em `If-None-Match` na próxima leitura: se o conteúdo não mudou, você recebe 304 SEM CORPO e não paga a transferência de novo. É como descobrir que algo mudou sem reler o arquivo inteiro.",
            "filtros": "empresa (obrigatória), ano (obrigatório), mes",
            "escopo": "fiscal.read"
        },
        {
            "metodo": "GET",
            "caminho": "/v1/fiscal/solicitacoes",
            "descricao": "Fila das extrações fiscais. Só assuntos fiscais aparecem aqui. Pedido ABERTO traz `fila`: `na_frente` (quantos protocolos serão atendidos antes dele) e `previsao_min` (pela vazão medida nas últimas 2h). Status parado com `na_frente` alto é FILA, não falha — repetir o pedido põe uma cópia no fim e atrasa o resto. `mensagem` (só em Erro/Invalido) é escrita para você e diz de quem é a ação: erro do PEDIDO (parâmetro faltando ou mal formado, ano/mês/data inválidos, empresa inválida) diz o que corrigir — corrija e faça um pedido NOVO; ASSUNTO indisponível para o sistema contábil do escritório diz que repetir não resolve; CADASTRO do escritório (conexão com o ERP, máquina de extração, credencial recusada) diz que repetir não resolve e que o responsável pelo portal precisa agir. O que não se encaixa nisso vem como \"Não conseguimos concluir este pedido. O detalhe ficou registrado para a nossa equipe.\" — sem detalhe técnico; não tente interpretar nem contornar, e não peça em laço.",
            "filtros": "protocolo, assunto, empresa, abertas, status (Solicitado|Processando|Concluido|Erro|Invalido)",
            "escopo": "fiscal.read"
        },
        {
            "metodo": "GET",
            "caminho": "/v1/uso-sistema/modulos",
            "descricao": "De-para do código do módulo do Domínio para o nome (1=Contabilidade, 5=Escrita Fiscal, 12=Folha de Pagamento...).",
            "escopo": "custo.uso.read"
        },
        {
            "metodo": "GET",
            "caminho": "/v1/honorarios",
            "descricao": "O que foi faturado e recebido de cada cliente, por mês. A outra metade da margem: /v1/uso-sistema dá o custo, este dá a receita. 🔴 NÃO junte as duas séries pelo campo \"empresa\": aqui ele é a EMISSORA (o escritório, e vem constante em todas as linhas), enquanto em /v1/uso-sistema é o CLIENTE. Junte por \"inscricao\" (o CNPJ) contra o \"cnpj\" de /v1/empresas, e de lá pegue o \"codigo_dominio\" para casar com /v1/uso-sistema. A resposta repete esse aviso em meta.ligacao — até 02/09/2026 esta descrição dizia o oposto, e um cliente montou o ETL pelo texto antes de ler o meta: o join saía errado sem erro nenhum.",
            "filtros": "ano (obrigatório), mes, empresa (codi_emp), grupo_id",
            "escopo": "financeiro.honorarios.read"
        },
        {
            "metodo": "GET",
            "caminho": "/v1/paineis/{slug}/datasets/{dataset}",
            "descricao": "Conteúdo de um dataset de UPLOAD — para o preview mostrar um painel já publicado sem ter os arquivos à mão. Dataset gerado por \"consulta\" responde 403: o conteúdo dele vem de um assunto com escopo próprio, e devolvê-lo aqui contornaria esse escopo.",
            "escopo": "dataset.write"
        },
        {
            "metodo": "GET",
            "caminho": "/v1/paineis/ferramenta-preview",
            "descricao": "Baixa o script Python que pré-visualiza o painel NA MÁQUINA do autor, com o mesmo SDK do portal (Accord.dataset/salvarParametros/altura). Use ANTES de publicar: editar e dar F5 é muito mais rápido que o ciclo declarar/enviar/validar/publicar. Rode: python painel_preview.py --pasta . --dados uso=dados/uso.json",
            "escopo": "painel.read"
        },
        {
            "metodo": "POST",
            "caminho": "/v1/paineis",
            "descricao": "Declara o painel e seus datasets. A resposta traz \"painel_id\" e um bloco \"identidade\" pronto para você GRAVAR em .accordbi-painel.json na pasta do painel — no próximo deploy, envie esse painel_id e a API atualiza o mesmo painel, mesmo que o slug ou o nome mudem. Sem ele, a identidade é o slug: reenviar o mesmo slug atualiza, um slug novo cria um painel a mais (invisível para quem já tinha acesso). A resposta diz \"criado\": true/false — confira sempre.",
            "corpo": "painel_id (opcional, mas RECOMENDADO ao atualizar), slug, nome, datasets[]",
            "agendamento": "Cada dataset pode declarar \"consulta\" + \"frequencia\" (diaria, semanal ou mensal) + \"hora\" (HH:MM) e passa a se regenerar sozinho. Só vale para dataset que vem do NOSSO DW: dataset de upload é dado seu e só muda quando você reenviar. A janela 20:00-05:00 é recusada com 422 (backup e fechamento na máquina do escritório) — use 05:00 a 19:59; sem \"hora\" o padrão é 05:00. O agendador dispara de hora em hora, então os minutos não separam dois datasets. Teto de 300s por execução. Confira no endpoint /historico do dataset.",
            "escopo": "painel.write"
        },
        {
            "metodo": "POST",
            "caminho": "/v1/paineis/{slug}/datasets/{dataset}",
            "descricao": "Envia os dados de um dataset já declarado (multipart, campo \"arquivo\", JSON com lista de registros). Aceita também o arquivo comprimido em gzip (.json.gz) — recomendado: reduz cerca de 85% do envio. Cada envio cria uma versão nova do dado.",
            "escopo": "dataset.write"
        },
        {
            "metodo": "DELETE",
            "caminho": "/v1/paineis/{slug}/datasets/{dataset}",
            "descricao": "Remove um conjunto. Exige ?confirmar=1 — sem ele devolve 422 com linhas, versão e tamanho do que seria perdido, para a decisão ser tomada com o número na frente. Conjunto consumido pela versão publicada devolve 409: republique sem ele no manifest antes. Irreversível — apaga o arquivo do storage junto.",
            "escopo": "dataset.write"
        },
        {
            "metodo": "POST",
            "caminho": "/v1/paineis/validar",
            "descricao": "Prévia: roda a MESMA análise do envio e não grava nada — nem painel, nem versão, nem arquivo (multipart, campo \"arquivo\"). Devolve \"aprovaria\" com a lista de problemas (reprovam) e avisos (não reprovam, mas o painel funciona pior). Use antes do /pacote para iterar sem deixar versão morta no histórico a cada tentativa.",
            "escopo": "painel.write"
        },
        {
            "metodo": "POST",
            "caminho": "/v1/paineis/{slug}/pacote",
            "descricao": "Envia o pacote .zip do painel: HTML e bibliotecas, SEM dados dentro (multipart, campo \"arquivo\"). CONFIRA O SLUG: o pacote substitui o conteúdo do painel de destino. Se ele for idêntico ao de outro painel seu, a chamada é recusada com 409 pacote_de_outro_painel — sinal de slug trocado; só passa com ?confirmar=1.",
            "escopo": "painel.write"
        },
        {
            "metodo": "POST",
            "caminho": "/v1/paineis/{slug}/datasets/{dataset}/atualizar",
            "descricao": "Refaz o dataset AGORA a partir da \"consulta\" declarada no manifest (ex: uso-sistema?ano=2026) — sem reenviar arquivo. Mesmo caminho do agendador. Dataset de upload devolve 422: não há de onde regerar um arquivo que veio da máquina de alguém.",
            "escopo": "dataset.write"
        },
        {
            "metodo": "GET",
            "caminho": "/v1/paineis/{slug}/datasets/{dataset}/historico",
            "descricao": "Últimas 50 atualizações do dataset, COM as falhas. Depois de agendar, é aqui que se confere se a de ontem funcionou — o painel com dado velho não avisa que está velho. `mensagem` da falha é a frase que escrevemos para você (declare `empresa`, reduza o recorte, a carga já foi pedida); falha do nosso lado vem como \"A atualização deste conjunto falhou por um problema do nosso lado...\", sem detalhe técnico — o painel segue com a versão anterior.",
            "escopo": "painel.read"
        },
        {
            "metodo": "POST",
            "caminho": "/v1/paineis/{slug}/publicar",
            "descricao": "Promove a última versão enviada e coloca o painel no ar. Não torna o painel visível: o acesso é liberado por perfil no portal.",
            "escopo": "painel.write"
        }
    ],
    "escopos": [
        {
            "chave": "mensagens.write",
            "rotulo": "Mensagens — perguntar",
            "dado_pessoal": false
        },
        {
            "chave": "mensagens.read",
            "rotulo": "Mensagens — ler",
            "dado_pessoal": false
        },
        {
            "chave": "cadastro.grupos.read",
            "rotulo": "Grupos de empresas — leitura",
            "dado_pessoal": false
        },
        {
            "chave": "cadastro.grupos.write",
            "rotulo": "Grupos de empresas — criar",
            "dado_pessoal": false
        },
        {
            "chave": "cadastro.unidades.write",
            "rotulo": "Unidades de negócio — criar",
            "dado_pessoal": false
        },
        {
            "chave": "cadastro.empresas.read",
            "rotulo": "Empresas — leitura",
            "dado_pessoal": false
        },
        {
            "chave": "cadastro.unidades.read",
            "rotulo": "Unidades de negócio — leitura",
            "dado_pessoal": false
        },
        {
            "chave": "cadastro.usuarios.read",
            "rotulo": "Usuários — leitura",
            "dado_pessoal": false
        },
        {
            "chave": "cadastro.usuarios.pii.read",
            "rotulo": "Usuários — dados de contato (e-mail e telefone)",
            "dado_pessoal": true
        },
        {
            "chave": "painel.read",
            "rotulo": "Painéis — leitura",
            "dado_pessoal": false
        },
        {
            "chave": "painel.write",
            "rotulo": "Painéis — publicar",
            "dado_pessoal": false
        },
        {
            "chave": "perfil.read",
            "rotulo": "Perfis de acesso — leitura",
            "dado_pessoal": false
        },
        {
            "chave": "perfil.write",
            "rotulo": "Perfis de acesso — conceder e revogar",
            "dado_pessoal": false
        },
        {
            "chave": "contabil.read",
            "rotulo": "Contabilidade — ler extrações",
            "dado_pessoal": false
        },
        {
            "chave": "contabil.solicitar",
            "rotulo": "Contabilidade — pedir extração",
            "dado_pessoal": false
        },
        {
            "chave": "folha.read",
            "rotulo": "Folha — ler extrações",
            "dado_pessoal": true
        },
        {
            "chave": "folha.solicitar",
            "rotulo": "Folha — pedir extração",
            "dado_pessoal": false
        },
        {
            "chave": "fiscal.read",
            "rotulo": "Fiscal — ler extrações",
            "dado_pessoal": false
        },
        {
            "chave": "fiscal.solicitar",
            "rotulo": "Fiscal — pedir extração",
            "dado_pessoal": false
        },
        {
            "chave": "fiscal.selagem.read",
            "rotulo": "Selagem SITRAM — ler",
            "dado_pessoal": false
        },
        {
            "chave": "fiscal.selagem.consultar",
            "rotulo": "Selagem SITRAM — consultar a SEFAZ",
            "dado_pessoal": false
        },
        {
            "chave": "fiscal.selagem.write",
            "rotulo": "Selagem SITRAM — gravar resultado",
            "dado_pessoal": false
        },
        {
            "chave": "custo.uso.read",
            "rotulo": "Auditoria de Acesso ERP — tempo por cliente",
            "dado_pessoal": false
        },
        {
            "chave": "custo.uso.solicitar",
            "rotulo": "Auditoria de Acesso ERP — pedir extração",
            "dado_pessoal": false
        },
        {
            "chave": "custo.valores.read",
            "rotulo": "Auditoria de Acesso ERP — custo em reais",
            "dado_pessoal": true
        },
        {
            "chave": "financeiro.honorarios.read",
            "rotulo": "Honorários — faturado e recebido",
            "dado_pessoal": false
        },
        {
            "chave": "dataset.write",
            "rotulo": "Dados dos painéis — enviar",
            "dado_pessoal": false
        }
    ],
    "paginacao": {
        "parametros": [
            "page",
            "per_page"
        ],
        "per_page_padrao": 50,
        "per_page_maximo": 100,
        "resposta": [
            "data",
            "total",
            "page",
            "per_page",
            "paginas"
        ],
        "dica": "Peça só as páginas que for usar; a resposta traz \"total\" para você decidir."
    },
    "erros": {
        "401 formato_invalido": "Header Authorization ausente ou fora do formato.",
        "401 token_invalido": "Token inexistente ou incorreto.",
        "401 token_revogado": "Token revogado no portal. Peça um novo ao usuário.",
        "401 token_expirado": "Token vencido. Peça um novo ao usuário.",
        "403 ec_no_request": "Você enviou o identificador da empresa contábil (ec_id ou variação). Remova — a empresa vem do token.",
        "403 escopo_ausente": "O token não tem permissão para este recurso. O usuário pode gerar outro com o escopo necessário.",
        "403 origem_nao_autorizada": "Só ocorre em token marcado como de máquina (endereço fixo): a chamada veio de outro endereço. O usuário autoriza em Minha Conta > API. Token de pessoa não sofre este bloqueio.",
        "403 token de unidade": "Criar grupo de empresa ou unidade de negócio exige token de EMPRESA CONTÁBIL. Este token está restrito a uma unidade e alcança só os dados dela. Não insista com o mesmo token — peça ao responsável pelo escritório um token de EC com o escopo de escrita.",
        "404 grupo inexistente": "O grupo_id informado não é deste escritório. Liste em GET /v1/grupos-empresas e use um id de lá, ou crie o grupo primeiro. É 404 e não 403 de propósito: grupo de outro escritório não existe para você.",
        "409 cnpj ja tem unidade": "O CNPJ já tem unidade de negócio neste escritório, em outro grupo. A resposta traz o id dela: USE essa unidade em vez de criar outra. Para saber antes, consulte GET /v1/unidades-negocio?cnpj=. Duas unidades com o mesmo CNPJ significam dois lugares de login para o mesmo cliente, com conteúdos diferentes — se for mesmo isso que você quer, é decisão do escritório e se faz no portal.",
        "409 criado no portal": "Já existe grupo com essa descrição (ou unidade com esse CNPJ no grupo), criado por uma PESSOA no portal. A API administra apenas o que ela mesma criou, para não adotar cadastro alheio. Use o registro existente pelo id, escolha outro nome, ou peça ao escritório para ajustá-lo na tela.",
        "422 origem_ceara": "A nota foi emitida no Ceará (a chave de acesso começa com 23). Selo do SITRAM é do trânsito INTERESTADUAL — operação interna não passa por posto fiscal e não recebe selo. Não reenvie esta chave: nenhuma consulta vai produzir selo para ela.",
        "422 modelo_nao_selavel": "Só NF-e (modelo 55, posições 21 e 22 da chave) é selada. NFC-e (65) é venda a consumidor e CT-e (57) é transporte — nenhum dos dois entra na selagem. Confira se a chave é de NF-e antes de reenviar.",
        "200 ja_selada": "Só em `recusadas` do POST /v1/fiscal/sitram-selagem/consultar: a nota JÁ tem selo, e a mensagem traz o número. Consultar de novo devolveria o mesmo valor e gastaria o único endereço com rota até a SEFAZ. Leia o selo em GET /v1/fiscal/sitram-selagem; não reenvie a chave.",
        "422 chave_invalida": "A chave de acesso tem exatamente 44 dígitos numéricos, sem pontos, espaços ou máscara. Remova a formatação e reenvie.",
        "403 chave_de_outra_ec": "Esta chave já está na fila de selagem de OUTRA empresa contábil. A tabela de selo é compartilhada e não tem coluna de empresa: gravar aqui reescreveria o painel do outro escritório. Confira se o token é o da empresa contábil dona da nota — não insista com este.",
        "409 pacote_de_outro_painel": "O pacote que você está enviando é byte a byte igual ao que já está publicado em OUTRO painel desta conta. Quase sempre significa slug errado no destino: publicar assim substitui o conteúdo do painel de destino pelo do outro, e quem tinha acesso ao primeiro passa a ver o segundo. A resposta traz painel_origem e painel_destino — confira qual você queria. Se a intenção é mesmo ter o mesmo conteúdo nos dois painéis, repita com ?confirmar=1. Reenviar o MESMO pacote no MESMO painel nunca cai aqui.",
        "413 dataset_grande": "Dataset acima do limite, considerando o tamanho DEPOIS de descomprimido.",
        "413 extracao_grande": "O arquivo existe e a extração está correta, mas não cabe numa resposta só. Refaça o pedido em fatias com limit/offset em \"parametros\", ou estreite por mes. A mensagem traz o comando pronto.",
        "422 limite pela API": "O escritório atingiu o teto de grupos ou de unidades criados PELA API (100 de cada). É freio de criação em rajada, não limite comercial: pare de criar e fale com a equipe da AccordBI se o escritório realmente precisa de mais. O que foi cadastrado por pessoas no portal NÃO entra nessa conta — um escritório com centenas de grupos na tela continua com os 100 disponíveis aqui.",
        "422 datasets.N.hora": "A \"hora\" do agendamento caiu entre 20:00 e 05:00, que é recusada: nesse intervalo rodam o backup e o fechamento na máquina do escritório, e a extração concorrendo atrasa as duas. Reenvie com uma hora entre 05:00 e 19:59 — 05:00 é a mais cedo que existe, e é o padrão se você omitir o campo. Nada foi criado pela metade: corrija e repita a chamada.",
        "422 datasets.N.frequencia": "A \"frequencia\" aceita só diaria, semanal ou mensal, em português e sem acento. Não existe frequência horária. Se o seu painel precisa de dado mais fresco que uma vez ao dia, chame /atualizar quando precisar, em vez de agendar.",
        "422 recurso não pode ser atualizado automaticamente": "Vem do endpoint /atualizar, não da criação: a \"consulta\" aponta para um assunto que não sabe se regenerar sozinho. A mensagem lista os disponíveis (hoje uso-sistema, empresas, honorarios). Os assuntos contábeis dependem de extração na máquina do cliente, que é fila e não consulta — peça a extração e reenvie o dataset quando ficar pronta. Dataset de upload nunca regenera: é dado seu.",
        "422 documento invalido (reforma-classtrib)": "O filtro `documento` aceita apenas nfe, nfce, cte ou nfse. Ele existe para você não oferecer, num documento, classificação que só vale para outro — o erro apareceria só na validação da SEFAZ.",
        "403 ec_inativa": "Empresa contábil inativa.",
        "403 recurso_exige_token_de_ec": "Este recurso só existe no nível da empresa contábil. Seu token é de unidade de negócio — peça ao usuário um token de empresa contábil se precisar dele. NÃO tente outra rota para o mesmo dado: a fronteira é do recurso, não do endpoint, e /v1/contabil responde igual para os assuntos da empresa contábil inteira.",
        "403 unidade_inconsistente": "A unidade de negócio do token não pertence mais à empresa contábil dele. Situação de cadastro: fale com o responsável pelo portal.",
        "405": "A API é somente leitura: use apenas GET.",
        "429 rate_limit": "Excedeu o limite de requisições por minuto DESTE TOKEN (60 por padrão). Espere o tempo do header Retry-After e repita — não descarte o 429 como anomalia, a requisição não chegou a ser processada.",
        "mensagem de pedido em Erro/Invalido": "Em /v1/{contabil,fiscal,folha}/solicitacoes, a `mensagem` diz de quem é a ação. Erro do PEDIDO (parâmetro obrigatório faltando ou mal formado, ano/mês/data inválidos, empresa inválida): diz o que corrigir — corrija e faça um pedido NOVO. ASSUNTO indisponível para o sistema contábil do escritório: repetir não resolve. CADASTRO do escritório (conexão com o ERP, máquina de extração, credencial recusada): repetir não resolve, o responsável pelo portal precisa agir. O resto vem como \"Não conseguimos concluir este pedido. O detalhe ficou registrado para a nossa equipe.\", sem detalhe técnico. Não peça em laço por causa dele."
    },
    "publicacao_de_painel": {
        "status": "disponivel",
        "fluxo": [
            "1. POST /v1/paineis — declare o painel e os datasets (com schema)",
            "2. POST /v1/paineis/{slug}/datasets/{id} — envie cada dataset (multipart). Comprima em gzip antes de enviar: mesmo conteúdo, ~85% menos tráfego. O pacote do painel (passo 3) já é um .zip — não comprima de novo.",
            "3. POST /v1/paineis/{slug}/pacote — envie o .zip do painel (multipart)",
            "4. Aguarde a validação: GET /v1/paineis mostra ultima_versao.status (recebida → validando → aprovada, ou rejeitada com o motivo)",
            "5. POST /v1/paineis/{slug}/publicar — coloque no ar (só versão aprovada)"
        ],
        "para_quem": "Cliente do escritório contábil que criou o próprio painel (HTML/JS) e quer publicá-lo na plataforma AccordBI.",
        "principio": "Separe DADOS de APRESENTAÇÃO, como um relatório e seu dataset. O painel publicado é somente leitura para os dados de fatos: ele não carrega arquivo do computador de quem visualiza e não usa localStorage como fonte de verdade.",
        "estrutura_do_projeto": {
            "manifest.json": "Declara o painel, os datasets e o schema de cada um.",
            "painel/index.html": "Apresentação. Sem dados embutidos e sem CDN externa.",
            "painel/libs/": "Bibliotecas usadas (Chart.js etc.) — enviadas junto.",
            "dados/<id>.json": "Um arquivo por dataset, já normalizado."
        },
        "exemplo_manifest": {
            "nome": "Financeiro",
            "versao": "1",
            "entrada": "painel/index.html",
            "datasets": [
                {
                    "id": "balancetes",
                    "arquivo": "dados/balancetes.json",
                    "schema": {
                        "competencia": "date",
                        "conta": "string",
                        "descricao": "string",
                        "saldo": "decimal"
                    },
                    "chave": [
                        "competencia",
                        "conta"
                    ],
                    "origem": "upload"
                },
                {
                    "id": "parametros",
                    "arquivo": "dados/parametros.json",
                    "editavel": true,
                    "schema": {
                        "meta_mensal": "decimal",
                        "departamento": "string"
                    }
                }
            ]
        },
        "por_que_declarar_schema": "Hoje o dataset vem do seu upload. Adiante o mesmo dataset poderá ser gerado pela AccordBI a partir da contabilidade, ou lido direto do seu ERP. Com o schema declarado, essa troca de origem não exige mudar o painel — sem ele, cada troca vira refação.",
        "como_o_painel_le_dados": {
            "codigo": "const linhas = await Accord.dataset(\"balancetes\")",
            "nota": "O objeto Accord é injetado pela plataforma. Não implemente autenticação: o painel roda isolado e nunca recebe token."
        },
        "como_o_painel_grava_parametros": {
            "codigo": "await Accord.salvarParametros({ meta_mensal: 150000 })",
            "nota": "Só datasets com \"editavel\": true aceitam gravação, e apenas para usuários com permissão de edição naquele painel. Toda alteração é auditada (quem, quando, valor anterior)."
        },
        "validacao_do_pacote": [
            "O pacote é verificado antes de poder ir ao ar. Se for rejeitado, o motivo aparece em ultima_versao.motivo_rejeicao — corrija e envie de novo.",
            "É rejeitado: script ou CSS de site externo, fetch/XMLHttpRequest/WebSocket/sendBeacon, tipo de arquivo fora da lista (só html, css, js, imagens e fontes), blob base64 gigante, pacote sem index.html e conteúdo descompactado grande demais."
        ],
        "proibido": [
            "Dados embutidos no HTML (const ds=[...]) — impedem atualizar sem republicar.",
            "localStorage como fonte de verdade — cada visitante veria números diferentes.",
            "<input type=\"file\"> — quem visualiza não carrega arquivo.",
            "Scripts de CDN externa — envie as bibliotecas em painel/libs/.",
            "Chamadas de rede para fora da plataforma — são bloqueadas.",
            "HTML dentro de HTML em base64 — publique cada painel separadamente."
        ],
        "limites": {
            "painel_mb": 10,
            "dataset_mb": 50,
            "datasets_por_painel": 20
        },
        "token_de_empresa_contabil": "Se o token for da empresa contábil (e não de uma unidade), informe unidade_negocio_id ao declarar o painel: é preciso dizer para qual unidade está publicando.",
        "quem_ve_o_painel": "Depois de publicado, o acesso é liberado por PERFIL no portal AccordBI (Minha Conta > Perfil de Usuário), do mesmo jeito que os relatórios. Publicar não torna o painel visível para ninguém por si só."
    },
    "extracao_de_dados": {
        "como_funciona": "Os dados são extraídos na máquina do próprio escritório (onde o ERP está), enviados para o armazenamento e ficam disponíveis como dataset. A extração roda de madrugada e também pode ser pedida sob demanda.",
        "assuntos": [
            {
                "assunto": "lancamentos_contabeis",
                "rotulo": "Lançamentos contábeis (Domínio)",
                "filtro_obrigatorio": "ec",
                "recortes": {
                    "ec+empresa": {
                        "permite": "base_completa",
                        "descricao": "Uma empresa: base completa, todos os períodos disponíveis."
                    },
                    "ec+grupo_empresa": {
                        "permite": "base_completa",
                        "descricao": "Grupo de empresas: base completa."
                    },
                    "ec": {
                        "permite": "anual",
                        "descricao": "Escritório inteiro: apenas o consolidado ANUAL. Base completa de todas as empresas de uma vez travaria a máquina do escritório."
                    }
                }
            },
            {
                "assunto": "contabil",
                "rotulo": "Contabilidade (Domínio ou outro ERP)",
                "filtro_obrigatorio": "empresa + ano",
                "recortes": {
                    "empresa+ano": {
                        "permite": "assunto_completo",
                        "descricao": "Uma empresa por vez. O ERP fica na máquina do escritório e a extração compete com o trabalho do dia — pedir o escritório inteiro de uma vez travaria a máquina."
                    }
                }
            },
            {
                "assunto": "uso_do_sistema",
                "rotulo": "Uso do sistema / custo de atendimento (Domínio)",
                "filtro_obrigatorio": "ano",
                "recortes": {
                    "ano+empresa": {
                        "permite": "diario",
                        "descricao": "Uma empresa: detalhe DIÁRIO por colaborador e módulo."
                    },
                    "ano+grupo_empresa": {
                        "permite": "mensal",
                        "descricao": "Grupo de empresas: consolidado MENSAL."
                    },
                    "ano": {
                        "permite": "mensal",
                        "descricao": "Escritório inteiro: consolidado MENSAL. O diário de todas as empresas passa de um milhão de linhas."
                    }
                }
            }
        ],
        "observacao": "Novos assuntos são acrescentados conforme entram em produção. Consulte este índice antes de montar o pedido."
    },
    "documentacao_markdown": "https://api.accordtecnologia.com.br/llms.txt",
    "skill": {
        "instalar": "https://api.accordtecnologia.com.br/skill.zip",
        "ler": "https://api.accordtecnologia.com.br/skill.md",
        "indice_das_skills": "accord-skills — vem dentro de qualquer pacote; instale junto e carregue quando não souber qual usar.",
        "especializadas": {
            "societario": "https://api.accordtecnologia.com.br/v1/skills/societario — O que precisa ser feito, e em que prazo, para abrir ou alterar esta empresa?",
            "analisebalancete": "https://api.accordtecnologia.com.br/v1/skills/analisebalancete — O que este balancete tem de errado ou estranho?",
            "analiseextrato": "https://api.accordtecnologia.com.br/v1/skills/analiseextrato — O extrato que recebi está completo e pronto para conciliar?",
            "analiselancamento": "https://api.accordtecnologia.com.br/v1/skills/analiselancamento — Estes lançamentos estão certos e bem suportados?",
            "analisenotas": "https://api.accordtecnologia.com.br/v1/skills/analisenotas — Estas notas podem ser escrituradas como estão?",
            "analiserelatorio": "https://api.accordtecnologia.com.br/v1/skills/analiserelatorio — Este diário ou razão está completo e consistente?",
            "apuracaomei": "https://api.accordtecnologia.com.br/v1/skills/apuracaomei — O MEI estourou o limite, e o que precisa ser feito agora?",
            "calculofolha": "https://api.accordtecnologia.com.br/v1/skills/calculofolha — Como calculo o holerite e o custo de um funcionário neste mês?",
            "conciliacaobancaria": "https://api.accordtecnologia.com.br/v1/skills/conciliacaobancaria — O saldo do banco bate com o razão, e o que explica a diferença?",
            "conciliacaocartoes": "https://api.accordtecnologia.com.br/v1/skills/conciliacaocartoes — As vendas no cartão caíram no banco, e quanto ficou de taxa?",
            "conciliacaoclientes": "https://api.accordtecnologia.com.br/v1/skills/conciliacaoclientes — O saldo de clientes no razão bate com os títulos em aberto?",
            "conciliacaofornecedores": "https://api.accordtecnologia.com.br/v1/skills/conciliacaofornecedores — O saldo de fornecedores bate, e há pagamento sem nota ou em duplicidade?",
            "conferenciaecf": "https://api.accordtecnologia.com.br/v1/skills/conferenciaecf — A ECF fecha com a contabilidade, e está pronta para transmitir?",
            "conferenciasimples": "https://api.accordtecnologia.com.br/v1/skills/conferenciasimples — A receita declarada no Simples bate com as notas emitidas?",
            "defesafiscal": "https://api.accordtecnologia.com.br/v1/skills/defesafiscal — Recebi um auto de infração — o que alego e em que prazo?",
            "dimob": "https://api.accordtecnologia.com.br/v1/skills/dimob — A DIMOB fecha com os contratos e os repasses do ano?",
            "dmed": "https://api.accordtecnologia.com.br/v1/skills/dmed — A DMED desta clínica fecha com as notas e os recebimentos do ano?",
            "dregerencial": "https://api.accordtecnologia.com.br/v1/skills/dregerencial — Como monto a DRE gerencial e quanto a empresa precisa vender para empatar?",
            "extratodominio": "https://api.accordtecnologia.com.br/v1/skills/extratodominio — Como transformo a conciliação revisada em arquivo para importar no sistema contábil?",
            "fechamentomensal": "https://api.accordtecnologia.com.br/v1/skills/fechamentomensal — O mês pode ser fechado, e o que ainda impede?",
            "fluxocaixa": "https://api.accordtecnologia.com.br/v1/skills/fluxocaixa — Vai faltar dinheiro nos próximos meses, e quando?",
            "ganhocapital": "https://api.accordtecnologia.com.br/v1/skills/ganhocapital — Quanto de imposto esta venda gera, e até quando pagar?",
            "icmsst": "https://api.accordtecnologia.com.br/v1/skills/icmsst — O ICMS-ST e o DIFAL desta operação estão calculados certo?",
            "imobilizado": "https://api.accordtecnologia.com.br/v1/skills/imobilizado — A depreciação está certa e o imobilizado bate com o controle?",
            "irpf": "https://api.accordtecnologia.com.br/v1/skills/irpf — A declaração de IR deste cliente está certa, e qual regra de ano se aplica?",
            "lancamentospadrao": "https://api.accordtecnologia.com.br/v1/skills/lancamentospadrao — Qual o lançamento certo para este fato, no plano de contas desta empresa?",
            "obrigacoesfederais": "https://api.accordtecnologia.com.br/v1/skills/obrigacoesfederais — A DCTFWeb do mês fecha com a folha, as retenções e os tributos apurados?",
            "parecercontabil": "https://api.accordtecnologia.com.br/v1/skills/parecercontabil — Como redijo um parecer contábil que se sustente perante terceiros?",
            "piscofinscumulativo": "https://api.accordtecnologia.com.br/v1/skills/piscofinscumulativo — O PIS e a COFINS do Presumido estão com a base certa?",
            "planocontas": "https://api.accordtecnologia.com.br/v1/skills/planocontas — O plano de contas desta empresa está bem montado e amarrado ao referencial?",
            "reformatributaria": "https://api.accordtecnologia.com.br/v1/skills/reformatributaria — O que a reforma tributária exige deste cliente, e até quando?",
            "regimetributario": "https://api.accordtecnologia.com.br/v1/skills/regimetributario — Qual regime tributário custa menos para esta empresa?",
            "rendavariavel": "https://api.accordtecnologia.com.br/v1/skills/rendavariavel — Quanto de imposto o investidor deve na bolsa este mês?",
            "zeramentodominio": "https://api.accordtecnologia.com.br/v1/skills/zeramentodominio — Como encerro o exercício e zero as contas de resultado sem duplicar?",
            "auditafolha": "https://api.accordtecnologia.com.br/v1/skills/auditafolha — A folha bate com as guias, e o que auditar no departamento pessoal? Traz o painel pronto.",
            "movimentacaofiscal": "https://api.accordtecnologia.com.br/v1/skills/movimentacaofiscal — Quanto entrou e saiu, e qual a carga tributária da carteira? Traz o painel pronto.",
            "resultadocontabil": "https://api.accordtecnologia.com.br/v1/skills/resultadocontabil — Como estão o resultado, o balanço e os indicadores desta empresa? Traz o painel pronto.",
            "rh": "https://api.accordtecnologia.com.br/v1/skills/rh — Como estão o quadro, a movimentação e o custo por área? Traz o painel pronto."
        },
        "o_que_vem_em_cada_uma": "Sempre SKILL.md com o método de trabalho e as referências. As de PAINEL trazem também o atualizador de dataset em Node (pede, converte e publica) e o painel completo já publicado em produção — HTML, CSS, JS, fontes e ícones: você troca os dados, não a tela. As de MÉTODO (cálculo, apuração, redação técnica) não trazem painel: trazem o roteiro, as tabelas vigentes com a fonte e o que conferir antes de entregar um número. A descrição de cada uma diz qual é qual. Formato: .zip. Exige painel.read.",
        "como": "Extraia o zip em .claude/skills/ (Claude Code) ou leia o .md. Traz o método que evita os erros que já custaram retrabalho a outros escritórios: quando vazio não é vazio, por que não reconstruir o que o sistema já apurou, e o que conferir antes de publicar um número. Peça a decisão de instalar a quem for dono do repositório — o arquivo fica versionado lá."
    },
    "suporte": "suporte@grupoaccord.com.br"
}