API de HTML a PDF#

La API de HTML a PDF convierte un archivo HTML subido en un PDF de alta calidad usando el renderizado de WeasyPrint. Envía un archivo .html o .htm a POST /v1/convert/html-to-pdf y el PDF renderizado se devuelve de forma síncrona: como bytes sin procesar por defecto, o como metadatos JSON con una URL de descarga prefirmada cuando direct_download=false. El tamaño de página, los márgenes, la orientación, los encabezados, los pies de página y la salida en escala de grises se controlan mediante pdf_options.


Endpoint#

POST /v1/convert/html-to-pdf

Content-Type: multipart/form-data

Entrada aceptada: archivos .html o .htm (codificados en UTF-8)

Formato de salida: .pdf (application/pdf)


Autenticación#

Requiere una clave API privada o un token JWT obtenido de una clave pública.

X-API-Key: sk_your_private_key

O bien:

Authorization: Bearer <jwt_token>

Parámetros de la solicitud#

Parámetro Tipo Obligatorio Predeterminado Descripción
file file -- El archivo .html o .htm a convertir. Debe estar codificado en UTF-8.
output_filename string No Nombre del archivo de entrada Nombre de archivo de salida personalizado. La extensión .pdf se añade automáticamente.
direct_download boolean No true Con true, devuelve los bytes del PDF sin procesar. Con false, devuelve metadatos JSON con una URL de descarga prefirmada.
pdf_options string No null Cadena JSON con opciones de configuración del PDF. Ver más abajo.

Opciones de PDF#

Pásalas como una cadena JSON en el campo de formulario pdf_options. Todos los campos son opcionales.

Parámetro Tipo Predeterminado Descripción
page_size string "A4" Tamaño de página con nombre. Se ignora cuando page_width y page_height están definidos a la vez.
page_width float null Ancho de página personalizado en milímetros. page_width y page_height deben definirse juntos.
page_height float null Alto de página personalizado en milímetros.
orientation string "portrait" "portrait" o "landscape".
margins object {"top": 10, "bottom": 10, "left": 10, "right": 10} Márgenes de página en milímetros.
grayscale boolean false Convierte la salida a escala de grises mediante posprocesado con Ghostscript.
header object null Encabezado de página. Formato: {"content": "<text>", "height": 15}. Admite variables de plantilla.
footer object null Pie de página. Mismo formato que el encabezado.

Tamaños de página admitidos: A0, A1, A2, A3, A4, A5, A6, B0, B1, B2, B3, B4, B5, Letter, Legal, Tabloid, Ledger

Variables de plantilla para encabezado/pie: {{page}}, {{total_pages}}, {{date}}, {{title}}, {{url}}


Detalles de la conversión#

  • Usa WeasyPrint para el renderizado de PDF basado en CSS
  • Las pdf_options se traducen a reglas CSS @page que se inyectan en el HTML antes del renderizado
  • WeasyPrint respeta los estilos CSS propios del documento además de las reglas de página inyectadas
  • Todo el renderizado es síncrono y del lado del servidor
Nota: Los recursos externos referenciados por URL en el HTML (imágenes, hojas de estilo, fuentes) pueden no resolverse. Para mejores resultados, usa CSS en línea e imágenes codificadas en base64, o asegúrate de que todos los recursos sean accesibles públicamente.

Respuesta#

Descarga directa (direct_download=true, predeterminado)#

HTTP 200 OK
Content-Type: application/pdf
Content-Disposition: inline; filename="document_20260405_123456789.pdf"

Devuelve los bytes del PDF sin procesar.

Respuesta con metadatos (direct_download=false)#

{
    "presigned_url": "https://spaces.example.com/...",
    "object_key": "env/files/{project_id}/html-to-pdf/document_20260405_123456789.pdf",
    "filename": "document_20260405_123456789.pdf",
    "file_size": 45678,
    "conversion_time_seconds": 1.2
}

Ejemplos de código#

Python#

import requests
import json

with open("report.html", "rb") as f:
    response = requests.post(
        "https://api.enconvert.com/v1/convert/html-to-pdf",
        headers={"X-API-Key": "sk_your_private_key"},
        files={"file": ("report.html", f, "text/html")},
        data={
            "pdf_options": json.dumps({
                "page_size": "A4",
                "orientation": "portrait",
                "margins": {"top": 20, "bottom": 20, "left": 15, "right": 15}
            })
        }
    )

with open("report.pdf", "wb") as out:
    out.write(response.content)

Node.js#

const form = new FormData();
form.append("file", fs.createReadStream("report.html"));
form.append("pdf_options", JSON.stringify({
    page_size: "A4",
    orientation: "portrait",
    margins: { top: 20, bottom: 20, left: 15, right: 15 }
}));

const response = await fetch("https://api.enconvert.com/v1/convert/html-to-pdf", {
    method: "POST",
    headers: { "X-API-Key": "sk_your_private_key" },
    body: form
});

fs.writeFileSync("report.pdf", Buffer.from(await response.arrayBuffer()));

PHP#

$ch = curl_init("https://api.enconvert.com/v1/convert/html-to-pdf");
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ["X-API-Key: sk_your_private_key"],
    CURLOPT_POSTFIELDS => [
        "file" => new CURLFile("report.html", "text/html"),
        "pdf_options" => json_encode([
            "page_size" => "A4",
            "margins" => ["top" => 20, "bottom" => 20, "left" => 15, "right" => 15]
        ])
    ]
]);
$pdf = curl_exec($ch);
curl_close($ch);
file_put_contents("report.pdf", $pdf);

Go#

body := &bytes.Buffer{}
writer := multipart.NewWriter(body)

part, _ := writer.CreateFormFile("file", "report.html")
file, _ := os.Open("report.html")
io.Copy(part, file)

writer.WriteField("pdf_options", `{"page_size":"A4","margins":{"top":20,"bottom":20,"left":15,"right":15}}`)
writer.Close()

req, _ := http.NewRequest("POST", "https://api.enconvert.com/v1/convert/html-to-pdf", body)
req.Header.Set("Content-Type", writer.FormDataContentType())
req.Header.Set("X-API-Key", "sk_your_private_key")
resp, _ := http.DefaultClient.Do(req)

Respuestas de error#

Estado Condición
400 Bad Request El archivo no es un archivo .html o .htm
400 Bad Request Codificación HTML no válida (se espera UTF-8)
400 Bad Request La conversión de HTML a PDF falló
400 Bad Request JSON de pdf_options no válido
401 Unauthorized Clave API o token JWT ausente o no válido
402 Payment Required Cuota mensual de ops agotada
402 Payment Required Límite de almacenamiento alcanzado
413 Payload Too Large El archivo supera el tamaño máximo del plan

Límites#

Límite Valor
Tamaño máximo de archivo Según el plan (Founding: 5 MB)
Codificación de entrada Solo UTF-8
Contenido de encabezado/pie Máximo 2000 caracteres
Rango de escala 0.1 -- 2.0
Conversiones mensuales Según el plan

Preguntas frecuentes#

¿Cómo convierto HTML a PDF con una API REST?#

Envía una solicitud multipart/form-data a POST /v1/convert/html-to-pdf con tu archivo .html o .htm en el campo file, autenticándote mediante X-API-Key o un JWT Bearer. Por defecto, la respuesta son los bytes del PDF sin procesar con Content-Type: application/pdf.

¿Puedo establecer un tamaño de página, márgenes u orientación personalizados para el PDF?#

Sí. Pasa una cadena JSON en el campo de formulario pdf_options con page_size (p. ej. A4, Letter, Legal), margins en milímetros y orientation (portrait o landscape). Para dimensiones no estándar, define page_width y page_height juntos en milímetros.

¿Cómo añado números de página o encabezados y pies de página al PDF generado?#

Define header o footer en pdf_options como {"content": "<text>", "height": 15}. El contenido admite las variables de plantilla {{page}}, {{total_pages}}, {{date}}, {{title}} y {{url}}, y está limitado a 2000 caracteres.

¿Por qué faltan imágenes, fuentes u hojas de estilo en mi PDF de salida?#

Los recursos externos referenciados por URL en el HTML pueden no resolverse durante el renderizado del lado del servidor. Usa CSS en línea e imágenes codificadas en base64, o asegúrate de que todos los recursos referenciados sean accesibles públicamente.

¿Puedo obtener una URL de descarga en lugar de los bytes del PDF sin procesar?#

Sí. Establece direct_download=false y el endpoint devuelve metadatos JSON que incluyen presigned_url, object_key, filename, file_size y conversion_time_seconds en lugar del cuerpo del PDF.