{"id":40014662,"url":"https://github.com/nfe/client-nodejs","last_synced_at":"2026-04-26T03:01:18.125Z","repository":{"id":23055851,"uuid":"26409130","full_name":"nfe/client-nodejs","owner":"nfe","description":"Official NFe.io API Client for Node.js","archived":false,"fork":false,"pushed_at":"2026-04-26T01:13:59.000Z","size":1045,"stargazers_count":129,"open_issues_count":0,"forks_count":27,"subscribers_count":12,"default_branch":"master","last_synced_at":"2026-04-26T01:22:06.965Z","etag":null,"topics":["javascript","nfe","nfse","nfse-nacional","nota-fiscal-eletronica"],"latest_commit_sha":null,"homepage":"http://nfe.io","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nfe.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2014-11-09T21:03:57.000Z","updated_at":"2026-04-25T23:47:23.000Z","dependencies_parsed_at":"2022-07-12T16:07:32.315Z","dependency_job_id":null,"html_url":"https://github.com/nfe/client-nodejs","commit_stats":null,"previous_names":["nfeio/client-nodejs"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/nfe/client-nodejs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nfe%2Fclient-nodejs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nfe%2Fclient-nodejs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nfe%2Fclient-nodejs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nfe%2Fclient-nodejs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nfe","download_url":"https://codeload.github.com/nfe/client-nodejs/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nfe%2Fclient-nodejs/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32284333,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-25T18:29:39.964Z","status":"online","status_checked_at":"2026-04-26T02:00:05.962Z","response_time":129,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["javascript","nfe","nfse","nfse-nacional","nota-fiscal-eletronica"],"created_at":"2026-01-19T03:03:08.116Z","updated_at":"2026-04-26T03:01:18.117Z","avatar_url":"https://github.com/nfe.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# NFE.io SDK para Node.js (v3)\n\n[![npm version](https://img.shields.io/npm/v/nfe-io.svg)](https://www.npmjs.com/package/nfe-io)\n[![Node.js Version](https://img.shields.io/node/v/nfe-io.svg)](https://nodejs.org)\n[![TypeScript](https://img.shields.io/badge/TypeScript-5.3-blue.svg)](https://www.typescriptlang.org/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\n**SDK Oficial NFE.io para Node.js 18+** - SDK TypeScript moderno para emissão de notas fiscais de serviço eletrônicas (NFS-e).\n\n\u003e ✨ **Versão 3.0** - Reescrita completa com TypeScript, zero dependências em runtime e API moderna async/await.\n\n## 📋 Índice\n\n- [Recursos](#-recursos)\n- [Instalação](#-instalação)\n- [Início Rápido](#-início-rápido)\n- [Documentação](#-documentação)\n- [Migração da v2](#-migração-da-v2)\n- [Exemplos](#-exemplos)\n- [Referência da API](#-referência-da-api)\n- [Contribuindo](#-contribuindo)\n- [Licença](#-licença)\n\n## ✨ Recursos\n\n- 🎯 **TypeScript Moderno** - Segurança de tipos completa com TypeScript 5.3+\n- 🚀 **Zero Dependências** - Usa API fetch nativa do Node.js (Node 18+)\n- ⚡ **Async/Await** - API limpa baseada em promises\n- 🔄 **Retry Automático** - Lógica de retry com exponential backoff integrada\n- 📦 **ESM \u0026 CommonJS** - Funciona com ambos os sistemas de módulos\n- 🧪 **Bem Testado** - Mais de 80 testes com 88% de cobertura\n- 📖 **JSDoc Completo** - Documentação completa da API\n- 🛡️ **Tratamento de Erros** - Classes de erro tipadas para melhor tratamento\n\n## 📦 Instalação\n\n**Requisitos:**\n- Node.js \u003e= 18.0.0\n- TypeScript \u003e= 5.0 (se usar TypeScript)\n\n```bash\nnpm install nfe-io\n```\n\nou\n\n```bash\nyarn add nfe-io\n```\n\nou\n\n```bash\npnpm add nfe-io\n```\n\n## 🚀 Início Rápido\n\n### ⚡ Setup Rápido para Testes\n\n```bash\n# 1. Clone e instale\ngit clone https://github.com/nfe/client-nodejs.git\ncd client-nodejs\nnpm install\n\n# 2. Configure suas credenciais (interativo)\nnpm run examples:setup\n\n# 3. Teste a conexão\nnpm run examples:test\n\n# 4. Execute os exemplos\nnpm run examples\n```\n\n### 📦 Instalação em Projeto Novo\n\n```bash\nnpm install nfe-io\n```\n\n### Uso Básico (ESM)\n\n```typescript\nimport { NfeClient } from 'nfe-io';\n\n// Inicializar o cliente\nconst nfe = new NfeClient({\n  apiKey: 'sua-chave-api',\n  environment: 'production' // ou 'development'\n});\n\n// Criar uma empresa\nconst empresa = await nfe.companies.create({\n  federalTaxNumber: '12345678000190',\n  name: 'Minha Empresa Ltda',\n  email: 'empresa@exemplo.com.br',\n  taxRegime: 1, // Simples Nacional\n  address: {\n    country: 'BRA',\n    postalCode: '01310-100',\n    street: 'Av. Paulista',\n    number: '1578',\n    city: { code: '3550308', name: 'São Paulo' },\n    state: 'SP'\n  }\n});\n\n// Emitir uma nota fiscal de serviço\nconst notaFiscal = await nfe.serviceInvoices.create(empresa.id, {\n  cityServiceCode: '01234',\n  description: 'Serviços de desenvolvimento web',\n  servicesAmount: 1000.00,\n  borrower: {\n    type: 'LegalEntity',\n    federalTaxNumber: 12345678000190,\n    name: 'Empresa Cliente',\n    email: 'cliente@exemplo.com.br',\n    address: {\n      country: 'BRA',\n      postalCode: '01310-100',\n      street: 'Av. Paulista',\n      number: '1000',\n      city: { code: '3550308', name: 'São Paulo' },\n      state: 'SP'\n    }\n  }\n});\n\nconsole.log(`Nota fiscal criada: ${notaFiscal.number}`);\n```\n\n### Uso com CommonJS\n\n```javascript\nconst { NfeClient } = require('nfe-io');\n\nconst nfe = new NfeClient({\n  apiKey: process.env.NFE_API_KEY,\n  environment: 'production'\n});\n\n// Mesma API que ESM\n```\n\n## 📚 Documentação\n\n### Recursos da API\n\nO SDK fornece os seguintes recursos:\n\n#### 🧾 Notas Fiscais de Serviço (`nfe.serviceInvoices`)\n\nGerenciar NFS-e (Nota Fiscal de Serviço Eletrônica):\n\n```typescript\n// ⭐ RECOMENDADO: Criar e aguardar conclusão (lida com processamento assíncrono)\nconst notaFiscal = await nfe.serviceInvoices.createAndWait(empresaId, {\n  borrower: {\n    federalTaxNumber: 12345678901,\n    name: 'João da Silva',\n    email: 'joao@example.com',\n  },\n  cityServiceCode: '10677',\n  description: 'Serviços de consultoria',\n  servicesAmount: 1500.00,\n}, {\n  pollingInterval: 2000,  // Verificar a cada 2 segundos\n  maxWaitTime: 60000,     // Aguardar até 60 segundos\n});\n\nconsole.log(`✅ Nota fiscal emitida: ${notaFiscal.number}`);\n\n// Criar nota fiscal manualmente (retorna 201 imediato ou 202 async)\nconst result = await nfe.serviceInvoices.create(empresaId, dadosNota);\n\n// Verificar se é síncrono (201) ou assíncrono (202)\nif ('id' in result) {\n  // Síncrono - nota emitida imediatamente\n  console.log('Nota emitida:', result.number);\n} else {\n  // Assíncrono - requer polling\n  console.log('Processando:', result.flowStatus);\n  // Use createAndWait() ou pollUntilComplete() em vez disso\n}\n\n// Listar notas fiscais com filtros\nconst notas = await nfe.serviceInvoices.list(empresaId, {\n  pageCount: 50,\n  pageIndex: 0,\n  searchPeriod: {\n    startDate: '2024-01-01',\n    endDate: '2024-01-31',\n  },\n});\n\n// Buscar nota fiscal específica\nconst nota = await nfe.serviceInvoices.retrieve(empresaId, notaFiscalId);\n\n// Verificar status de processamento\nconst status = await nfe.serviceInvoices.getStatus(empresaId, notaFiscalId);\nconsole.log(`Status: ${status.status}, Completo: ${status.isComplete}`);\n\n// Cancelar nota fiscal\nconst notaCancelada = await nfe.serviceInvoices.cancel(empresaId, notaFiscalId);\n\n// Enviar nota fiscal por email\nawait nfe.serviceInvoices.sendEmail(empresaId, notaFiscalId, {\n  emails: ['cliente@example.com', 'financeiro@example.com'],\n});\n\n// Baixar PDF (single ou bulk)\nconst pdfBuffer = await nfe.serviceInvoices.downloadPdf(empresaId, notaFiscalId);\nfs.writeFileSync('nota.pdf', pdfBuffer);\n\n// Baixar todas as notas como ZIP\nconst zipBuffer = await nfe.serviceInvoices.downloadPdf(empresaId);\nfs.writeFileSync('todas-notas.zip', zipBuffer);\n\n// Baixar XML\nconst xmlBuffer = await nfe.serviceInvoices.downloadXml(empresaId, notaFiscalId);\nfs.writeFileSync('nota.xml', xmlBuffer);\n\n// Criar múltiplas notas em lote (batch)\nconst notasData = [/* ... array de dados de notas ... */];\nconst notas = await nfe.serviceInvoices.createBatch(empresaId, notasData, {\n  waitForComplete: true,  // Aguardar todas completarem\n  maxConcurrent: 5,       // Processar 5 por vez\n});\n\nconsole.log(`✅ ${notas.length} notas fiscais criadas em lote`);\n```\n\n**Recursos Avançados:**\n\n- ⏱️ **Polling Automático**: `createAndWait()` lida automaticamente com processamento assíncrono\n- 📦 **Criação em Lote**: `createBatch()` cria múltiplas notas com controle de concorrência\n- 📥 **Downloads Bulk**: Baixe todas as notas como ZIP (PDF ou XML)\n- 🔍 **Verificação de Status**: `getStatus()` verifica se nota completou processamento\n- 🎯 **Discriminated Unions**: TypeScript detecta automaticamente tipo de resposta (201 vs 202)\n\n---\n\n#### 🏢 Empresas (`nfe.companies`)\n\nGerenciar empresas na sua conta:\n\n```typescript\n// Criar empresa\nconst empresa = await nfe.companies.create({\n  federalTaxNumber: '12345678000190',\n  name: 'Nome da Empresa',\n  // ... outros campos\n});\n\n// Listar todas as empresas\nconst empresas = await nfe.companies.list();\n\n// Buscar empresa específica\nconst empresa = await nfe.companies.retrieve(empresaId);\n\n// Atualizar empresa\nconst atualizada = await nfe.companies.update(empresaId, {\n  email: 'novoemail@empresa.com.br'\n});\n\n// Upload de certificado digital\nawait nfe.companies.uploadCertificate(empresaId, {\n  file: certificadoBuffer,\n  password: 'senha-certificado'\n});\n```\n\n#### 👔 Pessoas Jurídicas (`nfe.legalPeople`)\n\nGerenciar pessoas jurídicas (empresas/negócios):\n\n```typescript\n// Criar pessoa jurídica\nconst pessoa = await nfe.legalPeople.create(empresaId, {\n  federalTaxNumber: '12345678000190',\n  name: 'Nome da Empresa',\n  email: 'empresa@exemplo.com.br',\n  address: { /* ... */ }\n});\n\n// Listar todas as pessoas jurídicas\nconst pessoas = await nfe.legalPeople.list(empresaId);\n\n// Buscar por CNPJ\nconst pessoa = await nfe.legalPeople.findByTaxNumber(empresaId, '12345678000190');\n```\n\n#### 👤 Pessoas Físicas (`nfe.naturalPeople`)\n\nGerenciar pessoas físicas (indivíduos):\n\n```typescript\n// Criar pessoa física\nconst pessoa = await nfe.naturalPeople.create(empresaId, {\n  federalTaxNumber: 12345678901,\n  name: 'João da Silva',\n  email: 'joao@exemplo.com.br',\n  address: { /* ... */ }\n});\n\n// Buscar por CPF\nconst pessoa = await nfe.naturalPeople.findByTaxNumber(empresaId, '12345678901');\n```\n\n#### 🔗 Webhooks (`nfe.webhooks`)\n\nGerenciar configurações de webhook:\n\n```typescript\n// Criar webhook\nconst webhook = await nfe.webhooks.create(empresaId, {\n  url: 'https://meuapp.com.br/webhooks/nfe',\n  events: ['invoice.issued', 'invoice.cancelled'],\n  active: true\n});\n\n// Listar webhooks\nconst webhooks = await nfe.webhooks.list(empresaId);\n\n// Atualizar webhook\nawait nfe.webhooks.update(empresaId, webhookId, {\n  events: ['invoice.issued']\n});\n\n// Validar assinatura do webhook\nconst ehValido = nfe.webhooks.validateSignature(\n  payload,\n  assinatura,\n  segredo\n);\n```\n\n#### 📍 Endereços (`nfe.addresses`)\n\nConsultar endereços brasileiros por CEP ou termo de busca:\n\n```typescript\n// Buscar endereço por CEP\nconst endereco = await nfe.addresses.lookupByPostalCode('01310-100');\nconsole.log(endereco.street);   // 'Avenida Paulista'\nconsole.log(endereco.city.name); // 'São Paulo'\nconsole.log(endereco.state);     // 'SP'\n\n// Buscar por termo (nome de rua, bairro, etc.)\nconst resultado = await nfe.addresses.lookupByTerm('Paulista');\nfor (const end of resultado.addresses) {\n  console.log(`${end.postalCode}: ${end.street}, ${end.city.name}`);\n}\n\n// Buscar com filtro OData\nconst filtrado = await nfe.addresses.search({\n  filter: \"city.name eq 'São Paulo'\"\n});\n```\n\n\u003e **Nota:** A API de Endereços usa um host separado (`address.api.nfe.io`). Você pode configurar uma chave API específica com `dataApiKey`, ou o SDK usará `apiKey` como fallback.\n\n#### 🚚 Notas de Transporte - CT-e (`nfe.transportationInvoices`)\n\nConsultar CT-e (Conhecimento de Transporte Eletrônico) via Distribuição DFe:\n\n```typescript\n// Ativar busca automática de CT-e para uma empresa\nconst settings = await nfe.transportationInvoices.enable('empresa-id');\nconsole.log('Status:', settings.status);\nconsole.log('Iniciando do NSU:', settings.startFromNsu);\n\n// Ativar a partir de um NSU específico\nconst settings = await nfe.transportationInvoices.enable('empresa-id', {\n  startFromNsu: 12345\n});\n\n// Ativar a partir de uma data específica\nconst settings = await nfe.transportationInvoices.enable('empresa-id', {\n  startFromDate: '2024-01-01T00:00:00Z'\n});\n\n// Verificar configurações atuais\nconst config = await nfe.transportationInvoices.getSettings('empresa-id');\nconsole.log('Busca ativa:', config.status);\n\n// Desativar busca automática\nawait nfe.transportationInvoices.disable('empresa-id');\n\n// Consultar CT-e por chave de acesso (44 dígitos)\nconst cte = await nfe.transportationInvoices.retrieve(\n  'empresa-id',\n  '35240112345678000190570010000001231234567890'\n);\nconsole.log('Remetente:', cte.nameSender);\nconsole.log('Valor:', cte.totalInvoiceAmount);\nconsole.log('Emissão:', cte.issuedOn);\n\n// Baixar XML do CT-e\nconst xml = await nfe.transportationInvoices.downloadXml(\n  'empresa-id',\n  '35240112345678000190570010000001231234567890'\n);\nfs.writeFileSync('cte.xml', xml);\n\n// Consultar evento do CT-e\nconst evento = await nfe.transportationInvoices.getEvent(\n  'empresa-id',\n  '35240112345678000190570010000001231234567890',\n  'chave-evento'\n);\n\n// Baixar XML do evento\nconst eventoXml = await nfe.transportationInvoices.downloadEventXml(\n  'empresa-id',\n  '35240112345678000190570010000001231234567890',\n  'chave-evento'\n);\n```\n\n\u003e **Nota:** A API de CT-e usa um host separado (`api.nfse.io`). Você pode configurar uma chave API específica com `dataApiKey`, ou o SDK usará `apiKey` como fallback.\n\n**Pré-requisitos:**\n- Empresa deve estar cadastrada com certificado digital A1 válido\n- Webhook deve estar configurado para receber notificações de CT-e\n\n#### 📥 NF-e de Entrada - Distribuição (`nfe.inboundProductInvoices`)\n\nConsultar NF-e (Nota Fiscal Eletrônica de Produto) recebidas via Distribuição NF-e:\n\n```typescript\n// Ativar busca automática de NF-e para uma empresa\nconst settings = await nfe.inboundProductInvoices.enableAutoFetch('empresa-id', {\n  environmentSEFAZ: 'Production',\n  webhookVersion: '2',\n});\nconsole.log('Status:', settings.status);\n\n// Ativar a partir de um NSU específico\nconst settings = await nfe.inboundProductInvoices.enableAutoFetch('empresa-id', {\n  startFromNsu: '999999',\n  environmentSEFAZ: 'Production',\n});\n\n// Verificar configurações atuais\nconst config = await nfe.inboundProductInvoices.getSettings('empresa-id');\nconsole.log('Busca ativa:', config.status);\n\n// Desativar busca automática\nawait nfe.inboundProductInvoices.disableAutoFetch('empresa-id');\n\n// Consultar NF-e por chave de acesso - formato webhook v2 (recomendado)\nconst nfe_doc = await nfe.inboundProductInvoices.getProductInvoiceDetails(\n  'empresa-id',\n  '35240112345678000190550010000001231234567890'\n);\nconsole.log('Emissor:', nfe_doc.issuer?.name);\nconsole.log('Valor:', nfe_doc.totalInvoiceAmount);\n\n// Baixar XML da NF-e\nconst xml = await nfe.inboundProductInvoices.getXml(\n  'empresa-id',\n  '35240112345678000190550010000001231234567890'\n);\nfs.writeFileSync('nfe.xml', xml);\n\n// Baixar PDF (DANFE)\nconst pdf = await nfe.inboundProductInvoices.getPdf(\n  'empresa-id',\n  '35240112345678000190550010000001231234567890'\n);\n\n// Enviar manifestação (Ciência da Operação por padrão)\nawait nfe.inboundProductInvoices.manifest(\n  'empresa-id',\n  '35240112345678000190550010000001231234567890'\n);\n\n// Manifestar com evento específico\nawait nfe.inboundProductInvoices.manifest(\n  'empresa-id',\n  '35240112345678000190550010000001231234567890',\n  210220 // Confirmação da Operação\n);\n\n// Consultar evento da NF-e\nconst evento = await nfe.inboundProductInvoices.getEventDetails(\n  'empresa-id',\n  '35240112345678000190550010000001231234567890',\n  'chave-evento'\n);\n\n// Baixar XML do evento\nconst eventoXml = await nfe.inboundProductInvoices.getEventXml(\n  'empresa-id',\n  '35240112345678000190550010000001231234567890',\n  'chave-evento'\n);\n\n// Reprocessar webhook\nawait nfe.inboundProductInvoices.reprocessWebhook('empresa-id', '35240...');\n```\n\n\u003e **Nota:** A API de NF-e Distribuição usa um host separado (`api.nfse.io`). Você pode configurar uma chave API específica com `dataApiKey`, ou o SDK usará `apiKey` como fallback.\n\n**Pré-requisitos:**\n- Empresa deve estar cadastrada com certificado digital A1 válido\n- Webhook deve estar configurado para receber notificações de NF-e\n\n**Tipos de Manifestação:**\n\n| Código | Evento |\n|--------|--------|\n| `210210` | Ciência da Operação (padrão) |\n| `210220` | Confirmação da Operação |\n| `210240` | Operação não Realizada |\n\n#### 📦 NF-e de Produto - Emissão (`nfe.productInvoices`)\n\nCiclo completo de gestão de NF-e (Nota Fiscal Eletrônica de Produto) — emissão, listagem, consulta, cancelamento, carta de correção (CC-e), inutilização e download de arquivos (PDF/XML):\n\n```typescript\n// Emitir NF-e (assíncrono — retorna 202)\nconst result = await nfe.productInvoices.create('empresa-id', {\n  operationNature: 'Venda de mercadoria',\n  operationType: 'Outgoing',\n  buyer: { name: 'Empresa LTDA', federalTaxNumber: 12345678000190 },\n  items: [{ code: 'PROD-001', description: 'Produto X', quantity: 1, unitAmount: 100 }],\n  payment: [{ paymentDetail: [{ method: 'Cash', amount: 100 }] }],\n});\n\n// Listar NF-e (environment é obrigatório)\nconst invoices = await nfe.productInvoices.list('empresa-id', {\n  environment: 'Production',\n  limit: 10,\n});\n\n// Consultar NF-e por ID\nconst invoice = await nfe.productInvoices.retrieve('empresa-id', 'invoice-id');\n\n// Cancelar NF-e (assíncrono)\nawait nfe.productInvoices.cancel('empresa-id', 'invoice-id', 'Motivo do cancelamento');\n\n// Download de PDF e XML\nconst pdf = await nfe.productInvoices.downloadPdf('empresa-id', 'invoice-id');\nconst xml = await nfe.productInvoices.downloadXml('empresa-id', 'invoice-id');\n\n// Carta de correção (CC-e) — razão de 15 a 1.000 caracteres\nawait nfe.productInvoices.sendCorrectionLetter('empresa-id', 'invoice-id',\n  'Correcao do endereco do destinatario conforme novo cadastro');\n\n// Inutilizar faixa de numeração\nawait nfe.productInvoices.disableRange('empresa-id', {\n  environment: 'Production',\n  serie: 1,\n  state: 'SP',\n  beginNumber: 100,\n  lastNumber: 110,\n});\n```\n\n\u003e **Nota:** Operações de emissão, cancelamento, CC-e e inutilização são assíncronas — retornam 202/204. Conclusão é notificada via webhooks.\n\n#### 🏛️ Inscrições Estaduais (`nfe.stateTaxes`)\n\nCRUD de inscrições estaduais (IE) — configuração necessária para emissão de NF-e de produto:\n\n```typescript\n// Listar inscrições estaduais\nconst taxes = await nfe.stateTaxes.list('empresa-id');\n\n// Criar inscrição estadual\nconst tax = await nfe.stateTaxes.create('empresa-id', {\n  taxNumber: '123456789',\n  serie: 1,\n  number: 1,\n  code: 'sP',\n  environmentType: 'production',\n  type: 'nFe',\n});\n\n// Consultar, atualizar e excluir\nconst retrieved = await nfe.stateTaxes.retrieve('empresa-id', 'state-tax-id');\nawait nfe.stateTaxes.update('empresa-id', 'state-tax-id', { serie: 2 });\nawait nfe.stateTaxes.delete('empresa-id', 'state-tax-id');\n```\n\n\u003e **Nota:** Usa o host `api.nfse.io`. Configure `dataApiKey` para chave separada, ou o SDK usará `apiKey` como fallback.\n\n#### 🔍 Consulta de NF-e por Chave de Acesso (`nfe.productInvoiceQuery`)\n\nConsultar NF-e (Nota Fiscal Eletrônica de Produto) diretamente na SEFAZ por chave de acesso. Recurso somente leitura sem necessidade de escopo de empresa:\n\n```typescript\n// Consultar dados completos da NF-e\nconst invoice = await nfe.productInvoiceQuery.retrieve(\n  '35240112345678000190550010000001231234567890'\n);\nconsole.log('Status:', invoice.currentStatus);\nconsole.log('Emissor:', invoice.issuer?.name);\nconsole.log('Valor:', invoice.totals?.icms?.invoiceAmount);\n\n// Baixar DANFE (PDF)\nconst pdf = await nfe.productInvoiceQuery.downloadPdf(\n  '35240112345678000190550010000001231234567890'\n);\nfs.writeFileSync('danfe.pdf', pdf);\n\n// Baixar XML da NF-e\nconst xml = await nfe.productInvoiceQuery.downloadXml(\n  '35240112345678000190550010000001231234567890'\n);\nfs.writeFileSync('nfe.xml', xml);\n\n// Listar eventos fiscais (cancelamentos, correções, manifestações)\nconst result = await nfe.productInvoiceQuery.listEvents(\n  '35240112345678000190550010000001231234567890'\n);\nfor (const event of result.events ?? []) {\n  console.log(event.description, event.authorizedOn);\n}\n```\n\n\u003e **Nota:** A API de Consulta NF-e usa um host separado (`nfe.api.nfe.io`). Você pode configurar uma chave API específica com `dataApiKey`, ou o SDK usará `apiKey` como fallback.\n\n#### 🧾 Consulta de Cupom Fiscal Eletrônico - CFe-SAT (`nfe.consumerInvoiceQuery`)\n\nConsultar CFe-SAT (Cupom Fiscal Eletrônico) por chave de acesso. Recurso somente leitura sem necessidade de escopo de empresa:\n\n```typescript\n// Consultar dados completos do cupom fiscal\nconst coupon = await nfe.consumerInvoiceQuery.retrieve(\n  '35240112345678000190590000000012341234567890'\n);\nconsole.log('Status:', coupon.currentStatus);   // 'Authorized'\nconsole.log('Emissor:', coupon.issuer?.name);\nconsole.log('Valor:', coupon.totals?.couponAmount);\n\n// Baixar XML do CFe\nconst xml = await nfe.consumerInvoiceQuery.downloadXml(\n  '35240112345678000190590000000012341234567890'\n);\nfs.writeFileSync('cfe.xml', xml);\n```\n\n\u003e **Nota:** A API de Consulta CFe-SAT usa o mesmo host (`nfe.api.nfe.io`) e chave de API que a consulta de NF-e.\n\n#### 🏢 Consulta CNPJ / Pessoa Jurídica (`nfe.legalEntityLookup`)\n\nConsultar dados cadastrais de empresas brasileiras (CNPJ) na Receita Federal e nas SEFAZs estaduais:\n\n```typescript\n// Consulta básica por CNPJ (aceita com ou sem pontuação)\nconst result = await nfe.legalEntityLookup.getBasicInfo('12.345.678/0001-90');\nconsole.log('Razão Social:', result.legalEntity?.name);\nconsole.log('Nome Fantasia:', result.legalEntity?.tradeName);\nconsole.log('Status:', result.legalEntity?.status);        // 'Active'\nconsole.log('Porte:', result.legalEntity?.size);            // 'ME', 'EPP', etc.\nconsole.log('Cidade:', result.legalEntity?.address?.city?.name);\n\n// Consulta com opções\nconst result = await nfe.legalEntityLookup.getBasicInfo('12345678000190', {\n  updateAddress: false,    // Não atualizar endereço via Correios\n  updateCityCode: true,    // Atualizar código IBGE da cidade\n});\n\n// Consultar Inscrição Estadual (IE) por estado\nconst ieSP = await nfe.legalEntityLookup.getStateTaxInfo('SP', '12345678000190');\nfor (const tax of ieSP.legalEntity?.stateTaxes ?? []) {\n  console.log(`IE: ${tax.taxNumber} - Status: ${tax.status}`);\n  console.log(`  NFe: ${tax.nfe?.status}, CTe: ${tax.cte?.status}`);\n}\n\n// Avaliar IE para emissão de nota fiscal\nconst invoice = await nfe.legalEntityLookup.getStateTaxForInvoice('MG', '12345678000190');\nfor (const tax of invoice.legalEntity?.stateTaxes ?? []) {\n  if (tax.status === 'Abled') {\n    console.log(`Pode emitir com IE: ${tax.taxNumber}`);\n  }\n}\n\n// Obter melhor IE sugerida para emissão\nconst sugestao = await nfe.legalEntityLookup.getSuggestedStateTaxForInvoice('SP', '12345678000190');\nconst melhorIE = sugestao.legalEntity?.stateTaxes?.[0];\nconsole.log('IE recomendada:', melhorIE?.taxNumber);\n```\n\n\u003e **Nota:** A API de Consulta CNPJ usa um host separado (`legalentity.api.nfe.io`). Você pode configurar uma chave API específica com `dataApiKey`, ou o SDK usará `apiKey` como fallback.\n\n#### 👤 Consulta CPF / Pessoa Física (`nfe.naturalPersonLookup`)\n\nConsultar a situação cadastral de CPF (pessoa física) na Receita Federal:\n\n```typescript\n// Consulta com CPF e data de nascimento\nconst result = await nfe.naturalPersonLookup.getStatus('123.456.789-01', '1990-01-15');\nconsole.log('Nome:', result.name);      // 'JOÃO DA SILVA'\nconsole.log('Status:', result.status);  // 'Regular'\n\n// Também aceita Date object\nconst result = await nfe.naturalPersonLookup.getStatus('12345678901', new Date(1990, 0, 15));\nconsole.log('Situação Cadastral:', result.status);\n```\n\n\u003e **Nota:** A API de Consulta CPF usa um host separado (`naturalperson.api.nfe.io`). Você pode configurar uma chave API específica com `dataApiKey`, ou o SDK usará `apiKey` como fallback.\n\n#### 🧮 Cálculo de Impostos (`nfe.taxCalculation`)\n\nCalcular todos os tributos aplicáveis (ICMS, ICMS-ST, PIS, COFINS, IPI, II) para operações com produtos usando o Motor de Cálculo de Tributos:\n\n```typescript\n// Calcular impostos de uma operação de venda\nconst resultado = await nfe.taxCalculation.calculate('tenant-id', {\n  operationType: 'Outgoing',\n  issuer: { state: 'SP', taxRegime: 'RealProfit' },\n  recipient: { state: 'RJ' },\n  items: [{\n    id: 'item-1',\n    operationCode: 121,\n    origin: 'National',\n    ncm: '61091000',\n    quantity: 10,\n    unitAmount: 100.00\n  }]\n});\n\nfor (const item of resultado.items ?? []) {\n  console.log(`Item ${item.id}: CFOP ${item.cfop}`);\n  console.log(`  ICMS: CST=${item.icms?.cst}, valor=${item.icms?.vICMS}`);\n  console.log(`  PIS: CST=${item.pis?.cst}, valor=${item.pis?.vPIS}`);\n  console.log(`  COFINS: CST=${item.cofins?.cst}, valor=${item.cofins?.vCOFINS}`);\n}\n```\n\n\u003e **Nota:** A API de Cálculo de Impostos usa o host `api.nfse.io`. Configure `dataApiKey` para uma chave específica, ou o SDK usará `apiKey` como fallback.\n\n#### 📋 Códigos Auxiliares de Impostos (`nfe.taxCodes`)\n\nConsultar tabelas de referência necessárias para o cálculo de impostos:\n\n```typescript\n// Listar códigos de operação (natureza de operação)\nconst codigos = await nfe.taxCodes.listOperationCodes({ pageIndex: 1, pageCount: 20 });\nfor (const cod of codigos.items ?? []) {\n  console.log(`${cod.code} - ${cod.description}`);\n}\n\n// Listar finalidades de aquisição\nconst finalidades = await nfe.taxCodes.listAcquisitionPurposes();\n\n// Listar perfis fiscais do emissor\nconst perfisEmissor = await nfe.taxCodes.listIssuerTaxProfiles();\n\n// Listar perfis fiscais do destinatário\nconst perfisDestinatario = await nfe.taxCodes.listRecipientTaxProfiles();\n```\n\n\u003e **Nota:** Todas as listagens suportam paginação via `pageIndex` (1-based) e `pageCount` (padrão: 50).\n\n---\n\n### Opções de Configuração\n\n```typescript\nconst nfe = new NfeClient({\n  // Chave API principal do NFE.io (operações com documentos fiscais)\n  apiKey: 'sua-chave-api',\n  \n  // Opcional: Chave API para serviços de consulta (Endereços, CT-e, CNPJ, CPF)\n  // Se não fornecida, usa apiKey como fallback\n  dataApiKey: 'sua-chave-data-api',\n  \n  // Opcional: Ambiente (padrão: 'production')\n  environment: 'production', // ou 'sandbox'\n  \n  // Opcional: URL base customizada (sobrescreve environment)\n  baseUrl: 'https://api-customizada.nfe.io/v1',\n  \n  // Opcional: Timeout de requisição em milissegundos (padrão: 30000)\n  timeout: 60000,\n  \n  // Opcional: Configuração de retry\n  retryConfig: {\n    maxRetries: 3,\n    baseDelay: 1000,\n    maxDelay: 10000,\n    backoffMultiplier: 2\n  }\n});\n```\n\n#### Variáveis de Ambiente\n\nO SDK suporta as seguintes variáveis de ambiente:\n\n| Variável | Descrição |\n|----------|-----------|\n| `NFE_API_KEY` | Chave API principal (fallback para `apiKey`) |\n| `NFE_DATA_API_KEY` | Chave API para serviços de consulta (fallback para `dataApiKey`) |\n\n```bash\n# Configurar via ambiente\nexport NFE_API_KEY=\"sua-chave-api\"\nexport NFE_DATA_API_KEY=\"sua-chave-data\"\n\n# Usar SDK sem passar chaves no código\nconst nfe = new NfeClient({});\n```\n\n### Tratamento de Erros\n\nO SDK fornece classes de erro tipadas:\n\n```typescript\nimport { \n  NfeError, \n  AuthenticationError, \n  ValidationError,\n  NotFoundError,\n  RateLimitError \n} from 'nfe-io';\n\ntry {\n  const notaFiscal = await nfe.serviceInvoices.create(empresaId, dados);\n} catch (erro) {\n  if (erro instanceof AuthenticationError) {\n    console.error('Chave API inválida:', erro.message);\n  } else if (erro instanceof ValidationError) {\n    console.error('Dados inválidos:', erro.details);\n  } else if (erro instanceof NotFoundError) {\n    console.error('Recurso não encontrado:', erro.message);\n  } else if (erro instanceof RateLimitError) {\n    console.error('Limite de requisições excedido, tente novamente em:', erro.retryAfter);\n  } else if (erro instanceof NfeError) {\n    console.error('Erro da API:', erro.code, erro.message);\n  } else {\n    console.error('Erro inesperado:', erro);\n  }\n}\n```\n\n## 🔄 Migração da v2\n\nVeja [MIGRATION.md](./MIGRATION.md) para um guia completo de migração.\n\n**Principais Mudanças:**\n\n```javascript\n// v2 (callbacks + promises)\nvar nfe = require('nfe-io')('chave-api');\nnfe.serviceInvoices.create('id-empresa', dados, function(err, notaFiscal) {\n  if (err) return console.error(err);\n  console.log(notaFiscal);\n});\n\n// v3 (async/await + TypeScript)\nimport { NfeClient } from 'nfe-io';\nconst nfe = new NfeClient({ apiKey: 'chave-api' });\n\ntry {\n  const notaFiscal = await nfe.serviceInvoices.create('id-empresa', dados);\n  console.log(notaFiscal);\n} catch (erro) {\n  console.error(erro);\n}\n```\n\n## 📝 Exemplos\n\n### ⚡ Exemplos Práticos Prontos para Uso\n\nO diretório [`examples/`](./examples/) contém exemplos completos que você pode executar com suas credenciais:\n\n```bash\n# Modo interativo com menu\nnpm run examples\n\n# Ou diretamente\nnode examples/run-examples.js\n```\n\n**Exemplos disponíveis**:\n1. 📊 **Listar Notas Fiscais** - Consulte notas existentes (comece por aqui!)\n2. 👥 **Gerenciar Pessoas** - CRUD de clientes (pessoas físicas/jurídicas)\n3. 🧾 **Emitir Nota Fiscal** - Fluxo completo: criar → enviar email → baixar PDF/XML\n4. 🔔 **Configurar Webhooks** - Receba notificações de eventos\n\nVeja [`examples/README.md`](./examples/README.md) para documentação completa.\n\n---\n\n### Fluxo Completo de Emissão de Nota Fiscal\n\n```typescript\nimport { NfeClient } from 'nfe-io';\n\nconst nfe = new NfeClient({\n  apiKey: process.env.NFE_API_KEY!,\n  environment: 'production'\n});\n\nasync function emitirNotaFiscal() {\n  // 1. Buscar ou criar empresa\n  const empresas = await nfe.companies.list();\n  const empresa = empresas.data[0];\n  \n  // 2. Criar nota fiscal com polling automático\n  const notaFiscal = await nfe.serviceInvoices.createAndWait(empresa.id, {\n    cityServiceCode: '01234',\n    description: 'Consultoria em TI',\n    servicesAmount: 5000.00,\n    borrower: {\n      type: 'LegalEntity',\n      federalTaxNumber: 12345678000190,\n      name: 'Cliente Exemplo Ltda',\n      email: 'contato@cliente.com.br',\n      address: {\n        country: 'BRA',\n        postalCode: '01310-100',\n        street: 'Av. Paulista',\n        number: '1000',\n        city: { code: '3550308', name: 'São Paulo' },\n        state: 'SP'\n      }\n    }\n  }, {\n    maxAttempts: 30,\n    intervalMs: 2000\n  });\n  \n  console.log(`✅ Nota fiscal emitida: ${notaFiscal.number}`);\n  \n  // 3. Enviar por email\n  await nfe.serviceInvoices.sendEmail(empresa.id, notaFiscal.id);\n  console.log('📧 Email enviado');\n  \n  // 4. Baixar PDF\n  const pdf = await nfe.serviceInvoices.downloadPdf(empresa.id, notaFiscal.id);\n  await fs.promises.writeFile(`nota-fiscal-${notaFiscal.number}.pdf`, pdf);\n  console.log('💾 PDF salvo');\n}\n\nemitirNotaFiscal().catch(console.error);\n```\n\n### Configuração de Webhook\n\n```typescript\n// Configurar webhook para receber eventos de notas fiscais\nconst webhook = await nfe.webhooks.create(empresaId, {\n  url: 'https://meuapp.com.br/api/webhooks/nfe',\n  events: [\n    'invoice.issued',\n    'invoice.cancelled',\n    'invoice.error'\n  ],\n  active: true\n});\n\n// No seu endpoint de webhook\napp.post('/api/webhooks/nfe', (req, res) =\u003e {\n  const assinatura = req.headers['x-nfe-signature'];\n  const ehValido = nfe.webhooks.validateSignature(\n    req.body,\n    assinatura,\n    process.env.WEBHOOK_SECRET\n  );\n  \n  if (!ehValido) {\n    return res.status(401).send('Assinatura inválida');\n  }\n  \n  const { event, data } = req.body;\n  \n  if (event === 'invoice.issued') {\n    console.log('Nota fiscal emitida:', data.id);\n  }\n  \n  res.status(200).send('OK');\n});\n```\n\n### Criação de Notas Fiscais em Lote\n\n```typescript\nasync function emitirNotasEmLote(empresaId: string, notasFiscais: DadosNota[]) {\n  const resultados = await Promise.allSettled(\n    notasFiscais.map(dados =\u003e \n      nfe.serviceInvoices.createAndWait(empresaId, dados)\n    )\n  );\n  \n  const sucesso = resultados.filter(r =\u003e r.status === 'fulfilled');\n  const falha = resultados.filter(r =\u003e r.status === 'rejected');\n  \n  console.log(`✅ ${sucesso.length} notas fiscais emitidas`);\n  console.log(`❌ ${falha.length} notas fiscais falharam`);\n  \n  return { sucesso, falha };\n}\n```\n\n## 🏗️ Referência da API\n\nDocumentação completa da API disponível em:\n- [Documentação TypeDoc](https://nfe.github.io/client-nodejs/) *(em breve)*\n- [Documentação Oficial da API](https://nfe.io/docs/nota-fiscal-servico/integracao-nfs-e/)\n- [Referência da API REST](https://nfe.io/doc/rest-api/nfe-v1/)\n\n## 🧪 Desenvolvimento \u0026 Testes\n\n### Executando Testes\n\n```bash\n# Executar todos os testes (unit + integration)\nnpm test\n\n# Executar apenas testes unitários\nnpm run test:unit\n\n# Executar apenas testes de integração (requer chave API)\nnpm run test:integration\n\n# Executar com cobertura\nnpm run test:coverage\n\n# Executar com UI\nnpm run test:ui\n```\n\n### Testes de Integração\n\nOs testes de integração validam contra a **API real do NFE.io**:\n\n```bash\n# Definir sua chave API de desenvolvimento/teste\nexport NFE_API_KEY=\"sua-chave-api-desenvolvimento\"\nexport NFE_TEST_ENVIRONMENT=\"development\"\nexport RUN_INTEGRATION_TESTS=\"true\"\n\n# Executar testes de integração\nnpm run test:integration\n```\n\nVeja [tests/integration/README.md](./tests/integration/README.md) para documentação detalhada.\n\n**Nota**: Testes de integração fazem chamadas reais à API e podem gerar custos dependendo do seu plano.\n\n### Geração de Tipos OpenAPI\n\nO SDK gera tipos TypeScript automaticamente a partir de especificações OpenAPI:\n\n```bash\n# Baixar specs mais recentes da API (se disponível)\nnpm run download:spec\n\n# Validar todas as specs OpenAPI\nnpm run validate:spec\n\n# Gerar tipos TypeScript a partir das specs\nnpm run generate\n\n# Modo watch - regenerar automaticamente ao modificar specs\nnpm run generate:watch\n```\n\n**Localização das specs**: `openapi/spec/*.yaml`  \n**Tipos gerados**: `src/generated/*.ts`  \n**Configuração**: `openapi/generator-config.yaml`\n\nO processo de build valida automaticamente as specs e gera tipos antes da compilação:\n\n```bash\nnpm run build\n# → Executa: validate:spec → generate → typecheck → tsup\n```\n\n**Nota**: Arquivos gerados não devem ser editados manualmente. Edite as specs OpenAPI e regenere.\n\nPara orientações de migração, veja [docs/MIGRATION-TO-GENERATED-TYPES.md](./docs/MIGRATION-TO-GENERATED-TYPES.md).\n\n### Verificação de Tipos\n\n```bash\nnpm run typecheck\n```\n\n### Build\n\n```bash\nnpm run build\n```\n\n## 🤝 Contribuindo\n\nContribuições são bem-vindas! Por favor, veja [CONTRIBUTING.md](./CONTRIBUTING.md) para orientações.\n\n## 📄 Licença\n\nMIT © [NFE.io](https://nfe.io)\n\n## 🆘 Suporte\n\n- 📧 Email: suporte@nfe.io\n- 📖 Documentação: https://nfe.io/docs/\n- 🐛 Issues: https://github.com/nfe/client-nodejs/issues\n\n---\n\n**Feito com ❤️ pela equipe NFE.io**\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnfe%2Fclient-nodejs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnfe%2Fclient-nodejs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnfe%2Fclient-nodejs/lists"}