VXML 2.1.0

dotnet add package VXML --version 2.1.0
                    
NuGet\Install-Package VXML -Version 2.1.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="VXML" Version="2.1.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="VXML" Version="2.1.0" />
                    
Directory.Packages.props
<PackageReference Include="VXML" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add VXML --version 2.1.0
                    
#r "nuget: VXML, 2.1.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package VXML@2.1.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=VXML&version=2.1.0
                    
Install as a Cake Addin
#tool nuget:?package=VXML&version=2.1.0
                    
Install as a Cake Tool

VXML

Librería para la generación y cancelación de CFDI 4.0 y de CFDI de Retenciones e Información de Pagos 2.0, incluidos todos los complementos vigentes. Incluye el proceso de firmado, Sellado y tambien el Timbrado por medio del servicio de VXML, de acuerdo a la especificación del SAT.

Incluye tambien el servicio de Descarga Masiva del SAT (XML o Metadata de los CFDI emitidos o recibidos en un periodo) y metodos complementarios para la administración de distribuidores y emisores.

Uso

Uso Basico

using VXML;

... 

// Crear instancia de la clase VXML
var vxml = new VXML();

// Llamar los metodos para el llenado del CFDI
vxml.SetComprobanteInfo_cfdi40("A", "1", DateTime.Now.ToString("s"), "99", "Contado AÑA Comercial", "1000.00", "50.00", "MXN", "", "1102.00", "I", "PPD", "53050", "", "01");
vxml.AddCfdiRelacionados_cfdi40("04", "FF93C8BE-AF7B-4FC5-8854-6DAE18CFB5B4", "D8E18C2F-2859-4927-A0F0-EA3E93642DDC", "", "", "", "", "", "", "", "");
vxml.AddCfdiRelacionado_cfdi40("BE1D4B47-E167-47A3-8049-70D4D43BCBE8");
vxml.AddCfdiRelacionados_cfdi40("01", "FDBA380A-9732-4FB5-A6CB-5FB4BD831697", "", "", "", "", "", "", "", "", "");
vxml.SetEmisorInfo_cfdi40("EKU9003173C9", "ESCUELA KEMPER URGATE", "601", "");

// Tambien puede usarse de forma encadenada
vxml.SetReceptorInfo_cfdi40("CTE940531F58", "CIBERNETICA Y TECNOLOGIA", "", "", "G01", "53050", "601")
    .AddConcepto_cfdi40("84111506", "SEFXXX Ñ", "1", "H87", "Unidad", "Paquete X - ObjetoImp2", "500.00", "500.00", "", "02")
    .AddConceptoTraslado_cfdi40("500.00", "002", "Tasa", "0.160000", "80.00")
    .AddConcepto_cfdi40("84111506", "SEFXXX &", "2", "H87", "Unidad", "Paquete X - ObjetoImp2", "250.00", "500.00", "50.00", "02")
    .AddConceptoTraslado_cfdi40("450.00", "002", "Tasa", "0.160000", "72.00")
    .SetImpuestosInfo_cfdi40("200.00", "300.0");

vxml.SetImpuestosInfo_cfdi40("152.00", "");
vxml.AddTraslado_cfdi40("002", "Tasa", "0.160000", "152.00", "950.00");
vxml.SetAddendaText_cfdi40("Texto simple como adenda");

// Finalmente, solicitar el timbrado
var resultado = await vxml.TimbraCFDI40("demo_cibertec", "EKU9003173C9", csdPath, keyPath, "12345678a", true, true, true, true);

// Evaluar el resultado
if (resultado.IsSuccess)
{
    Console.WriteLine("UUID: {0}", resultado.uuid);

    var rawXML = Encoding.UTF8.GetString(Convert.FromBase64String(resultado.xmltimbrado));
    Console.WriteLine("XML: {0}", rawXML);

    if (resultado.qrpng != null) 
    {
        await File.WriteAllBytesAsync("Somewhere/Path/QR.png", resultado.qrpng);
        Console.WriteLine("png QR written");
    }

    if (resultado.qrccp30png != null) 
    {
        await File.WriteAllBytesAsync("Somewhere/Path/QRcpp.png", resultado.qrccp30png);
        Console.WriteLine("QR de Complemento Carta Porte guardado");
    }
}
else
{
    Console.WriteLine("Algo fallo con codigo {0} y mensaje {1}", resultado.InnerExitCode, resultado.Message);
}

Ejemplos

Complemento Pagos20

var vxml = new Cfdi();
vxml.AddCfdiRelacionados_cfdi40("01", "", "00000000-0000-0000-0000-000000000002", "", "00000000-0000-0000-0000-000000000004", "", "00000000-0000-0000-0000-000000000006", "", "00000000-0000-0000-0000-000000000008", "", "00000000-0000-0000-0000-000000000010");
vxml.AddCfdiRelacionado_cfdi40("00000000-0000-0000-0000-111111111111");
vxml.AddCfdiRelacionados_cfdi40("02", "00000000-0000-0000-0000-000000000001", "", "00000000-0000-0000-0000-000000000003", "", "00000000-0000-0000-0000-000000000005", "", "00000000-0000-0000-0000-000000000007", "", "00000000-0000-0000-0000-000000000009", "");
vxml.AddCfdiRelacionado_cfdi40("00000000-0000-0000-0000-222222222222");
vxml.SetInformacionGlobal_cfdi40("01", "10", "2023");
vxml.SetComprobanteInfo_cfdi40("", "12629", DateTime.Now.ToString("s"), "", "", "0", "", "XXX", "", "0", "P", "", "53000", "", "01");
vxml.SetEmisorInfo_cfdi40("EKU9003173C9", "ESCUELA KEMPER URGATE", "601", "");
vxml.SetReceptorInfo_cfdi40("ESD140725UP8", "\"E-SI SOLUCIONES DIGITALES\"", "", "", "CP01", "53050", "601");
vxml.AddConcepto_cfdi40("84111506", "", "1", "ACT", "", "Pago", "0", "0", "", "01");
vxml.SetPagos20("", "", "", "", "", "", "", "", "", "", "34925.52");
vxml.Pagos20AddPago("2021-01-01T01:01:01", "03", "USD", "1.00", "13144.66", "0000842", "", "", "", "", "", "", "", "", "");
vxml.Pagos20AddPagoDoctoRelacionado("88888888-4444-4444-4444-121212121212", "Serie", "Folio", "USD", "1", "2", "13144.66", "13144.66", "0.00", "01");
vxml.Pagos20AddPago("2021-02-02T02:02:02", "03", "USD", "1.00", "21780.86", "0000842", "", "", "", "", "", "", "", "", "");
vxml.Pagos20AddPagoDoctoRelacionado("AAAAAAAA-0000-0000-0000-666666666666", "Serie2", "Folio2", "USD", "1", "3", "14430.86", "14430.86", "0.00", "01");
vxml.Pagos20AddPagoDoctoRelacionado("AAAAAAAA-BBBB-CCCC-DDDD-666666666666", "Serie3", "Folio3", "USD", "1", "4", "7350.00", "7350.00", "0.00", "03");

// Para uso de la addenda como XML, el nodo especificado en la funcion 
// debera contener la declaracion de los namespaces en caso de usarlos
vxml.SetAddendaXml_cfdi40("<MyOwnNode name=\"CFDI40\"><AnyChildNode data=\"Pagos20\" /></MyOwnNode>");

// Custom Namespace
// vxml.SetAddendaXml_cfdi40("<MyOwnNode name=\"CFDI40\"><customNS:AnyChildNode data=\"Pagos20\" xmlns:customNS=\"http://acme.company.org\"/></MyOwnNode>");

Complemento Carta Porte 3.1

var vxml = new Cfdi();
vxml.SetComprobanteInfo_cfdi40("RogueOne", "HNFK231", DateTime.Now.ToString("s"), "01", "", "100.00", "", "MXN", "1", "100.00", "I", "PUE", "06300", "", "01");
vxml.SetEmisorInfo_cfdi40("EKU9003173C9", "ESCUELA KEMPER URGATE", "601", "");
vxml.SetReceptorInfo_cfdi40("ESD140725UP8", "\"E-SI SOLUCIONES DIGITALES\"", "", "", "CP01", "53050", "601");
vxml.AddConcepto_cfdi40("78101800", "UT421511", "1", "H87", "Pieza", "Transporte de carga por carretera", "100.00", "100.00", "", "01");

vxml.SetCartaPorte31("CCCBCD94-870A-4332-A52A-A52AA52AA52A", "No", "", "", "", "1", "Sí", "01", "01");
vxml.CartaPorte31AddUbicacion("Origen", "OR101010", "EKU9003173C9", "NombreRemitenteDestinatario1", "", "", "", "", "", "2023-08-01T00:00:00", "", "", "Calle1", "211", "212", "1957", "13", "casa blanca", "011", "CMX", "MEX", "13250");

vxml.CartaPorte31AddUbicacion("Destino", "DE202020", "EKU9003173C9", "NombreRemitenteDestinatario2", "", "", "", "", "", "2023-08-01T00:00:01", "", "1", "Calle2", "214", "215", "0347", "23", "casa negra", "004", "COA", "MEX", "25350");
vxml.CartaPorte31SetMercancias("1.0", "XBX", "1", "1", "", "Sí");
vxml.CartaPorte31AddMercancia("11121900", "", "Accesorios de equipo de telefonía", "1.0", "XBX", "", "", "No", "", "", "", "", "", "", "DenominacionGenericaProd1", "DenominacionDistintivaProd1", "Fabricante1", "2028-01-01", "LoteMedic1", "01", "01", "RegistroSanita1", "", "", "", "", "", "", "", "", "", "1", "", "", "", "", "", "");
vxml.CartaPorte31AddMercanciaCantidadTransporta("1", "OR101010", "DE202020", "");
vxml.CartaPorte31AddFiguraTransporteTiposFigura("01", "VAAM130719H60", "a234567890", "NombreFigura", "", "", "", "", "", "", "", "", "", "", "", "", "");
vxml.CartaPorte31SetMercanciasAutotransporte("TPAF01", "NumPermisoSCT1", "VL", "1", "plac892", "2020", "AseguraRespCivil", "123456789", "", "", "", "", "", "CTR004", "VL45K98", "", "");

vxml.SetAddendaXml_cfdi40("<MyOwnNode name=\"CFDI40\"><AnyChildNode data=\"CartaPorte31\" /></MyOwnNode>");

Complemento Concepto HidroYPetro10

var vxml = new Cfdi();
vxml.SetComprobanteInfo_cfdi40("A", "1", $"{DateTime.Now:s}", "99", "Contado AÑA Comercial", "50000.00", "", "MXN", "", "58000.00", "I", "PPD", "53050", "", "01");
vxml.AddCfdiRelacionados_cfdi40("04", "FF93C8BE-AF7B-4FC5-8854-6DAE18CFB5B4", "D8E18C2F-2859-4927-A0F0-EA3E93642DDC", "", "", "", "", "", "", "", "");
vxml.AddCfdiRelacionado_cfdi40("BE1D4B47-E167-47A3-8049-70D4D43BCBE8");
vxml.AddCfdiRelacionados_cfdi40("01", "FDBA380A-9732-4FB5-A6CB-5FB4BD831697", "", "", "", "", "", "", "", "", "");
vxml.SetEmisorInfo_cfdi40("EKU9003173C9", "ESCUELA KEMPER URGATE", "601", "");
vxml.SetReceptorInfo_cfdi40("ESD140725UP8", "\"E-SI SOLUCIONES DIGITALES\"", "", "", "CP01", "53050", "601");
vxml.AddConcepto_cfdi40("15101505", "COMB-001", "5000", "LTR", "Litro", "Gasolina regular", "10.00", "50000.00", "", "02");
vxml.AddConceptoTraslado_cfdi40("50000.00", "002", "Tasa", "0.160000", "8000.00");

vxml.AddConceptoComplementoHidroYPetro10("PER03", "PL/364/DIS/OM/2015", "15101505", "SP23");

vxml.AddTraslado_cfdi40("002", "Tasa", "0.160000", "8000.00", "50000.00");
vxml.SetImpuestosInfo_cfdi40("8000.00", "");

vxml.SetAddendaXml_cfdi40("<MyOwnNode name=\"CFDI40\"><AnyChildNode data=\"HidroYPetro10\" /></MyOwnNode>");

Cancelación de CFDI (esquema 2022)

Para cancelar un CFDI previamente timbrado se usa el metodo CancelaCFDI2022. La solicitud se firma localmente (tu llave privada y clave se usan localmente) y se envia al servicio de VXML en una sola fase.

using VXML;

...

var vxml = new Cfdi();

// CancelaCFDI2022(vxmlUser, rfcEmisor, uuid, motivo, foliosust, cer, key, passKey)
//  - vxmlUser : usuario/cuenta de VXML que realiza la cancelacion
//  - rfcEmisor: RFC del emisor que timbro el CFDI
//  - uuid     : UUID (Folio Fiscal) del CFDI a cancelar
//  - motivo   : clave de motivo del SAT (01, 02, 03, 04)
//  - foliosust: UUID del CFDI que sustituye. Requerido cuando motivo es "01", en otro caso ""
//  - cer/key  : certificado y llave (CSD) como ruta de archivo o Base64
//  - passKey  : clave de la llave privada
var resultado = await vxml.CancelaCFDI2022(
    "demo_cibertec",
    "EKU9003173C9",
    "FF93C8BE-AF7B-4FC5-8854-6DAE18CFB5B4",
    "02",
    "",
    csdPath,
    keyPath,
    "12345678a");

// Evaluar el resultado
if (resultado.IsSuccess)
{
    // InnerExitCode contiene el codigo del SAT: 201 (Aceptado) o 202 (Previamente aceptado)
    Console.WriteLine("Cancelacion exitosa. Codigo SAT: {0}", resultado.InnerExitCode);
    Console.WriteLine("UUID: {0}", resultado.uuid);

    // Acuse contiene el XML de acuse de cancelacion del SAT
    if (resultado.Acuse != null)
    {
        await File.WriteAllTextAsync("Somewhere/Path/AcuseCancelacion.xml", resultado.Acuse);
        Console.WriteLine("Acuse de cancelacion guardado");
    }
}
else
{
    Console.WriteLine("Algo fallo con codigo {0} y mensaje {1}", resultado.InnerExitCode, resultado.Message);
}
Motivos de cancelación (SAT)
Motivo Descripción FolioSustitución
01 Comprobante emitido con errores con relación Requerido (UUID del CFDI que sustituye)
02 Comprobante emitido con errores sin relación No aplica ("")
03 No se llevó a cabo la operación No aplica ("")
04 Operación nominativa relacionada en una factura global No aplica ("")

Retenciones 2.0 (Timbrado)

La generación y timbrado de CFDI de Retenciones e Información de Pagos 2.0 se expone a traves de la clase Retencion (interfaz IRetencion). El llenado del documento usa el mismo patron de metodos encadenables que el CFDI 4.0 y el timbrado se solicita al final con TimbraRetencion20.

using VXML;

...

var retencion = new Retencion();

// Llenado del documento (ejemplo con complemento Dividendos)
retencion.SetRetencionesInfo_ret20("FolioInt", DateTime.Now.ToString("s"), "68025", "01", "DescRetenc")
    .SetRetencionesEmisor_ret20("EKU9003173C9", "ESCUELA KEMPER URGATE", "601")
    .SetRetencionesReceptor_ret20("Nacional", "CACX7605101P8", "XOCHILT CASAS CHAVEZ", "CACX760510MPLRRL05", "36257", "", "")
    .SetRetencionesTotales_ret20("333333.33", "0.00", "333333.33", "33333.33", "", "")
    .AddRetencionesTotalesImpRetenidos_ret20("233333.33", "001", "23333.33", "03")
    .AddRetencionesTotalesImpRetenidos_ret20("100000.00", "001", "10000.00", "03")
    .SetRetencionesPeriodo_ret20("12", "12", "2023")
    .SetComplementoDividendos10("01", "142860.00", "0.00", "", "Sociedad Nacional", "", "", "", "");

// TimbraRetencion20(vxmlUser, rfcEmisor, cer, key, passKey, includeQRpng, includeQRbmp, includeQRjpg)
var resultado = await retencion.TimbraRetencion20("demo_cibertec", "EKU9003173C9", csdPath, keyPath, "12345678a", true, false, false);

// Evaluar el resultado
if (resultado.IsSuccess)
{
    Console.WriteLine("UUID: {0}", resultado.uuid);

    var rawXML = Encoding.UTF8.GetString(Convert.FromBase64String(resultado.xmltimbrado));
    Console.WriteLine("XML: {0}", rawXML);

    if (resultado.qrpng != null)
    {
        await File.WriteAllBytesAsync("Somewhere/Path/QR.png", resultado.qrpng);
        Console.WriteLine("png QR written");
    }
}
else
{
    Console.WriteLine("Algo fallo con codigo {0} y mensaje {1}", resultado.InnerExitCode, resultado.Message);
}

Complementos de Retenciones disponibles:

  • SetComplementoDividendos10
  • SetComplementoIntereses10
  • SetComplementoIntereseshipotecarios10
  • SetComplementoPagosaextranjeros10
  • SetComplementoPlataformasTecnologicas10 (+ AddComplementoPlataformasTecnologicas10DetallesDelServicio)
  • SetComplementoPremios10
  • SetComplementoEnajenaciondeAcciones10
  • SetComplementoArrendamientoenfideicomiso10
  • SetComplementoFideicomisonoempresarial10
  • SetComplementoOperacionesconderivados10
  • SetComplementoPlanesderetiro11
  • SetComplementoSectorFinanciero10

Cancelación de Retenciones (esquema 2022)

Para cancelar una Retencion previamente timbrada se usa el metodo CancelaRetencion2022. Al igual que en la cancelacion de CFDI, la solicitud se firma localmente y se envia al servicio de VXML en una sola fase. Los motivos del SAT son los mismos que en la cancelación de CFDI.

using VXML;

...

var retencion = new Retencion();

// CancelaRetencion2022(vxmlUser, rfcEmisor, uuid, motivo, foliosust, cer, key, passKey)
var resultado = await retencion.CancelaRetencion2022(
    "demo_cibertec",
    "EKU9003173C9",
    "489BD24E-9395-44B1-83A2-F08236F56B75",
    "02",
    "",
    csdPath,
    keyPath,
    "12345678a");

// Evaluar el resultado
if (resultado.IsSuccess)
{
    // InnerExitCode contiene el codigo del SAT: 1201 (Aceptada) o 1202 (Previamente solicitada)
    Console.WriteLine("Cancelacion exitosa. Codigo SAT: {0}", resultado.InnerExitCode);
    Console.WriteLine("UUID: {0}", resultado.uuid);

    // Acuse contiene el XML de acuse de cancelacion del SAT
    if (resultado.Acuse != null)
    {
        await File.WriteAllTextAsync("Somewhere/Path/AcuseCancelacionRet.xml", resultado.Acuse);
    }
}
else
{
    Console.WriteLine("Algo fallo con codigo {0} y mensaje {1}", resultado.InnerExitCode, resultado.Message);
}

Descarga Masiva

El servicio de Descarga Masiva del SAT permite descargar los XML o la Metadata de los CFDI emitidos o recibidos en un periodo. Se expone a traves de la clase Masiva (interfaz IMasiva) y el proceso consta de 3 pasos:

  1. Solicitar la descarga con alguno de los metodos MasivaSolicita* (devuelve un idsolicitud)
  2. Verificar el estado de la solicitud con MasivaVerificaSolicitud hasta que el SAT la termine (devuelve los idspaquetes)
  3. Descargar cada paquete ZIP con MasivaDescargaPaquete

IMPORTANTE: La Descarga Masiva requiere el certificado FIEL del contribuyente, no un CSD común. El archivo KEY y su clave solo se ocupan localmente para el firmado de las peticiones y NUNCA se envian.

using VXML;

...

var masiva = new Masiva();

// 1. Solicitar la descarga. Variantes: MasivaSolicitaEmitidosCFDI, MasivaSolicitaEmitidosMetadata,
//    MasivaSolicitaRecibidosCFDI y MasivaSolicitaRecibidosMetadata.
//    Los ultimos 6 parametros son filtros opcionales ("" = no aplicar):
//    estadoComprobante (Todos|Vigente|Cancelado), rfcReceptor/rfcEmisor, tipoComprobante (I|E|T|N|P),
//    complemento (ej. nomina12), rfcACuentaTerceros y uuid
var solicitud = await masiva.MasivaSolicitaEmitidosCFDI(
    "demo_cibertec",
    "EKU9003173C9",
    fielCerPath,
    fielKeyPath,
    "claveFIEL",
    "2026-01-01T00:00:00",
    "2026-01-31T23:59:59",
    "", "", "", "", "", "");

if (!solicitud.IsSuccess)
{
    Console.WriteLine("Fallo con codigo {0}: {1}", solicitud.InnerExitCode, solicitud.Message);
    return;
}

Console.WriteLine("Solicitud aceptada: {0}", solicitud.idsolicitud);

// 2. Verificar la solicitud. El SAT procesa de forma asincrona y puede tardar:
//    mientras no este terminada, InnerExitCode reporta el estado de la solicitud
//    (1: Aceptada | 2: En Proceso | 3: Terminada | 4: Error | 5: Rechazada | 6: Vencida)
//    y debera reintentarse mas tarde. IsSuccess sera verdadero cuando haya paquetes listos.
var verificacion = await masiva.MasivaVerificaSolicitud(
    "demo_cibertec", "EKU9003173C9", fielCerPath, fielKeyPath, "claveFIEL", solicitud.idsolicitud!);

if (!verificacion.IsSuccess)
{
    Console.WriteLine("Aun no lista (codigo {0}): {1}", verificacion.InnerExitCode, verificacion.Message);
    return;
}

Console.WriteLine("Solicitud terminada. {0} CFDI en {1} paquete(s)", verificacion.numerocfdis, verificacion.idspaquetes.Count);

// 3. Descargar cada paquete ZIP (el SAT permite maximo 2 descargas por paquete)
foreach (var idPaquete in verificacion.idspaquetes)
{
    var descarga = await masiva.MasivaDescargaPaquete(
        "demo_cibertec", "EKU9003173C9", fielCerPath, fielKeyPath, "claveFIEL", idPaquete);

    if (descarga.IsSuccess && descarga.paquete != null)
    {
        await File.WriteAllBytesAsync($"Somewhere/Path/{idPaquete}.zip", descarga.paquete);
        Console.WriteLine("Paquete {0} guardado ({1} bytes)", idPaquete, descarga.paquete.Length);
    }
    else
    {
        Console.WriteLine("Fallo la descarga de {0} con codigo {1}: {2}", idPaquete, descarga.InnerExitCode, descarga.Message);
    }
}
Metodo Descripción
MasivaSolicitaEmitidosCFDI Solicita los XML de los CFDI emitidos en un periodo
MasivaSolicitaEmitidosMetadata Solicita la Metadata de los CFDI emitidos en un periodo
MasivaSolicitaRecibidosCFDI Solicita los XML de los CFDI recibidos en un periodo (el SAT solo entrega recibidos Vigentes)
MasivaSolicitaRecibidosMetadata Solicita la Metadata de los CFDI recibidos en un periodo
MasivaVerificaSolicitud Verifica el estado de una solicitud; devuelve los idspaquetes cuando termina
MasivaDescargaPaquete Descarga un paquete ZIP; los bytes llegan en el campo paquete

Administración

Las operaciones administrativas permiten gestionar emisores y usuarios (distribuidores) dentro de una cuenta de VXML. Se exponen a traves de la clase Admin (interfaz IAdmin) y requieren una API key con privilegios de administracion. Todas devuelven un AdminResponseDto donde IsSuccess es verdadero cuando InnerExitCode == 0.

using VXML;

...

var admin = new Admin();

// Alta de un emisor bajo un usuario
var altaEmisor = await admin.AdminEmisorAdd(
    "MI_API_KEY",        // apiKey   : API key de administracion
    "demo_cibertec",     // usuario  : cuenta VXML que tendra al emisor
    "EKU9003173C9",      // rfcEmisor: RFC del emisor
    "",                  // pwdConsulta: clave del portal de consultas ("" para no establecer)
    "ESCUELA KEMPER URGATE", // razonSocial
    "correo@dominio.mx", // email
    "Persona de Contacto", // contacto
    100,                 // asignacion : timbres asignados inicialmente
    false,               // suspendido : true impide timbrar sin importar saldo
    true);               // notificacion: habilitar notificaciones por correo

if (altaEmisor.IsSuccess)
    Console.WriteLine("Emisor creado: {0}", altaEmisor.Message);
else
    Console.WriteLine("Fallo con codigo {0}: {1}", altaEmisor.InnerExitCode, altaEmisor.Message);

// Actualizar un emisor existente (sin modificar la asignacion de timbres)
await admin.AdminEmisorUpd("MI_API_KEY", "demo_cibertec", "EKU9003173C9", "", "ESCUELA KEMPER URGATE", "correo@dominio.mx", "Persona de Contacto", false, true);

// Asignar timbres a un emisor
await admin.AdminEmisorAsigna("MI_API_KEY", "demo_cibertec", "EKU9003173C9", 500);

// Configurar autoasignacion: cuando los timbres disponibles bajen de 'threshold',
// se asignan 'asignacion' timbres, sin exceder 'limit' en total
await admin.AdminEmisorAutoasignacion("MI_API_KEY", "demo_cibertec", "EKU9003173C9", 1000, 100, 10000, true);

// Alta de un usuario (distribuidor)
await admin.AdminUsuarioAdd("MI_API_KEY", "demo_cibertec", "nuevo_distribuidor", "claveSegura", "Razon Social", "correo@dominio.mx", "Contacto", "XAXX010101000", 1000);

// Actualizar un usuario (distribuidor) ("" en pwd para no sobre-escribir la clave)
await admin.AdminUsuarioUpd("MI_API_KEY", "demo_cibertec", "nuevo_distribuidor", "", "Razon Social", "correo@dominio.mx", "Contacto", "XAXX010101000");

// Asignar timbres a un usuario (distribuidor)
await admin.AdminUsuarioAsigna("MI_API_KEY", "demo_cibertec", "nuevo_distribuidor", 500);
Metodo Descripción
AdminEmisorAdd Registra un nuevo emisor bajo un usuario
AdminEmisorUpd Actualiza los datos de un emisor existente
AdminEmisorAsigna Asigna timbres a un emisor
AdminEmisorAutoasignacion Configura la regla de autoasignacion de timbres de un emisor
AdminUsuarioAdd Registra un nuevo usuario (distribuidor)
AdminUsuarioUpd Actualiza los datos de un usuario (distribuidor)
AdminUsuarioAsigna Asigna timbres a un usuario (distribuidor)

Características

  • Generación de CFDI 4.0
  • Cancelación de CFDI 4.0 (esquema 2022)
  • Generación de CFDI de Retenciones e Información de Pagos 2.0, con todos sus complementos
  • Cancelación de Retenciones (esquema 2022)
  • Descarga Masiva de XML y Metadata de CFDI emitidos y recibidos (requiere FIEL)
  • Administración de emisores y distribuidores
  • Generación de todos los complementos vigentes:
    • [Complementos y Complementos Concepto]
  • Generación de representacion impresa simple (PDF)
  • Generación de Codigo de Barras Bidimensional en formatos: png, jpg y bmp
  • Sellado local (tu llave privada y clave son usadas localmente)
  • Manejo de errores y logging

Requisitos técnicos

  • .NET 6.0 o superior

Requerimientos de servicio

  • Contar con un CSD vigente (Certificado de Sello Digital).
  • Contar con los archivos .cer, .key
  • Contar con la clave del archivo .key
  • En caso de desear timbrar con credenciales diferentes al demo; haber contratado un plan de timbres con VXML

NOTA: Los archivos .cer/.key de la FIEL no funcionan para el proceso de timbrado, deberan usarse los del CSD. Para la Descarga Masiva aplica lo contrario: se requiere la FIEL del contribuyente y un CSD sera rechazado por el SAT

Información DEMO

Estas credenciales pueden usarse sin necesidad de ningun tipo de registro

  • usuario: demo_cibertec
  • rfcemisor: EKU9003173C9
  • Certificado Emisor: CSD_EKU9003173C9.cer
  • Llave Privada Emisor: CSD_EKU9003173C9.key
  • Clave Llave Privada: 12345678a

Contacto

Licencia

Este proyecto se rige bajo la licencia MIT.

Product Compatible and additional computed target framework versions.
.NET 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 was computed.  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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.1.0 115 9/3/2026
2.0.9 148 6/30/2026
2.0.8 146 5/28/2026
2.0.0 359 9/19/2025

Soporte para CFDI de Retenciones e Informacion de Pagos 2.0 (timbrado y cancelacion) y para el servicio de Descarga Masiva del SAT