Esta documentación está en fase de desarrollo y puede contener errores.

Mostrar e imprimir el documento

Qué hacer con el HTML que devuelve un documento dinámico: incrustarlo en tu web dentro de un iframe o convertirlo en PDF con un navegador headless, sin que se queden las variables sin sustituir.

Ya tienes el documento generado: llamaste a POST /api/dynamicdocuments, lo exportaste desde Dinaup o lo recibiste por email. Lo que tienes en la mano es una página HTML completa. Esta página explica qué hacer con ella para verla en tu web o convertirla en PDF.

curl -X POST "https://webhook.dinaup.com/api/dynamicdocuments?id=<id-del-documento>" \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{ "factura": "<id-de-la-factura>" }' \
  -o factura.html

Lo único importante: el HTML llega vivo

Una plantilla de impresión no es HTML plano. Como cuenta Tecnologías compatibles, las plantillas se apoyan en Bootstrap, Vue y Google Charts, que se cargan desde internet y se ejecutan en el navegador. La plantilla de facturas es justo así: el fichero que recibes trae los datos y las instrucciones para pintarlos, pero el dibujo lo hace el navegador.

La consecuencia práctica es una sola, y de ella salen todos los errores típicos:

Hasta que un navegador ejecute el JavaScript, no hay factura

Si abres el HTML en algo que no ejecuta JavaScript, verás la plantilla en crudo: los huecos de datos aparecen como {{ ... }} sin sustituir, o directamente no aparece nada. No es que el documento se haya generado mal — es que todavía no ha terminado de montarse.

Así que solo hay dos destinos válidos, y los dos pasan por un navegador de verdad: incrustarlo en un iframe o pasarlo por un navegador headless para sacar el PDF.


Mostrarlo en tu web: siempre en un iframe

No lo metas con innerHTML

elemento.innerHTML = html nunca va a funcionar. Los navegadores no ejecutan las etiquetas <script> insertadas de esa forma, así que Vue no arranca y te quedas con la plantilla cruda. Además el documento trae su propio <style>, que se te mezclaría con el CSS de tu web.

Un documento es una página entera, así que necesita su propio marco. Tienes dos formas de dárselo, y la diferencia entre ellas no es si funciona — las dos pintan el documento igual de bien — sino cuánto acceso le das a tu página.

Aislado (srcdoc + sandbox)Mismo origen (blob:)
El documento se pinta
Puedes medirlo o imprimirlo desde fuera
El documento puede leer tu página (sesión, cookies)⚠️ sí
Cuándo usarloEl documento viene de otra empresa, otro tenant o de datos que no controlasEs tu Dinaup dentro de tu propia aplicación, y necesitas imprimir o ajustar el alto

Opción A · Aislado

La opción por defecto. allow-scripts es lo que deja arrancar a Vue; al no incluir allow-same-origin, el documento vive en un origen aparte y no puede tocar tu página.

<iframe id="doc" sandbox="allow-scripts" style="width:100%;height:100vh;border:0"></iframe>

<script>
  const respuesta = await fetch('/mi-backend/factura/123'); // tu backend llama a Dinaup
  document.getElementById('doc').srcdoc = await respuesta.text();
</script>

El sandbox vacío no vale

sandbox="" no significa «protección normal»: significa todos los permisos apagados, empezando por ejecutar JavaScript. Es la causa número uno de que un documento aparezca con los {{ }} a la vista. Y añadir allow-same-origin junto a allow-scripts anula el aislamiento por completo: si vas a hacer eso, usa directamente la opción B.

Opción B · Mismo origen

Conviertes el HTML en un fichero temporal del navegador y se lo das al iframe por su src. El documento queda en tu mismo origen, así que puedes medir su altura o lanzar la impresión desde fuera. Llama a la clave API solo desde tu backend.

const marco = document.getElementById('doc');
const url = URL.createObjectURL(new Blob([html], { type: 'text/html' }));

marco.onload = () => URL.revokeObjectURL(url); // libera la memoria del fichero temporal
marco.src = url;

Y a partir de ahí, con el documento ya cargado:

marco.contentWindow.print();                          // abrir el diálogo de impresión
marco.style.height = marco.contentDocument.body.scrollHeight + 'px';  // ajustar el alto

Convertirlo en PDF

Para archivar la factura o adjuntarla a un email necesitas un PDF. Vale cualquier navegador headless — Puppeteer o Playwright en tu servidor, o un servicio de render como Cloudflare Browser Rendering, Browserless o similar — pero en todos hay que cumplir tres condiciones, o el PDF sale mal:

Las tres condiciones

  1. Esperar a que el JavaScript termine. El PDF se captura cuando tú digas; si lo capturas al instante, congelas la página a medio montar y salen los {{ }}.
  2. Imprimir los fondos. Las plantillas usan colores de fondo en cabeceras y totales; sin esta opción salen en blanco.
  3. Tamaño A4. Las plantillas ya declaran @page { size: A4 }; dale al navegador un lienzo acorde (794 × 1123 px a 96 ppp).

Con Puppeteer son cuatro líneas:

const pagina = await navegador.newPage();
await pagina.setViewport({ width: 794, height: 1123 });
await pagina.setContent(html, { waitUntil: 'networkidle0' }); // condición 1
const pdf = await pagina.pdf({ format: 'A4', printBackground: true }); // condiciones 2 y 3

networkidle0 espera a que no queden descargas en curso, que es justo lo que necesitas: Bootstrap y Vue vienen de internet, y hasta que llegan y se ejecutan no hay factura. Si tu servicio de render no ofrece esa espera, casi todos aceptan una espera fija (uno o dos segundos) o esperar a que aparezca un elemento de la plantilla; cualquiera de las dos sirve.


Enviarlo por email

No hace falta que montes tú el correo: la propia plantilla puede fijar asunto, cuerpo, destinatario y nombre del adjunto. Está en Envío de emails.


Errores típicos


Crear documento dinámicoPlantilla de impresión de facturasEnvío de emailsReferencia del endpoint

On this page