@creativeproject/fiscal-gateway
v0.4.0
Published
SDK Node.js/TypeScript do Fiscal Gateway — emissão de NFS-e Padrão Nacional
Maintainers
Readme
@creativeproject/fiscal-gateway
SDK Node.js/TypeScript do Fiscal Gateway da Creative Project — emissão de NFS-e Padrão Nacional com uma chamada de função.
- Zero dependências (usa
fetchnativo — Node 18+) - ESM + CJS + tipos TypeScript completos
- Retry automático com backoff para 429/5xx/falhas de rede (seguro: a emissão é idempotente)
- Verificação de assinatura HMAC de webhooks embutida (com replay protection)
Instalação
npm install @creativeproject/fiscal-gatewayUso
Emitir uma NFS-e
import { FiscalGateway } from '@creativeproject/fiscal-gateway';
const fiscal = new FiscalGateway({
apiKey: process.env.FISCAL_API_KEY!,
baseUrl: 'https://api.fiscal.creativeproject.com.br',
});
const nota = await fiscal.nfse.emit({
organizationId: 'org_...',
externalId: 'charge_987', // seu ID — reenviar nunca duplica a nota
customer: { name: 'João da Silva', cpfCnpj: '39053344705' },
service: { description: 'Taxa de administração 06/2026', amount: 200.0 },
metadata: { source: 'mylapro', contractId: 'contract_123' },
});
// nota.status === 'pending' — o resultado chega via webhookReceber o resultado via webhook (recomendado)
import express from 'express';
import { createWebhookHandler } from '@creativeproject/fiscal-gateway';
const app = express();
// IMPORTANTE: express.raw — o HMAC é calculado sobre o corpo cru
app.post(
'/hooks/fiscal',
express.raw({ type: 'application/json' }),
createWebhookHandler({
secret: process.env.FISCAL_WEBHOOK_SECRET!, // retornado ao criar o endpoint
onAuthorized: async (nota) => {
await marcarCobrancaComNota(nota.externalId, nota.accessKey!);
},
onRejected: async (nota) => {
await alertarOperacao(nota.externalId, nota.rejectionReason!);
},
onCancelled: async (nota) => { /* ... */ },
}),
);Ou verifique manualmente (qualquer framework):
import { verifyWebhook } from '@creativeproject/fiscal-gateway';
const event = verifyWebhook(rawBody, req.headers['x-fiscal-signature'], secret);
// lança WebhookVerificationError se a assinatura for inválida/expiradaOutras operações
// Consulta e polling (scripts/testes — em produção prefira webhooks)
const doc = await fiscal.nfse.get(id);
const final = await fiscal.nfse.waitForResult(id, { timeoutMs: 30_000 });
// Listagem, XML, DANFSe, cancelamento
const lista = await fiscal.nfse.list({ status: 'authorized', limit: 20 });
const xml = await fiscal.nfse.xml(id);
const { url } = await fiscal.nfse.pdf(id); // URL pré-assinada (15 min)
await fiscal.nfse.cancel(id, 'Valor incorreto');
// Consulta/cancelamento POR CHAVE DE ACESSO — funciona inclusive para notas
// emitidas FORA do gateway (Emissor Web), desde que do mesmo CNPJ:
const nota = await fiscal.nfse.consultByKey(accessKey, organizationId); // XML + dados da Sefin
const pdf = await fiscal.nfse.officialDanfse(accessKey, organizationId); // ArrayBuffer do PDF oficial
await fiscal.nfse.cancelByKey(accessKey, organizationId, 'Valor incorreto');
// Emissão completa: endereço do tomador + tributos federais (todos opcionais)
await fiscal.nfse.emit({
organizationId,
externalId: 'invoice_77',
customer: { name: 'Diagonal Ltda', cpfCnpj: '01115194000133', email: '[email protected]' },
service: { description: 'Consultoria', amount: 13971.99 },
customerAddress: { cityCode: '3550308', zipCode: '01009907', street: 'Líbero Badaró', number: '293', complement: 'Andar 31', neighborhood: 'Centro' },
federalTaxes: { pisCofinsCst: '00', vRetIRRF: 15.5, vRetCSLL: 10 },
});
// Emissão com retenção de ISS nesta nota (ex.: tomador PJ que retém):
await fiscal.nfse.emit({
organizationId,
externalId: 'invoice_42',
customer: { name: 'Holding XYZ', cpfCnpj: '11222333000181' },
service: { description: 'Consultoria', amount: 5000, issWithheld: true },
});
// Buscar código de tributação nacional (cTribNac) — autocomplete no onboarding
const codes = await fiscal.serviceCodes.search({ q: 'corretagem' });
// codes.items → [{ code: '100501', description: 'Agenciamento, corretagem...' }, ...]
const detail = await fiscal.serviceCodes.get('080201');
// Onboarding de organizações
const org = await fiscal.organizations.create({
cnpj: '12345678000190',
legalName: 'Imobiliária Alfa Ltda',
cityCode: '3550308',
state: 'SP',
taxRegime: 'simples_nacional',
fiscalSettings: {
provider: 'nacional',
serviceCode: '070101',
serviceDescription: 'Administração imobiliária',
issRate: 2.0,
},
});
await fiscal.organizations.addCredential(org.id, {
type: 'certificate_a1',
payload: { pfxBase64: '...', password: '...' }, // validado no upload
});
// Webhook endpoints
const endpoint = await fiscal.webhookEndpoints.create('https://meuapp.com/hooks/fiscal');
console.log(endpoint.secret); // exibido SÓ aqui — guarde no seu secret managerTratamento de erros
import { FiscalGatewayError } from '@creativeproject/fiscal-gateway';
try {
await fiscal.nfse.emit(params);
} catch (err) {
if (err instanceof FiscalGatewayError) {
err.status; // HTTP status
err.body; // corpo da resposta do gateway
err.isClientError; // 4xx — corrija o payload, não retente
}
}Erros 429/5xx/rede são retentados automaticamente (3x, backoff exponencial). Configure com maxRetries e timeoutMs no construtor.
Desenvolvimento
npm install
npm test # vitest — 14 testes (HMAC, retry, contrato HTTP)
npm run build # tsup — dist/ com ESM + CJS + .d.tsPublicação no npm
O prepublishOnly roda testes + build automaticamente.
Opção A — npm público (npmjs.com)
# 1ª vez: criar a organização "creativeproject" em npmjs.com e fazer login
npm login
cd packages/sdk
npm version patch # ou minor/major — atualiza package.json e cria tag
npm publish # access public já configurado no package.jsonOpção B — GitHub Packages (privado, dentro da org)
# .npmrc do projeto consumidor:
# @creativeproject:registry=https://npm.pkg.github.com
cd packages/sdk
npm publish --registry=https://npm.pkg.github.comOpção C — automática por tag (workflow já configurado)
git tag sdk-v0.1.0 && git push origin sdk-v0.1.0
# o workflow .github/workflows/publish-sdk.yml testa, builda e publica
# requer o secret NPM_TOKEN configurado no repositório (npmjs → Access Tokens → Automation)