---
seo_title: API de Excel a PDF: convierte XLSX y XLS a PDF | EnConvert
meta_desc: Convierte Excel a PDF vía API REST. POST /v1/convert/excel-to-pdf genera PDFs de alta fidelidad desde hojas de cálculo .xlsx y .xls con renderizado LibreOffice.
keywords: api excel a pdf, xlsx a pdf api, convertir xlsx a pdf api, xls a pdf api rest, hoja de cálculo a pdf api, convertir excel a pdf programáticamente, xlsx a pdf api python, excel a pdf api node js
---

# API de Excel a PDF

La API de Excel a PDF convierte hojas de cálculo de Microsoft Excel (`.xlsx`, `.xls`) a PDF mediante `POST /v1/convert/excel-to-pdf`, usando el motor de renderizado de alta fidelidad de LibreOffice. El formato, las fuentes y el diseño de la propia hoja de cálculo se conservan en el PDF de salida. La respuesta son los bytes del PDF en bruto por defecto, o metadatos JSON con una URL de descarga prefirmada cuando `direct_download=false`.

---

## Endpoint

```
POST /v1/convert/excel-to-pdf
```

**Content-Type:** `multipart/form-data`

**Entrada aceptada:** archivos `.xlsx or .xls`

**Formato de salida:** `.pdf` (`application/pdf`)

---

## Autenticación

Requiere una clave API privada o un token JWT emitido a partir 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 | Requerido | Por defecto | Descripción |
|-----------|------|----------|---------|-------------|
| `file` | file | Sí | -- | El archivo `.xlsx or .xls` a convertir. |
| `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 en bruto. Con `false`, devuelve metadatos JSON con una URL de descarga prefirmada. |
| `pdf_options` | `string` | No | `null` | Cadena JSON. Solo se soporta la opción `grayscale` en este endpoint (ver abajo). |

### Opciones de PDF

Para los conversores de documentos basados en LibreOffice, el diseño de página (tamaño, márgenes, orientación) lo determinan los ajustes del propio documento. El único campo de `pdf_options` que aplica es:

| Parámetro | Tipo | Por defecto | Descripción |
|-----------|------|---------|-------------|
| `grayscale` | `boolean` | `false` | Convierte el PDF de salida a escala de grises mediante posprocesado con Ghostscript. |

<div class="alert alert-info">
<strong>Nota:</strong> El tamaño de página, los márgenes, la orientación, la escala, los encabezados y los pies de página de <code>pdf_options</code> no aplican a este endpoint. El PDF de salida conserva el formato definido en el documento original. Para cambiar el diseño de página, modifica el documento de origen antes de subirlo.
</div>

---

## Detalles de la conversión

- Usa **LibreOffice** (vía unoserver) para el renderizado de documentos en el servidor
- Se conservan el formato, las fuentes, el diseño de página y los medios incrustados del propio documento
- Tiempo límite de conversión: 120 segundos
- La salida reproduce fielmente el documento tal y como se imprimiría desde LibreOffice

---

## Respuesta

### Descarga directa (`direct_download=true`, por defecto)

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

Devuelve los bytes del PDF en bruto.

### Respuesta con metadatos (`direct_download=false`)

```json
{
    "presigned_url": "https://spaces.example.com/...",
    "object_key": "env/files/{project_id}/excel-to-pdf/document_20260405_123456789.pdf",
    "filename": "document_20260405_123456789.pdf",
    "file_size": 67890,
    "conversion_time_seconds": 3.5
}
```

---

## Ejemplos de código

### Python

```python
import requests

with open("document.xlsx", "rb") as f:
    response = requests.post(
        "https://api.enconvert.com/v1/convert/excel-to-pdf",
        headers={"X-API-Key": "sk_your_private_key"},
        files={"file": ("document.xlsx", f)}
    )

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

### Node.js

```javascript
const form = new FormData();
form.append("file", fs.createReadStream("document.xlsx"));

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

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

### PHP

```php
$ch = curl_init("https://api.enconvert.com/v1/convert/excel-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("document.xlsx")]
]);
$pdf = curl_exec($ch);
curl_close($ch);
file_put_contents("output.pdf", $pdf);
```

### Go

```go
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
part, _ := writer.CreateFormFile("file", "document.xlsx")
file, _ := os.Open("document.xlsx")
io.Copy(part, file)
writer.Close()

req, _ := http.NewRequest("POST", "https://api.enconvert.com/v1/convert/excel-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)
```

### Con salida en escala de grises

```python
import requests
import json

with open("document.xlsx", "rb") as f:
    response = requests.post(
        "https://api.enconvert.com/v1/convert/excel-to-pdf",
        headers={"X-API-Key": "sk_your_private_key"},
        files={"file": ("document.xlsx", f)},
        data={"pdf_options": json.dumps({"grayscale": True})}
    )
```

---

## Respuestas de error

| Estado | Condición |
|--------|-----------|
| `400 Bad Request` | El archivo no es un archivo `.xlsx or .xls` |
| `400 Bad Request` | La conversión del documento falló (archivo corrupto o no soportado) |
| `400 Bad Request` | JSON de `pdf_options` inválido |
| `401 Unauthorized` | Clave API o token JWT ausente o invá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 de archivo del plan |
| `500 Internal Server Error` | La conversión superó el tiempo límite (límite de 120 segundos) |

---

## Límites

| Límite | Valor |
|-------|-------|
| Tamaño máximo de archivo | Depende del plan (Founding: 5 MB) |
| Tiempo límite de conversión | 120 segundos |
| Conversiones mensuales | Depende del plan |

## Preguntas frecuentes

### ¿Cómo convierto una hoja de cálculo XLSX a PDF con una API REST?

Envía una solicitud `multipart/form-data` a `POST /v1/convert/excel-to-pdf` con tu archivo `.xlsx` o `.xls` en el campo `file`, autenticada vía `X-API-Key` o un JWT Bearer. Por defecto la respuesta son los bytes del PDF en bruto con `Content-Type: application/pdf`.

### ¿La conversión de Excel a PDF conserva el formato de la hoja de cálculo?

Sí. El endpoint usa LibreOffice (vía unoserver) para el renderizado en el servidor, por lo que se conservan el formato, las fuentes, el diseño de página y los medios incrustados de la propia hoja de cálculo. La salida reproduce el documento tal y como se imprimiría desde LibreOffice.

### ¿Puedo definir el tamaño de página, los márgenes o la orientación al convertir Excel a PDF?

No. El diseño de página lo determinan los ajustes de la propia hoja de cálculo, y el único campo de `pdf_options` soportado en este endpoint es `grayscale`. Para cambiar el diseño de página, modifica el archivo de origen antes de subirlo.

### ¿Por qué mi conversión de Excel a PDF falló o expiró?

Un `400 Bad Request` significa que el archivo no es `.xlsx` ni `.xls`, está corrupto o no está soportado, o el JSON de `pdf_options` es inválido. Un `500 Internal Server Error` significa que la conversión superó el tiempo límite de 120 segundos.

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

Sí. Establece `direct_download=false` y el endpoint devuelve metadatos JSON que incluyen `presigned_url`, `object_key`, `filename`, `file_size` y `conversion_time_seconds`.
