---
seo_title: ODS to PDF API: Convert OpenDocument Spreadsheets | EnConvert
meta_desc: Convert OpenDocument Spreadsheet (.ods) files from LibreOffice or OpenOffice Calc to PDF with POST /v1/convert/ods-to-pdf. Returns PDF bytes or presigned URL.
keywords: ods to pdf api, convert ods to pdf programmatically, libreoffice calc to pdf api, openoffice ods to pdf api, opendocument spreadsheet to pdf api, ods to pdf rest api, convert ods to pdf python, ods to pdf api curl
---

# ODS to PDF API

The ODS to PDF API converts OpenDocument Spreadsheet files (`.ods`) to PDF through the `POST /v1/convert/ods-to-pdf` endpoint. ODS is the native spreadsheet format of LibreOffice and OpenOffice Calc. Upload an `.ods` file as `multipart/form-data` and receive raw PDF bytes back, or set `direct_download=false` to get JSON metadata with a presigned download URL. Rendering is handled server-side by LibreOffice, so the spreadsheet's own formatting, fonts, and layout are preserved in the PDF output.

---

## Endpoint

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

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

**Accepted input:** `.ods` files

**Output format:** `.pdf` (`application/pdf`)

---

## Authentication

Requires either a private API key or a JWT token from a public key.

```
X-API-Key: sk_your_private_key
```

Or:

```
Authorization: Bearer <jwt_token>
```

---

## Request Parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `file` | file | Yes | -- | The `.ods` file to convert. |
| `output_filename` | `string` | No | Input filename | Custom output filename. The `.pdf` extension is added automatically. |
| `direct_download` | `boolean` | No | `true` | When `true`, returns raw PDF bytes. When `false`, returns JSON metadata with a presigned download URL. |
| `pdf_options` | `string` | No | `null` | JSON string. Only the `grayscale` option is supported for this endpoint (see below). |

### PDF Options

For document converters powered by LibreOffice, page layout (size, margins, orientation) is determined by the document's own settings. The only `pdf_options` field that applies is:

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `grayscale` | `boolean` | `false` | Convert the output PDF to grayscale via Ghostscript post-processing. |

<div class="alert alert-info">
<strong>Note:</strong> Page size, margins, orientation, scale, headers, and footers from <code>pdf_options</code> do not apply to this endpoint. The PDF output preserves the formatting defined in the original document. To change page layout, modify the source document before uploading.
</div>

---

## Conversion Details

- Uses **LibreOffice** (via unoserver) for server-side document rendering
- The document's own formatting, fonts, page layout, and embedded media are preserved
- Conversion timeout: 120 seconds
- The output faithfully reproduces the document as it would appear when printed from LibreOffice

---

## Response

### Direct Download (`direct_download=true`, default)

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

Returns raw PDF bytes.

### Metadata Response (`direct_download=false`)

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

---

## Code Examples

### Python

```python
import requests

with open("document.ods", "rb") as f:
    response = requests.post(
        "https://api.enconvert.com/v1/convert/ods-to-pdf",
        headers={"X-API-Key": "sk_your_private_key"},
        files={"file": ("document.ods", 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.ods"));

const response = await fetch("https://api.enconvert.com/v1/convert/ods-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/ods-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.ods")]
]);
$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.ods")
file, _ := os.Open("document.ods")
io.Copy(part, file)
writer.Close()

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

### With Grayscale Output

```python
import requests
import json

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

---

## Error Responses

| Status | Condition |
|--------|-----------|
| `400 Bad Request` | File is not a `.ods` file |
| `400 Bad Request` | Document conversion failed (corrupt or unsupported file) |
| `400 Bad Request` | Invalid `pdf_options` JSON |
| `401 Unauthorized` | Missing or invalid API key / JWT token |
| `402 Payment Required` | Monthly ops allowance exhausted |
| `402 Payment Required` | Storage limit reached |
| `413 Payload Too Large` | File exceeds plan's maximum file size |
| `500 Internal Server Error` | Conversion timed out (120-second limit) |

---

## Limits

| Limit | Value |
|-------|-------|
| Max file size | Plan-dependent (Founding: 5 MB) |
| Conversion timeout | 120 seconds |
| Monthly conversions | Plan-dependent |

## Frequently asked questions

### How do I convert an ODS spreadsheet to PDF with a REST API?

Send a `POST` request to `/v1/convert/ods-to-pdf` with the `.ods` file in a `multipart/form-data` body, authenticated with an `X-API-Key` header or an `Authorization: Bearer` JWT. The response contains the converted PDF bytes by default.

### Can I convert LibreOffice or OpenOffice Calc spreadsheets to PDF with this API?

Yes. The endpoint accepts `.ods` files, the OpenDocument Spreadsheet format used by LibreOffice and OpenOffice Calc, and renders them server-side with LibreOffice so the output matches how the spreadsheet would print from LibreOffice.

### Can I get a download URL instead of the raw PDF bytes?

Yes. Set `direct_download=false` and the API returns JSON metadata including a `presigned_url`, the output `filename`, `file_size`, and `conversion_time_seconds`.

### Can I change the page size, margins, or orientation of the PDF output?

No. Page layout is taken from the ODS document's own settings; the only supported `pdf_options` field is `grayscale`. To change the layout, modify the source document before uploading.

### Why does the ods-to-pdf endpoint return 400 Bad Request?

A `400 Bad Request` is returned when the upload is not an `.ods` file, when the document is corrupt or unsupported, or when the `pdf_options` value is not valid JSON.
