---
seo_title: API de HTML a PDF: convierte archivos HTML a PDF | EnConvert
meta_desc: Convierte HTML a PDF con una API REST. POST /v1/convert/html-to-pdf renderiza archivos HTML a PDF con WeasyPrint: tamaños de página, márgenes, encabezados y pies.
keywords: api html a pdf, convertir html a pdf api, generar pdf desde html api, html a pdf api rest, html a pdf python, html a pdf node js, weasyprint html a pdf api, crear pdf desde html
---

# 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 | Sí | -- | 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

<div class="alert alert-info">
<strong>Nota:</strong> 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.
</div>

---

## 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`)

```json
{
    "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

```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

```javascript
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

```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

```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.
