PDF y layouts
Todo comprobante tiene tres archivos: el PDF (su representación impresa), el XML firmado que se envió a SUNAT y el CDR, la constancia con que SUNAT respondió.
Enlaces públicos
Sección titulada «Enlaces públicos»El comprobante los trae en links. Son direcciones que funcionan sin llave de API, para
enviarlas a tu cliente o enlazarlas desde tu sistema:
{ "links": { "pdf": "https://files.emitay.com/files/…/F001-1.pdf", "xml": "https://files.emitay.com/files/…/F001-1.xml", "cdr": "https://files.emitay.com/files/…/R-F001-1.zip" }}- El enlace lleva un token imposible de adivinar: es todo el permiso. Quien tenga el enlace puede ver el archivo.
cdresnullhasta que SUNAT responde.- El del PDF admite
?format=a4,ticket80oticket58.
Formatos
Sección titulada «Formatos»format |
Papel |
|---|---|
a4 |
Hoja A4, las que haga falta. Es el formato por defecto |
ticket80 |
Rollo de 80 mm, una sola hoja del alto de su contenido |
ticket58 |
Rollo de 58 mm |
Descargar con la llave
Sección titulada «Descargar con la llave»curl "https://api.emitay.com/v1/documents/doc_…/pdf?format=ticket80" \ -H "Authorization: Bearer $EMITAY_API_KEY" \ -o F001-1.pdfCon el SDK, cada archivo llega como bytes:
import { writeFile } from "node:fs/promises";
const pdf = await emitay.documents.pdf("doc_…", { format: "ticket80" }); // Uint8Arrayconst xml = await emitay.documents.xml("doc_…"); // el XML firmadoconst cdr = await emitay.documents.cdr("doc_…"); // el zip del CDR de SUNAT
await writeFile("F001-1.pdf", pdf);El PDF se genera al pedirlo y se guarda: la segunda petición no vuelve a dibujarlo. El QR de una factura, una boleta o una nota se calcula al emitir, así que el PDF existe aunque SUNAT todavía no haya respondido.
Tu propio diseño
Sección titulada «Tu propio diseño»Sin hacer nada, cada formato usa la plantilla de Emitay, con el logo de tu empresa si lo subiste. Un layout es tu propia plantilla: dónde va cada dato, con qué tamaño y qué textos fijos lleva.
- Es de posición libre: textos, tablas, imágenes, QR, líneas y figuras, cada uno donde lo
pongas. No lleva código ni expresiones: cada elemento se enlaza a un dato del comprobante
elegido de una lista (
issuer.ruc,document_id,qr, la tabla de ítems, los totales…). - La misma plantilla sirve para todos los tipos de comprobante: una columna que ninguna línea llena no se dibuja, y una guía muestra sus bienes sin precios.
- El motor que dibuja la vista previa es el mismo que genera el PDF: lo que ves es lo que sale.
En el panel
Sección titulada «En el panel»En el panel, en Layouts de PDF, Nuevo layout copia la plantilla de Emitay del formato que elijas —A4, ticket de 80 mm o ticket de 58 mm— y la abre en el editor visual:
- En el editor del panel cada elemento se arrastra a su sitio. Agregar dato pone un dato del comprobante, elegido de una lista; Agregar elemento, lo que tú escribes o dibujas: un texto, una imagen, una línea, un recuadro o una elipse.
- En el mismo editor del panel, Vista previa muestra el PDF con un comprobante de muestra y Guardar deja una versión nueva. Si al diseño le falta algo de lo que una plantilla no puede quitar, el editor dice qué y no guarda.
- Un layout nuevo no cambia lo que imprimes. En la lista del panel, en el menú de acciones del layout, Usar como predeterminado hace que todos los PDF de ese formato salgan con él, también los de comprobantes ya emitidos.
Por la API
Sección titulada «Por la API»Un layout es { name, format, template, is_default }. La plantilla es un documento JSON de
pdfme; lo habitual es partir de una que ya existe.
| Operación | Qué hace |
|---|---|
POST /v1/layouts |
Crea un layout. La plantilla queda como versión 1 |
PATCH /v1/layouts/{id} |
Cambia solo lo que envías. Un template nuevo no reemplaza al anterior: queda como la versión siguiente |
POST /v1/layouts/{id}/preview |
Devuelve el PDF de la versión vigente con un comprobante de muestra (sample) o con uno tuyo (document_id). No guarda nada |
GET /v1/layouts |
Lista tus layouts |
const layouts = await emitay.layouts.list();const [primero] = layouts.data;if (primero) { const pdf = await emitay.layouts.preview(primero.id, { sample: "invoice" }); console.log(`${primero.name} (${primero.format}), versión ${primero.version}: ${pdf.byteLength} bytes`);}is_default: truehace que todos los PDF de ese formato usen el layout. Hay uno predeterminado por formato; marcar otro se lo quita al anterior.- Las muestras de
previewsoninvoice,receipt,credit_note,despatch_adviceyretention. - Los layouts son de la empresa: sirven al modo de prueba y a producción.
Lo que una plantilla no puede quitar
Sección titulada «Lo que una plantilla no puede quitar»SUNAT exige ciertos datos en la representación impresa. Una plantilla que no los tenga no se
guarda: la API responde 422 con una entrada en errors por cada uno que falta.
- El RUC y la razón social del emisor.
- El tipo de comprobante, su serie y su número.
- El código QR o el valor resumen (hash): basta uno.
- La leyenda «Representación impresa de…».
Un dato no cuenta si no se leería: casi transparente, diminuto o fuera de la hoja.
La referencia de cada operación está en Layouts.