Integración por REST local

Referencia técnica para integración por rest local dentro del cliente local.

Objetivo

Esta guía describe cómo integrar un sistema externo con el cliente local usando HTTP local, ya sea por loopback o por la IP del equipo en la LAN.

Si estás empezando la integración, primero lee Bandeja REST del cliente local. Esa guía funciona como punto de entrada y esta página queda como referencia operativa endpoint por endpoint.

Está pensada para integradores. Cubre:

URL base

Base URL por defecto:

http://127.0.0.1:18787

Notas:

Ejemplos de configuracion:

Endpoints disponibles

MétodoEndpointUso
GET/healthEstado rápido del daemon
GET/stateEstado local
POST/enqueueEncolado asíncrono
POST/status-cfeConsulta de estado por uuid o folio
POST/sign-cfeNumeración y firma con respuesta inmediata
POST/reprintReimpresión
POST/pdfGeneración de PDF
GET/proximo-serie-nroPróximo folio local
POST/validar-xmlValidación local
POST/existe-constanciaVerificación de existencia local

Ruteo por punto de emisión

Hay dos modos:

Regla:

Modos de integración REST

La bandeja REST local admite dos formas de integración:

Integración sincrónica

Usar POST /sign-cfe cuando la aplicación necesita cerrar la operación en la misma llamada y recibir de inmediato:

Casos típicos:

Tradeoff:

Integración asíncrona

Usar POST /enqueue cuando la aplicación solo necesita entregar el trabajo al módulo local y continuar.

El flujo recomendado es:

  1. enviar POST /enqueue
  2. guardar el uuid
  3. consultar POST /status-cfe hasta obtener un estado final

Casos típicos:

Tradeoff:

Regla práctica de elección

Elegir sincrónico si el integrador necesita el folio y el XML firmado en el acto.

Elegir asíncrono si el integrador puede trabajar con un uuid propio y consultar luego el resultado.

GET /health

Ejemplo:

curl http://127.0.0.1:18787/health

Respuesta esperada:

{
  "ok": true,
  "service": "modulo_local_daemon",
  "rest_base_url": "http://127.0.0.1:18787",
  "state": {
    "running": true
  }
}

GET /state

Devuelve el estado operativo local del daemon.

Uso recomendado:

POST /enqueue

Encola un comprobante para procesamiento local asíncrono.

Ejemplo:

{
  "tipo_cfe": 111,
  "uuid": "externo-123",
  "cod_comercio": "1",
  "cod_terminal": "1",
  "xml": "<CFE xmlns=\"http://cfe.dgi.gub.uy\" version=\"1.0\">...</CFE>",
  "adenda": "Texto opcional",
  "emails": ["[email protected]"],
  "impresora": "CajaFiscal;FORMATO=personalizado;COPIAS=2",
  "send_now": true
}

Respuesta:

{
  "ok": true,
  "stored_path": "/ruta/local/inbox/20260318121000123-externo-123.json",
  "uuid": "externo-123",
  "send_now": true
}

Importante:

POST /status-cfe

Consulta el estado local de un comprobante previamente encolado o firmado.

Permite buscar por:

Si se trabaja con varios puntos de emisión, conviene reenviar también:

Ejemplo por uuid:

{
  "uuid": "externo-123",
  "cod_comercio": "1",
  "cod_terminal": "1"
}

Respuesta cuando sigue en cola:

{
  "ok": true,
  "found": true,
  "uuid": "externo-123",
  "tipo_cfe": 111,
  "serie": "A",
  "numero": 301,
  "estado": "queued",
  "estado_descripcion": "En cola de envio",
  "codigo_respuesta": "11",
  "mensaje_respuesta": "En cola de envio",
  "codigo_terminal": "1",
  "codigo_comercio": "1",
  "retry_count": 0,
  "attempt_count": 1,
  "last_error": null,
  "last_error_code": null,
  "last_error_stage": null,
  "last_attempt_at": null,
  "next_retry_at": null,
  "confirmed_at": null,
  "fecha_firma_cfe": "2026-03-18T12:10:00Z",
  "NroConstanciaCae": "90160001010",
  "numero_inicial_cae": "301",
  "numero_final_cae": "400",
  "vencimiento_cae": "2028-01-01"
}

Respuesta cuando ya fue aceptado:

{
  "ok": true,
  "found": true,
  "uuid": "externo-123",
  "tipo_cfe": 111,
  "serie": "A",
  "numero": 301,
  "estado": "accepted",
  "estado_descripcion": "Aceptado",
  "codigo_respuesta": "00",
  "mensaje_respuesta": "Aceptado",
  "codigo_terminal": "1",
  "codigo_comercio": "1",
  "retry_count": 0,
  "attempt_count": 1,
  "last_error": null,
  "last_error_code": null,
  "last_error_stage": null,
  "last_attempt_at": "2026-03-18T12:10:03Z",
  "next_retry_at": null,
  "confirmed_at": "2026-03-18T12:10:05Z",
  "fecha_firma_cfe": "2026-03-18T12:10:00Z",
  "NroConstanciaCae": "90160001010",
  "numero_inicial_cae": "301",
  "numero_final_cae": "400",
  "vencimiento_cae": "2028-01-01"
}

POST /sign-cfe

Numerar, firmar y responder en el acto.

Precondición operativa:

Si esa condición no se cumple, la firma se rechaza con codigo_respuesta = "96".

Si send_now dispara el envío SOAP inmediato y no hay un timeout explícito configurado, el módulo local usa 60000 ms por defecto para EnviarCfeFirmado.

Ejemplo:

{
  "tipo_cfe": 111,
  "uuid": "externo-123",
  "cod_comercio": "1",
  "cod_terminal": "1",
  "xml": "<CFE xmlns=\"http://cfe.dgi.gub.uy\" version=\"1.0\">...</CFE>",
  "adenda": "Texto opcional",
  "emails": ["[email protected]"],
  "impresora": "CajaFiscal;FORMATO=personalizado;COPIAS=2",
  "send_now": false
}

Respuesta de éxito:

{
  "Uuid": "externo-123",
  "TipoCfe": "111",
  "Serie": "A",
  "Numero": "301",
  "CodigoRespuesta": "00",
  "MensajeRespuesta": "CFE firmado y encolado",
  "CodigoTerminal": "1",
  "CodigoComercio": "1",
  "NumeroInicialCae": "301",
  "NumeroFinalCae": "400",
  "VencimientoCae": "2028-01-01",
  "CfeFirmado": "<CFE>...</CFE>",
  "DatosCodigoQr": "https://...",
  "CodigoSeguridad": "ZmCpqT",
  "FechaFirmaCfe": "2026-03-18T12:10:00Z",
  "ImagenQr": null,
  "NroConstanciaCae": "90160001010"
}

Respuesta de error:

{
  "Uuid": "externo-123",
  "TipoCfe": "111",
  "Serie": null,
  "Numero": null,
  "CodigoRespuesta": "31",
  "MensajeRespuesta": "validation error: ...",
  "CodigoTerminal": "1",
  "CodigoComercio": "1",
  "NumeroInicialCae": null,
  "NumeroFinalCae": null,
  "VencimientoCae": null,
  "CfeFirmado": null,
  "DatosCodigoQr": null,
  "CodigoSeguridad": null,
  "FechaFirmaCfe": null,
  "ImagenQr": null,
  "NroConstanciaCae": null
}

Códigos funcionales

codigo_respuestaInterpretación
00Éxito
01Petición denegada
03Comercio inválido
12Requerimiento inválido
30Error en formato
31Error en formato de CFE
89Terminal inválida
96Error interno, de firma, permisos, rango, persistencia o SOAP

Códigos HTTP

HTTPInterpretación
200Operación procesada; revisar codigo_respuesta
422Request inválido o XML rechazado tempranamente
500Error interno del daemon

Regla recomendada:

POST /reprint

Encola la reimpresión de un comprobante emitido.

Se puede localizar por:

Ejemplo:

{
  "uuid": "externo-123",
  "impresora": "CajaFiscal;FORMATO=personalizado;COPIAS=2",
  "variant": "personalizado",
  "fallback_copies": 2,
  "cod_comercio": "1",
  "cod_terminal": "1"
}

Respuesta:

{
  "ok": true,
  "queued": true
}

HTTP esperado:

POST /pdf

Genera el PDF de un comprobante ya emitido y devuelve el binario.

Ejemplo:

{
  "uuid": "externo-123",
  "impresora": "pdf",
  "variant": "personalizado",
  "fallback_copies": 1,
  "cod_comercio": "1",
  "cod_terminal": "1"
}

Respuesta:

GET /proximo-serie-nro

Ejemplo:

curl "http://127.0.0.1:18787/proximo-serie-nro?tipo_cfe=111&cod_comercio=1&cod_terminal=1"

Respuesta con rango activo:

{
  "ok": true,
  "tipo_cfe": 111,
  "serie": "A",
  "numero_siguiente": 301,
  "numero_desde": 301,
  "numero_hasta": 400,
  "disponibles": 100,
  "vencimiento_cae": "2028-01-01"
}

POST /validar-xml

Request:

{
  "xml": "<CFE xmlns=\"http://cfe.dgi.gub.uy\" version=\"1.0\">...</CFE>"
}

Respuesta:

{
  "ok": true,
  "valido": false,
  "issues": []
}

POST /existe-constancia

Request:

{
  "tipo_cfe": 111,
  "serie": "A",
  "numero": 301,
  "cod_comercio": "1",
  "cod_terminal": "1"
}

Respuesta cuando existe:

{
  "ok": true,
  "existe": true,
  "codigo_respuesta": "00",
  "estado": "Accepted",
  "uuid": "externo-123",
  "tipo_cfe": 111,
  "serie": "A",
  "numero": 301
}

Impresoras

Los endpoints que usan impresora aceptan una especificación textual.

Ejemplos:

Parámetros:

ParámetroDescripción
nombre baseNombre o destino de impresora
FORMATO=personalizadoPlantilla HTML/PDF
FORMATO=escposImpresión térmica ESC/POS RAW
FORMATO=roll, FORMATO=rollo, FORMATO=tmlPDF tipo ticket usando parser .tml
COPIAS=2Cantidad de copias

Errores frecuentes

Recomendaciones