ElRoso.ARCA
2.1.2
dotnet add package ElRoso.ARCA --version 2.1.2
NuGet\Install-Package ElRoso.ARCA -Version 2.1.2
<PackageReference Include="ElRoso.ARCA" Version="2.1.2" />
<PackageVersion Include="ElRoso.ARCA" Version="2.1.2" />
<PackageReference Include="ElRoso.ARCA" />
paket add ElRoso.ARCA --version 2.1.2
#r "nuget: ElRoso.ARCA, 2.1.2"
#:package ElRoso.ARCA@2.1.2
#addin nuget:?package=ElRoso.ARCA&version=2.1.2
#tool nuget:?package=ElRoso.ARCA&version=2.1.2
ElRoso.ARCA
Cliente .NET 9 para facturación electrónica con ARCA (ex-AFIP). Hecho para que devs argentinos no sufran integrando como sufrimos los que vinimos antes.
Soporta:
- ✅ Autenticación WSAA (PKCS#7 + token cache cifrado DPAPI)
- ✅ Facturación doméstica WSFEv1 (FA / FB / FC + Notas de Crédito y Débito)
- ✅ Facturación exportación WSFEXv1 (Factura, NC, ND)
- ✅ Padrón A5 (consulta de inscripción AFIP por CUIT)
- ✅ Generación del QR oficial para impresión
- ✅ Verificación de comprobantes recibidos vía WSCDC (desde v1.1.0)
- ✅ Notificaciones del Domicilio Fiscal Electrónico (e-Ventanilla) vía WSCComu (desde v1.1.0)
📑 Tabla de contenidos
- Instalación
- Quick Start — Factura A en 5 líneas
- Configuración
- Manejo de certificados
- Tipos de comprobante soportados
- Recetario por escenario
- Manejo de errores
- Ambientes (Homologación vs Producción)
- QR code para impresión
- Cookbook — Pitfalls comunes
- Contribuir
- Apoyar el proyecto
📦 Instalación
dotnet add package ElRoso.ARCA
Requisitos: .NET 9.0 o superior. Funciona en Windows, Linux y macOS. El cache de tokens usa DPAPI en Windows y JSON plano en Linux/macOS (si esto es problema, ver Cookbook → cache de tokens).
⚡ Quick Start — Factura A en 5 líneas
// 1) Registrá la lib en DI
builder.Services.AddARCAClient(options =>
{
options.IsProduction = false; // homologación
options.CertificatePath = "/certs/mi-empresa.pfx";
options.CertificatePassword = "miPassword";
});
// 2) Emití la factura
var response = await billingService.AuthorizeAsync(new BillingDocumentNumberingRequest
{
BillingDocumentType = BillingDocumentTypeARCAEnum.FA,
BillingDocumentBookPrefix = 1,
BillingDocumentDate = DateTime.Today,
Currency = "Pesos",
ExchangeRate = 1,
ConceptType = ConceptTypeARCAEnum.Products,
AmountTax = 826.45,
BillingDocumentNumberingTaxes = [new() { PercentageTax = "21.00", BaseAmount = 826.45, Amount = 173.55 }],
IssuingCompany = new() { DocumentType = DocumentTypeARCAEnum.CUIT, DocumentNumber = 20123456789 },
Client = new() { DocumentType = DocumentTypeARCAEnum.CUIT, DocumentNumber = 30987654321 },
});
Console.WriteLine(response.Result
? $"CAE: {response.CAE} — Nro: {response.BillingDocumentNumber}"
: $"Errores: {string.Join("; ", response.Errors)}");
⚙️ Configuración
appsettings.json
{
"Arca": {
"IsProduction": false,
"CertificatePath": "/certs/mi-empresa.pfx",
"CertificatePassword": "",
"TokenCacheDirectory": "/tmp/arca-tokens",
"SoapTimeoutSeconds": 30
}
}
🔒 Seguridad: nunca commitees
CertificatePassworden texto plano. Usá variables de entorno, Azure Key Vault, AWS Secrets Manager, o User Secrets en desarrollo.
Registro en Program.cs
builder.Services.AddARCAClient(options =>
{
var cfg = builder.Configuration.GetSection("Arca");
options.IsProduction = cfg.GetValue<bool>("IsProduction");
options.CertificatePath = cfg["CertificatePath"]!;
options.CertificatePassword = cfg["CertificatePassword"];
options.TokenCacheDirectory = cfg["TokenCacheDirectory"] ?? Path.GetTempPath();
options.SoapTimeoutSeconds = cfg.GetValue<int>("SoapTimeoutSeconds", 30);
});
🔐 Manejo de certificados
ARCA requiere un certificado X.509 con clave privada (.pfx o .p12) para firmar los tokens de sesión (WSAA).
Generar el certificado paso a paso
# 1. Generar la clave privada
openssl genrsa -out empresa.key 2048
# 2. Generar el CSR (Certificate Signing Request)
openssl req -new -key empresa.key -subj "/C=AR/O=Mi Empresa/CN=20123456789/serialNumber=CUIT 20123456789" -out empresa.csr
# 3. Cargar el CSR en el portal ARCA → "Administración de Certificados Digitales"
# y descargar el .crt firmado.
# 4. Combinar clave privada + certificado en un .pfx
openssl pkcs12 -export -in empresa.crt -inkey empresa.key -out empresa.pfx -passout pass:miPassword
Docker
services:
myapp:
volumes:
- ./certs:/certs:ro
environment:
Arca__CertificatePath: /certs/empresa.pfx
Arca__CertificatePassword: ${ARCA_CERT_PASSWORD}
⚠️ El
.pfxcontiene la clave privada. Nunca lo commitees. Si por error te pasó, revocá el certificado en ARCA inmediatamente.
📋 Tipos de comprobante soportados
| Enum | Código ARCA | Descripción |
|---|---|---|
FA |
1 | Factura A |
NDA / NCA |
2 / 3 | Nota de Débito / Crédito A |
FB |
6 | Factura B |
NDB / NCB |
7 / 8 | Nota de Débito / Crédito B |
FC |
11 | Factura C |
NDC / NCC |
12 / 13 | Nota de Débito / Crédito C |
InvoiceExport |
19 | Factura de Exportación |
DebitNoteExport / CreditNoteExport |
20 / 21 | Notas Débito / Crédito Exportación |
Remittances |
91 | Remito R |
📖 Recetario por escenario
Factura A con CUIT del cliente
new BillingDocumentNumberingRequest
{
BillingDocumentType = BillingDocumentTypeARCAEnum.FA,
BillingDocumentBookPrefix = 1,
BillingDocumentDate = DateTime.Today,
Currency = "Pesos",
ExchangeRate = 1,
ConceptType = ConceptTypeARCAEnum.Products,
AmountTax = 1000,
BillingDocumentNumberingTaxes =
[
new() { PercentageTax = "21.00", BaseAmount = 1000, Amount = 210 }
],
IssuingCompany = new() { DocumentType = DocumentTypeARCAEnum.CUIT, DocumentNumber = 20123456789 },
Client = new() { DocumentType = DocumentTypeARCAEnum.CUIT, DocumentNumber = 30987654321 },
}
La lib consulta automáticamente el Padrón para resolver el nombre y la condición IVA del cliente.
Factura B / Factura C (Monotributo)
// FC — Monotributo no discrimina IVA
new BillingDocumentNumberingRequest
{
BillingDocumentType = BillingDocumentTypeARCAEnum.FC,
BillingDocumentBookPrefix = 1,
BillingDocumentDate = DateTime.Today,
Currency = "Pesos",
ExchangeRate = 1,
ConceptType = ConceptTypeARCAEnum.Products,
AmountTax = 1210, // total con IVA incluido
IssuingCompany = new() { DocumentType = DocumentTypeARCAEnum.CUIT, DocumentNumber = 20123456789 },
Client = new() { DocumentType = DocumentTypeARCAEnum.SIN_IDENTIFICAR, DocumentNumber = 0 },
}
Notas de Crédito y Débito
Deben incluir los comprobantes asociados:
new BillingDocumentNumberingRequest
{
BillingDocumentType = BillingDocumentTypeARCAEnum.NCA,
BillingDocumentNumberingAssociateds =
[
new()
{
BillingDocumentType = BillingDocumentTypeARCAEnum.FA,
BillingDocumentNumber = 42,
BillingDocumentBookPrefix = 1,
BillingDocumentDate = new DateTime(2026, 1, 15),
}
],
// resto de campos como Factura A...
}
Factura de Servicios
Concepto Services requiere rango de fechas y vencimiento:
ConceptType = ConceptTypeARCAEnum.Services,
DateOfServicesFrom = new DateTime(2026, 3, 1),
DateOfServicesTo = new DateTime(2026, 3, 31),
PaymentDue = new DateTime(2026, 4, 10),
Verificar un comprobante recibido (WSCDC)
Cuando recibís una Factura A de un proveedor, antes de pagarla podés validarla contra ARCA:
var verifier = sp.GetRequiredService<IInvoiceVerificationService>();
var response = await verifier.VerifyAsync(new InvoiceVerificationRequest
{
BillingDocumentType = BillingDocumentTypeARCAEnum.FA,
BillingDocumentBookPrefix = 1, // Punto de venta
BillingDocumentNumber = 42, // Nro. de comprobante
BillingDocumentDate = new DateTime(2026, 5, 1),
TotalAmount = 1210.00,
AuthorizationCode = "75123456789012", // CAE / CAI / CAEA
AuthorizationMode = AuthorizationModeARCAEnum.CAE,
IssuingCompany = new() { DocumentType = DocumentTypeARCAEnum.CUIT, DocumentNumber = 20123456789 },
});
if (response.IsAuthorized)
Console.WriteLine($"✅ CAE válido. Procesado: {response.ProcessedDate:yyyy-MM-dd}");
else
{
Console.WriteLine("❌ NO autorizado:");
foreach (var obs in response.Observations) Console.WriteLine($" {obs}");
}
Requiere el servicio
wscdcadherido en el portal de ARCA. Sample runnable ensamples/InvoiceVerification/.
Leer notificaciones del DFE (e-Ventanilla)
Consulta el buzón fiscal electrónico — ideal para correr en background y notificar al usuario apenas llega algo.
var mailbox = sp.GetRequiredService<IElectronicMailboxService>();
var inbox = await mailbox.ListAsync(new MailboxQueryRequest
{
IssuingCompany = new() { DocumentType = DocumentTypeARCAEnum.CUIT, DocumentNumber = 20123456789 },
Page = 1,
PageSize = 50,
});
foreach (var msg in inbox.Messages)
Console.WriteLine($"[{msg.Id}] {msg.PublishedDate:yyyy-MM-dd} {msg.StateName} {msg.Subject}");
// Leer el contenido completo (marca como leída en ARCA):
var detail = await mailbox.ConsumeAsync(new MailboxConsumeRequest
{
IssuingCompany = new() { DocumentNumber = 20123456789 },
MessageId = inbox.Messages[0].Id,
});
Console.WriteLine(detail.Message?.Body);
foreach (var a in detail.Message?.Attachments ?? [])
File.WriteAllBytes(a.FileName, a.Content);
Requiere
wsccomuadherido + DFE constituido. Sample ensamples/ElectronicMailbox/. Producción URL: ver Cookbook.
Factura de Exportación
new BillingDocumentNumberingRequest
{
BillingDocumentType = BillingDocumentTypeARCAEnum.InvoiceExport,
BillingDocumentId = 1, // ID único de la factura de exportación
Currency = "Dolares",
ExchangeRate = 1050.50,
ConceptType = ConceptTypeARCAEnum.Products,
AmountTax = 500.00,
Client = new()
{
DocumentType = DocumentTypeARCAEnum.CUIT,
DocumentNumber = 55123456789,
CountryId = 123, // código de país ARCA
Address = "123 Main St",
ClientLanguage = "Inglés",
},
Items = [ new() { ItemDescription = "Software license", Amount = 500.00 } ],
}
⚠️ Manejo de errores
La lib lanza excepciones tipadas:
try
{
var response = await billingService.AuthorizeAsync(request);
}
catch (ARCAValidationException ex)
{
// Validaciones locales (FluentValidation) — no llegó a la red
foreach (var err in ex.Errors) Console.WriteLine(err);
}
catch (ARCAAuthException ex)
{
// Falla de autenticación: certificado mal, WSAA caído, firma PKCS#7 fallida
Console.WriteLine(ex.Message);
}
catch (ARCAServiceException ex)
{
// ARCA devolvió un error desde WSFEv1/WSFEXv1/Padrón
Console.WriteLine($"Code {ex.ErrorCode}: {ex.Message}");
}
🌐 Ambientes (Homologación vs Producción)
| Servicio | Homologación (IsProduction=false) |
Producción (IsProduction=true) |
|---|---|---|
| WSAA | wsaahomo.afip.gov.ar |
wsaa.afip.gov.ar |
| WSFEv1 | wswhomo.afip.gov.ar |
servicios1.afip.gov.ar |
| WSFEXv1 | wswhomo.afip.gov.ar |
servicios1.afip.gov.ar |
| Padrón | awshomo.afip.gov.ar |
aws.afip.gov.ar |
Tip: siempre arrancá en homologación. Un mismo certificado no sirve para ambos ambientes — necesitás dos certificados separados.
🔳 QR code para impresión
var qr = response.QRCode();
// Devuelve: https://www.afip.gob.ar/fe/qr/?p=eyJ2ZXIiOjEsImZl...
Esa URL la generás como QR (con QRCoder, ZXing, etc.) y la imprimís en el ticket o PDF junto con el resto de los datos del CAE.
🤝 Contribuir
PRs y issues bienvenidos. Antes de mandar un PR grande, abrí una Discussion para alinear el approach. Ver CONTRIBUTING.md.
Si encontraste una vulnerabilidad de seguridad, no la reportes como issue público — ver SECURITY.md.
❤️ Apoyar el proyecto
Si esta lib te ahorró horas de sufrimiento con ARCA, considerá:
- ⭐ Darle una star al repo
- 💬 Compartirlo con otros devs argentinos
- ☕ Invitarme un cafecito
- 💙 GitHub Sponsors (en aprobación)
📜 Licencia
MIT © Di Rosolini Ezequiel (El Roso)
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | 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. |
-
net9.0
- FluentValidation (>= 12.1.1)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 9.0.16)
- Microsoft.Extensions.Logging.Abstractions (>= 9.0.16)
- Newtonsoft.Json (>= 13.0.4)
- System.Security.Cryptography.Pkcs (>= 9.0.15)
- System.Security.Cryptography.ProtectedData (>= 8.0.0)
- System.ServiceModel.Duplex (>= 6.0.0)
- System.ServiceModel.Federation (>= 8.1.2)
- System.ServiceModel.Http (>= 8.1.2)
- System.ServiceModel.NetTcp (>= 8.1.2)
- System.ServiceModel.Security (>= 6.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.