DocRaptor

Elixir client for the DocRaptor HTML-to-PDF and XLS API.

Prefer document_content (with inlined CSS/assets) over document_url when developing against localhost — DocRaptor cannot fetch private hosts without a tunnel. See Development Testing & Localhost Servers.

Installation

def deps do
  [
    {:docraptor, "~> 0.1.0"}
  ]
end

Usage

Built on Req. High-level helpers cover the Python DocApi surface; advanced callers can attach to a %Req.Request{} directly.

{:ok, client} = DocRaptor.Client.new(api_key: "YOUR_API_KEY")
# test: true by default — watermarked, free quota

{:ok, %DocRaptor.Document{body: pdf, num_pages: pages}} =
  DocRaptor.create_doc(client, %{
    name: "hello.pdf",
    document_type: :pdf,
    document_content: "<html><body>Hello</body></html>"
  })

{:ok, %DocRaptor.AsyncJob{status_id: status_id}} =
  DocRaptor.create_async_doc(client, %{
    name: "hello.pdf",
    document_type: :pdf,
    document_content: "<html><body>Hello</body></html>"
  })

{:ok, document} = DocRaptor.await_async_doc(client, status_id)

Low-level Req pipeline

Req.new(method: :post, url: "/docs", json: body, decode_body: false)
|> DocRaptor.Client.attach(client)
|> Req.request()

Set test: false on the client (or per document) for production documents.

API surface

DocRaptor HTTP API Client
POST /docs DocRaptor.create_doc/2
POST /async_docs DocRaptor.create_async_doc/2
POST /hosted_docs DocRaptor.create_hosted_doc/2
POST /hosted_async_docs DocRaptor.create_hosted_async_doc/2
GET /status/:id DocRaptor.get_async_doc_status/2
GET /download/:id DocRaptor.get_async_doc/2
PATCH /expire/:id DocRaptor.expire/2
poll + download DocRaptor.await_async_doc/3
custom Req DocRaptor.Client.attach/2

Document attrs are passed through to DocRaptor after validating name, document_type/type, and document_content/document_url. That includes every API parameter (javascript, pipeline, referrer, callback_url, tag, hosted limits, prince_options, …).

PDF tutorial parity

Official PDF tutorials are HTML/CSS/JS (plus a few prince_options). There are no extra Elixir endpoints to implement — if the request body can express it, this client can send it.

Tutorial What you send
CSS Flexbox Flexbox CSS in document_content
Custom Fonts @font-face CSS (Typekit: also javascript: true + referrer)
Custom Page Size @page { size: ... } CSS
Highcharts Chart Chart HTML/JS + javascript: true
HTML and JavaScript Script in content + javascript: true
Image-Based Watermark Image + Prince @prince-overlay / flow CSS (test: false)
Page Numbers @page + counter(page) / counter(pages) CSS
Print Protection prince_options: %{encrypt: true, disallow_print: true}
Printer's Marks Prince marks CSS in content
QR Code QR HTML/image/JS in content (javascript: true if JS-generated)
Rotated Text & Images CSS transform in content
Table of Contents Prince TOC / heading CSS in content
Text-Based Watermark Text + @prince-overlay / flow CSS (test: false)
Vector Images SVG (or similar) in content

Example: page numbers (CSS)

Mirrors How to create a PDF with Page Numbers:

{:ok, client} = DocRaptor.Client.new(api_key: "YOUR_API_KEY")

html = """
<div style="page-break-after: always;">Page 1</div>
<div style="page-break-after: always;">Page 2</div>
<div style="page-break-after: always;">Page 3</div>
<div id="page4" style="page-break-after: always;">Page 4, with reset page counter</div>

<style>
  @page {
    @bottom {
      content: "Page " counter(page, upper-alpha) " of " counter(pages, decimal);
    }
  }

  #page4 {
    counter-reset: page 1;
  }
</style>
"""

{:ok, %DocRaptor.Document{body: pdf}} =
  DocRaptor.create_doc(client, %{
    name: "page-numbers.pdf",
    document_type: :pdf,
    document_content: html
  })

File.write!("page-numbers.pdf", pdf)

Example: print protection (prince_options)

Mirrors How to create a PDF with Print Protection:

{:ok, client} = DocRaptor.Client.new(api_key: "YOUR_API_KEY")

{:ok, %DocRaptor.Document{body: pdf}} =
  DocRaptor.create_doc(client, %{
    name: "print-protection.pdf",
    document_type: :pdf,
    document_content: "You can't print me!",
    prince_options: %{
      encrypt: true,
      disallow_print: true
    }
  })

File.write!("print-protection.pdf", pdf)

Example: JavaScript chart (javascript: true)

Same pattern as the Highcharts and HTML + JavaScript tutorials — put the script in the HTML, enable DocRaptor’s JS engine:

{:ok, client} = DocRaptor.Client.new(api_key: "YOUR_API_KEY")

html = """
<div id="container" style="width: 600px; height: 400px;"></div>
<script src="https://code.highcharts.com/highcharts.js"></script>
<script>
  Highcharts.chart("container", {
    title: { text: "Fruit consumption" },
    series: [{ name: "Jane", data: [1, 0, 4] }]
  });
</script>
"""

{:ok, %DocRaptor.Document{body: pdf}} =
  DocRaptor.create_doc(client, %{
    name: "highcharts.pdf",
    document_type: :pdf,
    document_content: html,
    javascript: true,
    ignore_console_messages: true,
    pipeline: "10.1"
  })

File.write!("highcharts.pdf", pdf)

Other tutorial knobs that pass through the same way:

# Prince JS engine (canvas / PDF-specific JS)
prince_options: %{javascript: true, max_passes: 3}

# Watermarks use Prince overlay CSS; requires test: false
test: false

# Hosted async + callback
DocRaptor.create_hosted_async_doc(client, %{
  name: "report.pdf",
  document_type: :pdf,
  document_content: html,
  callback_url: "https://example.com/docraptor/callback",
  hosted_download_limit: 25,
  hosted_expires_at: "2026-12-31T23:59:59Z",
  tag: "invoices"
})

Docs