ArcaConnect.SDK
1.0.3
dotnet add package ArcaConnect.SDK --version 1.0.3
NuGet\Install-Package ArcaConnect.SDK -Version 1.0.3
<PackageReference Include="ArcaConnect.SDK" Version="1.0.3" />
<PackageVersion Include="ArcaConnect.SDK" Version="1.0.3" />
<PackageReference Include="ArcaConnect.SDK" />
paket add ArcaConnect.SDK --version 1.0.3
#r "nuget: ArcaConnect.SDK, 1.0.3"
#:package ArcaConnect.SDK@1.0.3
#addin nuget:?package=ArcaConnect.SDK&version=1.0.3
#tool nuget:?package=ArcaConnect.SDK&version=1.0.3
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?
- Arquitectura e infraestructura
- Requisitos
- Instalación
- Inicio rápido
- Referencia de uso
- Manejo de errores
- Enums de referencia
- Pipeline HTTP interno
- Configuración avanzada
- Publicar en NuGet
- Desarrollo local y tests
- Licencia
¿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) |
CuitEmisoryEnvironmentse 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
Pushpara el paqueteArcaConnect.SDK - .NET SDK 8.0 instalado localmente
2. Obtener la API key de NuGet
- Iniciar sesión en nuget.org
- Ir a Account settings → API Keys → Create
- 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
- 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-duplicateevita 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.mdactualizado 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 | Versions 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. |
-
net8.0
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.2)
- Microsoft.Extensions.Http (>= 8.0.1)
- System.Text.Json (>= 8.0.5)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.