Integra la emisión, firma y transmisión de Comprobantes Fiscales
Electrónicos ante la DGII con una sola API. Custodiamos el certificado
de cada emisor cifrado y firmamos los e-CF en su nombre, mientras tú
te concentras en tu producto.
Autenticación Bearer
Respuesta JSON uniforme
Trazabilidad total
SynerCore e-CF, operado por SYNERX SRL — Emisor Electrónico certificado por la DGII y actualmente en proceso de autorización como Proveedor de Servicios de Facturación Electrónica. Operamos en modelo SaaS: tú integras una sola API y nosotros nos encargamos de firmar y transmitir los comprobantes de cada uno de tus emisores.
API producción
api.ecf.synercore.do
API staging
devapi.ecf.synercore.do
Panel web
app.ecf.synercore.do
pruebas: devapp.ecf.synercore.do
Todas las respuestas de la API siguen un mismo sobre (envelope).
Una operación exitosa devuelve success: true junto al objeto data; un fallo devuelve success: false junto a un objeto error con message y statusCode. Mantén este contrato presente en toda tu integración.
Seguridad
Autenticación
La API se autentica con una clave de máquina (API key) enviada en la cabecera Authorization. El panel web usa JWT para usuarios humanos; tu integración siempre usa la API key.
Incluye tu clave en cada petición con el esquema Bearer. Toda solicitud que envíe o reciba JSON debe declarar también Content-Type: application/json.
Trata tu API key como una contraseña. Si se compromete, cualquiera
podría emitir comprobantes en nombre de tus emisores. Guárdala en
el servidor y rótala desde el panel ante cualquier sospecha.
Cabecera X-Emisor-RNC (requerida con la API key de integrador). Cuando
autenticas con la API key de integrador, cada
emisión (POST /v1/comprobantes) debe incluir esta cabecera con el RNC del emisor por el que
emites. El servicio valida que ese emisor sea tuyo: responde 400 si falta la cabecera, 404 si el RNC no corresponde a ninguno de tus emisores y 403 si el emisor no pertenece a tu integrador. Con la API key de un
emisor concreto la cabecera no es necesaria.
Cómo funciona
Flujo de integración
Como integrador das de alta a tus propios emisores (clientes), cargas el certificado de cada uno y emites e-CF en su nombre. Estos son los cuatro pasos del ciclo completo.
01
Recibe tu API key
Te entregamos una clave de integrador con la que autenticas todas tus llamadas a la API.
02
Da de alta tus emisores y sube el certificado
Registra a cada cliente (emisor) y carga su archivo .p12. Lo custodiamos cifrado con AES-256-GCM, con la clave maestra fuera de la base de datos; nunca queda expuesto.
03
Emite e-CF en su nombre
Envía el comprobante a POST /v1/comprobantes. Lo firmamos con el certificado del emisor y, si lo pides, lo transmitimos a la DGII.
04
Consulta estado, XML y QR
Verifica el estado en la DGII, descarga el XML firmado y obtén la bitácora de eventos para tu respaldo fiscal.
Emisión
Emitir un e-CF
Para emitir un comprobante envía un objeto ComprobanteInput a POST /v1/comprobantes. Con transmitir: true lo firmamos y lo enviamos a la DGII en la misma operación.
La validación de la DGII es asíncrona. La respuesta inicial puede
devolver estadoDgii: "EN_COLA"; consulta el comprobante más tarde para conocer el resultado
definitivo.
Integración
Ejemplos por lenguaje
El mismo request — emitir un Crédito Fiscal (tipo 31) — implementado en seis lenguajes. Todos apuntan a la misma URL, envían el mismo cuerpo JSON, leen eNCF, estado y codigoSeguridad, y manejan el error cuando el status es 400 o superior.
Cada snippet lee la API key desde la variable de entorno ECF_API_KEY. Nunca incrustes la clave en el código fuente. Cambia api.ecf.synercore.do por devapi.ecf.synercore.do para probar en staging.
// .NET 6+ — HttpClient + System.Text.Json
using System;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
class Program
{
const string ApiBase = "https://api.ecf.synercore.do";
static async Task Main()
{
var apiKey = Environment.GetEnvironmentVariable("ECF_API_KEY");
var payload = new
{
tipo = "31",
eNCF = "E310000000123",
fechaVencimientoSecuencia = "31-12-2026",
comprador = new { rnc = "131880681", razonSocial = "CLIENTE SRL" },
items = new[]
{
new { nombre = "Servicio de consultoría", cantidad = 1, precioUnitario = 10000, itbis = 18 }
},
tipoPago = 1,
transmitir = true
};
using var http = new HttpClient();
http.DefaultRequestHeaders.Add("Authorization", $"Bearer {apiKey}");
var json = JsonSerializer.Serialize(payload);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var res = await http.PostAsync($"{ApiBase}/v1/comprobantes", content);
var bodyText = await res.Content.ReadAsStringAsync();
using var doc = JsonDocument.Parse(bodyText);
var root = doc.RootElement;
if ((int)res.StatusCode >= 400 || !root.GetProperty("success").GetBoolean())
{
var msg = root.GetProperty("error").GetProperty("message").GetString();
throw new Exception(msg ?? $"HTTP {(int)res.StatusCode}");
}
var data = root.GetProperty("data");
Console.WriteLine($"e-NCF: {data.GetProperty("eNCF").GetString()} | " +
$"estado: {data.GetProperty("estado").GetString()} | " +
$"código: {data.GetProperty("codigoSeguridad").GetString()}");
}
}
Todos reciben la misma respuesta 201: { success: true, data: { eNCF, estado, codigoSeguridad, ... } }. Consulta la sección
Ejemplos de uso para ver respuestas completas por escenario.
Cálculo
Lo que calcula el servicio
Solo envías los datos económicos del comprobante (ítems, precios, descuentos, impuestos). El servicio calcula todos los totales y genera la identidad fiscal. Estos campos NUNCA se envían en la petición.
MontoTotal y todos los totales (ITBIS por tramo, MontoGravado, MontoExento).
codigoSeguridad y el código QR de la representación impresa.
El XML firmado con el certificado del emisor.
Funciones
Conceptos avanzados
Más allá de los ítems básicos, el ComprobanteInput admite formas de pago, descuentos, impuestos adicionales, propina, retenciones y moneda extranjera. Consulta la Referencia de la API para los campos exactos de cada uno.
Numeración (eNCF) y secuencia
eNCF = 'E' + tipo (2 díg.) + secuencial (10 díg.) = 13 chars (ej. E310000000005). Cada integrador maneja su PROPIA secuencia: si ENVÍAS eNCF, el servicio lo usa, firma y registra (único por emisor; repetirlo → 409). Si lo OMITES, lo genera el servicio (modo certificación). fechaVencimientoSecuencia (dd-MM-yyyy) es obligatoria en 31, 33, 41, 43, 44, 45, 46 y 47; no aplica en 32 ni 34. Aparte y SIN efecto fiscal, numeroFacturaInterna lleva TU consecutivo interno (máx. 20 chars): si lo mandas más largo se omite, el comprobante se emite igual.
Formas de pago
tipoPago (1 Contado · 2 Crédito · 3 Gratuito) y formasPago[] { forma 1-8, monto } (máx. 7). En contado la suma de los montos debe igualar el MontoTotal; en crédito añade fechaLimitePago y terminoPago; en gratuito no se envían formas de pago.
Descuentos y recargos
Por ítem (descuentoMonto / recargoMonto, con subDescuentos / subRecargos) o globales (descuentosGlobales[] { tipoAjuste D/R, tipoValor $/%, valor, monto, indicadorFacturacion, indicadorNorma1007 }). Siempre se envían NETOS. Con indicadorMontoGravado=1 el servicio grossea el de ÍTEM (viaja dentro de MontoItem, que es bruto); el GLOBAL NO se grossea: la DGII lo resta DESPUÉS de dividir el detalle entre (1+tasa), así que lo espera neto.
Impuestos adicionales
items[].impuestosAdicionales[] { tipoImpuesto } con el código del catálogo DGII (ISC específico 006-022, ISC ad-valorem 023-039, CDT, Primera Placa). Máx. 2 por ítem. El servicio calcula el monto y lo suma al MontoTotal.
Propina legal
propina { habilitada: true, tasa? } — 10% por defecto. Se reporta como impuesto adicional código 001 y suma al MontoTotal. Solo en tipos 31, 32, 33, 34, 44 y 45.
Retenciones y percepciones
Por ítem: itbisRetenidoRate / isrRetenidoRate (fracción) o ...Monto (absoluto, gana sobre la tasa). La percepción se activa con indicadorAgente=2 y el objeto percepcion. Obligatoria en 41 y 47; 47 solo admite retención de ISR.
Moneda extranjera
moneda { tipo, tipoCambio }. El servicio emite el bloque OtraMoneda (cada monto = monto DOP / tipoCambio). Es solo representación: NO altera los Totales en DOP ni el MontoTotal.
Los montos de descuentos, recargos y retenciones se envían
siempre NETOS (sin ITBIS). Si tus precios ya
incluyen ITBIS, indica indicadorMontoGravado: 1 y el servicio grossea el descuento/recargo de ítem
al emitir (viaja dentro de MontoItem, que es bruto). El
descuento/recargo global NO se grossea: se emite
neto en los dos modos, porque la DGII lo resta después de dividir
el detalle entre (1+tasa).
Matriz
Soporte de funciones por tipo
No todos los tipos admiten todas las funciones. El servicio rechaza con 400 los datos que el XSD del tipo no define. Esta matriz resume qué aplica a cada uno.
Tipo
Descuentos
Formas pago
Imp. adic.
Propina
Ret./Perc.
Moneda
31
Sí
Sí
Sí
Sí
Ret + Perc.
Completo
32
Sí
Sí
Sí
Sí
—
Completo
33
Sí
Sí
Sí
Sí
Ret + Perc.
Completo
34
Sí
—
Sí
Sí
Ret + Perc.
Completo
41
Sí
Sí
—
—
Ret + Perc. (oblig.)
Sin imp. adic.
43
—
—
—
—
—
Solo exento
44
Sí
Sí
Sí
Sí
—
Exento + imp. adic.
45
Sí
Sí
Sí
Sí
—
Completo
46
Sí
Sí
—
—
—
Franja tasa-0
47
—
Sí
—
—
Solo ISR (oblig.)
Solo exento
Exclusiones clave: 43 (Gastos Menores) es mínimo —
solo ítems, sin descuentos ni formas de pago. 44
no lleva ITBIS por tramo. 46 (Exportación) opera en
franja tasa-0. 47 solo admite retención de ISR. El
comprador es por RNC en 31/33/34/41/45, con razón social en
31/41/44/45/46, y por identificador extranjero en 46/47. En Consumo
(32) con MontoTotal ≥ RD$250,000 también se exige comprador
identificado (RNC/Cédula + razón social).
Sincronización
Consultar estados: cómo sincronizar tu sistema
El servicio NO envía webhooks ni callbacks: tu sistema consulta el estado contra la API. Diseña la integración con este modelo desde el inicio — son tres niveles y cubren desde el punto de venta hasta el cierre contable.
Nivel 1 — Veredicto en la misma respuesta (esperarDgiiMs)
POST /v1/comprobantes
{ "tipo": "32", "transmitir": true, "esperarDgiiMs": 8000, ... }
// Factura de Consumo (32) < RD$250,000 → canal SÍNCRONO:
// → 201 { "estadoDgii": "ACEPTADO", ... } en 1-2 segundos.
// No necesitas consultar nada más.
// Resto de tipos (31, 33, 34, …) → asíncrono con TrackId:
// → 201 { "estadoDgii": "EN_PROCESO", "trackId": "5f8b...", ... }
// El veredicto final llega en segundos o minutos:
// recógelo con la reconciliación o GET /v1/comprobantes/:id.
// Máximo 20000 ms. Si se agota, el comprobante sigue su curso
// normal: la espera es un atajo, nunca un requisito.
Nivel 2 — Reconciliación periódica (el mecanismo principal)
Un proceso recurrente en tu ERP que barre los comprobantes
sin veredicto definitivo. Es la
pieza que garantiza que ningún comprobante quede sin su estado
final, y te recomendamos implementarla sin excepción:
GET /v1/comprobantes?estado=EN_PROCESO&desde=04-08-2026&hasta=09-08-2026&limit=200
Parámetros de referencia (los
mismos que usamos en producción): intervalo de 10 minutos,
ventana de 5 días hacia atrás, máximo 500 documentos por ciclo,
y escribir en tu base solo si algo cambió.
La regla más importante:
consulta SOLO los comprobantes sin veredicto terminal. Un
ACEPTADO,
ACEPTADO_CONDICIONAL
o RECHAZADO
no vuelve a cambiar nunca —
márcalo en tu base y deja de consultarlo. Sin ese filtro
repetirás cientos de llamadas sobre datos inmutables.
Presupuesto: con el límite de
120 peticiones/minuto, este patrón consume una fracción mínima.
No hay riesgo de agotarlo.
Nivel 3 — Conciliación por lote (cierre contable)
POST /v1/comprobantes/estados
{ "eNCF": ["E310000000001", "E310000000002", "E320000000007"] }
// → 200
{
"success": true,
"data": {
"solicitados": 3, "encontrados": 3, "noEncontrados": 0,
"porEstadoDgii": { "ACEPTADO": 2, "EN_PROCESO": 1 },
"items": [
{ "eNCF": "E310000000001", "encontrado": true,
"estadoDgii": "ACEPTADO", "montoTotal": "17700.00",
"trackId": "5f8b...", "mensajeDgii": null }
]
}
}
// Hasta 500 e-NCF por llamada. Un e-NCF inexistente se marca
// encontrado:false SIN tumbar el lote — y que aparezca ya es
// información útil: tu ERP lo dio por emitido y no lo está.
# ─ Estado ────────────────────────────────────────────────────
GET /v1/comprobantes/:id # Estado actual (consulta puntual, barata)
GET /v1/comprobantes?estado=&q= # Listado con filtros (base de la reconciliación)
POST /v1/comprobantes/estados # Conciliación por LOTE (hasta 500 e-NCF)
POST /v1/comprobantes/:id/refresh # FUERZA una consulta a la DGII ahora mismo
GET /v1/comprobantes/resumen # Totales por estado (cuadre/cierre)
GET /v1/comprobantes/reporte # Reporte comercial (por tipo, serie, vs. período anterior)
# ─ Documentos ────────────────────────────────────────────────
GET /v1/comprobantes/:id/xml # XML firmado (representación fiscal)
GET /v1/comprobantes/:id/pdf # Representación impresa (A4 con QR)
GET /v1/comprobantes/:id/qr.png # Solo el QR del timbre DGII
# ─ Auditoría ─────────────────────────────────────────────────
GET /v1/comprobantes/:id/eventos # Bitácora de eventos (trazabilidad)
GET /v1/comprobantes/:id/timeline # Duración de cada etapa
GET /v1/comprobantes/:id/input # JSON original enviado al emitir
¿Y si la DGII se cae? Tu
facturación no se detiene: el e-CF se firma igual, queda en
EN_COLA
y el servicio reintenta con espera incremental (30 s → … → 15 min)
durante ~74 horas hasta transmitirlo. Tu reconciliación lo verá
pasar a estado terminal por sí solo. No reenvíes, no reintentes, no cambies de modo. Detalle en
la Política de Contingencia.
Catálogo
Tipos de e-CF
La DGII reconoce diez tipos de Comprobante Fiscal Electrónico. Indica el código correspondiente en el campo tipo al emitir.
Código
Tipo
Uso
31
Crédito Fiscal
Ventas a contribuyentes que sustentan crédito de ITBIS y costos.
32
Consumo
Ventas a consumidores finales que no requieren crédito fiscal.
33
Nota de Débito
Aumenta el valor de un comprobante emitido previamente.
34
Nota de Crédito
Disminuye o anula el valor de un comprobante emitido previamente.
41
Compras
Registra compras a personas no obligadas a emitir comprobantes.
43
Gastos Menores
Sustenta gastos menores sin comprobante formal del proveedor.
44
Regímenes Especiales
Operaciones bajo regímenes tributarios especiales.
45
Gubernamental
Ventas a instituciones del Estado dominicano.
46
Exportaciones
Ventas de bienes o servicios hacia el exterior.
47
Pagos al Exterior
Pagos realizados a beneficiarios fuera del país.
Ciclo de vida
Estados: firma vs. DGII
Un comprobante tiene dos estados independientes. firmado indica si el XML ya se firmó con el certificado del emisor; estadoDgii refleja en qué punto del ciclo de validación de la DGII se encuentra.
Estado de firma — campo firmado
false
El comprobante aún no ha sido firmado digitalmente con el certificado del emisor.
true
El XML fue firmado con el certificado .p12 del emisor y está listo para transmitirse.
Estado DGII — campo estadoDgii
NO_ENVIADO
El e-CF existe en SynerCore pero todavía no se ha transmitido a la DGII.
EN_COLA
El comprobante está encolado para su envío a la DGII.
ENVIADO
El e-CF fue transmitido a la DGII y se generó un trackId.
EN_PROCESO
La DGII recibió el comprobante y está evaluando su validez.
ACEPTADO
La DGII aceptó el comprobante. Es fiscalmente válido.
ACEPTADO_CONDICIONAL
Aceptado con observaciones que conviene revisar, pero válido.
RECHAZADO
La DGII rechazó el comprobante. Revisa los eventos para conocer el motivo.
Padrón
Búsqueda de RNC
Consulta el padrón de la DGII para autollenar la razón social del comprador a partir de su RNC antes de emitir.
Usa el endpoint GET /v1/integrator/rnc/:rnc para validar un RNC y obtener los datos del contribuyente. Esto te
permite reducir errores de captura y precargar la razón social en tu
formulario.
Cuando una operación falla, la API devuelve success: false junto a un objeto error con un mensaje legible y el código HTTP. Procesa siempre este sobre antes de asumir éxito.
Sobre de error
{
"success": false,
"error": {
"message": "El campo 'comprador.rnc' es obligatorio.",
"statusCode": 400
}
}
Validación XSD. Antes de transmitir, el servicio
valida el e-CF firmado contra el XSD oficial de la DGII para ese
tipo. Si no cumple, responde 400 con el detalle del incumplimiento en error.message. Así el fallo se detecta de inmediato y no en la DGII.
Código
Significado
Cuándo ocurre
400
Solicitud inválida
Faltan campos obligatorios, el JSON es incorrecto, el tipo no admite un concepto, o el e-CF generado no cumple el XSD oficial de la DGII. El mensaje indica el campo exacto: corrígelo antes de reintentar.
401
No autenticado
La cabecera Authorization no se envió o la API key es inválida o fue revocada.
403
Prohibido
El emisor del header X-Emisor-RNC existe pero no pertenece a tu cuenta de integrador.
404
No encontrado
El comprobante consultado no existe o no pertenece a tu cuenta, o el RNC del header X-Emisor-RNC no existe como emisor (si existe pero pertenece a otro integrador, la respuesta es 403). La búsqueda de RNC en el padrón (GET /v1/integrator/rnc/:rnc) NO devuelve 404: responde 200 con data: null si el RNC no existe.
409
Conflicto
Ya existe un comprobante con ese e-NCF para el emisor en ese ambiente. EL DOCUMENTO YA EXISTE: recupéralo con GET /v1/comprobantes?q=<eNCF> en vez de reemitirlo — es tu señal de idempotencia tras un timeout.
429
Demasiadas solicitudes
Se superó el límite de 120 peticiones/minuto de la API key. El mensaje indica cuánto esperar; respétalo y reintenta.
502
Error de la DGII
No se pudo consultar un servicio de la DGII (p. ej. el directorio). Reintenta con espera.
500
Error interno
Fallo inesperado del servidor. Reintenta y, si persiste, contacta soporte con el id del comprobante.
Observaciones y rechazos de la DGII
Distintos de los errores HTTP: estos códigos los emite la DGII al
procesar el comprobante y llegan en el campo
mensajeDgii
y en la bitácora de eventos. Documentamos los que vemos en
operación real; cualquier otro código viaja íntegro para que
soporte pueda ayudarte a interpretarlo.
Código
Observación
Resultado
Qué hacer
1100
Falta la Fecha Límite de Pago
RECHAZADO
Factura a crédito (tipoPago=2) sin fechaLimitePago. El servicio lo valida ANTES de firmar, así que este rechazo no debería llegar a ocurrir: si lo ves como 400 local, envía fechaLimitePago (dd-MM-yyyy).
1385
RNC del comprador no válido
ACEPTADO_CONDICIONAL
El RNC/cédula cumple el formato pero no figura en el padrón de la DGII. Es una OBSERVACIÓN, no un rechazo: el e-CF es válido. Verifica el identificador del cliente en tu maestro. En notas 33/34 el servicio omite automáticamente identificadores no exigidos para prevenirla.
2020
Falta el desglose del descuento
Prevenido
Una línea con DescuentoMonto/RecargoMonto exige su tabla de desglose. El servicio la genera automáticamente si no la envías — no tienes que hacer nada.
11094
Totales no reconcilian con el detalle
Prevenido
La DGII recalcula los totales desde el detalle y los compara. El servicio liquida por tramo y recomputa la propina desde el detalle firmado, precisamente para que siempre reconcilien. Si tu ERP redondea distinto, usa montoTotalObjetivo.
ACEPTADO_CONDICIONAL no es un rechazo.
El comprobante es fiscalmente válido; la DGII solo dejó una
observación. Muéstrala a tu usuario desde
mensajeDgii
y trátalo como emitido.
Recomendaciones
Buenas prácticas
Recomendaciones para una integración robusta y segura: protege tus credenciales, evita comprobantes duplicados y maneja la naturaleza asíncrona de la validación fiscal.
Protege la API key
Guarda la clave en variables de entorno o en un gestor de secretos. Nunca la incluyas en el código del cliente, repositorios públicos ni logs. Rota la clave si sospechas que fue expuesta.
Reintentos con espera
Ante errores 429 o 5xx, reintenta con backoff exponencial (1s, 2s, 4s...). No reintentes en respuestas 4xx de validación: corrige los datos antes de volver a enviar.
Idempotencia: envía TU eNCF
Aporta siempre tu propio eNCF al emitir: se convierte en la clave de idempotencia exacta. Si un timeout te deja sin respuesta, reintenta con el MISMO eNCF — si ya se registró recibes 409 y lo recuperas con GET /v1/comprobantes?q=<eNCF>; si no llegó, se emite normal. Nunca se duplica.
Consulta, no esperes webhooks
El servicio no envía notificaciones a tu infraestructura: tu sistema consulta el estado. Usa esperarDgiiMs para el veredicto inmediato en punto de venta, y una reconciliación periódica (cada 10 min, solo los SIN veredicto terminal) para el resto. Un ACEPTADO o RECHAZADO ya no cambia: deja de consultarlo.
Valida en staging
Prueba toda la integración contra el ambiente de pruebas antes de producción. Revisa el campo ambiente en cada respuesta para confirmar dónde se emitió cada comprobante.
Conserva el XML firmado
Descarga y resguarda el XML firmado y la bitácora de eventos de cada comprobante. Son tu respaldo fiscal ante cualquier verificación posterior.
Siguiente paso
¿Listo para integrar la facturación electrónica?
Solicita tu API key y empieza a emitir e-CF válidos ante la DGII en tu propia plataforma, con custodia de certificados y trazabilidad completa.