SSDDO.ECF_DGII.SDK
4.0.0
dotnet add package SSDDO.ECF_DGII.SDK --version 4.0.0
NuGet\Install-Package SSDDO.ECF_DGII.SDK -Version 4.0.0
<PackageReference Include="SSDDO.ECF_DGII.SDK" Version="4.0.0" />
<PackageVersion Include="SSDDO.ECF_DGII.SDK" Version="4.0.0" />
<PackageReference Include="SSDDO.ECF_DGII.SDK" />
paket add SSDDO.ECF_DGII.SDK --version 4.0.0
#r "nuget: SSDDO.ECF_DGII.SDK, 4.0.0"
#:package SSDDO.ECF_DGII.SDK@4.0.0
#addin nuget:?package=SSDDO.ECF_DGII.SDK&version=4.0.0
#tool nuget:?package=SSDDO.ECF_DGII.SDK&version=4.0.0
DGII ECF
| Paquetes | |
|---|---|
| SDK |
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 es: 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
dotnet add package SSDDO.ECF_DGII.SDK
3. Envía tu primer comprobante
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
// SendEcfAsync hace todo: enruta al endpoint correcto, envía, y espera hasta que la DGII responda
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:
| Campo | Tipo | Descripción |
|---|---|---|
ImpresionUrl |
string |
URL para generar el código QR requerido por la DGII en el comprobante impreso |
CodSec |
string |
Código de seguridad — debe aparecer en el comprobante impreso |
FechaFirma |
DateTimeOffset |
Fecha y hora en que el comprobante fue firmado digitalmente |
Estatus |
EcfEstado |
Estado asignado por la DGII (Aceptado, AceptadoCondicional, Rechazado) |
Progress |
EcfProgress |
Estado del procesamiento (Queued, Sending, Polling, Finished, Error) |
Encf |
string |
Número de comprobante fiscal electrónico (eNCF) |
RncEmisor |
string |
RNC del emisor |
Mensaje |
string |
Mensaje de respuesta de la DGII |
Errors |
string |
Detalle de errores (si los hay) |
MontoTotal |
double |
Monto total del comprobante |
SecuenciaUtilizada |
bool |
Indica si la secuencia fue utilizada |
DgiiEnvironment |
DGIIEnvironment |
Ambiente DGII donde fue procesado |
MessageId |
string |
Identificador ú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:
EcfResponse resultado = await client.SendEcfAsync(ecf);
// Datos necesarios para el comprobante impreso
string urlQr = resultado.ImpresionUrl; // codificar como QR
string codigoSeguridad = resultado.CodSec; // imprimir en el comprobante
DateTimeOffset fechaFirma = resultado.FechaFirma; // fecha de firma digital
// Verificar aceptación
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
| Variable | Descripción |
|---|---|
ECF_API_KEY |
JWT Bearer token (obtenido en ecf.ssd.com.do) |
ECF_API_URL |
URL base (solo si necesitas override) |
Ambientes
| Ambiente | URL | Uso |
|---|---|---|
| Test | https://api.test.ecfx.ssd.com.do |
Desarrollo y pruebas |
| Cert | https://api.cert.ecfx.ssd.com.do |
Proceso de certificación DGII |
| Prod | https://api.prod.ecfx.ssd.com.do |
Producción |
Opciones de Polling
SendEcfAsync espera automáticamente a que la DGII procese el comprobante. Puedes personalizar el comportamiento:
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
| TipoeCF | Ruta | Descripción |
|---|---|---|
FacturaDeCreditoFiscalElectronica |
/ecf/31 |
Factura de Crédito Fiscal |
FacturaDeConsumoElectronica |
/ecf/32 |
Factura de Consumo |
NotaDeDebitoElectronica |
/ecf/33 |
Nota de Débito |
NotaDeCreditoElectronica |
/ecf/34 |
Nota de Crédito |
ComprasElectronico |
/ecf/41 |
Compras |
GastosMenoresElectronico |
/ecf/43 |
Gastos Menores |
RegimenesEspecialesElectronico |
/ecf/44 |
Regímenes Especiales |
GubernamentalElectronico |
/ecf/45 |
Gubernamental |
ComprobanteDeExportacionesElectronico |
/ecf/46 |
Exportaciones |
ComprobanteParaPagosAlExteriorElectronico |
/ecf/47 |
Pagos 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:
{
"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"
}
]
}
Arquitectura Backend / Frontend
En la mayoría de implementaciones, el backend maneja la lógica de negocio (validación, almacenamiento, conversión) y envía el comprobante. El frontend obtiene un token de solo lectura para consultar el estado directamente:
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)
{
// 1. Validar y guardar la factura en tu base de datos
var invoice = await _invoiceService.ValidateAndSave(request);
// 2. Convertir tu factura interna al formato ECF
var ecf = _mapper.ToEcf(invoice);
// 3. Enviar a ECF SSD (sin polling)
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 frontend
[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 });
}
El frontend almacena el token de forma segura, lo renueva al recibir 401 o al expirar, y consulta ECF SSD directamente sin pasar por el backend. Ver README principal para el diagrama completo y ejemplo de frontend.
SendEcfAsynces una conveniencia que encapsula envío + polling en una sola llamada. Ideal para scripts o backends simples sin frontend.
Acceso Directo al API
Para operaciones que no cubre SendEcfAsync, usa client.Api directamente:
// 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ón | Cuándo |
|---|---|
EcfException |
El comprobante fue procesado pero la DGII lo rechazó |
PollingMaxRetriesException |
Se agotaron los reintentos esperando respuesta |
PollingTimeoutException |
Se agotó el timeout esperando respuesta |
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:
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 firmarla | No necesario — el servicio lo maneja |
| Serializar a XML y firmar | No necesario — envías JSON, el servicio firma |
| Enviar XML a la DGII | await client.SendEcfAsync(ecf) |
| Parsear respuesta XML | Respuesta tipada EcfResponse |
| Implementar reintentos | Polling automático con backoff exponencial |
SSDDO.ECF_DGII.Models + SSDDO.ECF_DGII.SDK |
Solo 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
Para más información visita https://ecf.ssd.com.do
🇩🇴 Hecho con plátano power
© Smart Software Development SSD SRL 2026
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 is compatible. net5.0-windows was computed. net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 is compatible. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 is compatible. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- Microsoft.Kiota.Bundle (>= 1.21.2)
-
.NETStandard 2.1
- Microsoft.Kiota.Bundle (>= 1.21.2)
-
net5.0
- Microsoft.Kiota.Bundle (>= 1.21.2)
-
net6.0
- Microsoft.Kiota.Bundle (>= 1.21.2)
-
net7.0
- Microsoft.Kiota.Bundle (>= 1.21.2)
-
net8.0
- Microsoft.Kiota.Bundle (>= 1.21.2)
-
net9.0
- Microsoft.Kiota.Bundle (>= 1.21.2)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.