Pacote de integração para NFSe Campinas no Padrão Nacional NFS-e / DPS v1.01, conforme implantação da Reforma Tributária do Consumo.
A versão 3.x não usa mais ABRASF 2.03, RPS, SOAP ou WSDL. A API pública passa a trabalhar com DPS e envio REST/JSON municipal.
Para continuar usando ABRASF 2.03, instale a linha anterior:
pnpm add @4success/nfse-campinas@^2Para DSFNET legacy, use a linha 1.x.
pnpm add @4success/nfse-campinasOs novos endereços de Campinas são usados por padrão, incluindo cancelamento em produção. O
guia oficial atualizado em 18/09/2026
informa a disponibilidade de produção desde 21/09/2026.
- Base de homologação:
https://preprod-nfseapi.ima.sp.gov.br/notafiscal-ws/nfse. - Base de produção:
https://nfseapi.campinas.sp.gov.br/notafiscal-ws/nfse.
| Operação | Método e rota |
|---|---|
| Envio de DPS | POST {base} |
| Consulta por DPS | GET {base}/dps/{idDps} |
| Consulta de NFSe | GET {base}/{chaveAcesso} |
| Cancelamento | POST {base}/{chaveAcesso}/eventos |
Para configurar endereços próprios, use endpoints.dps, endpoints.consulta, endpoints.consultaDps e
endpoints.eventos. A consulta por DPS prioriza consultaDps; se ausente, reutiliza um dps explicitamente configurado
para preservar integrações antigas. Sem esses overrides, usa a constante de consulta por DPS do ambiente. Ao
sobrescrever o envio com o novo endereço terminado em /nfse, informe também consultaDps terminado em /nfse/dps.
O SDK desabilita redirecionamentos HTTP (maxRedirects: 0). Um 302 gera erro imediato com o status e o cabeçalho
Location preservados, evitando que o redirecionamento converta um POST em GET. Consulte
o guia de homologação para diagnosticar esses erros.
import fs from 'node:fs';
import { assertNfseXmlMatchesDps, decodeNfseXmlGZipB64, NfseCampinas } from '@4success/nfse-campinas';
const nfse = new NfseCampinas({
environment: 'homologacao',
certificate: fs.readFileSync('./certificado.pfx'),
certPassword: process.env.CERTIFICATE_PASSWORD!,
// O endpoint de homologacao pode levar mais de 30 segundos para responder.
timeoutMs: 120000,
});
const result = await nfse.enviarDps({
ambiente: 'homologacao',
serie: '00001',
numeroDps: '1',
dataCompetencia: '2026-06-30',
dataHoraEmissao: '2026-06-30T21:41:28-03:00',
tipoEmitente: 1,
municipioEmissao: '3509502',
prestador: {
cnpj: '99999999000199',
inscricaoMunicipal: '123456',
regimeTributario: { opcaoSimplesNacional: 1, regimeEspecialTributacao: 0 },
},
tomador: {
cnpj: '99999999000199',
razaoSocial: 'TOMADOR LTDA',
endereco: { municipio: '3509502', cep: '13000000', logradouro: 'Rua Exemplo', numero: '100', bairro: 'Centro' },
},
servico: {
municipioPrestacao: '3509502',
codigoTributacaoNacional: '010601',
codigoTributacaoMunicipal: '001',
descricao: 'descricao do servico prestado para fins de homologacao',
codigoNbs: '115011000',
},
valores: {
valorServico: '26947.27',
tributacaoMunicipal: { tributacaoIssqn: 1, tipoRetencaoIssqn: 1, aliquota: '5' },
tributacaoFederal: {
pisCofins: { cst: '00', tipoRetencaoPisCofins: 0 },
},
totalTributos: { indicadorTotalTributos: 0 },
},
ibsCbs: {
finalidadeNfse: 0,
codigoIndicadorOperacao: '100301',
indicadorDestinatario: 0,
cst: '000',
classificacaoTributaria: '000001',
},
});
console.log(result.status);
console.log(result.idDps);
console.log(result.rawResponse);
if (result.nfseXmlGZipB64) {
const nfseXml = decodeNfseXmlGZipB64(result.nfseXmlGZipB64);
assertNfseXmlMatchesDps(nfseXml, result.idDps);
console.log(nfseXml);
const danfseHtml = await nfse.imprimirDanfse({ nfseXmlGZipB64: result.nfseXmlGZipB64 });
console.log(danfseHtml);
}rawResponse preserva a resposta original da Prefeitura, parsedResponse expõe o corpo parseado quando possível, e
nfseXmlGZipB64 traz o XML autorizado da NFSe compactado em GZip/Base64.
Consulte uma NFSe autorizada pela chave de acesso retornada no envio:
const consulta = await nfse.consultarNfse('NFS35095022215547137000138000000000210026073571802007');
if (consulta.nfseXmlGZipB64) {
const xml = decodeNfseXmlGZipB64(consulta.nfseXmlGZipB64);
console.log(xml);
}Uma NFSe inexistente retorna HTTP 400 com alertas da Prefeitura, preservados em ConsultaHttpError.response.
Informe os dados do cancelamento. O SDK monta o pedRegEvento v1.01, gera o identificador do pedido, assina
infPedReg com o certificado configurado e transmite o evento 101101:
const cancelamento = await nfse.cancelarNfse({
chaveAcesso: 'NFS35095022215547137000138000000000210026073571802007',
autor: { cnpj: '15547137000138' },
codigoMotivo: 2,
motivo: 'Serviço não prestado pelo fornecedor conforme acordado',
dataHoraEvento: '2026-08-18T14:30:00-03:00', // opcional; por padrão, usa o instante atual
});
console.log(cancelamento.alertas);
console.log(cancelamento.rawResponse);Em homologação, a chamada síncrona usa
POST https://preprod-nfseapi.ima.sp.gov.br/notafiscal-ws/nfse/{chaveAcesso}/eventos. O SDK compacta o XML
assinado com GZip/Base64 e envia o JSON { pedidoRegistroEventoXmlGZipB64 }. Também é possível fornecer um
signedXml externo já pronto; nesse caso, o SDK preserva o XML e não o reassina. Consulte
o guia de cancelamento para configurar produção, usar essa opção avançada e tratar a resposta.
O exemplo local de consulta está em exemplos/consultar-nfse.ts; ele usa CERTIFICATE_PATH, CERTIFICATE_PASSWORD e
a chave de acesso como primeiro argumento.
Quando o envio tiver resultado incerto — por exemplo, timeout depois de a Prefeitura receber a DPS — consulte o mesmo identificador antes de considerar qualquer reenvio:
const consultaDps = await nfse.consultarDps('DPS350950221234567800019900001000000000000001');
console.log(consultaDps.chaveAcesso);consultarNfsePorDps é um alias de consultarDps. A consulta usa certificado digital (mTLS), e a chave só é revelada
quando o titular do certificado corresponde ao prestador, tomador ou intermediário da NFS-e. Erros HTTP preservam
alertas e a resposta bruta em ConsultaDpsHttpError.response.
Por segurança, não associe a chave retornada ao seu documento sem consultar a NFS-e e conferir se o Id de infDPS
no XML autorizado é igual ao identificador solicitado. Essa conferência também protege contra uma resposta municipal
inconsistente:
if (!consultaDps.chaveAcesso) {
throw new Error(`Consulta da DPS não retornou chave: ${consultaDps.rawResponse}`);
}
const chaveConsulta = consultaDps.chaveAcesso.startsWith('NFS')
? consultaDps.chaveAcesso
: `NFS${consultaDps.chaveAcesso}`;
const consultaNfse = await nfse.consultarNfse(chaveConsulta);
if (!consultaNfse.nfseXmlGZipB64) {
throw new Error(`Consulta da NFS-e não retornou XML: ${consultaNfse.rawResponse}`);
}
const xml = decodeNfseXmlGZipB64(consultaNfse.nfseXmlGZipB64);
assertNfseXmlMatchesDps(xml, 'DPS350950221234567800019900001000000000000001');O exemplo local completo está em exemplos/consultar-dps.ts.
Depois que a Prefeitura autoriza a NFSe, use o XML autorizado para gerar o HTML imprimível do DANFSe:
const html = await nfse.imprimirDanfse({ nfseXmlGZipB64: result.nfseXmlGZipB64! });Também é possível informar o XML autorizado já descompactado:
const html = await nfse.imprimirDanfse({ xml: nfseXml });O método retorna HTML. A geração de PDF deve ser feita pelo consumidor a partir desse HTML, usando o renderer apropriado para o ambiente de execução.
A classificação IBS/CBS é lida da DPS incluída no XML autorizado; os valores apurados são lidos do bloco IBS/CBS da NFS-e. XMLs históricos com os dados em apenas um desses blocos continuam aceitos. Não é necessário enriquecer o XML com snapshots do emissor para imprimir esses valores.
O ISS prioriza valores/pAliqAplic da NFS-e e, quando ausente, usa tribMun/pAliq da DPS incorporada.
Alíquotas informadas como zero são exibidas como 0,00%; campos ausentes continuam com -.
O indicador indDest=0 identifica o próprio tomador como destinatário. Nomes de municípios também podem ser
resolvidos pelo par cLocalidadeIncid/xLocalidadeIncid no mesmo XML. Horários, telefones e textos declarados são
preservados conforme o XML autorizado.
Opcionalmente, descricaoServico pode recuperar as quebras de linha da descrição original somente na apresentação:
const html = await nfse.imprimirDanfse({ xml: nfseXml, descricaoServico: descricaoOriginal });O complemento é aceito apenas quando seu texto integral coincide com a descrição do XML após remover exclusivamente CR e LF dos dois lados. Espaços, tabulações e todos os outros caracteres continuam significativos; as entidades XML são decodificadas uma vez para essa comparação. Uma divergência ignora o complemento e mantém a descrição autorizada. Tipos diferentes de string são rejeitados. O XML, sua assinatura e os campos tributários não são modificados. As quebras e os parágrafos vazios são preservados na apresentação, mantendo o escape HTML da descrição.
- Use certificado A1
.pfx/.p12do prestador. - Nunca versione certificados, senhas, XML real de cliente ou respostas com dados pessoais.
debug=trueimprime XML e resposta brutos para diagnóstico local.
Consulte docs/v3/migracao-v2-para-v3.md para o mapa entre ABRASF/RPS/SOAP e Padrão Nacional/DPS.