Skip to content

Apoiar o projeto

Seu apoio ajuda a manter este projeto. As contribuições ajudam a custear a infraestrutura, manter a documentação e dedicar tempo a correções, testes e melhorias. Qualquer valor é bem-vindo.

QR Code Pix para apoiar o projeto, com valor livre. O mesmo código está disponível no campo Pix Copia e Cola abaixo.

Pix com valor livre

RecebedorMILTON COSME DA SILVA JUN

Confira o recebedor e escolha o valor no aplicativo do seu banco.

Seu primeiro XML offline ​

Neste guia você cria nota-teste.xml no seu computador. O exemplo usa dados sintéticos, não usa certificado e não transmite a nota. Assim você confere a instalação e conhece a estrutura do ACBr.

Antes, conclua a instalação.

1. Baixe o exemplo completo ​

Salve primeiro-xml.mjs na pasta do projeto, ao lado do package.json. Esse arquivo já inclui todos os dados sintéticos usados na geração.

Há também uma versão TypeScript, com satisfies TNFeInput. A versão .mjs é a opção para executar diretamente no Node.js.

2. Execute ​

sh
node primeiro-xml.mjs

Você deve ver:

text
XML sintético salvo em nota-teste.xml. Estado: XML_GERADO

Abra o arquivo nota-teste.xml no editor. Ele contém o XML gerado pelo motor instalado, incluindo a identidade sintética e o texto TESTE OFFLINE.

3. Entenda a chamada ​

O arquivo importa criarEmissor e TNFe. Após definir o objeto nota, executa:

js
const emissor = criarEmissor({
  cnpj: '11222333000181',
  uf: 'CE',
  modelo: 55,
  ambiente: 2
});

try {
  const resultado = await emissor.gerarXml(new TNFe(nota));
  if (!resultado.sucesso || !resultado.xmlBase64) {
    throw new Error(resultado.codigo ?? resultado.xMotivo ?? resultado.estado);
  }
  await writeFile('./nota-teste.xml', Buffer.from(resultado.xmlBase64, 'base64'));
  console.log('XML sintético salvo em nota-teste.xml. Estado:', resultado.estado);
} finally {
  await emissor.fechar();
}

criarEmissor configura o emitente. new TNFe(nota) organiza os dados com os modelos gerados. gerarXml devolve um resultado que precisa ser conferido antes de salvar o arquivo. fechar() encerra a instância, inclusive quando ocorre uma falha.

O XML vem em xmlBase64. Buffer.from(..., 'base64') recupera os bytes originais para gravar UTF-8 sem alteração.

Os dados do exemplo ​

Ver o objeto completo da nota sintética
js
const nota = {
  "infNFe": {
    "Versao": "4.00"
  },
  "Ide": {
    "cUF": 23,
    "cNF": 12345678,
    "natOp": "VENDA TESTE OFFLINE",
    "modelo": 55,
    "serie": 1,
    "nNF": 1,
    "dEmi": "2026-10-08T12:00:00",
    "tpNF": "tnSaida",
    "idDest": "doInterna",
    "cMunFG": 2304400,
    "tpImp": "tiRetrato",
    "tpEmis": "teNormal",
    "tpAmb": "taHomologacao",
    "finNFe": "fnNormal",
    "indFinal": "cfConsumidorFinal",
    "indPres": "pcPresencial",
    "procEmi": "peAplicativoContribuinte",
    "verProc": "ACBR-NODE-OFFLINE"
  },
  "Emit": {
    "CNPJCPF": "11222333000181",
    "xNome": "Café São José TESTE OFFLINE SEM VALOR FISCAL",
    "IE": "123456789",
    "CRT": "crtSimplesNacional",
    "EnderEmit": {
      "xLgr": "RUA TESTE",
      "nro": "1",
      "xBairro": "TESTE",
      "cMun": 2304400,
      "xMun": "FORTALEZA",
      "UF": "CE",
      "CEP": 60000000,
      "cPais": 1058,
      "xPais": "BRASIL"
    }
  },
  "Dest": {
    "CNPJCPF": "12345678909",
    "xNome": "NF-E EMITIDA EM AMBIENTE DE HOMOLOGACAO - SEM VALOR FISCAL",
    "indIEDest": "inNaoContribuinte",
    "EnderDest": {
      "xLgr": "RUA TESTE",
      "nro": "2",
      "xBairro": "TESTE",
      "cMun": 2304400,
      "xMun": "FORTALEZA",
      "UF": "CE",
      "CEP": 60000000,
      "cPais": 1058,
      "xPais": "BRASIL"
    }
  },
  "Det": [
    {
      "Prod": {
        "nItem": 1,
        "cProd": "TESTE",
        "cEAN": "SEM GTIN",
        "xProd": "Café São José PRODUTO SINTÉTICO OFFLINE",
        "NCM": "22021000",
        "CFOP": "5102",
        "uCom": "UN",
        "qCom": "1",
        "vUnCom": "10",
        "vProd": "10",
        "cEANTrib": "SEM GTIN",
        "uTrib": "UN",
        "qTrib": "1",
        "vUnTrib": "10",
        "IndTot": "itSomaTotalNFe"
      },
      "Imposto": {
        "ICMS": {
          "orig": "oeNacional",
          "CSOSN": "csosn102"
        },
        "PIS": {
          "CST": "pis07"
        },
        "COFINS": {
          "CST": "cof07"
        }
      }
    }
  ],
  "Total": {
    "ICMSTot": {
      "vProd": "10",
      "vNF": "10"
    }
  },
  "Transp": {
    "modFrete": "mfSemFrete"
  },
  "pag": [
    {
      "tPag": "fpDinheiro",
      "indPag": "ipVista",
      "vPag": "10"
    }
  ]
};

Os nomes têm a mesma grafia do ACBr: Ide, Emit, Dest, Det, Total, Transp e pag. Valores como qCom, vProd e vNF são strings decimais. A data é uma string civil ISO; o motor escreve o fuso da UF no XML.

NCM, CFOP, CSOSN, CST e totais deste documento são dados sintéticos para aprender a estrutura. Eles não definem a tributação correta de uma venda.

O que você concluiu ​

Você verificou a importação e a execução do motor, e gerou um XML sem rede. O arquivo ainda não está assinado nem autorizado. A validação de schema de uma NF-e completa exige a assinatura; chamar validar neste XML sem assinatura não equivale ao fluxo completo.

Ambiente 2

ambiente: 2 significa homologação, não um simulador local. Métodos de transmissão e consulta usam serviços fiscais. O exemplo permanece offline porque chama apenas gerarXml.

O próximo passo é entender certificado A1 e assinatura.

Projeto independente · gratuito · LGPL-2.1-or-later