Skip to main content
ARCA no genera el PDF de un comprobante emitido por web service. Lo arma tu sistema, y las normas fijan qué datos lleva y dónde van. buildVoucherDocument() toma el comprobante autorizado, los mismos ítems con los que lo emitiste y los datos del emisor, y devuelve todo lo que el comprobante impreso tiene que mostrar. @facturas/pdf lo dibuja en A4 con la ubicación que fija la norma. Si preferís tu propia plantilla, el modelo ya viene derivado y controlado, sin I/O, para que no tenga que saber de clases, leyendas ni IVA.

Del comprobante autorizado al modelo

Este bloque es examples/comprobante-impreso.ts:
Sirve para cualquier resultado authorized, directo o recuperado, y para las notas de crédito y débito. Guardá los ítems junto a la venta: si se reimprime más tarde, el modelo sale igual.

Qué te pide

Si falta un dato obligatorio, tira ArcaInputError con ARCA_INPUT_MISSING_FIELD y el field que falta.

Qué devuelve

  • La letra, el código de tres dígitos, el título y el número con punto de venta, como 00003-00000041. En letterLegend, la leyenda que va junto a la letra A: OPERACIÓN SUJETA A RETENCIÓN para los tipos 51 a 53 o PAGO EN CBU INFORMADA.
  • El emisor y el receptor con su leyenda de condición frente al IVA, por ejemplo IVA RESPONSABLE INSCRIPTO o A CONSUMIDOR FINAL, y el documento del receptor cuando está identificado.
  • Las líneas. En la clase A van sin IVA y con su alícuota, en la clase B con IVA. Suman exactamente lo que autorizó ARCA.
  • Los totales: el descuento global, el subtotal, el exento, el no gravado, el IVA por alícuota en la clase A, los tributos y el total. Si un ajuste de IVA de la cabecera no entra en ninguna línea, aparece en totals.adjustment para que lo muestres.
  • En la clase B, el bloque del Régimen de Transparencia Fiscal al Consumidor con el IVA contenido y los otros impuestos nacionales indirectos.
  • El CAE con su vencimiento, el QR y las leyendas que correspondan: la de la Ley 27.618 en una factura A a un monotributista y, en la clase A, los códigos de las observaciones de ARCA.
Los importes siguen en centavos y las fechas en YYYY-MM-DD. El formato de moneda y el diseño quedan en tu plantilla. PRINTED_VOUCHER_TEXT trae los textos fijos tal como los escriben las normas, por ejemplo C.A.E. N° y el título de transparencia fiscal.

Dónde va cada dato

La RG 1415, Anexo II, Apartado B ubica los datos. El SDK sigue esa ubicación en el comprobante impreso aunque la RG 4291 dé por cumplidas las medidas de un comprobante electrónico:
  • Arriba a la izquierda: nombre de fantasía, razón social, domicilio y condición frente al IVA.
  • Arriba en el centro y destacada: la letra, y debajo Código Nº con el código. Si hay letterLegend, va junto a la letra.
  • Arriba a la derecha: número, fecha, CUIT, ingresos brutos e inicio de actividades. Estos datos y los de la izquierda van dentro de un recuadro de al menos 7 × 3 cm.
  • Después: el receptor, las condiciones de venta y las líneas, con el IVA por alícuota a continuación en la clase A.
  • Abajo a la izquierda: el bloque de transparencia fiscal.
  • Abajo a la derecha: el CAE y Fecha Vto.: con su vencimiento, en letra de 12 puntos o más (PRINTED_CAE_DUE_DATE_MIN_FONT_SIZE_PT).
El QR va en el frente sin tapar ningún dato obligatorio. No uses el logo de ARCA: ninguna norma lo pide y presenta tu documento como si lo hubiera generado ARCA.

Dibujarlo con @facturas/pdf

@facturas/pdf es el paquete que dibuja el modelo. Sale siempre con la misma versión que facturas, así que el modelo y el dibujo nunca quedan desfasados.
El ejemplo completo, de la emisión al archivo, es examples/comprobante-pdf.ts:
El comprobante sale con la ubicación de la sección anterior: el recuadro del emisor de al menos 7 × 3 cm, la letra en el centro, el bloque de transparencia abajo a la izquierda y el CAE con su vencimiento en 12 puntos abajo a la derecha. El QR se dibuja en vectores y además es un link a la constatación de ARCA. En un comprobante largo, el recuadro del emisor se repite en cada hoja y el CAE va en la última. Lo que podés cambiar:
  • theme: tipografía y colores. Los tamaños no, porque la norma fija algunos.
  • logo: va arriba a la izquierda, sobre la razón social.
  • notes: garantía, cambios, CBU, condiciones o lo que quieras decir. Va después del receptor y antes de las líneas, fuera de las zonas fiscales, y puede ser tan largo como haga falta: sigue en la hoja siguiente.
Con JSX tenés más espacios. Cada uno va en un lugar fijo, fuera de las zonas fiscales:
Los totales, las leyendas y el pie con el CAE van siempre juntos: si no entran en la hoja, pasan juntos a la siguiente, así que el CAE nunca queda solo. Si el desglose de impuestos es muy largo, sus renglones siguen en la hoja siguiente y el importe total, con <VoucherAside> a su izquierda, queda con el CAE. Las líneas y las notas, en cambio, siguen en la hoja siguiente cuando no entran, aunque una sola descripción sea más larga que una hoja. Los bloques fiscales no se exportan: <Voucher> los ubica solo. Cualquier otro hijo de <Voucher>, o un espacio repetido, hace que renderVoucherPdf() tire un error que nombra el problema antes de dibujar nada. Usá renderVoucherPdf() también con JSX: si llamás directo a renderToBuffer de react-pdf, ese error llega como un TypeError sin el mensaje.

Descuento global

En las clases A, B y C, ARCA no tiene un campo para un descuento sobre todo el comprobante: lo autoriza ya restado de los ítems. Para imprimir las líneas antes del descuento y un renglón “Descuento global”, pasá los ítems sin descontar y el descuento como lo repartiste al emitir:
El SDK no reparte el descuento: lo decidiste vos al emitir, y si lo recalculara con su redondeo podría quedar a un centavo de lo autorizado. Lo que hace es comprobar, alícuota por alícuota, que las líneas menos su descuento den la base que autorizó ARCA: sin IVA en la clase A y con IVA en la B. En la clase C, globalDiscount es un número y se compara con el neto. El exento y el no gravado no llevan descuento. El PDF imprime un solo renglón “Descuento global” con la suma, antes del importe neto gravado en la clase A y antes del subtotal en las clases B y C. Las líneas conservan su importe y su bonificación propia, si la tienen.

Qué rechaza

buildVoucherDocument() prefiere fallar a imprimir algo incorrecto:
  • Ítems que no suman lo autorizado: ARCA_INPUT_AMOUNT_MISMATCH. Con globalDiscount, el field nombra la alícuota que no cierra, como globalDiscount[5].
  • Un globalDiscount con la forma de otra clase, una clave que no es un id de alícuota o que ningún ítem lleva, o un importe negativo o con decimales: ARCA_INPUT_INVALID_VALUE.
  • Un receptor sin documento que no sea consumidor final: ARCA_INPUT_MISSING_FIELD.
  • Una cantidad por precio unitario que no da el importe de la línea: ARCA_INPUT_AMOUNT_MISMATCH.
  • Un emisor que no puede emitir esa clase o un CUIT distinto del comprobante: ARCA_INPUT_INVALID_VALUE.
  • Comprobantes FCE, que todavía no arma, comprobantes M de los tipos 51 a 53 anteriores al 1 de diciembre de 2025 y un comprobante sin QR: ARCA_INPUT_INVALID_VALUE.
Las fuentes de cada regla, con su norma, inciso y checksum, están en PRINTED_VOUCHER_SOURCES.md. Es una lectura técnica de las normas, no asesoramiento impositivo.
Last modified on October 9, 2026