How requests work
Every route takes a multipart/form-data POST: files, form fields and headers. It answers with a file, a ZIP of several files, or JSON.
Send files
Upload each file under files, once per file:
curl \
--request POST http://localhost:3000/forms/chromium/convert/html \
--form files=@index.html \
--form files=@style.css \
-o invoice.pdf
File names matter. The HTML route looks for index.html, and the PDFs a route produces are named after the files you sent.
Gotenberg takes the files in the alphanumeric order of their names, not in the order you upload them: 2.pdf comes before 10.pdf. To merge in a given order, name the files after it.
Send a ZIP
Upload a ZIP under archives. Gotenberg unpacks it, and each entry counts as a file uploaded under files:
curl \
--request POST http://localhost:3000/forms/chromium/convert/html \
--form archives=@site.zip \
-o invoice.pdf
You can mix archives and files in the same request. A ZIP uploaded under files stays a ZIP.
Download files
List URLs in downloadFrom and Gotenberg downloads them before it starts, as if you had uploaded them. Each entry takes a url and, optionally, extraHttpHeaders to send along:
curl \
--request POST http://localhost:3000/forms/libreoffice/convert \
--form 'downloadFrom=[
{ "url": "https://files.example.com/report.docx", "extraHttpHeaders": { "Authorization": "Bearer …" } }
]' \
-o report.pdf
The server must answer with a Content-Disposition header that names the file. A url that isn't an absolute http or https one answers 400, naming downloadFrom and the entry. Operators can turn the feature off with --api-disable-download-from.
Add stages
A stage is one operation on a PDF: merge, stamp, sign, make PDF/A, and so on. List them in the stages field, as a JSON array. Each item names its operation in op, with its options beside it:
curl \
--request POST http://localhost:3000/forms/chromium/convert/html \
--form files=@index.html \
--form files=@style.css \
--form 'stages=[
{ "op": "stamp-text", "text": "DRAFT", "x": 72, "y": 72 },
{ "op": "optimize" }
]' \
-o invoice.pdf
- Gotenberg runs the stages in order, on the PDFs the request makes.
- A stage that needs a file, such as an image to stamp, names it: upload the file with the others.
stagesworks on the Chromium conversion routes, the LibreOffice route and/forms/pdf/pipe. The screenshot routes, the single-stage routes such as/forms/pdf/merge, and the read routes answer 400 to it.
Run stages lists them all, and each has its own page.
Name the result
Set the Gotenberg-Output-Filename header, without extension. Gotenberg adds the right one:
curl \
--request POST http://localhost:3000/forms/chromium/convert/html \
--form files=@index.html \
--form files=@style.css \
--header 'Gotenberg-Output-Filename: invoice' \
-o invoice.pdf
HTTP/1.1 200 OK
Content-Disposition: attachment; filename="invoice.pdf"
Content-Type: application/pdf
Gotenberg adds the extension even to a name that has one: invoice.pdf gives invoice.pdf.pdf. A name with characters outside ASCII, such as facture-été, goes out as filename*=UTF-8''facture-%C3%A9t%C3%A9.pdf, next to an ASCII filename fallback.
Without the header, Gotenberg picks a name: report.docx.pdf for an uploaded report.docx, a random one for a web page.
Read the answer
One result comes back as is: Content-Type: application/pdf, for example. Several results come back in a ZIP, each named after its source. The ZIP itself takes a random UUID as its name, unless Gotenberg-Output-Filename sets it. Splitting a three-page report in two gives:
curl \
--request POST http://localhost:3000/forms/pdf/pipe \
--form files=@report.pdf \
--form 'stages=[
{ "op": "split", "ranges": [ "1", "2-3" ] }
]' \
-o report.zip
HTTP/1.1 200 OK
Content-Type: application/zip
report_0.pdf
report_1.pdf
The routes that read a PDF answer JSON, one entry per file:
curl \
--request POST http://localhost:3000/forms/pdf/info \
--form files=@report.pdf
{
"report.pdf": {
"pages": 3,
"version": "1.7",
"encrypted": false,
"tagged": false,
"linearized": false,
"formFields": false
}
}
The info route explains each field.
Follow a request
Every answer carries two headers:
Gotenberg-Traceidentifies the request in Gotenberg's logs. Send your own value to correlate it with yours; otherwise Gotenberg makes one up.Gotenberg-Versionnames the Gotenberg version that answered.
The 404 and 405 answers carry both too. With authentication on, the 401, 404 and 405 answers carry Gotenberg-Trace only: a caller without credentials learns no version.
Headers lists every header a request and an answer may carry.
Errors
An error answers with a status and a plain-text message that says what failed and how to fix it, such as Invalid form data: form field 'url' is required. Errors lists the statuses and the messages.