Saltar al pie de página
USANDO IRONPDF

API PDF .NET para VeriFactu, TicketBAI y Facturae en España | IronPDF

El entorno normativo español: por qué el diseño de la API PDF importa

Ningún otro mercado europeo impone a los ISV de software de facturación tantos requisitos técnicos simultáneos como España en 2026. VeriFactu, TicketBAI, Facturae, LOPDGDD y Crea y Crece no son regulaciones opcionales: son obligaciones con fechas y penalizaciones concretas. Antes de escribir una línea de código, los arquitectos de sistemas deben entender que su API PDF no es solo una herramienta de generación de documentos; es una pieza del sistema de cumplimiento normativo del ISV.

VeriFactu: el riesgo económico sobre el proveedor de software

El Real Decreto-Ley 15/2025 aplaza VeriFactu al 1 de enero de 2027 (impuesto de sociedades) y al 1 de julio de 2027 (demás contribuyentes), pero los ISV ya deben preparar su arquitectura. VeriFactu establece que cada registro de facturación incluya una huella SHA-256 encadenada —cada factura referencia el hash de la anterior, creando una cadena inalterable verificable por la AEAT.

La visualización del PDF debe incluir la leyenda exacta VERI*FACTU (con asterisco en el centro) o la alternativa Factura verificable en la sede electrónica de la AEAT, más un código QR que permite al receptor verificar la factura en la sede electrónica. Las penalizaciones de €150.000 anuales se imponen al proveedor de software, no solo al contribuyente —esto convierte el cumplimiento técnico en una obligación de negocio directa para el ISV.

IronPDF, como componente de generación de PDFs, no calcula ni gestiona la huella encadenada. Esta responsabilidad corresponde al motor de negocio del ISV. IronPDF renderiza el HTML de la factura —incluyendo la leyenda VERI*FACTU y el QR AEAT— y aplica la firma PAdES al documento resultante.

TicketBAI en el País Vasco: tres administraciones, tres esquemas

Los ISV que atienden a contribuyentes del País Vasco deben implementar las tres variantes forales del régimen TicketBAI:

Bizkaia (bizkaia.eus) opera el sistema BATUZ desde 2022. El XML del registro de facturación se firma con XAdES y se transmite a la plataforma BATUZ antes de emitir la factura al receptor. IronPDF genera el PDF de visualización que el receptor recibe; el XML BATUZ firmado lo gestiona el motor del ISV.

Gipuzkoa (gipuzkoa.eus) y Araba (araba.eus) tienen sus propios calendarios de implantación y esquemas XML con campos específicos. La lógica diferencial entre las tres variantes forales —qué campos son obligatorios, qué validaciones aplican, qué plataforma de transmisión usar— reside íntegramente en el motor de negocio del ISV. IronPDF es agnóstico a estas diferencias; genera el PDF de visualización a partir del HTML que le pasa el motor del ISV.

LOPDGDD y el archivo a largo plazo con validez probatoria

La LOPDGDD (Ley Orgánica de Protección de Datos y Garantía de Derechos Digitales), supervisada por la AEPD (Agencia Española de Protección de Datos), exige conservar documentos con datos personales durante plazos que pueden superar los cinco años. Un documento archivado cuya firma electrónica ya no puede validarse —porque el certificado expiró y no se incrustaron los datos de revocación— pierde su valor probatorio.

La firma PAdES-LTV (Long-Term Validation) incrusta los datos OCSP y CRL en el momento de la firma. Esto permite verificar la firma décadas después, incluso cuando el certificado original ha caducado. Para el archivo de facturas bajo LOPDGDD, PAdES-LTV no es opcional; es el mecanismo técnico que garantiza la cadena de confianza a largo plazo.

Facturae para la Administración Pública y Crea y Crece para el B2B

Facturae (perfil CIUS-ES sobre la norma europea EN 16931) es el formato XML exigido para la facturación electrónica B2G. Las facturas Facturae firmadas se envían a FACe (Punto General de Entrada de Facturas del Estado). El ISV genera el XML Facturae firmado; IronPDF puede generar opcionalmente el PDF de acuse o visualización adjunto.

La Ley Crea y Crece extiende la obligación de facturación electrónica al B2B: empresas con facturación superior a €8 millones desde 2027, el resto desde 2028. Esto significa que los ISV que hoy solo gestionan facturas en papel o PDF no estructurado deben adaptar su arquitectura en los próximos dos años.

La arquitectura correcta: IronPDF como componente, no como sistema

Un error frecuente en el diseño inicial es conceptualizar IronPDF como el núcleo del sistema de facturación. La arquitectura correcta es:

Motor de negocio del ISV (responsable de la certificación VeriFactu)
    │
    ├─► Calcula la huella encadenada SHA-256 (VeriFactu)
    ├─► Genera la URL del QR AEAT y el código de barras
    ├─► Firma el XML TicketBAI con XAdES (País Vasco)
    ├─► Genera el XML Facturae para FACe (sector público)
    └─► Gestiona el SII (Suministro Inmediato de Información IVA)
         │
         └─► IronPDF API (componente de generación de documentos)
                 ├─ Renderiza el HTML de la factura con VERI*FACTU y QR AEAT
                 ├─ Aplica la firma PAdES (documentos para archivo LOPDGDD)
                 └─ Genera PDF/A para archivo a largo plazo

Esta separación tiene implicaciones directas para la auditoría VeriFactu: el organismo certificador evalúa el motor de negocio del ISV —la cadena de huella, el registro en la AEAT, la transmisión TicketBAI—, no la biblioteca de generación de PDFs.

Instalación y generación del primer PDF con leyenda VERI*FACTU

Install-Package IronPdf

El servicio de generación de facturas en castellano requiere configuración UTF-8 explícita:

using IronPdf;
using IronPdf.Signing;
using System.Text;

public byte[] GenerarFacturaVeriFactu(FacturaEspanola factura)
{
    var renderer = new ChromePdfRenderer();
    renderer.RenderingOptions.InputEncoding = Encoding.UTF8;

    // Pie de página con la leyenda alternativa obligatoria
    renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter
    {
        MaxHeight = 15,
        HtmlFragment = "<center style='font-size:9px;'>" +
                       "Factura verificable en la sede electrónica de la AEAT" +
                       " · Pág. {page}/{total-pages}</center>",
        DrawDividerLine = true
    };

    // La leyenda VERI*FACTU (con asterisco) es la forma exacta exigida por la AEAT.
    // La huella encadenada y la URL del QR AEAT las calcula el motor del ISV.
    var leyenda = factura.EsVerifactu ? $@"
        <div style='margin-top:20px;padding:8px;background:#fff3cd;
                    border:1px solid #ffc107;font-weight:bold;text-align:center;'>
            VERI*FACTU | Factura verificable en la sede electrónica de la AEAT
            <br/><img src='{factura.UrlQrAeat}' width='70' height='70' alt='QR AEAT'/>
        </div>" : "";

    var html = $@"<!DOCTYPE html>
<html lang='es'><head><meta charset='UTF-8'/>
<style>body{{font-family:Arial,sans-serif;font-size:11px;}}</style></head>
<body>
  <h2>Factura N.º {factura.NumeroFactura}</h2>
  <p>NIF: {factura.NifEmisor} | {factura.RazonSocial}</p>
  <p>Destinatario: {factura.NombreCliente} — NIF: {factura.NifCliente}</p>
  {leyenda}
</body></html>";

    var pdfDoc = renderer.RenderHtmlAsPdf(html);

    // Firma PAdES para archivo bajo LOPDGDD
    if (!string.IsNullOrEmpty(factura.RutaCertificadoPfx))
    {
        var firma = new PdfSignature(factura.RutaCertificadoPfx, factura.ContrasenaCertificado)
        {
            SigningLocation = "España",
            SigningReason   = "Factura VeriFactu conforme con RDL 15/2025"
        };
        pdfDoc.Sign(firma);
    }

    return pdfDoc.BinaryData;
}
using IronPdf;
using IronPdf.Signing;
using System.Text;

public byte[] GenerarFacturaVeriFactu(FacturaEspanola factura)
{
    var renderer = new ChromePdfRenderer();
    renderer.RenderingOptions.InputEncoding = Encoding.UTF8;

    // Pie de página con la leyenda alternativa obligatoria
    renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter
    {
        MaxHeight = 15,
        HtmlFragment = "<center style='font-size:9px;'>" +
                       "Factura verificable en la sede electrónica de la AEAT" +
                       " · Pág. {page}/{total-pages}</center>",
        DrawDividerLine = true
    };

    // La leyenda VERI*FACTU (con asterisco) es la forma exacta exigida por la AEAT.
    // La huella encadenada y la URL del QR AEAT las calcula el motor del ISV.
    var leyenda = factura.EsVerifactu ? $@"
        <div style='margin-top:20px;padding:8px;background:#fff3cd;
                    border:1px solid #ffc107;font-weight:bold;text-align:center;'>
            VERI*FACTU | Factura verificable en la sede electrónica de la AEAT
            <br/><img src='{factura.UrlQrAeat}' width='70' height='70' alt='QR AEAT'/>
        </div>" : "";

    var html = $@"<!DOCTYPE html>
<html lang='es'><head><meta charset='UTF-8'/>
<style>body{{font-family:Arial,sans-serif;font-size:11px;}}</style></head>
<body>
  <h2>Factura N.º {factura.NumeroFactura}</h2>
  <p>NIF: {factura.NifEmisor} | {factura.RazonSocial}</p>
  <p>Destinatario: {factura.NombreCliente} — NIF: {factura.NifCliente}</p>
  {leyenda}
</body></html>";

    var pdfDoc = renderer.RenderHtmlAsPdf(html);

    // Firma PAdES para archivo bajo LOPDGDD
    if (!string.IsNullOrEmpty(factura.RutaCertificadoPfx))
    {
        var firma = new PdfSignature(factura.RutaCertificadoPfx, factura.ContrasenaCertificado)
        {
            SigningLocation = "España",
            SigningReason   = "Factura VeriFactu conforme con RDL 15/2025"
        };
        pdfDoc.Sign(firma);
    }

    return pdfDoc.BinaryData;
}
Imports IronPdf
Imports IronPdf.Signing
Imports System.Text

Public Function GenerarFacturaVeriFactu(factura As FacturaEspanola) As Byte()
    Dim renderer As New ChromePdfRenderer()
    renderer.RenderingOptions.InputEncoding = Encoding.UTF8

    ' Pie de página con la leyenda alternativa obligatoria
    renderer.RenderingOptions.HtmlFooter = New HtmlHeaderFooter With {
        .MaxHeight = 15,
        .HtmlFragment = "<center style='font-size:9px;'>" &
                        "Factura verificable en la sede electrónica de la AEAT" &
                        " · Pág. {page}/{total-pages}</center>",
        .DrawDividerLine = True
    }

    ' La leyenda VERI*FACTU (con asterisco) es la forma exacta exigida por la AEAT.
    ' La huella encadenada y la URL del QR AEAT las calcula el motor del ISV.
    Dim leyenda As String = If(factura.EsVerifactu, $"
        <div style='margin-top:20px;padding:8px;background:#fff3cd;
                    border:1px solid #ffc107;font-weight:bold;text-align:center;'>
            VERI*FACTU | Factura verificable en la sede electrónica de la AEAT
            <br/><img src='{factura.UrlQrAeat}' width='70' height='70' alt='QR AEAT'/>
        </div>", "")

    Dim html As String = $"
<!DOCTYPE html>
<html lang='es'><head><meta charset='UTF-8'/>
<style>body{{font-family:Arial,sans-serif;font-size:11px;}}</style></head>
<body>
  <h2>Factura N.º {factura.NumeroFactura}</h2>
  <p>NIF: {factura.NifEmisor} | {factura.RazonSocial}</p>
  <p>Destinatario: {factura.NombreCliente} — NIF: {factura.NifCliente}</p>
  {leyenda}
</body></html>"

    Dim pdfDoc = renderer.RenderHtmlAsPdf(html)

    ' Firma PAdES para archivo bajo LOPDGDD
    If Not String.IsNullOrEmpty(factura.RutaCertificadoPfx) Then
        Dim firma As New PdfSignature(factura.RutaCertificadoPfx, factura.ContrasenaCertificado) With {
            .SigningLocation = "España",
            .SigningReason = "Factura VeriFactu conforme con RDL 15/2025"
        }
        pdfDoc.Sign(firma)
    End If

    Return pdfDoc.BinaryData
End Function
$vbLabelText   $csharpLabel

El modelo FacturaEspanola incluye los campos normativos específicos de España:

public class FacturaEspanola
{
    public string NumeroFactura { get; set; }
    public string Serie { get; set; }
    public DateTime Fecha { get; set; }
    public string NifEmisor { get; set; }      // NIF empresa (B12345678)
    public string RazonSocial { get; set; }
    public string NombreCliente { get; set; }
    public string NifCliente { get; set; }
    public decimal TipoIva { get; set; } = 21m; // IVA general España

    // Campos VeriFactu — responsabilidad del motor de negocio del ISV
    public bool EsVerifactu { get; set; }
    public string HuellaEncadenada { get; set; }  // SHA-256 encadenada
    public string UrlQrAeat { get; set; }          // URL verificación AEAT

    // Certificado para firma PAdES (LOPDGDD)
    public string RutaCertificadoPfx { get; set; }
    public string ContrasenaCertificado { get; set; }

    // Variante foral si aplica
    public VarianteTicketBai? VarianteTicketBai { get; set; }
}
public enum VarianteTicketBai { Bizkaia, Gipuzkoa, Araba }
public class FacturaEspanola
{
    public string NumeroFactura { get; set; }
    public string Serie { get; set; }
    public DateTime Fecha { get; set; }
    public string NifEmisor { get; set; }      // NIF empresa (B12345678)
    public string RazonSocial { get; set; }
    public string NombreCliente { get; set; }
    public string NifCliente { get; set; }
    public decimal TipoIva { get; set; } = 21m; // IVA general España

    // Campos VeriFactu — responsabilidad del motor de negocio del ISV
    public bool EsVerifactu { get; set; }
    public string HuellaEncadenada { get; set; }  // SHA-256 encadenada
    public string UrlQrAeat { get; set; }          // URL verificación AEAT

    // Certificado para firma PAdES (LOPDGDD)
    public string RutaCertificadoPfx { get; set; }
    public string ContrasenaCertificado { get; set; }

    // Variante foral si aplica
    public VarianteTicketBai? VarianteTicketBai { get; set; }
}
public enum VarianteTicketBai { Bizkaia, Gipuzkoa, Araba }
Imports System

Public Class FacturaEspanola
    Public Property NumeroFactura As String
    Public Property Serie As String
    Public Property Fecha As DateTime
    Public Property NifEmisor As String      ' NIF empresa (B12345678)
    Public Property RazonSocial As String
    Public Property NombreCliente As String
    Public Property NifCliente As String
    Public Property TipoIva As Decimal = 21D ' IVA general España

    ' Campos VeriFactu — responsabilidad del motor de negocio del ISV
    Public Property EsVerifactu As Boolean
    Public Property HuellaEncadenada As String  ' SHA-256 encadenada
    Public Property UrlQrAeat As String         ' URL verificación AEAT

    ' Certificado para firma PAdES (LOPDGDD)
    Public Property RutaCertificadoPfx As String
    Public Property ContrasenaCertificado As String

    ' Variante foral si aplica
    Public Property VarianteTicketBai As VarianteTicketBai?
End Class

Public Enum VarianteTicketBai
    Bizkaia
    Gipuzkoa
    Araba
End Enum
$vbLabelText   $csharpLabel

Empiece con IronPDF ahora.
green arrow pointer

Endpoint REST y registro del servicio en ASP.NET Core

[ApiController, Route("api/[controller]")]
public class FacturaController : ControllerBase
{
    private readonly IFacturaPdfService _svc;
    public FacturaController(IFacturaPdfService svc) => _svc = svc;

    [HttpPost("generar")]
    public IActionResult Generar([FromBody] FacturaEspanola f)
        => File(_svc.GenerarFacturaVeriFactu(f), "application/pdf",
                $"Factura_{f.Serie}_{f.NumeroFactura}.pdf");
}

// Program.cs — Singleton para reutilizar ChromePdfRenderer
builder.Services.AddSingleton<IFacturaPdfService, FacturaPdfService>();
[ApiController, Route("api/[controller]")]
public class FacturaController : ControllerBase
{
    private readonly IFacturaPdfService _svc;
    public FacturaController(IFacturaPdfService svc) => _svc = svc;

    [HttpPost("generar")]
    public IActionResult Generar([FromBody] FacturaEspanola f)
        => File(_svc.GenerarFacturaVeriFactu(f), "application/pdf",
                $"Factura_{f.Serie}_{f.NumeroFactura}.pdf");
}

// Program.cs — Singleton para reutilizar ChromePdfRenderer
builder.Services.AddSingleton<IFacturaPdfService, FacturaPdfService>();
Imports Microsoft.AspNetCore.Mvc

<ApiController, Route("api/[controller]")>
Public Class FacturaController
    Inherits ControllerBase

    Private ReadOnly _svc As IFacturaPdfService

    Public Sub New(svc As IFacturaPdfService)
        _svc = svc
    End Sub

    <HttpPost("generar")>
    Public Function Generar(<FromBody> f As FacturaEspanola) As IActionResult
        Return File(_svc.GenerarFacturaVeriFactu(f), "application/pdf", $"Factura_{f.Serie}_{f.NumeroFactura}.pdf")
    End Function
End Class

' Program.vb — Singleton para reutilizar ChromePdfRenderer
builder.Services.AddSingleton(Of IFacturaPdfService, FacturaPdfService)()
$vbLabelText   $csharpLabel

Docker: dependencias de fuentes para el castellano en Linux

FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS final
WORKDIR /app
COPY --from=publish /app/publish .
# Latin-1 Extended: á, é, ü, ñ, ¿, ¡
RUN apt-get update && apt-get install -y \
    fonts-liberation fontconfig libgdiplus libc6-dev \
    && fc-cache -fv && rm -rf /var/lib/apt/lists/*
ENTRYPOINT ["dotnet", "FacturacionPdfApi.dll"]

La licencia comercial como ventaja normativa para ISV bajo VeriFactu

El entorno VeriFactu crea un escenario de riesgo compuesto para los ISV que usan bibliotecas PDF bajo licencia AGPL. iText 7 usa AGPL, que obliga a divulgar el código fuente al distribuir software propietario. Para un ISV cuyos ingresos dependen de software de facturación propietario, esto significa:

  • Riesgo AGPL: si un cliente o competidor exige el código fuente del software que incorpora iText bajo AGPL, el ISV debe entregarlo o reemplazar la biblioteca.
  • Riesgo VeriFactu: las penalizaciones de €150.000 anuales recaen sobre el ISV, no sobre la biblioteca. Si un litigio AGPL distrae recursos de ingeniería del mantenimiento de la conformidad VeriFactu, el riesgo normativo aumenta.

IronPDF: licencia comercial propietaria, pago único, sin obligaciones de divulgación. Para las opciones de licencia o una prueba gratuita, el ISV obtiene claridad jurídica inmediata.

Rendimiento para Crea y Crece (2027/2028)

La Ley Crea y Crece impone la facturación electrónica B2B en dos fases. Para volúmenes altos, configure ChromePdfRenderer con operaciones asíncronas y sin JavaScript (facturas no lo necesitan):

renderer.RenderingOptions.EnableJavaScript = false;
renderer.RenderingOptions.CssMediaType     = PdfCssMediaType.Print;
renderer.RenderingOptions.RenderDelay      = 0;
public async Task<byte[]> GenerarAsync(FacturaEspanola f)
    => await Task.Run(() => GenerarFacturaVeriFactu(f));
renderer.RenderingOptions.EnableJavaScript = false;
renderer.RenderingOptions.CssMediaType     = PdfCssMediaType.Print;
renderer.RenderingOptions.RenderDelay      = 0;
public async Task<byte[]> GenerarAsync(FacturaEspanola f)
    => await Task.Run(() => GenerarFacturaVeriFactu(f));
Imports System.Threading.Tasks

renderer.RenderingOptions.EnableJavaScript = False
renderer.RenderingOptions.CssMediaType = PdfCssMediaType.Print
renderer.RenderingOptions.RenderDelay = 0

Public Async Function GenerarAsync(f As FacturaEspanola) As Task(Of Byte())
    Return Await Task.Run(Function() GenerarFacturaVeriFactu(f))
End Function
$vbLabelText   $csharpLabel

Resumen

Su API PDF con ASP.NET Core e IronPDF cubre el entorno normativo español multirégimen:

  • VeriFactu: leyenda VERI*FACTU y QR AEAT en el PDF; huella encadenada en el motor del ISV.
  • TicketBAI (Bizkaia/BATUZ, Gipuzkoa, Araba): IronPDF genera el PDF de visualización; la firma XAdES del XML TicketBAI es responsabilidad del motor del ISV.
  • Facturae/FACe: IronPDF genera el PDF adjunto o de acuse; el XML Facturae firmado lo genera el motor del ISV.
  • LOPDGDD (supervisada por la AEPD): firma PAdES-LTV para archivo a largo plazo con validez probatoria.
  • Crea y Crece: arquitectura asíncrona escalable para los volúmenes B2B de 2027/2028.

Para firma avanzada con HSM: guía de firma con HSM. Para archivo PDF/A: guía de PDF/A. Para el QR AEAT: IronQR para España.

Preguntas Frecuentes

¿Puede IronPDF usarse dentro de software de facturación VeriFactu?

Sí. IronPDF es un componente de generación de PDF que se utiliza DENTRO del software de facturación certificado. No es un sistema de facturación certificado por sí mismo. La lógica de VeriFactu (huella encadenada, registro de facturación) la implementa el motor de negocio del ISV; IronPDF proporciona la capa de generación del documento PDF con la leyenda VERI*FACTU y el soporte QR.

¿Cómo incluyo la leyenda VERI*FACTU obligatoria en el PDF?

En el HTML de la factura, incluya un elemento con el texto exacto 'VERI*FACTU' (con asterisco) o la alternativa 'Factura verificable en la sede electrónica de la AEAT'. IronPDF renderiza el HTML fielmente, preservando la leyenda en el PDF generado. Ambas leyendas deben preservarse verbatim.

¿Soporta IronPDF la firma XAdES para TicketBAI en el País Vasco?

IronPDF soporta firmas digitales avanzadas PAdES para PDFs. Para XAdES (firma de documentos XML como los registros TicketBAI), el ISV implementa la firma en el motor de negocio y usa IronPDF para la visualización en PDF del documento firmado.

¿Cómo afecta la licencia AGPL de iText a los ISV bajo VeriFactu?

Los ISV bajo VeriFactu están sujetos a penalizaciones de hasta €150.000 anuales si el software de facturación no cumple. La AGPL obliga a divulgar el código fuente al distribuir el software. IronPDF ofrece una licencia comercial propietaria que evita este riesgo compuesto.

¿Cómo garantizo el renderizado correcto de los caracteres españoles (á, ñ, ¿) en Linux/Docker?

Configure el Dockerfile con el paquete fonts-liberation y ejecute fc-cache. Establezca InputEncoding a UTF-8 en ChromePdfRenderer. Esto garantiza el renderizado correcto de todo el Latin-1 Extended del castellano.

¿Qué diferencia hay entre TicketBAI en Bizkaia, Gipuzkoa y Araba?

Cada provincia vasca tiene su propia hacienda foral (bizkaia.eus, gipuzkoa.eus, araba.eus) con variantes específicas del esquema TicketBAI XML. Los ISV que sirven a clientes en el País Vasco deben implementar las tres variantes. IronPDF genera el PDF de visualización; la firma XAdES por variante foral la gestiona el motor de negocio.

Curtis Chau
Escritor Técnico

Curtis Chau tiene una licenciatura en Ciencias de la Computación (Carleton University) y se especializa en el desarrollo front-end con experiencia en Node.js, TypeScript, JavaScript y React. Apasionado por crear interfaces de usuario intuitivas y estéticamente agradables, disfruta trabajando con frameworks modernos y creando manuales bien ...

Leer más

Equipo de soporte de Iron

Estamos disponibles online las 24 horas, 5 días a la semana.
Chat
Email
Llámame