# cloudlayer.io — Complete Documentation
> Platform for captures, documents, and forms: capture reachable URLs, design templates visually or in HTML, merge data, and generate PDFs and images through repeatable workflows.
This document inlines every published documentation page. The index version
lives at https://cloudlayer.io/llms.txt
## API Reference
### API Overview
Source: https://cloudlayer.io/docs/api-overview/
# API Overview
The cloudlayer.io API lets you generate PDFs and images from HTML, URLs, and templates. All endpoints follow REST conventions and return standard HTTP status codes.
## Base URL
All API requests are made to:
```
https://api.cloudlayer.io/v1
```
Every endpoint path in this documentation is relative to this base URL. For example, `POST /v1/html/pdf` means you send your request to `https://api.cloudlayer.io/v1/html/pdf`.
```
https://api.cloudlayer.io/v2
```
Every endpoint path in this documentation is relative to this base URL. For example, `POST /v2/html/pdf` means you send your request to `https://api.cloudlayer.io/v2/html/pdf`.
---
## Authentication
Every request must include your API key in the `X-API-Key` header. You can find and manage your API keys in the [cloudlayer.io dashboard](https://beta-app.cloudlayer.io).
```
X-API-Key: your-api-key-here
```
Requests without a valid API key receive a `401 Unauthorized` response.
### Example: Authenticated Request
**cURL**
```bash
curl -X GET "https://api.cloudlayer.io/v1/account" \
-H "X-API-Key: your-api-key-here"
```
**JavaScript (fetch)**
```javascript
const response = await fetch("https://api.cloudlayer.io/v1/account", {
method: "GET",
headers: {
"X-API-Key": "your-api-key-here",
},
});
const data = await response.json();
```
**Python (requests)**
```python
import requests
response = requests.get(
"https://api.cloudlayer.io/v1/account",
headers={"X-API-Key": "your-api-key-here"},
)
data = response.json()
```
**cURL**
```bash
curl -X GET "https://api.cloudlayer.io/v2/account" \
-H "X-API-Key: your-api-key-here"
```
**JavaScript (fetch)**
```javascript
const response = await fetch("https://api.cloudlayer.io/v2/account", {
method: "GET",
headers: {
"X-API-Key": "your-api-key-here",
},
});
const data = await response.json();
```
**Python (requests)**
```python
import requests
response = requests.get(
"https://api.cloudlayer.io/v2/account",
headers={"X-API-Key": "your-api-key-here"},
)
data = response.json()
```
> **Security tip:** Never expose your API key in client-side code. Always call the cloudlayer.io API from your server.
---
## Content Types
Most endpoints accept JSON request bodies. Set the `Content-Type` header accordingly:
| Scenario | Content-Type |
| --- | --- |
| JSON body (most endpoints) | `application/json` |
| Multipart form data (template uploads) | `multipart/form-data` |
| GET requests | No `Content-Type` needed |
Response content types depend on the endpoint:
| Scenario | Response Content-Type |
| --- | --- |
| Document generation | `application/pdf`, `image/png`, `image/jpeg`, or `image/webp` |
| Account, jobs, assets, storage | `application/json` |
All document generation responses return the raw file binary directly.
All v2 responses return JSON:
| Scenario | Response Content-Type |
| --- | --- |
| Document generation (async — default) | `application/json` (job metadata) |
| Document generation (sync, `async: false`) | `application/json` (completed job with asset URL) |
| Account, jobs, assets, storage | `application/json` |
v2 always returns JSON with job metadata. Only v1 returns raw binary file content directly.
---
## Synchronous vs. Asynchronous Requests
All document generation requests in v1 are processed **synchronously**. The API waits for the document to be generated and returns the raw file binary (PDF or image) directly in the response body.
```bash
curl -X POST "https://api.cloudlayer.io/v1/html/pdf" \
-H "X-API-Key: your-api-key-here" \
-H "Content-Type: application/json" \
-d '{"html": "PGgxPkhlbGxvIFdvcmxkPC9oMT4="}' \
--output result.pdf
```
The response is the raw PDF binary. Use `--output` (cURL) or handle the response as a binary stream.
> **Tip:** For large or complex documents that take a long time to render, consider switching to the v2 API which supports asynchronous processing.
By default, document generation endpoints in v2 process your request **asynchronously**. The API returns a JSON response immediately with the job ID, and the generated file is stored and accessible via the [Assets](/docs/assets/) endpoint once processing completes.
### Asynchronous (default)
```bash
curl -X POST "https://api.cloudlayer.io/v2/html/pdf" \
-H "X-API-Key: your-api-key-here" \
-H "Content-Type: application/json" \
-d '{"html": "PGgxPkhlbGxvIFdvcmxkPC9oMT4="}'
```
Returns a JSON response immediately:
```json
{
"id": "1705312200000",
"status": "pending"
}
```
Poll the [Jobs](/docs/jobs/) endpoint or use [Webhooks](/docs/webhooks/) to be notified when the job completes. Once complete, retrieve the result from the [Assets](/docs/assets/) endpoint.
### Synchronous
To process a request synchronously, include `"async": false` in your request body. The API still returns JSON, but waits for processing to complete before responding:
```bash
curl -X POST "https://api.cloudlayer.io/v2/html/pdf" \
-H "X-API-Key: your-api-key-here" \
-H "Content-Type: application/json" \
-d '{"html": "PGgxPkhlbGxvIFdvcmxkPC9oMT4=", "async": false}'
```
The response is JSON with the completed job details, including the asset URL for downloading the generated file.
> **Note:** In v2, `storage` also defaults to `true`. When `async` is `true` (the default), the generated file is automatically stored and accessible via the Assets endpoint. You can set `"storage": false` to disable storage, but this requires `"async": false` as well.
---
## Rate Limits
All accounts are rate-limited to **60 requests per 60 seconds**. This limit applies to all endpoints and all plans equally. Exceeding the limit returns a `429 Too Many Requests` response.
Separately, your plan has a **usage quota** — a total number of API calls allowed per billing period. The `cl-calls-remaining` response header shows how many calls remain in your current period.
| Header | Description |
| --- | --- |
| `cl-calls-remaining` | Number of API calls remaining in your current billing period |
| `Retry-After` | Seconds to wait before retrying, sent on a `429` response |
**Best practice:** Implement retry logic with exponential backoff for `429` responses, honoring `Retry-After` when it is present. Monitor `cl-calls-remaining` to track usage against your plan quota.
### Concurrency
Rate limiting and concurrency are different controls and you can meet either one first. The rate limit above caps how many requests you may *send* in a window. Concurrency caps how many renders run *at the same time*, and unlike the rate limit it varies by plan: extra requests queue rather than failing, so a batch finishes more slowly rather than returning `429`.
The concurrency included with each plan is listed on the [pricing page](https://cloudlayer.io/pricing/) alongside the render allowance.
---
## HTTP Status Codes
| Code | Meaning | Description |
| --- | --- | --- |
| `200` | OK | Request succeeded. Response body contains the result. |
| `400` | Bad Request | The request body is malformed or missing required parameters. |
| `401` | Unauthorized | Missing or invalid API key, or account has exceeded its usage limits. |
| `404` | Not Found | The requested resource does not exist (e.g., invalid route). |
| `429` | Too Many Requests | Rate limit exceeded (60 requests per 60 seconds). Retry with exponential backoff. |
| `500` | Internal Server Error | Something went wrong on our end. Contact support if it persists. |
---
## Error Response Format
When an error occurs, the API returns a JSON body with the status code and a message:
```json
{
"statusCode": 400,
"message": "The 'html' field is required and must be a base64-encoded string."
}
```
| Field | Type | Description |
| --- | --- | --- |
| `statusCode` | number | The HTTP status code (matches the response status). |
| `message` | string | A human-readable description of the error. |
Some error responses may also include a `status` field with the value `"error"`:
```json
{
"status": "error",
"message": "Generation failed: page timeout exceeded."
}
```
---
## Common Request Parameters
Several parameters appear across multiple document generation endpoints. These are documented in detail on each endpoint page, but here is a quick reference:
### Async & Storage Parameters (v2 only)
| Parameter | Type | Default | Description |
| --- | --- | --- | --- |
| `async` | boolean | `true` | Process the request asynchronously. When `true`, the API returns immediately with a job ID. Set to `false` to wait for processing to complete before the API responds (response is still JSON). |
| `storage` | boolean | `true` | Store the generated file in cloudlayer.io storage. When `true`, the file is accessible via the [Assets](/docs/assets/) endpoint. Requires a plan that supports storage. |
### Base Parameters (all generation endpoints)
| Parameter | Type | Description |
| --- | --- | --- |
| `autoScroll` | boolean | Scroll the page to trigger lazy-loaded content before capture. |
| `delay` | number | Wait time in milliseconds after the page loads before capturing. |
| `filename` | string | Set the `Content-Disposition` filename for the response. |
| `timeout` | number | Maximum time in milliseconds to wait for the page to load. |
| `viewPort` | object | Configure the browser viewport dimensions and device emulation. |
| `waitUntil` | string | When to consider navigation complete (`load`, `domcontentloaded`, `networkidle0`, `networkidle2`). |
### PDF-Specific Parameters
| Parameter | Type | Description |
| --- | --- | --- |
| `format` | string | Page size (`letter`, `legal`, `tabloid`, `a0`-`a6`, etc.). |
| `margin` | object | Page margins with unit support (`px`, `in`, `cm`, `mm`). |
| `landscape` | boolean | Use landscape orientation. |
| `printBackground` | boolean | Include background colors and images. |
| `headerTemplate` | object | Custom header for each page. |
| `footerTemplate` | object | Custom footer for each page. |
### Image-Specific Parameters
| Parameter | Type | Description |
| --- | --- | --- |
| `imageType` | string | Output format: `png`, `jpg`, `jpeg`, `webp`, or `svg`. |
| `transparent` | boolean | Render with a transparent background (PNG and WebP only). |
| `trim` | boolean | Trim whitespace from the edges of the image. |
---
## List Results
List endpoints (`GET /jobs`, `GET /assets`) return the 10 most recent items, ordered by creation date (newest first). There are no pagination query parameters.
---
## Next Steps
- [HTML to PDF](/docs/html-to-pdf/) — Generate PDFs from raw HTML
- [URL to PDF](/docs/url-to-pdf/) — Capture any web page as a PDF
- [Template to PDF](/docs/template-to-pdf/) — Generate PDFs from reusable templates
- [HTML to Image](/docs/html-to-image/) — Generate images from raw HTML
- [URL to Image](/docs/url-to-image/) — Capture any web page as an image
- [Template to Image](/docs/template-to-image/) — Generate images from reusable templates
### HTML to PDF
Source: https://cloudlayer.io/docs/html-to-pdf/
# HTML to PDF
Generate a PDF document from raw HTML content. The HTML is sent as a base64-encoded string in the request body.
## Endpoint
```
POST /v1/html/pdf
```
All requests are processed synchronously. The response body is the raw PDF file.
```
POST /v2/html/pdf
```
Requests default to **asynchronous** processing (`async: true`, `storage: true`). Add `"async": false` to receive the raw PDF directly. See [Sync vs. Async](/docs/api-overview/#synchronous-vs-asynchronous-requests) for details.
---
## Quick Start
Encode your HTML as base64 and send it in the `html` field:
**cURL**
```bash
# Base64 encode your HTML
HTML_BASE64=$(echo '
Hello World
Generated by cloudlayer.io
' | base64)
curl -X POST "https://api.cloudlayer.io/v1/html/pdf" \
-H "X-API-Key: your-api-key-here" \
-H "Content-Type: application/json" \
-d "{\"html\": \"$HTML_BASE64\"}" \
--output result.pdf
```
**JavaScript (fetch)**
```javascript
const html = `
Hello World
Generated by cloudlayer.io
`;
const response = await fetch("https://api.cloudlayer.io/v1/html/pdf", {
method: "POST",
headers: {
"X-API-Key": "your-api-key-here",
"Content-Type": "application/json",
},
body: JSON.stringify({
html: btoa(html),
}),
});
const pdf = await response.arrayBuffer();
// Save to file, send to client, etc.
```
**Python (requests)**
```python
import base64
import requests
html = """
Hello World
Generated by cloudlayer.io
"""
response = requests.post(
"https://api.cloudlayer.io/v1/html/pdf",
headers={
"X-API-Key": "your-api-key-here",
"Content-Type": "application/json",
},
json={
"html": base64.b64encode(html.encode()).decode(),
},
)
with open("result.pdf", "wb") as f:
f.write(response.content)
```
**cURL**
```bash
# Base64 encode your HTML
HTML_BASE64=$(echo '
Hello World
Generated by cloudlayer.io
' | base64)
curl -X POST "https://api.cloudlayer.io/v2/html/pdf" \
-H "X-API-Key: your-api-key-here" \
-H "Content-Type: application/json" \
-d "{\"html\": \"$HTML_BASE64\"}"
```
Response:
```json
{
"id": "abc123",
"status": "pending"
}
```
**JavaScript (fetch)**
```javascript
const html = `
Hello World
Generated by cloudlayer.io
`;
const response = await fetch("https://api.cloudlayer.io/v2/html/pdf", {
method: "POST",
headers: {
"X-API-Key": "your-api-key-here",
"Content-Type": "application/json",
},
body: JSON.stringify({
html: btoa(html),
}),
});
const { id, status } = await response.json();
// Poll job status or use webhooks to know when the PDF is ready
```
**Python (requests)**
```python
import base64
import requests
html = """
Hello World
Generated by cloudlayer.io
"""
response = requests.post(
"https://api.cloudlayer.io/v2/html/pdf",
headers={
"X-API-Key": "your-api-key-here",
"Content-Type": "application/json",
},
json={
"html": base64.b64encode(html.encode()).decode(),
},
)
job = response.json()
# Poll job status or use webhooks to know when the PDF is ready
```
> **Tip:** v2 always returns JSON. Use the job `id` to poll the [Jobs](/docs/jobs/) endpoint or configure [Webhooks](/docs/webhooks/) for completion notifications. The generated file is accessible via the [Assets](/docs/assets/) endpoint. Add `"async": false` to wait for processing to complete — the response is still JSON but includes the completed job details.
---
## Parameters
### Required
| Parameter | Type | Description |
| --- | --- | --- |
| `html` | string | **Required.** Base64-encoded HTML content. The HTML can include inline CSS, `
| Item | Qty | Price | Total |
| Widget A | 10 | $25.00 | $250.00 |
| Widget B | 5 | $40.00 | $200.00 |
| Service Fee | 1 | $75.00 | $75.00 |
Total: $525.00