IQeSign.TicketBai.MultiTenant 1.0.0

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

IQeSign.TicketBai.MultiTenant

NuGet License: MIT .NET

Cliente .NET multi-tenant para la API IQ eSign TicketBAI de InnoQubit Software. Permite gestionar facturas TicketBAI de múltiples clientes desde una sola instancia, con caché de tokens JWT independiente por credencial y refresco automático.


Sobre InnoQubit

InnoQubit Business Software es una empresa tecnológica con sede en Castellón (España), especializada en la digitalización y automatización de procesos empresariales para sistemas ERP.

Su producto insignia IQ eSign agrupa soluciones de facturación electrónica y firma digital que se integran con cualquier ERP (Microsoft Dynamics 365 Business Central, Navision y software a medida):

Solución Descripción
IQ eSign VeriFactu Presentación de facturas al sistema VeriFactu de la AEAT
IQ eSign TicketBAI Facturación electrónica para el País Vasco
IQ eSign Facturae Generación y envío de facturas en formato Facturae
IQ eSign ePDF Generación de PDFs firmados digitalmente

¿Qué es TicketBAI?

TicketBAI es el sistema de facturación electrónica obligatorio en el País Vasco, regulado por las haciendas forales de Álava, Gipuzkoa y Bizkaia. Garantiza la integridad de cada factura mediante encadenamiento de firmas digitales y su presentación en tiempo real a la hacienda foral correspondiente.


¿Qué paquete utilizar?

Escenario Paquete recomendado
Una sola empresa / un solo credencial IQeSign.TicketBai
Múltiples clientes / credenciales dinámicos IQeSign.TicketBai.MultiTenant ← este paquete

Este paquete está pensado para integradores, ERPs en la nube y plataformas SaaS que gestionan las facturas TicketBAI de varios clientes desde una misma instancia de aplicación. Ambos paquetes son independientes entre sí: instala únicamente el que necesites.


Instalación

dotnet add package IQeSign.TicketBai.MultiTenant

Para obtener una cuenta y los CredentialGuid de tus clientes, contacta con el equipo comercial de InnoQubit en comercial@innoqubit.com.


Inicio rápido

1. Registro en el contenedor DI

// Program.cs
builder.Services.AddIQeSignTicketBaiMultiTenant(options =>
{
    options.Environment = IQeSignEnvironment.Production; // o Staging para pruebas
    options.TimeoutSeconds = 30;
});

O bien usando una sección de appsettings.json:

{
  "IQeSignTicketBaiMultiTenant": {
    "Environment": "Production",
    "TimeoutSeconds": 30
  }
}
builder.Services.AddIQeSignTicketBaiMultiTenant(
    builder.Configuration.GetSection(IQeSignMultiTenantOptions.SectionName));

Nota: No se especifica CredentialGuid en la configuración. Cada cliente aporta su propio credentialGuid en tiempo de ejecución.

2. Inyectar y usar el cliente

public class FacturacionMultiTenantService(IQeSignMultiTenantClient multiTenant)
{
    public async Task<string> EnviarFacturaAsync(
        string credentialGuid, AddDocumentRequest request, CancellationToken ct = default)
    {
        var tenant = multiTenant.ForTenant(credentialGuid);
        var response = await tenant.TicketBai.AddDocumentAsync(request, ct);

        if (!response.IsSuccess)
            throw new Exception($"Error TicketBAI [{response.ErrorCode}]: {response.ErrorMessage}");

        return response.Result!.Id!;
    }
}

3. Ejemplo completo: enviar una factura emitida

var tenant = multiTenantClient.ForTenant("credentialGuid-del-cliente");

var response = await tenant.TicketBai.AddDocumentAsync(new AddDocumentRequest
{
    CertificateId = "id-del-certificado-en-iqportal",
    CertificatePass = "contraseña-del-pfx",
    File = new TicketBaiDocumentFile
    {
        Issuer = new TicketBaiIssuerInfo
        {
            Name = "Mi Empresa S.L.",
            CifNif = "B12345678",
            TaxCategory = "662"
        },
        Serial = "FAC",
        Number = "2024-001",
        Date = "2024-01-15",
        Name = "Cliente S.A.",
        Nif = "A98765432",
        Address = "Calle Mayor 1",
        ZipCode = "28001",
        Country = "ES",
        Simplified = false,
        OperationType = OperationTypeEmitted.SinInversion,
        Rectified = false,
        TotalInvoice = 1210.00m,
        Administration = Administration.Gipuzkoa,
        Lines =
        [
            new InvoiceLine
            {
                Description = "Servicios de consultoría",
                Quantity = 1,
                UnitAmount = 1000.00m,
                DiscountAmount = 0m,
                Vat = 21m,
                VatEc = 0m,
                VatSubject = true,
                VatCause = VatCause.E1,
                TaxKey = TaxKey.RegimenGeneral
            }
        ]
    },
    Metadata = new DocumentMetadata
    {
        Platform = "MiApp",
        Version = "1.0.0",
        User = "usuario@empresa.com",
        Email = "facturacion@empresa.com",
        Company = "Mi Empresa S.L.",
        Tenant = "tenant-001",
        Description = "Factura generada desde MiApp"
    }
}, ct);

4. Facturas recibidas por tenant

var tenant = multiTenantClient.ForTenant("credentialGuid-del-cliente");
var response = await tenant.Received.AddReceivedAsync(new AddReceivedRequest
{
    CertificateId = "id-certificado",
    CertificatePass = "contraseña",
    File = new ReceivedDocumentFile
    {
        Issuer = new ReceivedIssuerInfo
        {
            Name = "Proveedor S.L.",
            CifNif = "B87654321",
            Country = "ES",
            IdentifierType = IdentifierType.NifIva
        },
        OperationType = ReceivedOperationType.AdquisicionBienesServicios,
        InvoiceType = ReceivedInvoiceType.FacturaConDestinatario,
        Serial = "PRV",
        Number = "2024-100",
        Exercise = 2024,
        ReceivedDate = "2024-01-20",
        InvoiceDate = "2024-01-18",
        SalesVatQuote = 0m,
        Name = "Mi Empresa S.L.",
        Nif = "B12345678",
        Description = "Servicios de consultoría recibidos",
        Rectified = false,
        TaxBase = 500.00m,
        TotalInvoice = 605.00m
    }
}, ct);

5. Certificados por tenant

var tenant = multiTenantClient.ForTenant("credentialGuid-del-cliente");
var certs = await tenant.Certificate.ListAsync(ct);

Cómo funciona internamente

Consumer code
  → IQeSignMultiTenantClient.ForTenant(credentialGuid)
    → TenantClient  (Certificate + TicketBai + Received vinculados al tenant)
      → MultiTenantHttpClient  (singleton, caché de tokens JWT por tenant)
        → IHttpClientFactory  (named client: Production o Staging)
          → https://iqesignapi.azurewebsites.net

Caché de tokens JWT

  • Un token por tenant: ConcurrentDictionary<credentialGuid, TokenEntry> garantiza aislamiento total entre clientes.
  • Refresco automático: El token se renueva cuando caduca (margen de 1 h sobre los 24 h reales de la API).
  • Sin bloqueos globales: Cada tenant tiene su propio SemaphoreSlim(1,1), evitando que el refresco de un cliente bloquee a los demás.
  • Double-check pattern: Tras adquirir el semáforo se vuelve a comprobar la caché para evitar refreshes redundantes.

Servicios disponibles en TenantClient

El TenantClient devuelto por ForTenant(credentialGuid) expone tres servicios:

tenant.TicketBaiITicketBaiService

Método Endpoint Descripción
GetUsageAsync() GET /api/v2/Ticketbai/Usage Consumo del plan contratado
AddDocumentAsync(request) POST /api/v2/TicketBai/Document Envía una factura emitida
GetDocumentByIdAsync(id) GET /api/v2/TicketBai/Document/{id} Consulta un documento
DownloadDocumentAsync(id) GET /api/v2/TicketBai/Document/{id}/Download Descarga el XML firmado (ZIP Base64)
CancelDocumentAsync(id) PUT /api/v2/TicketBai/Document/{id}/Cancel Cancela un documento
RetryDocumentAsync(id) PUT /api/v2/TicketBai/Document/{id}/Retry Reintenta un envío fallido
ListDocumentsAsync(filtros?) GET /api/v2/TicketBai/Document/List Lista documentos
AddZuzenduAsync(id, request) POST /api/v2/TicketBai/Document/{id}/Zuzendu Corrección Zuzendu (Álava/Gipuzkoa)
CancelZuzenduAsync(id) PUT /api/v2/TicketBai/Document/{id}/Zuzendu/Cancel Cancela un Zuzendu

tenant.ReceivedITicketBaiReceivedService

Método Endpoint Descripción
AddReceivedAsync(request) POST /api/v2/TicketBai/Received Registra una factura recibida
CancelReceivedAsync(id, request) PUT /api/v2/TicketBai/Received/{id}/Cancel Cancela una factura recibida
CheckReceivedAsync(id, request) PUT /api/v2/TicketBai/Received/{id}/Check Consulta el estado en hacienda
UpdateReceivedAsync(id, request) PUT /api/v2/TicketBai/Received/{id} Actualiza una factura recibida
ListReceivedAsync(filtros?) GET /api/v2/TicketBai/Received/List Lista facturas recibidas

tenant.CertificateICertificateService

Método Endpoint Descripción
AddAsync(request) POST /api/v2/Certificate Sube un certificado .pfx en Base64
GetByIdAsync(id) GET /api/v2/Certificate/{id} Consulta un certificado
DownloadAsync(id) GET /api/v2/Certificate/{id}/Download Descarga el .pfx
ListAsync() GET /api/v2/Certificate/List Lista todos los certificados
DeleteAsync(id) DELETE /api/v2/Certificate/{id} Elimina un certificado

Gestión avanzada de tokens

// Forzar un nuevo login para un tenant
multiTenantClient.InvalidateToken("credentialGuid-del-cliente");

// Limpiar tokens caducados (liberar memoria en aplicaciones con muchos tenants)
multiTenantClient.PurgeExpiredTokens();

// Número de tenants con token activo en caché
int activos = multiTenantClient.ActiveTenantCount;

Control de errores

var tenant = multiTenantClient.ForTenant(credentialGuid);
var response = await tenant.TicketBai.AddDocumentAsync(request, ct);

if (!response.IsSuccess)
{
    // ErrorCode "0"  → éxito
    // ErrorCode "8"  → error de validación (datos incorrectos, ID no encontrado)
    // ErrorCode "9"  → error no controlado (ver ErrorMessage)
    // Otros          → error de negocio (ver ErrorMessage)
    Console.WriteLine($"[{response.ErrorCode}] {response.ErrorMessage}");
}
Excepción Cuándo se lanza
IQeSignAuthException El credentialGuid es inválido o la cuenta está inactiva
IQeSignApiException La API devuelve un código HTTP 4xx/5xx inesperado

Entornos

Entorno URL Uso
IQeSignEnvironment.Production https://iqesignapi.azurewebsites.net Producción real
IQeSignEnvironment.Staging https://iqesignapistaging.azurewebsites.net Pruebas e integración

Requisitos

  • .NET 8.0 o .NET Standard 2.1 (compatible con .NET 6+, .NET 7+)
  • Cuenta activa en IQ Portal con la solución IQ eSign TicketBAI contratada para cada tenant
  • Certificados digitales .pfx válidos para firma de facturas

Documentación adicional


Licencia

MIT © InnoQubit Software

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  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 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. 
.NET Core netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.1 is compatible. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos 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.0 99 5/13/2026