REST API
The Laravel package is the recommended way to use BladePDF, but the underlying HTTP API is a single multipart endpoint you can call from any language. This page documents that raw contract.
Skip this page and use the BladePDF facade — it builds these requests, uploads assets, and handles responses for you.
Endpoint
1POST https://api.bladepdf.com/render
The request body is multipart/form-data. By default, a successful response streams the generated PDF back as application/pdf. Send Prefer: respond-async to receive an acceptance response instead.
Authentication
Send your API key as a bearer token. Requests without a valid key are rejected with 401.
1Authorization: Bearer blpdf_xxxxxxxxxxxxxxxxxxxxxxxx
Form fields
All fields are optional except source. JSON fields are sent as a string value; HTML, context, and assets are sent as file parts.
| Field | Kind | Description |
|---|---|---|
source | JSON | Render source. {"type":"html"} or {"type":"template","templateId":"…"}. |
html | File | The document HTML. Required when source.type is html. |
header_html | File | Repeating page header HTML (HTML renders only). |
footer_html | File | Repeating page footer HTML (HTML renders only). |
context | File | JSON context for the template. Required when source.type is template. |
asset:///<name> | File | An uploaded asset, referenced from your HTML/CSS as asset:///<name>. Repeat for each asset. |
pdf_options | JSON | PDF options such as format, margins, orientation, scale, page ranges. See Options. |
wait_until | Text | Wait condition: load, domcontentloaded, networkidle0, networkidle2, or function. |
wait_function | Text | A JavaScript expression to wait for before capturing (paid plans). |
emulate_media | Text | Media type to emulate: screen or print. |
metadata | JSON | Your own key/value metadata, echoed back on webhooks and render history. |
store_pdf | Text | Set to persist the output as a stored PDF. Required with Prefer: respond-async. |
webhook | JSON | Per-request callback for an async render: {"url":"…","secret":"…","events":["pdf.rendered"]}. See Webhooks. |
Example: render raw HTML
1curl https://api.bladepdf.com/render \
2 -H "Authorization: Bearer $BLADEPDF_API_KEY" \
3 -F 'source={"type":"html"};type=application/json' \
4 -F 'html=@invoice.html;type=text/html' \
5 -F 'pdf_options={"format":"A4","printBackground":true};type=application/json' \
6 -o invoice.pdf
Example: render a cloud template
1curl https://api.bladepdf.com/render \
2 -H "Authorization: Bearer $BLADEPDF_API_KEY" \
3 -F 'source={"type":"template","templateId":"invoice.standard"};type=application/json' \
4 -F 'context=@context.json;type=application/json' \
5 -F 'store_pdf=1' \
6 -o invoice.pdf
Response
Synchronously generated PDF
A successful render returns 200 OK and streams the PDF as the response body with Content-Type: application/pdf. Every response includes an x-request-id header — log it so you can correlate a request with its entry in render history and any webhook you receive.
When store_pdf=1 succeeds on a synchronous request, the response also includes a Link header with rel="stored-pdf". Laravel clients expose that value as $result->storedPdfUrl().
1Link: <https://app.bladepdf.com/pdf/{workspace_id}/{request_id}.pdf?expires=...&signature=...>; rel="stored-pdf"; type="application/pdf"
Asynchronous acceptance
Add Prefer: respond-async, Accept: application/json, and store_pdf=1. After the request body has been parsed, validated, checked for storage, and accepted within your workspace capacity, the API returns 202 Accepted. If all concurrency slots are busy, the request may wait before this response. Rendering continues in the background after the HTTP response.
1curl https://api.bladepdf.com/render \
2 -H "Authorization: Bearer $BLADEPDF_API_KEY" \
3 -H 'Prefer: respond-async' \
4 -H 'Accept: application/json' \
5 -F 'source={"type":"template","templateId":"invoice.standard"};type=application/json' \
6 -F 'context=@context.json;type=application/json' \
7 -F 'metadata={"reference":"INV-2026-0042"};type=application/json' \
8 -F 'store_pdf=1' \
9 -F 'webhook={"url":"https://example.com/bladepdf/webhook","secret":"whsec_request_secret","events":["pdf.rendered","pdf.failed"]};type=application/json'
1{
2 "request_id": "req_abc123",
3 "reference": "INV-2026-0042"
4}
Omitting store_pdf=1 returns 400. If the workspace cannot store another PDF because its storage quota is full, the async request returns 403 before it is accepted.
Status codes
| Status | Meaning |
|---|---|
200 | PDF generated and returned in the body. |
202 | Async render accepted for background processing. |
400 | Invalid request — malformed fields, bad source, or invalid options. |
401 | Missing or invalid API key. |
403 | Plan limit reached — monthly generations, bandwidth, or storage. |
413 | Request payload exceeds your plan's maximum. |
429 | No render capacity — the queue is full. Retry with backoff. |
5xx | Render failure or an unexpected server error. |
See Limits & Concurrency for what drives these responses and Errors for handling them.