ArcaConnect.SDK 1.0.3

dotnet add package ArcaConnect.SDK --version 1.0.3
                    
NuGet\Install-Package ArcaConnect.SDK -Version 1.0.3
                    
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="ArcaConnect.SDK" Version="1.0.3" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="ArcaConnect.SDK" Version="1.0.3" />
                    
Directory.Packages.props
<PackageReference Include="ArcaConnect.SDK" />
                    
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 ArcaConnect.SDK --version 1.0.3
                    
#r "nuget: ArcaConnect.SDK, 1.0.3"
                    
#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 ArcaConnect.SDK@1.0.3
                    
#: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=ArcaConnect.SDK&version=1.0.3
                    
Install as a Cake Addin
#tool nuget:?package=ArcaConnect.SDK&version=1.0.3
                    
Install as a Cake Tool

ArcaConnect SDK for .NET

SDK oficial de ArcaConnect para .NET 8.
Emitir y consultar comprobantes electrónicos AFIP/ARCA desde cualquier aplicación .NET sin tocar WSAA, certificados ni firma PKCS#7.


Tabla de contenidos


¿Qué es ArcaConnect SDK?

ArcaConnect es un proxy REST que abstrae la complejidad de integrar directamente con los WebServices SOAP de AFIP/ARCA. Este SDK es el cliente oficial para ese proxy: se comunica con la API REST de ArcaConnect y expone una interfaz .NET limpia, tipada y async.

Lo que el SDK hace por vos:

  • Autentica cada request con tu API key (X-API-Key).
  • Inyecta automáticamente el CUIT emisor y el entorno en cada operación.
  • Reintenta de forma transparente en errores transitorios (502, 503, 504, fallos de red) con backoff exponencial.
  • Adjunta un X-Correlation-ID único por request para trazabilidad.
  • Deserializa respuestas y mapea errores a excepciones tipadas.

Lo que el SDK NO hace:

  • No se conecta directamente a AFIP/ARCA SOAP.
  • No gestiona tokens WSAA ni certificados digitales.
  • No firma XML con PKCS#7.

Todo eso lo maneja el backend ArcaConnect; el SDK solo habla con él.


Arquitectura e infraestructura

Tu aplicación .NET
      │
      │  ArcaConnectClient (singleton)
      │    └── InvoiceService
      │          └── ArcaHttpClient
      │                ├── Headers: X-API-Key, X-CUIT, X-Environment, X-Correlation-ID
      │                └── RetryHandler (backoff exponencial)
      │
      ▼
API REST ArcaConnect   ──►  AFIP/ARCA SOAP
(proxy Laravel)              (WSAA + WSFE)

Componentes internos

Componente Rol
ArcaConnectClient Punto de entrada público. Instanciar una vez (singleton).
InvoiceService Métodos de alto nivel para CRUD de comprobantes.
ArcaHttpClient Wrapper interno sobre HttpClient. Aplica headers, serializa/deserializa JSON y mapea errores HTTP a excepciones.
RetryHandler DelegatingHandler que reintenta automáticamente en 502/503/504 y fallos de red. Usa backoff exponencial: baseDelay × 2^intento. No reintenta 4xx ni 500/501.

Endpoints cubiertos

Operación Método Path
Emitir comprobante POST /api/v1/arca/invoices
Listar comprobantes GET /api/v1/arca/invoices
Obtener detalle GET /api/v1/arca/invoices/{id}
Último número GET /api/v1/arca/invoices/last-number

Requisitos

  • .NET 8.0 o superior
  • Una API key de ArcaConnect (arca_sk_test_… para pruebas, arca_sk_live_… para producción); la API se expone en un único host (https://conectarca.com/api).
  • El CUIT del emisor registrado en ArcaConnect

Instalación

Vía .NET CLI:

dotnet add package ArcaConnect.SDK

Vía Package Manager (Visual Studio):

Install-Package ArcaConnect.SDK

Vía PackageReference en el .csproj:

<PackageReference Include="ArcaConnect.SDK" Version="1.*" />

Inicio rápido

Sin inyección de dependencias

Ideal para scripts, workers simples o proyectos sin contenedor DI.

using ArcaConnect.SDK;
using ArcaConnect.SDK.Enums;
using ArcaConnect.SDK.Models;

var client = new ArcaConnectClient(
    apiKey:      "arca_sk_test_abc123",
    cuitEmisor:  "20111111112",
    environment: ArcaEnvironment.Development);

var request = new InvoiceRequest
{
    PuntoVenta             = 1,
    CbteTipo               = CbteTipo.FacturaB,
    Concepto               = Concepto.Servicios,
    DocTipo                = DocTipo.ConsumidorFinal,
    DocNro                 = "0",
    CondicionIvaReceptorId = CondicionIvaReceptor.ConsumidorFinal,
    ImpTotal               = 1210.00m,
    ImpNeto                = 1000.00m,
    ImpIva                 =  210.00m,
    Iva                    = [new IvaItem(AlicuotaIva.Iva21, 1000.00m, 210.00m)],
    FchServDesde           = new DateOnly(2026, 3,  1),
    FchServHasta           = new DateOnly(2026, 3, 31),
    FchVtoPago             = new DateOnly(2026, 4, 10)
};

InvoiceResult result = await client.Invoices.CreateAsync(request);

Console.WriteLine($"CAE: {result.Cae}");
Console.WriteLine($"Vto CAE: {result.CaeFchVto}");
Console.WriteLine($"Nro comprobante: {result.CbteDesde}");

Con inyección de dependencias (ASP.NET Core)

Registrá el cliente en Program.cs o Startup.cs:

builder.Services.AddArcaConnect(options =>
{
    options.ApiKey      = builder.Configuration["ArcaConnect:ApiKey"]!;
    options.CuitEmisor  = builder.Configuration["ArcaConnect:CuitEmisor"]!;
    options.Environment = ArcaEnvironment.Production;
    options.Timeout     = TimeSpan.FromSeconds(15);
    options.MaxRetries  = 2;
});

ArcaConnectClient se registra como singleton. El HttpClient subyacente es gestionado por IHttpClientFactory.

Inyectalo donde lo necesités:

public class FacturacionController : ControllerBase
{
    private readonly ArcaConnectClient _arca;

    public FacturacionController(ArcaConnectClient arca) => _arca = arca;

    [HttpPost]
    public async Task<IActionResult> Emitir([FromBody] EmitirRequest body, CancellationToken ct)
    {
        var result = await _arca.Invoices.CreateAsync(body.ToInvoiceRequest(), ct);
        return Ok(result);
    }
}

Configuración recomendada en appsettings.json:

{
  "ArcaConnect": {
    "ApiKey": "arca_sk_live_...",
    "CuitEmisor": "20111111112"
  }
}

Nunca commitees la API key. Usá dotnet user-secrets, variables de entorno, o Azure Key Vault en producción.


Referencia de uso

Emitir un comprobante — CreateAsync

InvoiceResult result = await client.Invoices.CreateAsync(request, cancellationToken);

Factura B — Consumidor Final (IVA 21%):

var req = new InvoiceRequest
{
    PuntoVenta             = 1,
    CbteTipo               = CbteTipo.FacturaB,
    Concepto               = Concepto.Servicios,
    DocTipo                = DocTipo.ConsumidorFinal,
    DocNro                 = "0",
    CondicionIvaReceptorId = CondicionIvaReceptor.ConsumidorFinal,
    ImpTotal               = 1210.00m,
    ImpNeto                = 1000.00m,
    ImpIva                 =  210.00m,
    Iva                    = [new IvaItem(AlicuotaIva.Iva21, 1000.00m, 210.00m)],
    FchServDesde           = new DateOnly(2026, 3,  1),
    FchServHasta           = new DateOnly(2026, 3, 31),
    FchVtoPago             = new DateOnly(2026, 4, 10)
};

Factura A — Responsable Inscripto:

var req = new InvoiceRequest
{
    PuntoVenta             = 1,
    CbteTipo               = CbteTipo.FacturaA,
    Concepto               = Concepto.Productos,
    DocTipo                = DocTipo.Cuit,
    DocNro                 = "30999999991",
    CondicionIvaReceptorId = CondicionIvaReceptor.ResponsableInscripto,
    ImpTotal               = 1210.00m,
    ImpNeto                = 1000.00m,
    ImpIva                 =  210.00m,
    Iva                    = [new IvaItem(AlicuotaIva.Iva21, 1000.00m, 210.00m)],
};

Campos de InvoiceRequest:

Campo Tipo Req. Descripción
PuntoVenta int ✓ Punto de venta (1–9999)
CbteTipo CbteTipo ✓ Tipo de comprobante
Concepto Concepto ✓ Productos / Servicios / Ambos
DocTipo DocTipo ✓ Tipo de documento del receptor
DocNro string ✓ Número de documento. "0" para consumidor final
CondicionIvaReceptorId CondicionIvaReceptor ✓ Condición IVA del receptor
ImpTotal decimal ✓ Importe total del comprobante
ImpNeto decimal ✓ Importe neto gravado
ImpIva decimal ✓ Importe total de IVA
Iva IvaItem[]? — Detalle de alícuotas. Requerido cuando hay IVA
ImpTotConc decimal — Importe no gravado (default 0)
ImpOpEx decimal — Importe exento (default 0)
ImpTrib decimal — Importe de otros tributos (default 0)
CbteFecha DateOnly? — Fecha del comprobante. Si se omite, el backend usa la fecha actual
FchServDesde DateOnly? — Inicio período de servicios
FchServHasta DateOnly? — Fin período de servicios
FchVtoPago DateOnly? — Vencimiento del pago
MonId string — Moneda (default "PES")
MonCotiz decimal — Cotización (default 1)

CuitEmisor y Environment se inyectan automáticamente. No los setees manualmente.

Campos de InvoiceResult:

Campo Tipo Descripción
Id long ID interno en ArcaConnect
CbteDesde / CbteHasta long Número del comprobante
Resultado string "A" aprobado, "R" rechazado
Cae string? CAE asignado por AFIP
CaeFchVto DateOnly? Vencimiento del CAE
FchCbte DateOnly? Fecha de emisión
ImpTotal decimal Importe total
CreatedAt DateTimeOffset? Timestamp de creación

Listar comprobantes — ListAsync

var query = new InvoiceListQuery
{
    CuitEmisor  = "20111111112",   // opcional
    CbteTipo    = 6,               // opcional — código numérico AFIP
    PuntoVenta  = 1,               // opcional
    FechaDesde  = new DateOnly(2026, 1, 1),
    FechaHasta  = new DateOnly(2026, 3, 31),
    Resultado   = "A",             // opcional
    Page        = 1,
    PerPage     = 20
};

InvoiceCollection collection = await client.Invoices.ListAsync(query);

foreach (var invoice in collection.Data)
    Console.WriteLine($"{invoice.Id} — {invoice.Cae}");

Console.WriteLine($"Página {collection.CurrentPage} de {collection.LastPage} ({collection.Total} total)");

Iteración sobre todas las páginas:

var query = new InvoiceListQuery { PerPage = 50 };
int page = 1;

do
{
    query.Page = page++;
    var col = await client.Invoices.ListAsync(query);

    foreach (var inv in col.Data)
        Procesar(inv);

    if (!col.HasNextPage) break;
}
while (true);

Obtener un comprobante — GetAsync

InvoiceResult invoice = await client.Invoices.GetAsync("42");

Console.WriteLine($"CAE: {invoice.Cae}  |  Total: {invoice.ImpTotal:C}");

Último número autorizado — GetLastNumberAsync

Útil para calcular el próximo número a emitir antes de hacer un CreateAsync.

LastNumberResult last = await client.Invoices.GetLastNumberAsync(
    puntoVenta: 1,
    cbteTipo:   6);   // Factura B = 6

long siguienteNumero = last.CbteNro + 1;
Console.WriteLine($"Próximo Nro: {siguienteNumero}");

Manejo de errores

Todas las excepciones del SDK heredan de ArcaException. Capturá de lo más específico a lo más general.

try
{
    var result = await client.Invoices.CreateAsync(request);
}
catch (ArcaValidationException ex)
{
    // HTTP 422 — el backend rechazó los datos por validación
    Console.WriteLine($"Errores de validación: {ex.Message}");
    foreach (var (campo, mensajes) in ex.Errors)
        Console.WriteLine($"  {campo}: {string.Join(", ", mensajes)}");
}
catch (ArcaAuthException ex)
{
    // HTTP 401 / 403 — API key inválida, expirada o sin permisos
    Console.WriteLine($"Error de autenticación ({ex.HttpStatusCode}): {ex.Message}");
}
catch (ArcaException ex)
{
    // Cualquier otro error de la API (5xx, errores de red, timeouts exhaustos)
    Console.WriteLine($"Error [{ex.HttpStatusCode}]: {ex.Message}");
    Console.WriteLine($"Correlation ID: {ex.CorrelationId}");  // para soporte
}

Jerarquía de excepciones:

ArcaException               (base — cualquier error del SDK)
 ├── ArcaValidationException (HTTP 422 — errores de campo)
 └── ArcaAuthException       (HTTP 401 / 403 — autenticación)
Propiedad Tipo Descripción
HttpStatusCode int? Código HTTP de la respuesta
ErrorCode string? Código de error de la API
CorrelationId string? ID del request para diagnóstico / soporte
Errors (solo Validation) IDictionary<string, IReadOnlyList> Mapa campo → mensajes de error

Enums de referencia

CbteTipo — Tipo de comprobante

Valor Nombre Descripción
1 FacturaA Factura A — responsable inscripto
2 NotaDebitoA Nota de Débito A
3 NotaCreditoA Nota de Crédito A
6 FacturaB Factura B — consumidor final / exento
7 NotaDebitoB Nota de Débito B
8 NotaCreditoB Nota de Crédito B
11 FacturaC Factura C — monotributista
12 NotaDebitoC Nota de Débito C
13 NotaCreditoC Nota de Crédito C
19 FacturaE Factura de exportación

AlicuotaIva — Alícuota de IVA

Valor Nombre Porcentaje
1 NoGravado No gravado
2 Exento Exento
3 Iva0 0%
4 Iva10_5 10,5%
5 Iva21 21%
6 Iva27 27%
8 Iva5 5%
9 Iva2_5 2,5%

DocTipo — Tipo de documento del receptor

Valor Nombre
80 Cuit
86 Cuil
87 Cdi
96 Dni
99 ConsumidorFinal

Concepto

Valor Nombre
1 Productos
2 Servicios
3 ProductosYServicios

CondicionIvaReceptor

Valor Nombre
1 ResponsableInscripto
2 ResponsableNoInscripto
3 NoResponsable
4 SujetoExento
5 ConsumidorFinal
6 Monotributo
7 Nocategorizado
8 ImportadorExterior
9 ClienteExterior
10 IvaLiberado
11 AgentePercepcion
12 PequenoContribuyenteEvental
13 MonotributistaSocial
14 PequenoContribuyenteEventualSocial

Pipeline HTTP interno

El SDK construye la siguiente cadena de handlers para cada request:

Request
  └── RetryHandler          backoff exponencial, max reintentos configurable
        └── HttpClientHandler   transporte TCP real

Headers automáticos

Header Valor
X-API-Key Tu API key
X-CUIT CUIT emisor configurado
X-Environment "development" o "production" (entorno ARCA/AFIP)
X-Correlation-ID ID único por request (Activity.Current?.Id o Guid)
Accept application/json
Content-Type application/json (solo en POST)

Política de reintentos

Condición ¿Reintenta?
HTTP 502 Bad Gateway ✓
HTTP 503 Service Unavailable ✓
HTTP 504 Gateway Timeout ✓
HttpRequestException (red) ✓
TaskCanceledException (timeout por request) ✓
HTTP 4xx (incluyendo 422) ✗
HTTP 500 / 501 ✗
Cancelación del usuario ✗

El retardo entre reintentos sigue backoff exponencial: baseDelay × 2^intento.
Con los valores por defecto (3 reintentos, 300 ms base): 300 ms → 600 ms → 1200 ms.


Configuración avanzada

ArcaConnectOptions (vía DI)

builder.Services.AddArcaConnect(options =>
{
    options.ApiKey         = "arca_sk_live_...";
    options.CuitEmisor     = "20111111112";
    options.Environment    = ArcaEnvironment.Production;
    options.Timeout        = TimeSpan.FromSeconds(20);   // default: 30 s
    options.MaxRetries     = 3;                          // default: 3
    options.RetryBaseDelay = TimeSpan.FromMilliseconds(500); // default: 300 ms
});

Constructor directo con timeout personalizado

var client = new ArcaConnectClient(
    apiKey:      "arca_sk_test_...",
    cuitEmisor:  "20111111112",
    environment: ArcaEnvironment.Development,
    timeout:     TimeSpan.FromSeconds(10));

Usar CancellationToken en todos los métodos

using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5));

var result = await client.Invoices.CreateAsync(request, cts.Token);

Publicar en NuGet

Esta sección es para los mantenedores del SDK que quieran publicar una nueva versión en nuget.org.

1. Requisitos previos

  • Cuenta en nuget.org (gratuita)
  • API key de NuGet con permiso Push para el paquete ArcaConnect.SDK
  • .NET SDK 8.0 instalado localmente

2. Obtener la API key de NuGet

  1. Iniciar sesión en nuget.org
  2. Ir a Account settings → API Keys → Create
  3. Configurar:
  • Name: arcaconnect-sdk-push (o cualquier nombre descriptivo)
  • Expiration: 365 días (máximo)
  • Package owner: tu usuario u organización
  • Glob pattern: ArcaConnect.*
  • Permissions: Push new packages and package versions
  1. Copiar la key generada (se muestra una sola vez)

3. Actualizar la versión

Editar la versión en src/ArcaConnect.SDK/ArcaConnect.SDK.csproj:

<Version>1.1.0</Version>

Seguir SemVer 2.0:

  • Patch (1.0.x): correcciones de bugs sin cambios de API pública
  • Minor (1.x.0): nuevas funcionalidades compatibles hacia atrás
  • Major (x.0.0): cambios que rompen compatibilidad (breaking changes)

4. Build y empaquetado

# Desde la raíz del repositorio

# Compilar en Release
dotnet build src/ArcaConnect.SDK/ArcaConnect.SDK.csproj -c Release

# Ejecutar todos los tests antes de publicar
dotnet test --no-build -c Release

# Generar el paquete .nupkg
dotnet pack src/ArcaConnect.SDK/ArcaConnect.SDK.csproj \
    -c Release \
    --no-build \
    -o ./nupkg

El archivo resultante estará en ./nupkg/ArcaConnect.SDK.1.x.x.nupkg.

5. Publicar en nuget.org

Opción A — variable de entorno (recomendada para CI/CD):

# Guardá la key como variable de entorno (no la hardcodees)
export NUGET_API_KEY="tu_api_key_aqui"

dotnet nuget push ./nupkg/ArcaConnect.SDK.*.nupkg \
    --api-key $NUGET_API_KEY \
    --source https://api.nuget.org/v3/index.json \
    --skip-duplicate

Opción B — línea de comandos directa:

dotnet nuget push ./nupkg/ArcaConnect.SDK.1.1.0.nupkg \
    --api-key oy2...tu_key... \
    --source https://api.nuget.org/v3/index.json

La flag --skip-duplicate evita error si la versión ya existe (útil en pipelines CI).

6. Verificar la publicación

La indexación puede demorar entre 5 y 30 minutos. Verificar en:

https://www.nuget.org/packages/ArcaConnect.SDK

O buscar desde .NET CLI:

dotnet package search ArcaConnect.SDK --source https://api.nuget.org/v3/index.json

7. Pipeline CI/CD (GitHub Actions)

Ejemplo de workflow para publicar automáticamente al crear un tag v*.*.*:

# .github/workflows/publish-nuget.yml
name: Publish NuGet

on:
  push:
    tags: ["v*.*.*"]

jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup .NET
        uses: actions/setup-dotnet@v4
        with:
          dotnet-version: "8.0.x"

      - name: Run tests
        run: dotnet test --configuration Release

      - name: Pack
        run: dotnet pack src/ArcaConnect.SDK/ArcaConnect.SDK.csproj -c Release -o ./nupkg

      - name: Push to NuGet
        run: |
          dotnet nuget push ./nupkg/*.nupkg \
            --api-key ${{ secrets.NUGET_API_KEY }} \
            --source https://api.nuget.org/v3/index.json \
            --skip-duplicate

Configurar el secreto NUGET_API_KEY en GitHub → Settings → Secrets and variables → Actions.

8. Checklist antes de publicar

  • Versión actualizada en el .csproj
  • README.md actualizado con los cambios de la versión
  • Todos los tests pasan: dotnet test
  • Build limpio en Release: dotnet build -c Release
  • CHANGELOG o Release Notes redactados
  • No hay credenciales ni secrets hardcodeados en el código

Desarrollo local y tests

Clonar y compilar

git clone https://github.com/arca-connect/sdk-csharp-net.git
cd arca-connect-sdk-csharp-net

dotnet restore
dotnet build

Ejecutar tests

# Todos los tests
dotnet test

# Con output detallado
dotnet test -v normal

# Con cobertura de código
dotnet test --collect:"XPlat Code Coverage"

Estructura del proyecto

arca-connect-sdk-csharp-net/
├── src/
│   └── ArcaConnect.SDK/
│       ├── ArcaConnectClient.cs      # Punto de entrada público
│       ├── Config/                   # ArcaConfig (inmutable) + ArcaConnectOptions (DI)
│       ├── Enums/                    # ArcaEnvironment, CbteTipo, Concepto, DocTipo, etc.
│       ├── Exceptions/               # ArcaException, ArcaValidationException, ArcaAuthException
│       ├── Extensions/               # ServiceCollectionExtensions (AddArcaConnect)
│       ├── Http/                     # ArcaHttpClient + RetryHandler
│       ├── Models/                   # InvoiceRequest, InvoiceResult, InvoiceListQuery, etc.
│       └── Services/                 # InvoiceService
└── tests/
    └── ArcaConnect.SDK.Tests/
        ├── Http/                     # Tests de ArcaHttpClient (headers, errores, retry)
        ├── Services/                 # Tests de InvoiceService (MockHttp + FakeHandler)
        ├── Models/                   # Tests de modelos y serialización
        ├── Extensions/               # Tests de AddArcaConnect
        └── Helpers/                  # ArcaTestFixtures, FakeHttpMessageHandler, MockHttpFactory

Licencia

MIT — ver LICENSE para detalles.


¿Preguntas o problemas? Abrí un issue en el repositorio o contactá a soporte@arcaconnect.ar.

Product Compatible and additional computed target framework versions.
.NET 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 was computed.  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
1.0.3 203 4/9/2026
1.0.2 117 4/8/2026
1.0.1 118 4/8/2026