API Reference

Convert Markdown or HTML to a production-ready PDF with a single HTTP request.

Base URL

https://www.docrenders.com

All endpoints accept and return JSON unless otherwise noted. PDF responses are application/pdf.

Authentication

Every render endpoint requires an API key passed as a Bearer token in the Authorization header.

Authorization: Bearer dcr_live_YOUR_API_KEY

Keys are prefixed dcr_live_. Generate keys from your dashboard.

Errors

All errors return a consistent JSON shape:

{
  "error": {
    "code": "quota_exceeded",
    "message": "monthly render limit of 100 reached; upgrade your plan to continue"
  }
}
CodeHTTPMeaning
unauthorized401Missing or invalid API key
quota_exceeded429Monthly render limit reached
rate_limited429Too many requests per minute
invalid_request400Malformed JSON, missing fields, or unknown parameters
missing_fields400Required template data fields not provided
render_timeout504Render exceeded the 26s time limit
render_failed500Internal rendering error
internal_error500Unexpected server error

Rate Limits

PlanRequests / minuteRenders / month
Free10100
Starter605,000
Pro30025,000

Exceeding the per-minute limit returns 429 rate_limited. Exceeding the monthly quota returns 429 quota_exceeded.

SDKs

Official client libraries are available for Go, JavaScript/TypeScript, and Python. All SDKs are open source at github.com/JWhist/docrenders-sdks.

Install

go get github.com/JWhist/docrenders-sdks/go

Render from markdown

import docrenders "github.com/JWhist/docrenders-sdks/go"

client := docrenders.NewClient("dcr_live_YOUR_API_KEY")

pdf, err := client.Render(ctx, docrenders.RenderRequest{
    Markdown: "# Hello\n\nGenerated by DocRenders.",
    Options:  docrenders.RenderOptions{Format: "A4"},
})

Render from template + data

pdf, err := client.Render(ctx, docrenders.RenderRequest{
    Template: "invoice",
    Data: map[string]any{
        "name":  "Acme Corp",
        "date":  "2026-06-03",
        "total": 1500.00,
        "items": []map[string]any{
            {"description": "Design", "qty": 1, "unit_price": 1500, "amount": 1500},
        },
    },
})

Render to signed URL

result, err := client.RenderSignedURL(ctx, docrenders.RenderRequest{
    Markdown: "# Report",
})
fmt.Println(result.URL) // expires in 15 minutes

Check usage

usage, err := client.Usage(ctx)
fmt.Printf("%d / %d renders used\n", usage.RendersUsed, usage.RendersLimit)

Install

npm install docrenders-sdk

Render from markdown

import DocRendersClient from "docrenders-sdk";

const client = new DocRendersClient("dcr_live_YOUR_API_KEY");

const pdf = await client.render({
  markdown: "# Hello\n\nGenerated by DocRenders.",
  options: { format: "A4" },
}); // Uint8Array

Render from template + data

const pdf = await client.render({
  template: "invoice",
  data: {
    name: "Acme Corp",
    date: "2026-06-03",
    total: 1500,
    items: [{ description: "Design", qty: 1, unit_price: 1500, amount: 1500 }],
  },
});

Render to signed URL

const { url, expires_at } = await client.renderSignedURL({
  markdown: "# Report",
});
console.log(url); // expires in 15 minutes

Error handling

import { DocRendersError } from "docrenders-sdk";

try {
  const pdf = await client.render({ markdown: "# Hello" });
} catch (err) {
  if (err instanceof DocRendersError) {
    console.error(err.code, err.message);
  }
}

Check usage

const usage = await client.usage();
console.log(`${usage.renders_used} / ${usage.renders_limit} renders used`);

Install

pip install docrenders-sdk

Render from markdown

from docrenders import DocRendersClient, RenderRequest, RenderOptions

client = DocRendersClient("dcr_live_YOUR_API_KEY")

pdf = client.render(RenderRequest(
    markdown="# Hello\n\nGenerated by DocRenders.",
    options=RenderOptions(format="A4"),
))

Render from template + data

pdf = client.render(RenderRequest(
    template="invoice",
    data={
        "name": "Acme Corp",
        "date": "2026-06-03",
        "total": 1500.00,
        "items": [{"description": "Design", "qty": 1, "unit_price": 1500, "amount": 1500}],
    },
))

Render to signed URL

result = client.render_signed_url(RenderRequest(markdown="# Report"))
print(result.url)  # expires in 15 minutes

Error handling

from docrenders import DocRendersError

try:
    pdf = client.render(RenderRequest(markdown="# Hello"))
except DocRendersError as e:
    print(e.code, str(e))

Check usage

usage = client.usage()
print(f"{usage.renders_used} / {usage.renders_limit} renders used")

POST /render

POST/render

Synchronously converts Markdown or HTML to a PDF and returns the raw binary.

Request body

{
  "markdown": "# Hello\n\nGenerated by DocRenders.",
  "template": "invoice",
  "data": {
    "name": "Acme Corp",
    "date": "2026-06-03",
    "total": 1500.00,
    "items": [{ "description": "Design", "qty": 1, "unit_price": 1500, "amount": 1500 }]
  },
  "options": {
    "format": "A4",
    "margin_top": "1in",
    "margin_right": "1in",
    "margin_bottom": "1in",
    "margin_left": "1in",
    "landscape": false
  },
  "output": "binary"
}
FieldTypeDefaultNotes
markdownrequired*stringMarkdown content. GFM supported.
htmlrequired*stringRaw HTML. Alternative to markdown.
templateoptionalstringBuilt-in or custom template name/ID. See Templates.
dataoptionalobjectVariables injected into the template. When provided with template, the template supplies the content — no markdown needed. See Templates.
options.formatoptionalstring"A4""A4", "Letter", or "Legal"
options.margin_topoptionalstring"1in"Any CSS length: "1in", "20mm", "72px"
options.margin_rightoptionalstring"1in"
options.margin_bottomoptionalstring"1in"
options.margin_leftoptionalstring"1in"
options.landscapeoptionalboolfalseRotate page to landscape orientation
outputoptionalstring"binary""binary" returns raw PDF bytes; "url" returns a signed download URL
filenameoptionalstring"render.pdf"Name of the stored file. Also used as the Content-Disposition filename on binary responses.

*One of markdown, html, or template + data is required.

Every render is stored server-side regardless of the output value. The output parameter only controls what is returned in the response — the PDF is always retained and accessible via its signed URL.

Response — output=binary (default)

HTTP 200
Content-Type: application/pdf
Content-Disposition: attachment; filename="render.pdf"

<binary PDF bytes>

Response — output=url

{
  "url": "https://storage.docrenders.dev/pdfs/...",
  "expires_at": "2026-05-30T15:00:00Z",
  "render_time_ms": 1240
}

The signed URL expires after 15 minutes and is scoped to your account — it cannot be used to access another user's files. Use this mode when you want to redirect a user directly to the PDF rather than proxy the bytes through your own server.

Example — binary

curl -X POST https://www.docrenders.com/render \
  -H "Authorization: Bearer dcr_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"markdown":"# Hello\n\nGenerated by DocRenders."}' \
  --output output.pdf

Example — signed URL

curl -X POST https://www.docrenders.com/render \
  -H "Authorization: Bearer dcr_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"markdown":"# Hello\n\nGenerated by DocRenders.","output":"url"}'

POST /render/file

POST/render/file

Same as /render but accepts a file upload via multipart/form-data. Supports .md, .markdown, and .html files.

Form fields

FieldNotes
filerequired.md, .markdown, or .html — max 10 MB
formatoptional"A4" (default), "Letter", "Legal"
margin_topoptionalCSS length, default "1in"
margin_rightoptionalCSS length, default "1in"
margin_bottomoptionalCSS length, default "1in"
margin_leftoptionalCSS length, default "1in"
landscapeoptional"true" to enable landscape

Response

HTTP 200
Content-Type: application/pdf
Content-Disposition: attachment; filename="render.pdf"

<binary PDF bytes>

Example

curl -X POST https://www.docrenders.com/render/file \
  -H "Authorization: Bearer dcr_live_YOUR_API_KEY" \
  -F "file=@invoice.md" \
  -F "format=A4" \
  --output output.pdf