SDK .NET / C#

SDK oficial para integrar la facturación electrónica (e-CF) en República Dominicana a través del servicio ECF SSD.

Qué cambió en v3

Las versiones anteriores (v1, v2) requerían que cada empresa implementara la comunicación directa con la DGII: manejo de certificados, firmado de XML, semilla/token, envío de comprobantes, manejo de errores, reintentos, almacenamiento, etc. Todo eso era responsabilidad del desarrollador.

La v3 cambia el enfoque completamente. Ahora el SDK se conecta a la plataforma ECF SSD, que se encarga de:

  • Firmado de comprobantes (XML signing)
  • Autenticación con la DGII (semilla/token)
  • Envío y recepción de e-CF
  • Validación emisor-receptor
  • Almacenamiento seguro
  • Reintentos automáticos
  • Manejo de certificados digitales

Tu único trabajo: registrarte en ecf.ssd.com.do, completar la certificación DGII, obtener tu API key, y enviar tus comprobantes con este SDK.

Comenzar

1. Regístrate en ecf.ssd.com.do

Crea tu cuenta y obtén tu API Key. Luego contacta al equipo de ECF SSD para integrar y certificar tu sistema (la certificación es para tu plataforma, no para las empresas de tus clientes). Una vez certificado, podrás usar el ambiente de producción. Si vienes de otro proveedor, ECF SSD soporta migración.

2. Instala el paquete

typescript
dotnet add package SSDDO.ECF_DGII.SDK

3. Envía tu primer comprobante

typescript
using EcfDgii.Client;
using EcfDgii.Client.Generated.Models;
// Configura el cliente con tu API key (JWT obtenido en ecf.ssd.com.do)
var client = new EcfClient(new EcfClientOptions
{
ApiKey = "tu-jwt-token", // o usa la variable de entorno ECF_API_KEY
Environment = EcfEnvironment.Prod
});
// Construye el comprobante
var ecf = new ECF
{
Encabezado = new Encabezado
{
IdDoc = new IdDoc
{
TipoeCF = TipoeCFType.FacturaDeCreditoFiscalElectronica,
Encf = "E310000000001"
},
Emisor = new Emisor
{
RncEmisor = "123456789",
RazonSocialEmisor = "Mi Empresa SRL",
DireccionEmisor = "Calle Principal #1, Santo Domingo",
FechaEmision = new Date(2026, 1, 10)
},
Totales = new Totales
{
// montos, ITBIS, etc.
}
},
DetallesItems = new List<Item>
{
new Item
{
NombreItem = "Servicio de consultoría",
IndicadorFacturacion = IndicadorFacturacionType.NoFacturable_18Percent,
CantidadItem = new UntypedDouble(1),
PrecioUnitarioItem = new UntypedDouble(10000.00),
MontoItem = new UntypedDouble(10000.00)
}
}
};
// Envía y espera el resultado
try
{
EcfResponse resultado = await client.SendEcfAsync(ecf);
Console.WriteLine($"Comprobante procesado exitosamente!");
Console.WriteLine($"Estado: {resultado.Progress}");
Console.WriteLine($"Mensaje DGII: {resultado.Mensaje}");
Console.WriteLine($"Código seguridad: {resultado.CodSec}");
Console.WriteLine($"URL impresión: {resultado.ImpresionUrl}");
}
catch (EcfException ex)
{
Console.WriteLine($"Error: {ex.Message}");
Console.WriteLine($"Detalle: {ex.Response.Errors}");
}

Eso es todo. No necesitas manejar XML, firmar documentos, obtener semillas, ni reintentar requests. El servicio ECF SSD se encarga de todo.

Respuesta (EcfResponse)

Cuando SendEcfAsync termina exitosamente, retorna un EcfResponse con toda la información que necesitas para cumplir con los requisitos de la DGII:

CampoTipoDescripción
ImpresionUrlstringURL para generar el código QR requerido por la DGII en el comprobante impreso.
CodSecstringCódigo de seguridad — debe aparecer en el comprobante impreso.
FechaFirmaDateTimeOffsetFecha y hora en que el comprobante fue firmado digitalmente.
EstatusEcfEstadoEstado asignado por la DGII (Aceptado, AceptadoCondicional, Rechazado).
ProgressEcfProgressEstado del procesamiento (Queued, Sending, Polling, Finished, Error).
EncfstringNúmero de comprobante fiscal electrónico (eNCF).
RncEmisorstringRNC del emisor.
MensajestringMensaje de respuesta de la DGII.
ErrorsstringDetalle de errores (si los hay).
MontoTotaldoubleMonto total del comprobante.
SecuenciaUtilizadaboolIndica si la secuencia fue utilizada.
DgiiEnvironmentDGIIEnvironmentAmbiente DGII donde fue procesado.
MessageIdstringIdentificador único del mensaje.

QR e Impresión del Comprobante

La DGII requiere que los comprobantes impresos incluyan un código QR. El ImpresionUrl contiene la URL que debe codificarse como QR:

java
EcfResponse resultado = await client.SendEcfAsync(ecf);
string urlQr = resultado.ImpresionUrl; // codificar como QR
string codigoSeguridad = resultado.CodSec; // imprimir en el comprobante
DateTimeOffset fechaFirma = resultado.FechaFirma; // fecha de firma digital
if (resultado.Estatus == EcfEstado.Aceptado)
{
Console.WriteLine("Comprobante aceptado por la DGII");
Console.WriteLine($"QR URL: {urlQr}");
Console.WriteLine($"Código seguridad: {codigoSeguridad}");
Console.WriteLine($"Firmado: {fechaFirma}");
}

Configuración

Variables de Entorno

VariableDescripción
ECF_API_KEYJWT Bearer token (obtenido en ecf.ssd.com.do).
ECF_API_URLURL base (solo si necesitas override).

Ambientes

AmbienteURLUso
Testhttps://api.test.ecfx.ssd.com.doDesarrollo y pruebas.
Certhttps://api.cert.ecfx.ssd.com.doProceso de certificación DGII.
Prodhttps://api.prod.ecfx.ssd.com.doProducción.

Opciones de Polling

SendEcfAsync espera automáticamente a que la DGII procese el comprobante. Puedes personalizar el comportamiento:

typescript
var resultado = await client.SendEcfAsync(ecf, new PollingOptions
{
InitialDelayMs = 1000, // espera inicial entre consultas
MaxDelayMs = 30000, // espera máxima entre consultas
MaxRetries = 60, // máximo de reintentos
BackoffMultiplier = 2, // multiplicador exponencial
TimeoutMs = 120000 // timeout total (2 minutos)
});

Tipos de Comprobantes

TipoeCFRutaDescripción
FacturaDeCreditoFiscalElectronica/ecf/31Factura de Crédito Fiscal
FacturaDeConsumoElectronica/ecf/32Factura de Consumo
NotaDeDebitoElectronica/ecf/33Nota de Débito
NotaDeCreditoElectronica/ecf/34Nota de Crédito
ComprasElectronico/ecf/41Compras
GastosMenoresElectronico/ecf/43Gastos Menores
RegimenesEspecialesElectronico/ecf/44Regímenes Especiales
GubernamentalElectronico/ecf/45Gubernamental
ComprobanteDeExportacionesElectronico/ecf/46Exportaciones
ComprobanteParaPagosAlExteriorElectronico/ecf/47Pagos al Exterior

Ejemplo completo — Factura de Crédito Fiscal (e-CF 31)

El SDK genera modelos específicos por tipo de comprobante (Ecf31ECF, Ecf31Encabezado, etc.) con todas las propiedades tipadas. Este es un ejemplo completo de una Factura de Crédito Fiscal con ITBIS, impuestos adicionales, descuentos y montos no facturables:

typescript
{
"encabezado": {
"idDoc": {
"encf": "E310000051630",
"TipoeCF": "FacturaDeCreditoFiscalElectronica",
"TipoPago": "Contado",
"TipoIngresos": "01",
"TablaFormasPago": [
{ "FormaPago": "Efectivo", "MontoPago": 1015.25 }
],
"IndicadorMontoGravado": "ConITBISIncluido",
"FechaVencimientoSecuencia": "2028-12-31T00:00:00"
},
"Emisor": {
"RNCEmisor": "131460941",
"FechaEmision": "2026-01-10",
"DireccionEmisor": "AVE. ISABEL AGUIAR NO. 269, ZONA INDUSTRIAL DE HERRERA",
"RazonSocialEmisor": "DOCUMENTOS ELECTRONICOS DE 02"
},
"Totales": {
"ITBIS1": 18,
"MontoGravadoI1": 762.71,
"MontoGravadoTotal": 762.71,
"TotalITBIS1": 137.29,
"TotalITBIS": 137.29,
"MontoNoFacturable": 100.0,
"ImpuestosAdicionales": [
{
"TipoImpuesto": "002",
"TasaImpuestoAdicional": 2,
"OtrosImpuestosAdicionales": 15.25
}
],
"MontoImpuestoAdicional": 15.25,
"MontoTotal": 1015.25,
"MontoPeriodo": 1015.25
},
"Version": "Version1_0",
"Comprador": {
"RNCComprador": "131880681",
"RazonSocialComprador": "DOCUMENTOS ELECTRONICOS DE 03"
}
},
"DetallesItems": [
{
"MontoItem": 1016.95,
"NombreItem": "Iphone 18 Pro max",
"NumeroLinea": 1,
"CantidadItem": 1,
"UnidadMedida": "Unidad",
"PrecioUnitarioItem": 1016.95,
"IndicadorFacturacion": "ITBIS1_18Percent",
"IndicadorBienoServicio": "Bien",
"TablaImpuestoAdicional": [
{ "TipoImpuesto": "002" }
]
},
{
"MontoItem": 100.0,
"NombreItem": "Costo de Envío",
"NumeroLinea": 2,
"CantidadItem": 1,
"UnidadMedida": "Unidad",
"PrecioUnitarioItem": 100.0,
"IndicadorFacturacion": "NoFacturable_18Percent",
"IndicadorBienoServicio": "Servicio"
}
],
"DescuentosORecargos": [
{
"TipoValor": "$",
"TipoAjuste": "D",
"NumeroLinea": 1,
"MontoDescuentooRecargo": 84.75,
"DescripcionDescuentooRecargo": "Descuento",
"IndicadorFacturacionDescuentooRecargo": "ITBIS1_18Percent"
}
]
}

Frontend — Cliente de solo lectura

El backend envía los comprobantes; el cliente sólo necesita consultar el estado. EcfFrontendClient usa un token con alcance limitado y maneja cache + refresh automáticamente.

typescript
// 1. Enviar la factura al backend
var invoiceResponse = await httpClient.PostAsJsonAsync("/api/v1/invoices", invoiceData);
var result = await invoiceResponse.Content.ReadFromJsonAsync<InvoiceResult>();
// 2. Crear cliente de solo lectura (GetToken se llama automáticamente)
var frontend = new EcfFrontendClient(new EcfFrontendClientOptions
{
GetToken = async () =>
{
var response = await httpClient.GetAsync("/api/v1/ecf-token");
var json = await response.Content.ReadFromJsonAsync<TokenResponse>();
return json.ApiKey;
},
Environment = EcfEnvironment.Prod
// CacheToken usa archivo encriptado en disco por defecto
});
// 3. Consultar el estado del ECF
var ecf = await frontend.QueryEcfAsync(result.Rnc, result.Encf);
var ecfs = await frontend.SearchEcfsAsync(result.Rnc);

Backend — emitir token de lectura

typescript
var ecfClient = new EcfClient(new EcfClientOptions
{
ApiKey = backendJwtToken,
Environment = EcfEnvironment.Prod
});
// Endpoint de facturación — tu lógica de negocio + envío a ECF SSD
[HttpPost("/api/v1/invoices")]
public async Task<IActionResult> CreateInvoice(CreateInvoiceRequest request)
{
var invoice = await _invoiceService.ValidateAndSave(request);
var ecf = _mapper.ToEcf(invoice);
var response = await ecfClient.Api.Ecf.E31[rnc].PostAsync(ecf);
await _invoiceService.UpdateMessageId(invoice.Id, response.MessageId);
return Ok(new { invoice.Id, response.MessageId });
}
// Endpoint separado: generar token de lectura para el cliente
[HttpGet("/api/v1/ecf-token")]
public async Task<IActionResult> GetEcfToken()
{
var apiKey = await ecfClient.Api.ApiKey.PostAsync(new NewCompanyApiKeyRequest
{
// token restringido al tenant y RNC, solo lectura
});
return Ok(new { apiKey.Token });
}

Acceso Directo al API

Para operaciones que no cubre SendEcfAsync, usa client.Api directamente:

typescript
// Consultar comprobantes
var comprobantes = await client.Api.Ecf["123456789"].GetAsync();
// Buscar un comprobante específico
var resultado = await client.Api.Ecf["123456789"]["E310000000001"].GetAsync();
// Consultar estado en la DGII
var estado = await client.Api.Dgii["123456789"].Consultaestado.Estado.GetAsync(config =>
{
config.QueryParameters.RncEmisor = "123456789";
config.QueryParameters.NcfElectronico = "E310000000001";
config.QueryParameters.RncComprador = "987654321";
config.QueryParameters.CodigoSeguridad = "ABC123";
});
// Gestión de empresas
var empresas = await client.Api.Company.GetAsync();
await client.Api.Company.PutAsync(new UpsertCompanyRequest { /* ... */ });
// Aprobación comercial
await client.Api.Ecf.Aprobacioncomercial["123456789"]["E310000000001"]
.PostAsync(new SendAcecfRequest { /* ... */ });
// Anulación de rangos
await client.Api.Ecf.Anularrango["123456789"]
.PostAsync(new AnulacionRequest { /* ... */ });
// Estatus de servicios DGII
var estatus = await client.Api.Dgii["123456789"].Estatusservicios.ObtenerEstatus.GetAsync();

Manejo de Errores

ExcepciónCuándo
EcfExceptionEl comprobante fue procesado pero la DGII lo rechazó.
PollingMaxRetriesExceptionSe agotaron los reintentos esperando respuesta.
PollingTimeoutExceptionSe agotó el timeout esperando respuesta.
typescript
try
{
var resultado = await client.SendEcfAsync(ecf);
}
catch (EcfException ex)
{
// La DGII rechazó el comprobante
Console.WriteLine($"Rechazado: {ex.Response.Errors}");
Console.WriteLine($"Estado DGII: {ex.Response.Estatus}");
}
catch (PollingTimeoutException)
{
// El comprobante fue enviado pero no se recibió respuesta a tiempo
// Puedes consultar el estado después con client.Api.Ecf[rnc][encf].GetAsync()
}

Cancelación

Todas las operaciones async soportan CancellationToken:

typescript
using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(5));
var resultado = await client.SendEcfAsync(ecf, cancellationToken: cts.Token);

Migración desde v2

v2 (implementación propia)v3 (ECF SSD)
Manejar certificado digital (.p12/.pfx)Subir certificado una vez en ecf.ssd.com.do
Obtener semilla y firmarlaNo necesario — el servicio lo maneja
Serializar a XML y firmarNo necesario — envías JSON, el servicio firma
Enviar XML a la DGIIawait client.SendEcfAsync(ecf)
Parsear respuesta XMLRespuesta tipada EcfResponse
Implementar reintentosPolling automático con backoff exponencial
SSDDO.ECF_DGII.Models + SSDDO.ECF_DGII.SDKSolo SSDDO.ECF_DGII.SDK v3

Por qué ECF SSD

Con la v2 tenías la librería, pero aún debías implementar seguridad, almacenamiento, firmado, manejo de certificados, módulo de recepción, reintentos, y más.

Con la v3 y ECF SSD:

  • Instalas el paquete NuGet
  • Te registras y certificas en ecf.ssd.com.do
  • Envías comprobantes con una línea de código
  • El servicio se encarga del firmado, validación, envío a DGII, almacenamiento y más