Gotenberg A Docker-powered stateless API for converting HTML, Markdown and Office documents to PDF.

#
Introduction

Gotenberg is a Docker-powered stateless API for converting HTML, Markdown and Office documents to PDF.

- HTML and Markdown conversions using Google Chrome headless
- Office conversions (.txt, .rtf, .docx, .doc, .odt, .pptx, .ppt, .odp and so on) using unoconv
- Assets: send your header, footer, images, fonts, stylesheets and so on for converting your HTML and Markdown to beaufitul PDFs!
- Easily interact with the API using our Go and PHP libraries

#
Install

Gotenberg is shipped within a Docker image.

You may start it with:

    $ docker run --rm -p 3000:3000 thecodingmachine/gotenberg:6

> The API will be available at http://localhost:3000.

The image uses a dedicated non-root user called `gotenberg` with uid and gid `1001`.

If you wish to change those uid and gid, you will have to:

- clone the project
- re-build the image
- publish the image in your own Docker registry

For instance:

    $ git clone https://github.com/thecodingmachine/gotenberg.git
    $ make publish GOTENBERG_USER_GID=your_custom_gid GOTENBERG_USER_UID=your_custom_uid DOCKER_REGISTRY=your_registry DOCKER_USER=registry_user DOCKER_PASSWORD=registry_password VERSION=version

> `master` branch is always up-to-date with the latest version of the API.

##
Docker Compose

You may also add it in your Docker Compose stack:

    version: '3'

    services:

      # your other services

      gotenberg:
        image: thecodingmachine/gotenberg:6

> The API will be available under `gotenberg:3000` in your Docker Compose network.

##
Kubernetes

It may also be deployed with Kubernetes.

Make sure to provide enough memory and CPU requests (for instance `512Mi` and `0.2` CPU).

> The more resources are granted, the quicker will be the conversions.

In the deployment specification of the pod, also specify the uid of the user `gotenberg`:

    securityContext:
      privileged: false
      runAsUser: 1001

##
Cloud Run (Google Cloud)

If you’re looking for cost savings, you might be interested by Cloud Run. However, according to some users, doing asynchronous conversion (with a webhook) might not working.

In the following examples, we will assume your Gotenberg API is available at http://localhost:3000.

#
Clients

We provide clients in various languages for easing the interactions with the API.

##
Go client

    $ go get -u github.com/thecodingmachine/gotenberg-go-client/v7

See also the example from the README.

##
PHP client

Unless your project already has a PSR7 `HttpClient`, install `php-http/guzzle6-adapter`:

    $ composer require php-http/guzzle6-adapter

Then the PHP client:

    $ composer require thecodingmachine/gotenberg-php-client

See also the example from the README.

##
Community clients

- JavaScript/TypeScript client by yumauri
- C# client by ChangemakerStudios

#
Environment variables

You may customize the API behaviour thanks to environment variables.

##
Log level

The API provides structured logging allowing you to have relevant information about what’s going on.

> If a TTY is attached, the log entries are displayed in text format with colors, otherwise in JSON format.

You may customize the severity of the log entries thanks to the environment variable `LOG_LEVEL`.

It accepts one of the following severities: `"DEBUG"`, `"INFO"` (default) and `"ERROR"`.

##
Default listen port

By default, the API will listen on port `3000`.

You may customize this value with the environment variable `DEFAULT_LISTEN_PORT`.

This environment variable accepts any string that can be turned into a port number.

##
Root path

By default, the API root path is `/`.

You may customize this value with the environment variable `ROOT_PATH`.

This environment variable accepts a string starting and ending with `/`.

For instance, `/gotenberg/` is a valid value while `gotenberg` is not.

> This is useful if you wish to do service discovery via URL paths.

##
Disable Google Chrome

In order to save some resources, the Gotenberg image accepts the environment variable `DISABLE_GOOGLE_CHROME` for disabling Google Chrome.

It takes the strings `"0"` or `"1"` as value where `1` means `true`

> If Google Chrome is disabled, the following conversions will not be available anymore: HTML, URL and Markdown

##
Default Google Chrome rpcc buffer size

When performing a HTML, URL or Markdown conversion, the API might return a `400` HTTP code with the message `increase the Google Chrome rpcc buffer size`.

If so, you may increase this buffer size with the environment variable `DEFAULT_GOOGLE_CHROME_RPCC_BUFFER_SIZE`.

It takes a string representation of an int as value (e.g. `"1048576"` for 1 MB). The hard limit is 100 MB and is defined by Google Chrome itself.

> The default Google Chrome rpcc buffer size may also be overridden per request thanks to the form field `googleChromeRpccBufferSize`. See the rpcc buffer size section.

##
Google Chrome ignore certificate errors

When performing a URL conversion, Google Chrome will not accept certificate errors.

You may allow insecure connections by setting the `GOOGLE_CHROME_IGNORE_CERTIFICATE_ERRORS` environment variable to `"1"`.

You should be careful with this feature and only enable it in your development environment.

##
Disable LibreOffice (unoconv)

You may also disable LibreOffice (unoconv) with `DISABLE_UNOCONV`.

> If LibreOffice (unoconv) is disabled, the following conversion will not be available anymore: Office

##
Default wait timeout

By default, the API will wait 10 seconds before it considers the conversion to be unsuccessful. If unsucessful, it returns a `504` HTTP code.

You may customize this timeout thanks to the environment variable `DEFAULT_WAIT_TIMEOUT`.

It takes a string representation of a float as value (e.g `"2.5"` for 2.5 seconds).

> The default timeout may also be overridden per request thanks to the form field `waitTimeout`. See the timeout section.

##
Maximum wait timeout

By default, the value of the form field `waitTimeout` cannot be more than 30 seconds.

You may increase or decrease this limit thanks to the environment variable `MAXIMUM_WAIT_TIMEOUT`.

It takes a string representation of a float as value (e.g `"2.5"` for 2.5 seconds).

##
Default webhook URL timeout

By default, the API will wait 10 seconds before it considers the sending of the resulting PDF to be unsuccessful.

> See the webhook section.

You may customize this timeout thanks to the environment variable `DEFAULT_WEBHOOK_URL_TIMEOUT`.

It takes a string representation of a float as value (e.g `"2.5"` for 2.5 seconds).

> The default timeout may also be overridden per request thanks to the form field `webhookURLTimeout`. See the webhook timeout section.

##
Maximum webhook URL timeout

By default, the value of the form field `webhookURLTimeout` cannot be more than 30 seconds.

You may increase or decrease this limit thanks to the environment variable `MAXIMUM_WEBHOOK_URL_TIMEOUT`.

It takes a string representation of a float as value (e.g `"2.5"` for 2.5 seconds).

##
Maximum wait delay

By default, the value of the form field `waitDelay` cannot be more than 10 seconds.

> See the wait delay section.

You may increase or decrease this limit thanks to the environment variable `MAXIMUM_WAIT_DELAY`.

It takes a string representation of a float as value (e.g `"2.5"` for 2.5 seconds).

#
HTML

Gotenberg provides the endpoint `/convert/html` for HTML conversions.

It accepts `POST` requests with a `multipart/form-data` Content-Type.

##
Basic

The only requirement is to send a file named `index.html`: it is the file which will be converted to PDF.

For instance:

    <!doctype html>
    <html lang="en">
      <head>
        <meta charset="utf-8">
        <title>My PDF</title>
      </head>
      <body>
        <h1>Hello world!</h1>
      </body>
    </html>

###
cURL

    $ curl --request POST \
        --url http://localhost:3000/convert/html \
        --header 'Content-Type: multipart/form-data' \
        --form files=@index.html \
        -o result.pdf

###
Go

    import "github.com/thecodingmachine/gotenberg-go-client/v7"

    c := &gotenberg.Client{Hostname: "http://localhost:3000"}
    index, _ := gotenberg.NewDocumentFromPath("index.html", "/path/to/file")
    req := gotenberg.NewHTMLRequest(index)
    dest := "result.pdf"
    c.Store(req, dest)

###
PHP

    use TheCodingMachine\Gotenberg\Client;
    use TheCodingMachine\Gotenberg\DocumentFactory;
    use TheCodingMachine\Gotenberg\HTMLRequest;

    $client = new Client('http://localhost:3000', new \Http\Adapter\Guzzle6\Client());
    $index = DocumentFactory::makeFromPath('index.html', '/path/to/file');
    $request = new HTMLRequest($index);
    $dest = 'result.pdf';
    $client->store($request, $dest);

##
Header and footer

You may also add a header and/or a footer in the resulting PDF. Respectively, a file named `header.html` and `footer.html`.

Each of them has to be a complete HTML document:

    <html>
        <head>
            <style>
                body {
                    font-size: 8rem;
                    margin: 4rem auto;
                }
            </style>
        </head>
        <body>
            <p>
                <span class="pageNumber"></span> of <span class="totalPages"></span>
            </p>
        </body>
    </html>

The following classes allow you to inject printing values:

- `date`: formatted print date
- `title`: document title
- `pageNumber`: current page number
- `totalPage`: total pages in the document

There are some limitations:

- JavaScript is not executed
- external resources are not loaded
- the CSS properties are independant of the ones used in the `index.html` file
- `footer.html` CSS properties override the ones from `header.html`
- only fonts installed in the Docker image are loaded (see the fonts section)
- images only work using a `base64` encoded source (`<img src="data:image/png;base64, iVBORw0K... />`)
- `background-color` and `color` CSS properties require an additional `-webkit-print-color-adjust: exact` CSS property in order to work

###
cURL

    $ curl --request POST \
        --url http://localhost:3000/convert/html \
        --header 'Content-Type: multipart/form-data' \
        --form files=@index.html \
        --form files=@header.html \
        --form files=@footer.html \
        -o result.pdf

###
Go

    import "github.com/thecodingmachine/gotenberg-go-client/v7"

    c := &gotenberg.Client{Hostname: "http://localhost:3000"}
    index, _ := gotenberg.NewDocumentFromPath("index.html", "/path/to/file")
    header, _ := gotenberg.NewDocumentFromPath("header.html", "/path/to/file")
    footer, _ := gotenberg.NewDocumentFromPath("footer.html", "/path/to/file")
    req := gotenberg.NewHTMLRequest(index)
    req.Header(header)
    req.Footer(footer)
    dest := "result.pdf"
    c.Store(req, dest)

###
PHP

    use TheCodingMachine\Gotenberg\Client;
    use TheCodingMachine\Gotenberg\DocumentFactory;
    use TheCodingMachine\Gotenberg\HTMLRequest;

    $client = new Client('http://localhost:3000', new \Http\Adapter\Guzzle6\Client());
    $index = DocumentFactory::makeFromPath('index.html', '/path/to/file');
    $header = DocumentFactory::makeFromPath('header.html', '/path/to/file');
    $footer = DocumentFactory::makeFromPath('footer.html', '/path/to/file');
    $request = new HTMLRequest($index);
    $request->setHeader($header);
    $request->setFooter($footer);
    $dest = 'result.pdf';
    $client->store($request, $dest);

##
Assets

You may also send additional files. For instance: images, fonts, stylesheets and so on.

The only requirement is to make sure that their paths are on the same level as the `index.html` file.

In other words, this will work:

    <!doctype html>
    <html lang="en">
      <head>
        <meta charset="utf-8">
        <title>My PDF</title>
      </head>
      <body>
        <h1>Hello world!</h1>
        <img src="img.png">
      </body>
    </html>

But this won’t:

    <!doctype html>
    <html lang="en">
      <head>
        <meta charset="utf-8">
        <title>My PDF</title>
      </head>
      <body>
        <h1>Hello world!</h1>
        <img src="/foo/img.png">
      </body>
    </html>

You may also use remote paths for Google fonts, images and so on.

> If you want to install fonts directly in the Gotenberg Docker image, see to the fonts section.

###
cURL

    $ curl --request POST \
        --url http://localhost:3000/convert/html \
        --header 'Content-Type: multipart/form-data' \
        --form files=@index.html \
        --form files=@style.css \
        --form files=@img.png \
        --form files=@font.woff \
        -o result.pdf

###
Go

    import "github.com/thecodingmachine/gotenberg-go-client/v7"

    c := &gotenberg.Client{Hostname: "http://localhost:3000"}
    index, _ := gotenberg.NewDocumentFromPath("index.html", "/path/to/file")
    style, _ := gotenberg.NewDocumentFromPath("style.css", "/path/to/file")
    img, _ := gotenberg.NewDocumentFromPath("img.png", "/path/to/file")
    font, _ := gotenberg.NewDocumentFromPath("font.woff", "/path/to/file")
    req := gotenberg.NewHTMLRequest(index)
    req.Assets(style, img, font)
    dest := "result.pdf"
    c.Store(req, dest)

###
PHP

    use TheCodingMachine\Gotenberg\Client;
    use TheCodingMachine\Gotenberg\DocumentFactory;
    use TheCodingMachine\Gotenberg\HTMLRequest;

    $client = new Client('http://localhost:3000', new \Http\Adapter\Guzzle6\Client());
    $index = DocumentFactory::makeFromPath('index.html', '/path/to/file');
    $assets = [
        DocumentFactory::makeFromPath('style.css', '/path/to/file'),
        DocumentFactory::makeFromPath('img.png', '/path/to/file'),
        DocumentFactory::makeFromPath('font.woff', '/path/to/file'),
    ];
    $request = new HTMLRequest($index);
    $request->setAssets($assets);
    $dest = 'result.pdf';
    $client->store($request, $dest);

##
Paper size, margins, orientation, scaling

You may also customize the resulting PDF format.

By default, it will be rendered with `A4` size, `1 inch` margins and `portrait` orientation and 100% (`1.0`) page scale.

> Paper size and margins have to be provided in `inches`. Same for margins.

###
cURL

    $ curl --request POST \
        --url http://localhost:3000/convert/html \
        --header 'Content-Type: multipart/form-data' \
        --form files=@index.html \
        --form paperWidth=8.27 \
        --form paperHeight=11.69 \
        --form marginTop=0 \
        --form marginBottom=0 \
        --form marginLeft=0 \
        --form marginRight=0 \
        --form landscape=true \
        --form scale=0.75 \
        -o result.pdf

###
Go

    import "github.com/thecodingmachine/gotenberg-go-client/v7"

    c := &gotenberg.Client{Hostname: "http://localhost:3000"}
    index, _ := gotenberg.NewDocumentFromPath("index.html", "/path/to/file")
    req := gotenberg.NewHTMLRequest(index)
    req.PaperSize(gotenberg.A4)
    req.Margins(gotenberg.NoMargins)
    req.Landscape(true)
    req.Scale(0.75)
    dest := "result.pdf"
    c.Store(req, dest)

###
PHP

    use TheCodingMachine\Gotenberg\Client;
    use TheCodingMachine\Gotenberg\DocumentFactory;
    use TheCodingMachine\Gotenberg\HTMLRequest;
    use TheCodingMachine\Gotenberg\Request;

    $client = new Client('http://localhost:3000', new \Http\Adapter\Guzzle6\Client());
    $index = DocumentFactory::makeFromPath('index.html', '/path/to/file');
    $request = new HTMLRequest($index);
    $request->setPaperSize(Request::A4);
    $request->setMargins(Request::NO_MARGINS);
    $request->setLandscape(true);
    $request->setScale(0.75);
    $dest = 'result.pdf';
    $client->store($request, $dest);

##
Page ranges

You may specify the page ranges to convert.

The format is the same as the one from the print options of Google Chrome, e.g. `1-5,8,11-13`.

###
cURL

    $ curl --request POST \
        --url http://localhost:3000/convert/html \
        --header 'Content-Type: multipart/form-data' \
        --form files=@index.html \
        --form pageRanges='1-3,5' \
        -o result.pdf

###
Go

    import "github.com/thecodingmachine/gotenberg-go-client/v7"

    c := &gotenberg.Client{Hostname: "http://localhost:3000"}
    index, _ := gotenberg.NewDocumentFromPath("index.html", "/path/to/file")
    req := gotenberg.NewHTMLRequest(index)
    req.PageRanges("1-3,5")
    dest := "result.pdf"
    c.Store(req, dest)

###
PHP

    use TheCodingMachine\Gotenberg\Client;
    use TheCodingMachine\Gotenberg\DocumentFactory;
    use TheCodingMachine\Gotenberg\HTMLRequest;
    use TheCodingMachine\Gotenberg\Request;

    $client = new Client('http://localhost:3000', new \Http\Adapter\Guzzle6\Client());
    $index = DocumentFactory::makeFromPath('index.html', '/path/to/file');
    $request = new HTMLRequest($index);
    $request->setPageRanges('1-3,5');
    $dest = 'result.pdf';
    $client->store($request, $dest);

##
Wait delay

In some cases, you may want to wait a certain amount of time to make sure the page you’re trying to generate is fully rendered. For instance, if your page relies a lot on JavaScript for rendering.

> The wait delay is a duration in seconds (e.g `2.5` for 2.5 seconds).

###
cURL

    $ curl --request POST \
        --url http://localhost:3000/convert/html \
        --header 'Content-Type: multipart/form-data' \
        --form files=@index.html \
        --form waitDelay=5.5 \
        -o result.pdf

###
Go

    import "github.com/thecodingmachine/gotenberg-go-client/v7"

    c := &gotenberg.Client{Hostname: "http://localhost:3000"}
    index, _ := gotenberg.NewDocumentFromPath("index.html", "/path/to/file")
    req := gotenberg.NewHTMLRequest(index)
    req.WaitDelay(5.5)
    dest := "result.pdf"
    c.Store(req, dest)

###
PHP

    use TheCodingMachine\Gotenberg\Client;
    use TheCodingMachine\Gotenberg\DocumentFactory;
    use TheCodingMachine\Gotenberg\HTMLRequest;
    use TheCodingMachine\Gotenberg\Request;

    $client = new Client('http://localhost:3000', new \Http\Adapter\Guzzle6\Client());
    $index = DocumentFactory::makeFromPath('index.html', '/path/to/file');
    $request = new HTMLRequest($index);
    $request->setWaitDelay(5.5);
    $dest = 'result.pdf';
    $client->store($request, $dest);

##
Rpcc buffer size

The API might return a `400` HTTP code with the message `increase the Google Chrome rpcc buffer size`.

If so, you may increase this buffer size with a form field named `googleChromeRpccBufferSize`.

It takes an int as value (e.g. `1048576` for 1 MB). The hard limit is 100 MB and is defined by Google Chrome itself.

> You may also define this value globally: see the environment variables section.

###
cURL

    $ curl --request POST \
        --url http://localhost:3000/convert/html \
        --header 'Content-Type: multipart/form-data' \
        --form files=@index.html \
        --form googleChromeRpccBufferSize=1048576 \
        -o result.pdf

###
Go

    import "github.com/thecodingmachine/gotenberg-go-client/v7"

    c := &gotenberg.Client{Hostname: "http://localhost:3000"}
    index, _ := gotenberg.NewDocumentFromPath("index.html", "/path/to/file")
    req := gotenberg.NewHTMLRequest(index)
    req.GoogleChromeRpccBufferSize(1048576)
    dest := "result.pdf"
    c.Store(req, dest)

###
PHP

    use TheCodingMachine\Gotenberg\Client;
    use TheCodingMachine\Gotenberg\DocumentFactory;
    use TheCodingMachine\Gotenberg\HTMLRequest;
    use TheCodingMachine\Gotenberg\Request;

    $client = new Client('http://localhost:3000', new \Http\Adapter\Guzzle6\Client());
    $index = DocumentFactory::makeFromPath('index.html', '/path/to/file');
    $request = new HTMLRequest($index);
    $request->setGoogleChromeRpccBufferSize(1048576);
    $dest = 'result.pdf';
    $client->store($request, $dest);

#
URL

Gotenberg provides the endpoint `/convert/url` for remote URL conversions.

It accepts `POST` requests with a `multipart/form-data` Content-Type.

##
Basic

This endpoint does not accept an `index.html` file nor assets files but a form field named `remoteURL` instead. Otherwise, URL conversions work the same as HTML conversions.

> Attention: when converting a website to PDF, you should remove all margins. If not, some of the content of the page might be hidden.

> Attention: if you try to convert a URL from a Docker Compose service named `app` (i.e. `removeURL` = `http://app/an/entrypoint`), the resulting PDF will be blank. Make sure to rename your service to avoid this issue.

###
cURL

    $ curl --request POST \
        --url http://localhost:3000/convert/url \
        --header 'Content-Type: multipart/form-data' \
        --form remoteURL=https://google.com \
        --form marginTop=0 \
        --form marginBottom=0 \
        --form marginLeft=0 \
        --form marginRight=0 \
        -o result.pdf

###
Go

    import "github.com/thecodingmachine/gotenberg-go-client/v7"

    c := &gotenberg.Client{Hostname: "http://localhost:3000"}
    req := gotenberg.NewURLRequest("https://google.com")
    req.Margins(gotenberg.NoMargins)
    dest := "result.pdf"
    c.Store(req, dest)

###
PHP

    use TheCodingMachine\Gotenberg\Client;
    use TheCodingMachine\Gotenberg\URLRequest;

    $client = new Client('http://localhost:3000', new \Http\Adapter\Guzzle6\Client());
    $request = new URLRequest('https://google.com');
    $request->setMargins(Request::NO_MARGINS);
    $dest = 'result.pdf';
    $client->store($request, $dest);

##
Custom HTTP headers

You may send your own HTTP headers to the `remoteURL`.

For instance, by adding the HTTP header `Gotenberg-Remoteurl-Your-Header` to your request, the API will send a request to the `remoteURL` with the HTTP header `Your-Header`.

> Attention: the API uses a canonical format for the HTTP headers: it transforms the first letter and any letter following a hyphen to upper case; the rest are converted to lowercase. For example, the canonical key for `accept-encoding` is `Accept-Encoding`.

###
cURL

    $ curl --request POST \
        --url http://localhost:3000/convert/url \
        --header 'Content-Type: multipart/form-data' \
        --header 'Gotenberg-Remoteurl-Your-Header: Foo' \
        --form remoteURL=https://google.com \
        -o result.pdf

###
Go

    import "github.com/thecodingmachine/gotenberg-go-client/v7"

    c := &gotenberg.Client{Hostname: "http://localhost:3000"}
    req := gotenberg.NewURLRequest("https://google.com")
    req.AddRemoteURLHTTPHeader("Your-Header", "Foo")
    dest := "result.pdf"
    c.Store(req, dest)

###
PHP

    use TheCodingMachine\Gotenberg\Client;
    use TheCodingMachine\Gotenberg\URLRequest;

    $client = new Client('http://localhost:3000', new \Http\Adapter\Guzzle6\Client());
    $request = new URLRequest('https://google.com');
    $request->addRemoteURLHTTPHeader('Your-Header', 'Foo')
    $dest = 'result.pdf';
    $client->store($request, $dest);

#
Markdown

Gotenberg provides the endpoint `/convert/markdown` for Markdown conversions.

It accepts `POST` requests with a `multipart/form-data` Content-Type.

##
Basic

Markdown conversions work the same as HTML conversions.

Only difference is that you have access to the Go template function `toHTML` in the file `index.html`. This function will convert a given markdown file to HTML.

For instance:

    <!doctype html>
    <html lang="en">
      <head>
        <meta charset="utf-8">
        <title>My PDF</title>
      </head>
      <body>
        {{ toHTML .DirPath "file.md" }}
      </body>
    </html>

###
cURL

    $ curl --request POST \
        --url http://localhost:3000/convert/markdown \
        --header 'Content-Type: multipart/form-data' \
        --form files=@index.html \
        --form files=@file.md \
        -o result.pdf

###
Go

    import "github.com/thecodingmachine/gotenberg-go-client/v7"

    c := &gotenberg.Client{Hostname: "http://localhost:3000"}
    index, _ := gotenberg.NewDocumentFromPath("index.html", "/path/to/file")
    markdown, _ := gotenberg.NewDocumentFromPath("file.md", "/path/to/file")
    req := gotenberg.NewMarkdownRequest(index, markdown)
    dest := "result.pdf"
    c.Store(req, dest)

###
PHP

    use TheCodingMachine\Gotenberg\Client;
    use TheCodingMachine\Gotenberg\DocumentFactory;
    use TheCodingMachine\Gotenberg\MarkdownRequest;

    $client = new Client('http://localhost:3000', new \Http\Adapter\Guzzle6\Client());
    $index = DocumentFactory::makeFromPath('index.html', '/path/to/file');
    $markdowns = [
        DocumentFactory::makeFromPath('file.md', '/path/to/file'),
    ];
    $request = new MarkdownRequest($index, $markdowns);
    $dest = 'result.pdf';
    $client->store($request, $dest);

#
Office

Gotenberg provides the endpoint `/convert/office` for Office document conversions.

It accepts `POST` requests with a `multipart/form-data` Content-Type.

##
Basic

You may send one or more Office documents. Following file extensions are accepted:

- `.txt`
- `.rtf`
- `.fodt`
- `.doc`
- `.docx`
- `.odt`
- `.xls`
- `.xlsx`
- `.ods`
- `.ppt`
- `.pptx`
- `.odp`

All files will be merged into a single resulting PDF.

> Attention: Gotenberg merges the PDF files alphabetically.

###
cURL

    $ curl --request POST \
        --url http://localhost:3000/convert/office \
        --header 'Content-Type: multipart/form-data' \
        --form files=@document.docx \
        --form files=@document2.docx \
        -o result.pdf

###
Go

    import "github.com/thecodingmachine/gotenberg-go-client/v7"

    c := &gotenberg.Client{Hostname: "http://localhost:3000"}
    doc, _ := gotenberg.NewDocumentFromPath("document.docx", "/path/to/file")
    doc2, _ := gotenberg.NewDocumentFromPath("document2.docx", "/path/to/file")
    req := gotenberg.NewOfficeRequest(doc, doc2)
    dest := "result.pdf"
    c.Store(req, dest)

###
PHP

    use TheCodingMachine\Gotenberg\Client;
    use TheCodingMachine\Gotenberg\DocumentFactory;
    use TheCodingMachine\Gotenberg\OfficeRequest;

    $client = new Client('http://localhost:3000', new \Http\Adapter\Guzzle6\Client());
    $files = [
        DocumentFactory::makeFromPath('document.docx', '/path/to/file'),
        DocumentFactory::makeFromPath('document2.docx', '/path/to/file'),
    ];
    $request = new OfficeRequest($files);
    $dest = 'result.pdf';
    $client->store($request, $dest);

##
Orientation

You may also customize the resulting PDF format.

By default, it will be rendered with `portrait` orientation.

###
cURL

    $ curl --request POST \
        --url http://localhost:3000/convert/office \
        --header 'Content-Type: multipart/form-data' \
        --form files=@document.docx \
        --form landscape=true \
        -o result.pdf

###
Go

    import "github.com/thecodingmachine/gotenberg-go-client/v7"

    c := &gotenberg.Client{Hostname: "http://localhost:3000"}
    doc, _ := gotenberg.NewDocumentFromPath("document.docx", "/path/to/file")
    req := gotenberg.NewOfficeRequest(doc)
    req.Landscape(true)
    dest := "result.pdf"
    c.Store(req, dest)

###
PHP

    use TheCodingMachine\Gotenberg\Client;
    use TheCodingMachine\Gotenberg\DocumentFactory;
    use TheCodingMachine\Gotenberg\OfficeRequest;

    $client = new Client('http://localhost:3000', new \Http\Adapter\Guzzle6\Client());
    $files = [
        DocumentFactory::makeFromPath('document.docx', '/path/to/file'),
    ];
    $request = new OfficeRequest($files);
    $request->setLandscape(true);
    $dest = 'result.pdf';
    $client->store($request, $dest);

##
Page ranges

You may specify the page ranges to convert.

The format is the same as the one from the print options of LibreOffice, e.g. `1-1` or `1-4`.

> Attention: if more than one document, the page ranges will be applied for each document.

###
cURL

    $ curl --request POST \
        --url http://localhost:3000/convert/office \
        --header 'Content-Type: multipart/form-data' \
        --form files=@document.docx \
        --form pageRanges='1-3' \
        -o result.pdf

###
Go

    import "github.com/thecodingmachine/gotenberg-go-client/v7"

    c := &gotenberg.Client{Hostname: "http://localhost:3000"}
    doc, _ := gotenberg.NewDocumentFromPath("document.docx", "/path/to/file")
    req := gotenberg.NewOfficeRequest(doc)
    req.PageRanges("1-3")
    dest := "result.pdf"
    c.Store(req, dest)

###
PHP

    use TheCodingMachine\Gotenberg\Client;
    use TheCodingMachine\Gotenberg\DocumentFactory;
    use TheCodingMachine\Gotenberg\OfficeRequest;

    $client = new Client('http://localhost:3000', new \Http\Adapter\Guzzle6\Client());
    $files = [
        DocumentFactory::makeFromPath('document.docx', '/path/to/file'),
    ];
    $request = new OfficeRequest($files);
    $request->setPageRanges('1-3');
    $dest = 'result.pdf';
    $client->store($request, $dest);

#
Merge

Gotenberg provides the endpoint `/merge` for merging PDFs.

It accepts `POST` requests with a `multipart/form-data` Content-Type.

##
Basic

Nothing fancy here: you may send one or more PDF files and the API will merge them and return the resulting PDF file.

> Attention: Gotenberg merges the PDF files alphabetically.

###
cURL

    $ curl --request POST \
        --url http://localhost:3000/merge \
        --header 'Content-Type: multipart/form-data' \
        --form files=@file.pdf \
        --form files=@file2.pdf \
        -o result.pdf

###
Go

    import "github.com/thecodingmachine/gotenberg-go-client/v7"

    c := &gotenberg.Client{Hostname: "http://localhost:3000"}
    pdf, _ := gotenberg.NewDocumentFromPath("file.pdf", "/path/to/file")
    pdf2, _ := gotenberg.NewDocumentFromPath("file2.pdf", "/path/to/file")
    req := gotenberg.NewMergeRequest(pdf, pdf2)
    dest := "result.pdf"
    c.Store(req, dest)

###
PHP

    use TheCodingMachine\Gotenberg\Client;
    use TheCodingMachine\Gotenberg\DocumentFactory;
    use TheCodingMachine\Gotenberg\MergeRequest;

    $client = new Client('http://localhost:3000', new \Http\Adapter\Guzzle6\Client());
    $files = [
        DocumentFactory::makeFromPath('file.pdf', '/path/to/file'),
        DocumentFactory::makeFromPath('file2.pdf', '/path/to/file'),
    ];
    $request = new MergeRequest($files);
    $dest = 'result.pdf';
    $client->store($request, $dest);

#
Timeout

All endpoints accept a form field named `waitTimeout`.

The API will wait the given seconds before it considers the conversion to be unsucessful. If unsucessful, it returns a `504` HTTP code.

It takes a float as value (e.g `2.5` for 2.5 seconds).

> You may also define this value globally: see the environment variables section.

##
Examples

###
cURL

    $ curl --request POST \
        --url http://localhost:3000/convert/html \
        --header 'Content-Type: multipart/form-data' \
        --form files=@index.html \
        --form waitTimeout=2.5

###
Go

    import "github.com/thecodingmachine/gotenberg-go-client/v7"

    c := &gotenberg.Client{Hostname: "http://localhost:3000"}
    index, _ := gotenberg.NewDocumentFromPath("index.html", "/path/to/file")
    req := gotenberg.NewHTMLRequest(index)
    req.WaitTimeout(2.5)
    resp, _ := c.Post(req)

###
PHP

    use TheCodingMachine\Gotenberg\Client;
    use TheCodingMachine\Gotenberg\DocumentFactory;
    use TheCodingMachine\Gotenberg\HTMLRequest;
    use TheCodingMachine\Gotenberg\Request;

    $client = new Client('http://localhost:3000', new \Http\Adapter\Guzzle6\Client());
    $index = DocumentFactory::makeFromPath('index.html', '/path/to/file');
    $request = new HTMLRequest($index);
    $request->setWaitTimeout(2.5);
    $dest = 'result.pdf';
    $client->store($request, $dest);

#
Webhook

All endpoints accept a form field named `webhookURL`.

If provided, the API will send the resulting PDF file in a `POST` request with the `application/pdf` Content-Type to given URL.

By doing so, your requests to the API will be over before the conversions are actually done!

##
Examples

###
cURL

    $ curl --request POST \
        --url http://localhost:3000/convert/html \
        --header 'Content-Type: multipart/form-data' \
        --form files=@index.html \
        --form webhookURL='http://myapp.com/webhook/'

###
Go

    import "github.com/thecodingmachine/gotenberg-go-client/v7"

    c := &gotenberg.Client{Hostname: "http://localhost:3000"}
    index, _ := gotenberg.NewDocumentFromPath("index.html", "/path/to/file")
    req := gotenberg.NewHTMLRequest(index)
    req.WebhookURL("http://myapp.com/webhook/")
    resp, _ := c.Post(req)

###
PHP

    use TheCodingMachine\Gotenberg\Client;
    use TheCodingMachine\Gotenberg\DocumentFactory;
    use TheCodingMachine\Gotenberg\HTMLRequest;

    $client = new Client('http://localhost:3000', new \Http\Adapter\Guzzle6\Client());
    $index = DocumentFactory::makeFromPath('index.html', '/path/to/file');
    $request = new HTMLRequest($index);
    $request->setWebhookURL('http://myapp.com/webhook/');
    $resp = $client->post($request);

##
Timeout

If a `webhookURL` is provided, you may also send a form field named `webhookURLTimeout`.

The API will wait the given seconds before it considers the sending of the resulting PDF to be unsucessful.

It takes a float as value (e.g `2.5` for 2.5 seconds).

> You may also define this value globally: see the environment variables section.

###
cURL

    $ curl --request POST \
        --url http://localhost:3000/convert/html \
        --header 'Content-Type: multipart/form-data' \
        --form files=@index.html \
        --form webhookURL='http://myapp.com/webhook/' \
        --form webhookURLTimeout=2.5

###
Go

    import "github.com/thecodingmachine/gotenberg-go-client/v7"

    c := &gotenberg.Client{Hostname: "http://localhost:3000"}
    index, _ := gotenberg.NewDocumentFromPath("index.html", "/path/to/file")
    req := gotenberg.NewHTMLRequest(index)
    req.WebhookURL("http://myapp.com/webhook/")
    req.WebhookURLTimeout(2.5)
    resp, _ := c.Post(req)

###
PHP

    use TheCodingMachine\Gotenberg\Client;
    use TheCodingMachine\Gotenberg\DocumentFactory;
    use TheCodingMachine\Gotenberg\HTMLRequest;

    $client = new Client('http://localhost:3000', new \Http\Adapter\Guzzle6\Client());
    $index = DocumentFactory::makeFromPath('index.html', '/path/to/file');
    $request = new HTMLRequest($index);
    $request->setWebhookURL('http://myapp.com/webhook/');
    $request->setWebhookURLTimeout(2.5);
    $resp = $client->post($request);

##
Custom HTTP headers

You may send your own HTTP headers to the `webhookURL`.

For instance, by adding the HTTP header `Gotenberg-Webhookurl-Your-Header` to your request, the API will send a request to the `webhookURL` with the HTTP header `Your-Header`.

> Attention: the API uses a canonical format for the HTTP headers: it transforms the first letter and any letter following a hyphen to upper case; the rest are converted to lowercase. For example, the canonical key for `accept-encoding` is `Accept-Encoding`.

###
cURL

    $ curl --request POST \
        --url http://localhost:3000/convert/html \
        --header 'Content-Type: multipart/form-data' \
        --header 'Gotenberg-Webhookurl-Your-Header: Foo' \
        --form files=@index.html \
        --form webhookURL='http://myapp.com/webhook/'

###
Go

    import "github.com/thecodingmachine/gotenberg-go-client/v7"

    c := &gotenberg.Client{Hostname: "http://localhost:3000"}
    index, _ := gotenberg.NewDocumentFromPath("index.html", "/path/to/file")
    req := gotenberg.NewHTMLRequest(index)
    req.WebhookURL("http://myapp.com/webhook/")
    req.AddWebhookURLHTTPHeader("Your-Header", "Foo")
    resp, _ := c.Post(req)

###
PHP

    use TheCodingMachine\Gotenberg\Client;
    use TheCodingMachine\Gotenberg\DocumentFactory;
    use TheCodingMachine\Gotenberg\HTMLRequest;

    $client = new Client('http://localhost:3000', new \Http\Adapter\Guzzle6\Client());
    $index = DocumentFactory::makeFromPath('index.html', '/path/to/file');
    $request = new HTMLRequest($index);
    $request->setWebhookURL('http://myapp.com/webhook/');
    $request->addWebhookURLHTTPHeader('Your-Header', 'Foo');
    $resp = $client->post($request);

#
Result filename

All endpoints accept a form field named `resultFilename`.

If provided, the API will return the resulting PDF file with the given filename. Otherwise a random filename is used.

> Attention: this feature does not work if the form field `webhookURL` is given.

##
Examples

###
cURL

    $ curl --request POST \
        --url http://localhost:3000/convert/html \
        --header 'Content-Type: multipart/form-data' \
        --form files=@index.html \
        --form resultFilename='foo.pdf'

###
Go

    import "github.com/thecodingmachine/gotenberg-go-client/v7"

    c := &gotenberg.Client{Hostname: "http://localhost:3000"}
    index, _ := gotenberg.NewDocumentFromPath("index.html", "/path/to/file")
    req := gotenberg.NewHTMLRequest(index)
    req.ResultFilename("foo.pdf")
    resp, _ := c.Post(req)

###
PHP

    use TheCodingMachine\Gotenberg\Client;
    use TheCodingMachine\Gotenberg\DocumentFactory;
    use TheCodingMachine\Gotenberg\HTMLRequest;
    use TheCodingMachine\Gotenberg\Request;

    $client = new Client('http://localhost:3000', new \Http\Adapter\Guzzle6\Client());
    $index = DocumentFactory::makeFromPath('index.html', '/path/to/file');
    $request = new HTMLRequest($index);
    $request->setResultFilename('foo.pdf');
    $resp = $client->post($request);

#
Scalability

The API uses under the hood intricate programs.

Gotenberg tries to abstract as much complexity as possible but it can only do it to a certain extent.

For instance, Office and Merge endpoints will start respectively as many LibreOffice (unoconv) and PDTk instances as there are requests. The limitation here is the available memory and CPU usage.

On another hand, for the HTML, URL and Markdown endpoints, the API does only 6 conversions in parallel. Indeed, Google Chrome misbehaves if there are too many concurrent conversions.

The more concurrent requests, the more `504` HTTP codes the API will return.

> See our load testing use case for more details about the API behaviour under heavy load.

##
Strategies

###
Increase timeout

You may increase the conversion timeout. In other words, you accept that a conversion takes more time if the API is under heavy load.

> See timeout section.

###
Scaling

The API being stateless, you may scale it as much as you want.

For instance, using the following Docker Compose file:

    version: '3'

    services:

      # your other services

      gotenberg:
        image: thecodingmachine/gotenberg:6

You may now launch your services using:

    $ docker-compose up --scale gotenberg=your_number_of_instances

When requesting the Gotenberg service with your client(s), Docker will automatically redirect a request to a Gotenberg container according to the round-robin strategy.

#
Ping

Gotenberg provides the endpoint `/ping` for checking the API availability with a simple `GET` request.

Currently this endpoint does nothing special. A better way to monitor Gotenberg would be by checking the memory usage.

Also, as the API uses under the hood intricate programs, you should restart your Gotenberg instances from time to time to ensure a nominal behaviour.

#
Fonts

By default, a handful of fonts are installed. Asian characters are also supported out of the box.

If you wish to use more fonts, you will have to create your own image:

    FROM thecodingmachine/gotenberg:6

    USER root

    RUN apt-get -y install yourfonts

    USER gotenberg

#
Links

- Follow the progress on the GitHub repository
- Follow @gulnap on Twitter
- Thanks to @mafredri for his help and his wonderful cdp library
- OpenAPI documentation for the API can be found on GitHub