@useinvio/nfse-sdk 3.0.0 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +176 -0
- package/README.en.md +146 -0
- package/README.md +77 -518
- package/dist/agent.d.ts +131 -0
- package/dist/agent.js +551 -0
- package/dist/agent.js.map +1 -0
- package/dist/certificate.d.ts +96 -0
- package/dist/certificate.js +218 -0
- package/dist/certificate.js.map +1 -0
- package/dist/certificateValidation.d.ts +11 -6
- package/dist/certificateValidation.js +23 -12
- package/dist/certificateValidation.js.map +1 -1
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +520 -0
- package/dist/cli.js.map +1 -0
- package/dist/cliBin.d.ts +2 -0
- package/dist/cliBin.js +6 -0
- package/dist/cliBin.js.map +1 -0
- package/dist/cliExample.d.ts +6 -0
- package/dist/cliExample.js +29 -0
- package/dist/cliExample.js.map +1 -0
- package/dist/client.d.ts +51 -4
- package/dist/client.js +41 -10
- package/dist/client.js.map +1 -1
- package/dist/config.d.ts +3 -0
- package/dist/config.js +8 -0
- package/dist/config.js.map +1 -1
- package/dist/consultas.d.ts +34 -0
- package/dist/consultas.js +61 -0
- package/dist/consultas.js.map +1 -0
- package/dist/dpsJson.js +1 -41
- package/dist/dpsJson.js.map +1 -1
- package/dist/dpsJsonSchema.d.ts +17 -0
- package/dist/dpsJsonSchema.js +184 -0
- package/dist/dpsJsonSchema.js.map +1 -0
- package/dist/emissaoNota.d.ts +11 -6
- package/dist/emissaoNota.js +10 -6
- package/dist/emissaoNota.js.map +1 -1
- package/dist/eventoJson.d.ts +76 -0
- package/dist/eventoJson.js +128 -0
- package/dist/eventoJson.js.map +1 -0
- package/dist/eventosNfse.d.ts +38 -0
- package/dist/eventosNfse.js +73 -0
- package/dist/eventosNfse.js.map +1 -0
- package/dist/fiscalDomains.d.ts +22 -0
- package/dist/fiscalDomains.js +99 -0
- package/dist/fiscalDomains.js.map +1 -0
- package/dist/fiscalValidation.js +21 -53
- package/dist/fiscalValidation.js.map +1 -1
- package/dist/gzipB64.d.ts +5 -0
- package/dist/gzipB64.js +12 -0
- package/dist/gzipB64.js.map +1 -1
- package/dist/index.d.ts +22 -7
- package/dist/index.js +11 -4
- package/dist/index.js.map +1 -1
- package/dist/jsonSchemaCheck.d.ts +12 -0
- package/dist/jsonSchemaCheck.js +70 -0
- package/dist/jsonSchemaCheck.js.map +1 -0
- package/dist/loadPfx.d.ts +2 -0
- package/dist/loadPfx.js +2 -1
- package/dist/loadPfx.js.map +1 -1
- package/dist/mcpCli.d.ts +2 -0
- package/dist/mcpCli.js +7 -0
- package/dist/mcpCli.js.map +1 -0
- package/dist/mcpServer.d.ts +49 -0
- package/dist/mcpServer.js +159 -0
- package/dist/mcpServer.js.map +1 -0
- package/dist/nfseXml.d.ts +48 -0
- package/dist/nfseXml.js +86 -0
- package/dist/nfseXml.js.map +1 -0
- package/dist/rejeicoes.d.ts +50 -0
- package/dist/rejeicoes.js +62 -0
- package/dist/rejeicoes.js.map +1 -0
- package/dist/rejeicoesCatalog.d.ts +10 -0
- package/dist/rejeicoesCatalog.js +4449 -0
- package/dist/rejeicoesCatalog.js.map +1 -0
- package/dist/sefinClient.d.ts +107 -7
- package/dist/sefinClient.js +232 -22
- package/dist/sefinClient.js.map +1 -1
- package/dist/signXml.d.ts +3 -3
- package/dist/signXml.js +17 -7
- package/dist/signXml.js.map +1 -1
- package/dist/testing.d.ts +80 -0
- package/dist/testing.js +285 -0
- package/dist/testing.js.map +1 -0
- package/dist/xmlBuild.d.ts +11 -0
- package/dist/xmlBuild.js +44 -0
- package/dist/xmlBuild.js.map +1 -0
- package/dist/xmlInspection.d.ts +1 -1
- package/dist/xmlInspection.js +10 -9
- package/dist/xmlInspection.js.map +1 -1
- package/dist/xsdValidation.d.ts +24 -5
- package/dist/xsdValidation.js +97 -67
- package/dist/xsdValidation.js.map +1 -1
- package/docs/README.md +47 -0
- package/docs/REGRAS_NEGOCIO_EMISSAO.md +8 -8
- package/docs/conceitos/como-funciona.md +87 -0
- package/docs/guias/adn.md +51 -0
- package/docs/guias/agentes-ia.md +111 -0
- package/docs/guias/cancelar.md +70 -0
- package/docs/guias/certificado.md +88 -0
- package/docs/guias/cli.md +68 -0
- package/docs/guias/consultar.md +54 -0
- package/docs/guias/emitir.md +172 -0
- package/docs/guias/recuperar-emissao.md +33 -0
- package/docs/guias/rejeicoes.md +70 -0
- package/docs/guias/testes.md +79 -0
- package/docs/guias/timeouts.md +33 -0
- package/docs/referencia/ambientes.md +35 -0
- package/docs/referencia/api.md +137 -0
- package/docs/referencia/erros.md +55 -0
- package/docs/tutoriais/primeira-nfse.md +130 -0
- package/examples/README.md +3 -1
- package/examples/cancel-nfse.ts +29 -0
- package/examples/client-resource.ts +3 -5
- package/examples/emit-homologation.ts +3 -4
- package/examples/handle-errors.ts +3 -3
- package/examples/recover-emission.ts +29 -0
- package/llms.txt +97 -82
- package/package.json +31 -6
package/README.md
CHANGED
|
@@ -1,52 +1,35 @@
|
|
|
1
1
|
# @useinvio/nfse-sdk
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@useinvio/nfse-sdk)
|
|
4
|
-
[](https://github.com/useinvio/nfse-sdk/actions/workflows/ci.yml)
|
|
5
5
|
[](https://nodejs.org/)
|
|
6
|
+
[](./LICENSE)
|
|
6
7
|
|
|
7
|
-
[Website](https://sdk.useinvio.com/)
|
|
8
|
+
[Website](https://sdk.useinvio.com/) · [Playground](https://useinvio.github.io/nfse-sdk/) · [Documentação](./docs/README.md) · [English](./README.en.md)
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
<img width="959" height="296" alt="NFS-e SDK" src="https://github.com/user-attachments/assets/d6c45737-e7ca-4ea7-a06f-d93b7c16e4f0" />
|
|
10
11
|
|
|
11
|
-
|
|
12
|
+
**Emita, consulte e cancele NFS-e Nacional em TypeScript, sem escrever XML fiscal na mão.**
|
|
12
13
|
|
|
13
|
-
|
|
14
|
+
Você descreve a nota em JSON; o SDK monta a DPS, valida contra o XSD oficial,
|
|
15
|
+
assina com o certificado A1, compacta, envia por mTLS para a SEFIN e devolve a
|
|
16
|
+
resposta oficial em formato estruturado. Sem binários nativos e sem `xmllint`.
|
|
14
17
|
|
|
15
|
-
|
|
18
|
+
## O que ele faz
|
|
16
19
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
-
|
|
30
|
-
- [Quick start](#quick-start)
|
|
31
|
-
- [Por que usar](#por-que-usar)
|
|
32
|
-
- [Escolhendo o ponto de entrada](#escolhendo-o-ponto-de-entrada)
|
|
33
|
-
- [Cliente orientado a recursos](#cliente-orientado-a-recursos)
|
|
34
|
-
- [Certificado A1](#certificado-a1)
|
|
35
|
-
- [Emitir a partir de XML pronto](#emitir-a-partir-de-xml-pronto)
|
|
36
|
-
- [Emitir a partir de JSON declarativo](#emitir-a-partir-de-json-declarativo)
|
|
37
|
-
- [Inspecionar o XML antes de enviar](#inspecionar-o-xml-antes-de-enviar)
|
|
38
|
-
- [Tratar rejeições da SEFIN](#tratar-rejeições-da-sefin)
|
|
39
|
-
- [Consultar uma NFS-e emitida](#consultar-uma-nfs-e-emitida)
|
|
40
|
-
- [Enviar evento](#enviar-evento-ex-cancelamento)
|
|
41
|
-
- [Série e número da DPS](#série-e-número-da-dps)
|
|
42
|
-
- [Ambientes](#ambientes)
|
|
43
|
-
- [Referência da API](#referência-da-api)
|
|
44
|
-
- [Desenvolvimento](#desenvolvimento)
|
|
45
|
-
- [Publicação no npm](#publicação-no-npm)
|
|
46
|
-
- [Divulgação e exemplos](#divulgação-e-exemplos)
|
|
47
|
-
- [Assistente GPT](#assistente-gpt)
|
|
48
|
-
|
|
49
|
-
---
|
|
20
|
+
| Operação | Função | No `NfseClient` |
|
|
21
|
+
|---|---|---|
|
|
22
|
+
| Emitir a partir de JSON ou XML | `emitirNfse` | `invoices.create` |
|
|
23
|
+
| Validar sem enviar (JSON + XSD) | `validateDpsJsonRequest`, `buildDpsFromJson` | `invoices.buildDpsJson` |
|
|
24
|
+
| Consultar com resultado tipado | `obterNfse` | `invoices.retrieve` |
|
|
25
|
+
| Recuperar uma emissão após timeout | `recuperarNfsePorDps` | `invoices.recover` |
|
|
26
|
+
| Cancelar / cancelar por substituição | `cancelarNfse`, `cancelarNfsePorSubstituicao` | `invoices.cancel`, `invoices.cancelBySubstitution` |
|
|
27
|
+
| Baixar o DANFSe em PDF | `baixarDanfse` | `invoices.danfse` |
|
|
28
|
+
| Distribuição por NSU e parâmetros municipais (ADN) | `distribuirDfePorNsu`, `consultarAliquota`… | `distribution`, `municipalParameters` |
|
|
29
|
+
| Explicar rejeições com o texto oficial | `explicarRejeicao`, `explicarErros`, [uma página por código](./docs/rejeicoes/README.md) | – |
|
|
30
|
+
| Usar pelo terminal | `npx nfse init`, `doctor`, `validate`, `emit`, `explain` | – |
|
|
31
|
+
| Testar sem certificado nem rede | `@useinvio/nfse-sdk/testing` | – |
|
|
32
|
+
| Servidor MCP e ferramentas para agentes de IA | `npx -y @useinvio/nfse-mcp`, `@useinvio/nfse-sdk/agent` | – |
|
|
50
33
|
|
|
51
34
|
## Instalação
|
|
52
35
|
|
|
@@ -54,21 +37,23 @@ O SDK cuida da camada protocolar: certificado A1, montagem de DPS, validações
|
|
|
54
37
|
npm install @useinvio/nfse-sdk
|
|
55
38
|
```
|
|
56
39
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
---
|
|
40
|
+
Node.js 20 ou mais recente. Nada para instalar no sistema: a validação XSD roda
|
|
41
|
+
em WebAssembly.
|
|
60
42
|
|
|
61
|
-
##
|
|
43
|
+
## Em 60 segundos
|
|
62
44
|
|
|
63
|
-
|
|
45
|
+
```bash
|
|
46
|
+
NFSE_CERT_PATH=./certificado.pfx
|
|
47
|
+
NFSE_CERT_PASSWORD=sua-senha
|
|
48
|
+
```
|
|
64
49
|
|
|
65
50
|
```ts
|
|
66
|
-
import { emitirNfse,
|
|
51
|
+
import { emitirNfse, EmitirNotaError, NfseCertificate } from '@useinvio/nfse-sdk';
|
|
67
52
|
|
|
68
|
-
const
|
|
53
|
+
const certificado = NfseCertificate.fromEnv(); // a chave privada nunca aparece em logs
|
|
69
54
|
|
|
70
55
|
const nota = {
|
|
71
|
-
ambiente: 'restrita' as const,
|
|
56
|
+
ambiente: 'restrita' as const, // produção restrita: o sandbox oficial
|
|
72
57
|
prestador: {
|
|
73
58
|
cnpj: '12345678000195',
|
|
74
59
|
cLocEmi: '4106902',
|
|
@@ -87,505 +72,79 @@ const nota = {
|
|
|
87
72
|
dhEmi: '2026-06-15T10:30:00-03:00',
|
|
88
73
|
dCompet: '2026-06-01',
|
|
89
74
|
valores: { vServ: '1500.00' },
|
|
90
|
-
tributacaoMunicipal: {
|
|
91
|
-
tribISSQN: '1',
|
|
92
|
-
tpRetISSQN: '1',
|
|
93
|
-
},
|
|
94
|
-
tributacaoFederal: {
|
|
95
|
-
piscofins: { CST: '07' },
|
|
96
|
-
},
|
|
97
|
-
totTrib: {
|
|
98
|
-
pTotTribFed: '0.00',
|
|
99
|
-
pTotTribEst: '0.00',
|
|
100
|
-
pTotTribMun: '5.00',
|
|
101
|
-
},
|
|
102
|
-
},
|
|
103
|
-
};
|
|
104
|
-
|
|
105
|
-
try {
|
|
106
|
-
const resultado = await emitirNfse(nota, pfx);
|
|
107
|
-
console.log(resultado.chaveAcesso); // chave de 50 dígitos
|
|
108
|
-
console.log(resultado.nfseXml); // XML autorizado pela SEFIN
|
|
109
|
-
} catch (error) {
|
|
110
|
-
if (error instanceof EmitirNotaError) {
|
|
111
|
-
for (const rejeicao of error.erros) {
|
|
112
|
-
console.error(rejeicao.Codigo, rejeicao.Descricao);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
---
|
|
119
|
-
|
|
120
|
-
## Por que usar
|
|
121
|
-
|
|
122
|
-
- Entrada JSON tipada para construir DPS no layout nacional.
|
|
123
|
-
- Assinatura XMLDSIG, GZip/Base64 e mTLS encapsulados em uma API Node.js.
|
|
124
|
-
- Erros oficiais da SEFIN preservados em formato estruturado.
|
|
125
|
-
- Builder separado para inspecionar ou salvar o XML antes de transmitir.
|
|
126
|
-
- Cliente `NfseClient` para configurar certificado, ambiente e defaults uma vez.
|
|
127
|
-
- Validação explícita de campos fiscais obrigatórios, sem defaults silenciosos.
|
|
128
|
-
|
|
129
|
-
---
|
|
130
|
-
|
|
131
|
-
## Escolhendo o ponto de entrada
|
|
132
|
-
|
|
133
|
-
| Situação | O que usar |
|
|
134
|
-
|---|---|
|
|
135
|
-
| Quer uma API de cliente com `client.invoices.create(...)` | `new NfseClient(...)` |
|
|
136
|
-
| Outro sistema já gera o XML da DPS | `emitirNfse(xmlString, pfx)` |
|
|
137
|
-
| Você monta os dados e quer que a SDK construa o XML | `emitirNfse(notaJson, pfx)` |
|
|
138
|
-
| Precisa inspecionar ou salvar o XML antes de enviar | `buildDpsFromJson(nota)` |
|
|
139
|
-
| Fluxo customizado (assinar, compactar ou enviar separadamente) | funções de baixo nível |
|
|
140
|
-
|
|
141
|
-
---
|
|
142
|
-
|
|
143
|
-
## Cliente orientado a recursos
|
|
144
|
-
|
|
145
|
-
Use `NfseClient` quando preferir configurar ambiente e certificado uma vez e
|
|
146
|
-
emitir notas por recursos, como `client.invoices.create(...)`.
|
|
147
|
-
|
|
148
|
-
O cliente usa os mesmos campos do JSON declarativo (`prestador`, `servico` e
|
|
149
|
-
`emissao`). Os `defaults` seguem o mesmo formato e podem ser sobrescritos em
|
|
150
|
-
cada chamada.
|
|
151
|
-
|
|
152
|
-
```ts
|
|
153
|
-
import { NfseClient } from '@useinvio/nfse-sdk';
|
|
154
|
-
|
|
155
|
-
const client = new NfseClient({
|
|
156
|
-
environment: 'sandbox',
|
|
157
|
-
certificate: {
|
|
158
|
-
content: process.env.NFSE_CERTIFICATE!, // PFX em base64
|
|
159
|
-
password: process.env.NFSE_CERTIFICATE_PASSWORD!,
|
|
160
|
-
},
|
|
161
|
-
defaults: {
|
|
162
|
-
prestador: {
|
|
163
|
-
cnpj: '12345678000195',
|
|
164
|
-
cLocEmi: '4106902',
|
|
165
|
-
serie: '1601',
|
|
166
|
-
opSimpNac: '1',
|
|
167
|
-
regEspTrib: '0',
|
|
168
|
-
},
|
|
169
|
-
servico: {
|
|
170
|
-
cTribNac: '010201',
|
|
171
|
-
xDescServ: 'Servico ficticio de desenvolvimento de software',
|
|
172
|
-
cLocPrestacao: '4106902',
|
|
173
|
-
},
|
|
174
|
-
},
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
const invoice = await client.invoices.create({
|
|
178
|
-
emissao: {
|
|
179
|
-
nDPS: '1',
|
|
180
|
-
valores: { vServ: '1000.00' },
|
|
181
|
-
tomador: {
|
|
182
|
-
CPF: '00000000000',
|
|
183
|
-
xNome: 'Cliente Exemplo',
|
|
184
|
-
end: {
|
|
185
|
-
endNac: { cMun: '4106902', CEP: '80010000' },
|
|
186
|
-
xLgr: 'Rua Exemplo', nro: '100', xBairro: 'Centro',
|
|
187
|
-
},
|
|
188
|
-
},
|
|
189
|
-
tributacaoMunicipal: {
|
|
190
|
-
tribISSQN: '1',
|
|
191
|
-
tpRetISSQN: '1',
|
|
192
|
-
},
|
|
193
|
-
tributacaoFederal: {
|
|
194
|
-
piscofins: { CST: '07' },
|
|
195
|
-
},
|
|
196
|
-
totTrib: {
|
|
197
|
-
pTotTribFed: '0.00',
|
|
198
|
-
pTotTribEst: '0.00',
|
|
199
|
-
pTotTribMun: '5.00',
|
|
200
|
-
},
|
|
201
|
-
},
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
console.log(invoice.chaveAcesso);
|
|
205
|
-
console.log(invoice.nfseXml);
|
|
206
|
-
```
|
|
207
|
-
|
|
208
|
-
`environment: 'sandbox'` é alias de `restrita`, e `production` é alias de
|
|
209
|
-
`producao`. O campo `certificate.content` aceita o conteúdo binário do PFX em
|
|
210
|
-
`Buffer` ou o PFX codificado em base64, formato comum para variáveis de
|
|
211
|
-
ambiente.
|
|
212
|
-
|
|
213
|
-
Para inspecionar a DPS gerada sem assinar nem enviar:
|
|
214
|
-
|
|
215
|
-
```ts
|
|
216
|
-
const dps = client.invoices.buildDpsJson({
|
|
217
|
-
prestador: {
|
|
218
|
-
serie: '1701',
|
|
219
|
-
},
|
|
220
|
-
emissao: {
|
|
221
|
-
nDPS: '2',
|
|
222
|
-
valores: { vServ: '2500.00' },
|
|
223
75
|
tributacaoMunicipal: { tribISSQN: '1', tpRetISSQN: '1' },
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
});
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
---
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
### Validacao e compatibilidade
|
|
233
|
-
|
|
234
|
-
`validateDpsJsonRequest(entrada)` retorna `valid`, `issues` (erros), `warnings` (avisos) e uma copia `normalizedPayload`. Campos opcionais devem ser omitidos ou `undefined`; strings vazias, `null` e tipos incorretos sao rejeitados. Consulte [o mapeamento JSON](JSON_MAPPING.md) para os limites de datas e valores.
|
|
235
|
-
|
|
236
|
-
Divergencias entre `vServ` e a conversao cambial geram avisos, preservando o valor explicito. O mesmo vale para o valor estrangeiro do bloco de comercio exterior. Todos os valores monetarios sao arredondados para duas casas, inclusive `comExt.vServMoeda`; valores de servico que arredondam para zero sao rejeitados. Leia `warnings` antes da emissao quando quiser apresentar esses avisos ao usuario.
|
|
237
|
-
|
|
238
|
-
`prepararNota` verifica a vigencia do certificado antes de assinar; `transmitirNotaPreparada` verifica novamente antes do envio. `assertCertificateValidity(pfx, now?)` expoe essa verificacao. A checagem de titularidade continua explicita via `assertCertificateForProvider(pfx, documento, now?)`; o SDK nao resolve representacao fiscal.
|
|
239
|
-
|
|
240
|
-
O ambiente para JSON segue `options.ambiente` → `request.ambiente` → `restrita`, tanto no XML quanto no destino. XML externo usa `tpAmb` e rejeita uma opcao divergente. Notas preparadas tambem precisam ter o mesmo ambiente no XML assinado e no envio.
|
|
241
|
-
|
|
242
|
-
`client.invoices.get(chaveAcesso, { ambiente: 'producao' })` permite consultar uma emissao feita com sobrescrita de ambiente. Sem opcao, usa `defaults.ambiente` ou o ambiente do construtor. O cliente nao memoriza o ambiente da ultima emissao.
|
|
243
|
-
|
|
244
|
-
HTTP 2xx sem XML NFS-e bem formado e chave de 50 digitos consistente gera `EmitirNotaError` com codigo `INVALID_AUTHORIZATION_RESPONSE`, preservando corpo, status e DPS. Isso nao confirma rejeicao fiscal: concilie a emissao antes de reenviar. Nao ha retentativa automatica nem verificacao da assinatura da NFS-e recebida.
|
|
245
|
-
|
|
246
|
-
Veja [as correcoes e mudancas de comportamento](docs/CORRECOES_EMISSAO.md) e os [payloads nacional e exterior testados](examples/payloads.ts). Os exemplos declaram cenarios ilustrativos; a aplicacao escolhe o enquadramento aplicavel.
|
|
247
|
-
|
|
248
|
-
> **Migracao para 3.0.0:** esta versao tem breaking changes de validacao e resposta de autorizacao. Leia o guia curto em [CORRECOES_EMISSAO.md](docs/CORRECOES_EMISSAO.md) antes de atualizar.
|
|
249
|
-
|
|
250
|
-
## Certificado A1
|
|
251
|
-
|
|
252
|
-
### A partir de arquivo
|
|
253
|
-
|
|
254
|
-
```ts
|
|
255
|
-
import { loadPfx } from '@useinvio/nfse-sdk';
|
|
256
|
-
|
|
257
|
-
const pfx = loadPfx('./certificado.pfx', process.env.PFX_PASSWORD!);
|
|
258
|
-
```
|
|
259
|
-
|
|
260
|
-
### A partir de buffer (ex.: certificado descriptografado do banco)
|
|
261
|
-
|
|
262
|
-
```ts
|
|
263
|
-
import { loadPfxFromBuffer } from '@useinvio/nfse-sdk';
|
|
264
|
-
|
|
265
|
-
const pfx = loadPfxFromBuffer(pfxBuffer, password);
|
|
266
|
-
```
|
|
267
|
-
|
|
268
|
-
O objeto `pfx` retornado contém chave privada e certificado em PEM, pronto para assinar e fazer mTLS.
|
|
269
|
-
|
|
270
|
-
---
|
|
271
|
-
|
|
272
|
-
## Emitir a partir de XML pronto
|
|
273
|
-
|
|
274
|
-
Use quando outro sistema (ERP, sistema legado) já gera o XML da DPS no layout nacional.
|
|
275
|
-
|
|
276
|
-
```ts
|
|
277
|
-
import { emitirNfse, loadPfx } from '@useinvio/nfse-sdk';
|
|
278
|
-
|
|
279
|
-
const pfx = loadPfx('./certificado.pfx', process.env.PFX_PASSWORD!);
|
|
280
|
-
|
|
281
|
-
const resultado = await emitirNfse(dpsXml, pfx, { ambiente: 'restrita' });
|
|
282
|
-
|
|
283
|
-
console.log(resultado.chaveAcesso);
|
|
284
|
-
console.log(resultado.nfseXml);
|
|
285
|
-
```
|
|
286
|
-
|
|
287
|
-
> O XML precisa ter `Id` valido em `<infDPS>` e `tpAmb` consistente com o destino. `options.dpsId` apenas seleciona a referencia de assinatura; nao corrige um XML incompleto nem dispensa o XSD.
|
|
288
|
-
|
|
289
|
-
---
|
|
290
|
-
|
|
291
|
-
## Emitir a partir de JSON declarativo
|
|
292
|
-
|
|
293
|
-
Use quando a aplicação mantém os perfis de prestador e serviço e quer que a SDK monte o XML.
|
|
294
|
-
|
|
295
|
-
Para a referência completa de campos aceitos no JSON, consulte [JSON_MAPPING.md](./JSON_MAPPING.md).
|
|
296
|
-
O builder valida formatos e combinações mínimas antes de gerar XML, mas não escolhe códigos fiscais por você. Campos como `tributacaoMunicipal` e `totTrib` precisam ser informados explicita[...]
|
|
297
|
-
|
|
298
|
-
```ts
|
|
299
|
-
import { emitirNfse, loadPfx, type DpsJsonRequest } from '@useinvio/nfse-sdk';
|
|
300
|
-
|
|
301
|
-
const nota: DpsJsonRequest = {
|
|
302
|
-
ambiente: 'restrita',
|
|
303
|
-
prestador: {
|
|
304
|
-
cnpj: '12345678000195',
|
|
305
|
-
cLocEmi: '4106902',
|
|
306
|
-
serie: '1601',
|
|
307
|
-
opSimpNac: '1',
|
|
308
|
-
regEspTrib: '0',
|
|
309
|
-
},
|
|
310
|
-
servico: {
|
|
311
|
-
cTribNac: '010201',
|
|
312
|
-
xDescServ: 'Desenvolvimento de software',
|
|
313
|
-
cLocPrestacao: '4106902',
|
|
314
|
-
cNBS: '115022000',
|
|
315
|
-
},
|
|
316
|
-
emissao: {
|
|
317
|
-
nDPS: '1',
|
|
318
|
-
dhEmi: '2026-06-15T10:30:00-03:00',
|
|
319
|
-
dCompet: '2026-06-01',
|
|
320
|
-
valores: { vServ: '1500.00' },
|
|
321
|
-
tributacaoMunicipal: {
|
|
322
|
-
tribISSQN: '1',
|
|
323
|
-
tpRetISSQN: '1',
|
|
324
|
-
},
|
|
325
|
-
tributacaoFederal: {
|
|
326
|
-
piscofins: { CST: '07' },
|
|
327
|
-
},
|
|
328
|
-
totTrib: {
|
|
329
|
-
pTotTribFed: '0.00',
|
|
330
|
-
pTotTribEst: '0.00',
|
|
331
|
-
pTotTribMun: '5.00',
|
|
332
|
-
},
|
|
76
|
+
tributacaoFederal: { piscofins: { CST: '07' } },
|
|
77
|
+
totTrib: { pTotTribFed: '0.00', pTotTribEst: '0.00', pTotTribMun: '5.00' },
|
|
333
78
|
},
|
|
334
79
|
};
|
|
335
80
|
|
|
336
|
-
const pfx = loadPfx('./certificado.pfx', process.env.PFX_PASSWORD!);
|
|
337
|
-
const resultado = await emitirNfse(nota, pfx);
|
|
338
|
-
```
|
|
339
|
-
|
|
340
|
-
> `pTotTribFed`, `pTotTribEst` e `pTotTribMun` são percentuais com duas casas decimais (ex.: `"5.00"`), diferentes das alíquotas com quatro casas (`pAliq`).
|
|
341
|
-
> O shape simplificado legado de `tribNac` é rejeitado: IBS/CBS no layout nacional `v1.01` exige o bloco RTC `IBSCBS`, ainda não implementado nesta SDK.
|
|
342
|
-
|
|
343
|
-
---
|
|
344
|
-
|
|
345
|
-
## Inspecionar o XML antes de enviar
|
|
346
|
-
|
|
347
|
-
Útil para comparar com um XML de referência, salvar snapshots ou depurar rejeições de schema.
|
|
348
|
-
|
|
349
|
-
```ts
|
|
350
|
-
import { buildDpsFromJson } from '@useinvio/nfse-sdk';
|
|
351
|
-
|
|
352
|
-
const { id, xml } = buildDpsFromJson(nota);
|
|
353
|
-
|
|
354
|
-
console.log(id); // ex.: "DPS..."
|
|
355
|
-
console.log(xml); // XML não assinado da DPS
|
|
356
|
-
```
|
|
357
|
-
|
|
358
|
-
---
|
|
359
|
-
|
|
360
|
-
## Tratar rejeições da SEFIN
|
|
361
|
-
|
|
362
|
-
`emitirNfse` lança `EmitirNotaError` quando a SEFIN retorna HTTP fora de 2xx ou resposta sem XML autorizado.
|
|
363
|
-
|
|
364
|
-
```ts
|
|
365
|
-
import { EmitirNotaError, emitirNfse } from '@useinvio/nfse-sdk';
|
|
366
|
-
|
|
367
81
|
try {
|
|
368
|
-
await emitirNfse(nota,
|
|
82
|
+
const { chaveAcesso, nfseXml } = await emitirNfse(nota, certificado);
|
|
83
|
+
console.log(chaveAcesso); // chave de 50 dígitos
|
|
369
84
|
} catch (error) {
|
|
370
85
|
if (!(error instanceof EmitirNotaError)) throw error;
|
|
371
|
-
|
|
372
|
-
console.log('HTTP:', error.status);
|
|
373
|
-
console.log('DPS ID:', error.dpsId);
|
|
374
|
-
|
|
375
|
-
for (const rejeicao of error.erros) {
|
|
376
|
-
console.log(rejeicao.Codigo); // código oficial SEFIN
|
|
377
|
-
console.log(rejeicao.Descricao); // descrição da rejeição
|
|
378
|
-
console.log(rejeicao.Complemento); // detalhe adicional (quando presente)
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
```
|
|
382
|
-
|
|
383
|
-
---
|
|
384
|
-
|
|
385
|
-
## Consultar uma NFS-e emitida
|
|
386
|
-
|
|
387
|
-
```ts
|
|
388
|
-
import { consultarNfse } from '@useinvio/nfse-sdk';
|
|
389
|
-
|
|
390
|
-
const resposta = await consultarNfse(chaveAcesso, pfx, 'restrita');
|
|
391
|
-
|
|
392
|
-
if (resposta.status === 200) {
|
|
393
|
-
console.log(resposta.body);
|
|
394
|
-
} else {
|
|
395
|
-
console.error('Falha na consulta:', resposta.status, resposta.body);
|
|
86
|
+
for (const rejeicao of error.erros) console.error(rejeicao.Codigo, rejeicao.Descricao);
|
|
396
87
|
}
|
|
397
88
|
```
|
|
398
89
|
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
```ts
|
|
404
|
-
import { enviarEvento, gzipBase64, signEnveloped } from '@useinvio/nfse-sdk';
|
|
405
|
-
|
|
406
|
-
const signedEventXml = signEnveloped(pedRegXml, pedRegId, 'infPedReg', pfx);
|
|
407
|
-
const pedRegXmlGZipB64 = gzipBase64(signedEventXml);
|
|
408
|
-
|
|
409
|
-
const resposta = await enviarEvento(pedRegXmlGZipB64, pfx, chaveAcesso, 'restrita');
|
|
410
|
-
```
|
|
411
|
-
|
|
412
|
-
---
|
|
413
|
-
|
|
414
|
-
## Série e número da DPS
|
|
90
|
+
Primeira vez? Siga o [tutorial](./docs/tutoriais/primeira-nfse.md): emitir,
|
|
91
|
+
consultar, baixar o PDF e cancelar na produção restrita, do zero. Ou experimente
|
|
92
|
+
sem certificado, pelo terminal:
|
|
415
93
|
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
```ts
|
|
419
|
-
// série no perfil do prestador (padrão para todas as DPS)
|
|
420
|
-
prestador: {
|
|
421
|
-
serie: '1601',
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
// ou por emissão (sobrescreve prestador.serie apenas para esta DPS)
|
|
425
|
-
emissao: {
|
|
426
|
-
serie: '1601',
|
|
427
|
-
nDPS: '4',
|
|
428
|
-
}
|
|
429
|
-
```
|
|
430
|
-
|
|
431
|
-
O padrão usual é manter uma `serie` fixa e incrementar `nDPS` em cada nova DPS:
|
|
432
|
-
|
|
433
|
-
```
|
|
434
|
-
serie 1601, nDPS 1
|
|
435
|
-
serie 1601, nDPS 2
|
|
436
|
-
serie 1601, nDPS 3
|
|
437
|
-
```
|
|
438
|
-
|
|
439
|
-
> O Emissor Web usa séries como `70000`. Para emissão via API, use uma série válida para API (ex.: `1601`) e controle o `nDPS` na sua aplicação.
|
|
440
|
-
|
|
441
|
-
---
|
|
442
|
-
|
|
443
|
-
## Ambientes
|
|
444
|
-
|
|
445
|
-
| Chave | URL |
|
|
446
|
-
|---|---|
|
|
447
|
-
| `restrita` | `https://sefin.producaorestrita.nfse.gov.br/SefinNacional` |
|
|
448
|
-
| `producao` | `https://sefin.nfse.gov.br/SefinNacional` |
|
|
449
|
-
|
|
450
|
-
```ts
|
|
451
|
-
import { resolveSefinBaseUrl } from '@useinvio/nfse-sdk';
|
|
452
|
-
|
|
453
|
-
const baseUrl = resolveSefinBaseUrl('restrita');
|
|
94
|
+
```bash
|
|
95
|
+
npx nfse init && npx nfse emit nota.json --mock
|
|
454
96
|
```
|
|
455
97
|
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
## Observabilidade da SEFIN
|
|
459
|
-
|
|
460
|
-
O SDK pode emitir métricas de latência das chamadas mTLS feitas contra a SEFIN quando `NFSE_SEFIN_LATENCY_METRICS=1` está configurada. Por padrão, percentis como `p50Ms`, `p95Ms` e `p99Ms` ficam desligados e precisam de `includePercentiles: true`. Essas métricas medem o round-trip externo da SEFIN, separado da latência total da sua API.
|
|
98
|
+
## Documentação
|
|
461
99
|
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
---
|
|
465
|
-
|
|
466
|
-
## Referência da API
|
|
467
|
-
|
|
468
|
-
### Funções principais
|
|
469
|
-
|
|
470
|
-
| Função | Descrição |
|
|
100
|
+
| Guia | |
|
|
471
101
|
|---|---|
|
|
472
|
-
|
|
|
473
|
-
|
|
|
474
|
-
|
|
|
475
|
-
|
|
|
476
|
-
|
|
|
477
|
-
|
|
|
478
|
-
|
|
|
102
|
+
| [Certificado A1](./docs/guias/certificado.md) | Variáveis de ambiente, cofres de segredo, vários emitentes. |
|
|
103
|
+
| [Emitir](./docs/guias/emitir.md) | JSON, `NfseClient`, XML pronto, série e número. |
|
|
104
|
+
| [Consultar e DANFSe](./docs/guias/consultar.md) | Resultado tipado e PDF. |
|
|
105
|
+
| [Recuperar após timeout](./docs/guias/recuperar-emissao.md) | Sem notas duplicadas quando a conexão cai. |
|
|
106
|
+
| [Cancelar](./docs/guias/cancelar.md) | e101101 e substituição (e105102). |
|
|
107
|
+
| [Erros e rejeições](./docs/guias/rejeicoes.md) | O que cada erro significa e o que fazer. |
|
|
108
|
+
| [Linha de comando](./docs/guias/cli.md) | `nfse doctor`, `emit`, `cancel`, `explain`. |
|
|
109
|
+
| [Testar sem certificado](./docs/guias/testes.md) | SEFIN simulada para o seu CI. |
|
|
110
|
+
| [Agentes de IA e MCP](./docs/guias/agentes-ia.md) | Servidor MCP, plugin do Claude Code, ferramentas para o seu agente. |
|
|
111
|
+
| [Referência da API](./docs/referencia/api.md) | Todas as funções. |
|
|
112
|
+
| [Mapeamento do JSON](./JSON_MAPPING.md) | Cada campo de `DpsJsonRequest`. |
|
|
479
113
|
|
|
480
|
-
|
|
114
|
+
Exemplos executáveis em [`examples/`](./examples).
|
|
481
115
|
|
|
482
|
-
|
|
483
|
-
|---|---|
|
|
484
|
-
| `assertCertificateValidity(pfx, now?)` | Verifica vigencia do certificado; aplicada na preparacao e no envio. |
|
|
485
|
-
| `assertCertificateForProvider(pfx, documento, now?)` | Verifica explicitamente vigencia e correspondencia do titular. |
|
|
486
|
-
| `loadPfx(path, password)` | Carrega certificado A1 a partir de arquivo. |
|
|
487
|
-
| `loadPfxFromBuffer(buffer, password)` | Carrega certificado A1 a partir de buffer. |
|
|
116
|
+
## Com agentes de IA
|
|
488
117
|
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
| Função | Descrição |
|
|
492
|
-
|---|---|
|
|
493
|
-
| `signDps(xml, dpsId, pfx)` | Assina XML de DPS com XMLDSIG. |
|
|
494
|
-
| `signEnveloped(xml, id, ref, pfx)` | Assina XML genérico (eventos). |
|
|
495
|
-
| `verifyDps(xml, certPem)` | Verifica assinatura de uma DPS. |
|
|
496
|
-
| `gzipBase64(xml)` | Compacta XML em GZip e codifica em Base64. |
|
|
497
|
-
| `gunzipBase64(b64)` | Descompacta resposta GZip/Base64. |
|
|
498
|
-
| `extrairErros(body)` | Normaliza erros oficiais de uma resposta da SEFIN. |
|
|
499
|
-
| `resolveSefinBaseUrl(ambiente)` | Retorna a URL base do ambiente. |
|
|
500
|
-
|
|
501
|
-
### Tipos exportados
|
|
502
|
-
|
|
503
|
-
```ts
|
|
504
|
-
import type {
|
|
505
|
-
Ambiente,
|
|
506
|
-
CreateInvoiceInput,
|
|
507
|
-
GetInvoiceOptions,
|
|
508
|
-
DpsJsonInput,
|
|
509
|
-
DpsJsonRequest,
|
|
510
|
-
EmitirNotaOptions,
|
|
511
|
-
NfseClientDpsDefaults,
|
|
512
|
-
NfseClientOptions,
|
|
513
|
-
NotaInput,
|
|
514
|
-
PfxMaterial,
|
|
515
|
-
PrestadorProfile,
|
|
516
|
-
ResultadoEmissaoNota,
|
|
517
|
-
SefinErro,
|
|
518
|
-
SefinResposta,
|
|
519
|
-
ServicoProfile,
|
|
520
|
-
} from '@useinvio/nfse-sdk';
|
|
521
|
-
```
|
|
522
|
-
|
|
523
|
-
### Constantes
|
|
524
|
-
|
|
525
|
-
```ts
|
|
526
|
-
import { SEFIN_BASE_URL, TP_AMB, DEFAULT_AMBIENTE } from '@useinvio/nfse-sdk';
|
|
527
|
-
```
|
|
528
|
-
|
|
529
|
-
---
|
|
530
|
-
|
|
531
|
-
## Desenvolvimento
|
|
118
|
+
Emita uma NFS-e conversando com o Claude. Para experimentar sem certificado, o
|
|
119
|
+
modo de teste usa uma SEFIN simulada:
|
|
532
120
|
|
|
533
121
|
```bash
|
|
534
|
-
|
|
535
|
-
npm run typecheck # verifica tipos sem compilar
|
|
536
|
-
npm run build # compila para dist/
|
|
537
|
-
npm test # build + tipos + testes unitários
|
|
122
|
+
claude mcp add nfse --env NFSE_MCP_MOCK=1 --env NFSE_MCP_ALLOW_WRITE=1 -- npx -y @useinvio/nfse-mcp
|
|
538
123
|
```
|
|
539
124
|
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
### Uso local em outro projeto
|
|
125
|
+
Ou instale o plugin do Claude Code, que inclui o servidor e uma skill com o fluxo:
|
|
543
126
|
|
|
544
|
-
```
|
|
545
|
-
|
|
546
|
-
"dependencies": {
|
|
547
|
-
"@useinvio/nfse-sdk": "file:../nfse-sdk"
|
|
548
|
-
}
|
|
549
|
-
}
|
|
127
|
+
```text
|
|
128
|
+
/plugin install nfse-nacional --marketplace useinvio/nfse-sdk
|
|
550
129
|
```
|
|
551
130
|
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
Pacote publicado publicamente no npm como [`@useinvio/nfse-sdk`](https://www.npmjs.com/package/@useinvio/nfse-sdk).
|
|
557
|
-
|
|
558
|
-
```bash
|
|
559
|
-
npm install
|
|
560
|
-
npm run typecheck
|
|
561
|
-
npm run build
|
|
562
|
-
npm pack --dry-run # verifica o que será publicado
|
|
563
|
-
npm publish
|
|
564
|
-
```
|
|
565
|
-
|
|
566
|
-
O pacote usa `publishConfig.access = public`, necessário para publicar um pacote escopado público no npm.
|
|
567
|
-
|
|
568
|
-
---
|
|
569
|
-
|
|
570
|
-
## Divulgação e exemplos
|
|
571
|
-
|
|
572
|
-
- Exemplos copiáveis ficam em [`examples/`](./examples).
|
|
573
|
-
- Material de lançamento, mensagens para redes e prompt de landing page ficam em [`docs/launch.md`](./docs/launch.md).
|
|
574
|
-
|
|
575
|
-
---
|
|
131
|
+
Emitir e cancelar sempre passam por um resumo que você aprova antes do envio, e
|
|
132
|
+
o certificado nunca chega ao modelo. Veja o [guia de agentes e MCP](./docs/guias/agentes-ia.md).
|
|
133
|
+
Para assistentes de código, o pacote inclui [`llms.txt`](./llms.txt).
|
|
576
134
|
|
|
577
|
-
##
|
|
135
|
+
## O que fica com a sua aplicação
|
|
578
136
|
|
|
579
|
-
|
|
137
|
+
O SDK cuida do protocolo; ele não é um motor fiscal. Códigos de serviço, CST,
|
|
138
|
+
alíquotas, retenções, regime tributário e a numeração da DPS são decisões da
|
|
139
|
+
sua aplicação e de quem cuida da parte tributária. Campos fiscais obrigatórios
|
|
140
|
+
nunca recebem valores padrão silenciosos. O grupo IBS/CBS da reforma tributária
|
|
141
|
+
ainda não é suportado.
|
|
580
142
|
|
|
581
|
-
|
|
582
|
-
- [`docs/gpt-knowledge.md`](./docs/gpt-knowledge.md): resumo compacto para subir como arquivo de Knowledge.
|
|
143
|
+
## Contribuir
|
|
583
144
|
|
|
584
|
-
|
|
145
|
+
Issues e PRs são bem-vindos. Veja [CONTRIBUTING.md](./CONTRIBUTING.md) e o
|
|
146
|
+
[CHANGELOG](./CHANGELOG.md).
|
|
585
147
|
|
|
586
|
-
##
|
|
148
|
+
## Licença
|
|
587
149
|
|
|
588
|
-
|
|
589
|
-
- Funções pequenas, testáveis e reutilizáveis.
|
|
590
|
-
- Erros oficiais da SEFIN são preservados na íntegra, não engolidos.
|
|
591
|
-
- O SDK transporta declarações fiscais; não valida se estão contabilmente corretas.
|
|
150
|
+
[MIT](./LICENSE) © Invio
|