Documentación oficial

NFS-e Personalizada (Driver Externo)

El ExternalNfseDriver permite integrar cualquier proveedor de NFS-e que no puede soportarse directamente en el backend (p. ej. un sistema municipal sin SDK Node) a través de un único endpoint HTTP estilo RPC.

Referencia canónica: un contrato formal OpenAPI 3.0 está disponible en External-NFSE-Driver-OpenAPI.yaml. Úsalo para validar tu implementación con herramientas OpenAPI o para generar stubs de servidor.

Cómo funciona

Cada operación de NFS-e se delega al endpoint externo configurado vía un POST a la raíz del endpoint (/). El cuerpo de la petición lleva un campo operation que enruta la llamada:

operation Disparado por Propósito
getDriverDetails Botón “Sincronizar opciones” de la página de configuración Devuelve campos dinámicos de configuración + operaciones soportadas. Cacheado en el backend.
emit POST /invoices/:id/nfse (manual o automático) Emitir una NFS-e para una factura pagada.
fetchStatus Actualización de estado Consultar el estado de una NFS-e ya emitida.
getPdf GET /invoices/:id/nfse/pdf Devolver el PDF de la NFS-e (base64).
getXml GET /invoices/:id/nfse/xml Devolver el XML de la NFS-e.
cancel Flujo de cancelación Cancelar una NFS-e ya emitida.

Configuración (super configuraciones, prefijo _externalNfse)

Campo Descripción
_externalNfseEndpointUrl URL base del endpoint RPC externo.
_externalNfseAuthToken Token Bearer enviado en la cabecera Authorization.
Campos dinámicos Devueltos por la operación getDriverDetails y cacheados.

Payload de petición

{
  "operation": "emit",
  "driver": "external",
  "invoiceId": 42,
  "company": { "id": 1, "name": "Acme", "fiscalData": { "document": "..." } },
  "invoice": { "id": 42, "status": "paid", "value": 99.9, "dueDate": "2026-06-01" },
  "nfseData": {},
  "currentSettings": { "_externalNfseEndpointUrl": "..." },
  "idempotencyKey": "uuid-v4"
}

Payload de respuesta

{
  "success": true,
  "status": "authorized",
  "nfseData": { "driver": "external", "nfseId": "...", "nfseUrl": "..." },
  "nfseUrl": "https://..."
}

status también puede ser pending (cuando el proveedor procesará la nota de forma asíncrona) o error (cuando la petición falló, pero la operación en sí fue comprendida). En el caso error, el backend almacena nfseData.nfseStatus = "ERROR" y nfseData.nfseErrorMessage y notifica al frontend vía evento websocket NFSE_ERRO.

Para getPdf:

{
  "success": true,
  "pdfBase64": "JVBERi0xLjQ..."
}

Para getXml:

{
  "success": true,
  "xml": "<?xml version=\"1.0\"?>..."
}

Para getDriverDetails:

{
  "success": true,
  "fields": [
    { "name": "municipalCode", "title": "Código municipal", "type": "text" }
  ],
  "operations": ["emit", "fetchStatus", "getPdf", "getXml"]
}

El array fields sigue el mismo schema usado por el componente DynamicForm del frontend. Consulta Campos de formulario dinámico para la referencia completa de propiedades y ejemplos listos para copiar.

En caso de fallo:

{
  "success": false,
  "errorCode": "ERR_PROVIDER_REJECTED",
  "errorMessage": "Rejeição fiscal..."
}

Política de retry

El driver reintenta en errores transitorios (ECONNRESET, ECONNREFUSED, ETIMEDOUT, ENOTFOUND, EAI_AGAIN, HTTP 5xx y 429) con retrasos de 1s, 3s, 5s. Los errores permanentes (4xx excepto 429) fallan inmediatamente.

Especificación OpenAPI

Consulta External-NFSE-Driver-OpenAPI.yaml para el contrato completo legible por máquina.