Getting Started

DocForge is a PDF & Document Generation API. Convert HTML, URLs, and templates into polished PDFs and images with a single API call.

Base URL

https://your-domain/api  # or http://IP/api

Quick Example

Generate a PDF from raw HTML with a single cURL command:

curl -X POST https://your-domain/api/v1/pdf/from-html \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: df_live_xxxxx" \
  -d '{"html": "<h1>Hello DocForge</h1><p>Your first PDF.</p>"}' \
  --output document.pdf
Tip
Don't have an API key yet? Create a free account to get one instantly.

Authentication

DocForge supports three authentication methods. Use whichever fits your workflow.

1. API Key Header (Recommended)

Pass your API key in the X-Api-Key header:

curl -H "X-Api-Key: df_live_xxxxx" https://your-domain/api/v1/pdf/from-html

2. Query Parameter

Append the key as a query parameter (useful for quick tests, not recommended for production):

https://your-domain/api/v1/pdf/from-html?api_key=df_live_xxxxx

3. JWT Bearer Token

For dashboard and account operations, use the JWT token from login:

curl -H "Authorization: Bearer <token>" https://your-domain/api/v1/templates

How to Get an API Key

  1. Register for a free account
  2. Your first API key is shown immediately after registration
  3. You can generate additional keys from the Dashboard → API Keys page

PDF Endpoints

Generate PDF documents from HTML markup, live URLs, or saved templates.

POST /api/v1/pdf/from-html

Generate a PDF from raw HTML content.

Request Body

ParameterTypeDescription
html requiredstringThe HTML content to render
options.formatstringPaper format: A4, Letter, Legal, A3, etc. Default: A4
options.landscapebooleanLandscape orientation. Default: false
options.printBackgroundbooleanPrint background graphics. Default: true
options.scalenumberScale of the webpage rendering. Default: 1
options.marginobject{ top, right, bottom, left } in CSS units
options.displayHeaderFooterbooleanDisplay header and footer. Default: false
options.headerTemplatestringHTML for the header. Supports classes: date, title, url, pageNumber, totalPages
options.footerTemplatestringHTML for the footer
options.pageRangesstringPage ranges to print, e.g. 1-5, 8
options.widthstringPaper width in CSS units (overrides format)
options.heightstringPaper height in CSS units (overrides format)
options.cssstringAdditional CSS to inject before rendering
options.jsstringJavaScript to execute before rendering
options.waitForSelectorstringWait for a CSS selector to appear before generating
options.waitForTimeoutnumberWait N milliseconds before generating

Example Request

curl -X POST https://your-domain/api/v1/pdf/from-html \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: df_live_xxxxx" \
  -d '{
    "html": "<h1>Invoice #1042</h1><p>Total: $250.00</p>",
    "options": {
      "format": "A4",
      "printBackground": true,
      "margin": { "top": "20mm", "bottom": "20mm" }
    }
  }' \
  --output invoice.pdf
const response = await fetch('https://your-domain/api/v1/pdf/from-html', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-Api-Key': 'df_live_xxxxx'
  },
  body: JSON.stringify({
    html: '<h1>Invoice #1042</h1><p>Total: $250.00</p>',
    options: {
      format: 'A4',
      printBackground: true,
      margin: { top: '20mm', bottom: '20mm' }
    }
  })
});

const blob = await response.blob();
// Save or download the PDF blob
import requests

response = requests.post(
    "https://your-domain/api/v1/pdf/from-html",
    headers={
        "Content-Type": "application/json",
        "X-Api-Key": "df_live_xxxxx"
    },
    json={
        "html": "<h1>Invoice #1042</h1><p>Total: $250.00</p>",
        "options": {
            "format": "A4",
            "printBackground": True,
            "margin": {"top": "20mm", "bottom": "20mm"}
        }
    }
)

with open("invoice.pdf", "wb") as f:
    f.write(response.content)

Response

Returns the PDF file as binary data with Content-Type: application/pdf.


POST /api/v1/pdf/from-url

Generate a PDF from a live URL. DocForge navigates to the page, waits for it to load, and converts it.

Request Body

ParameterTypeDescription
url requiredstringThe URL to render as PDF
optionsobjectSame options as /pdf/from-html

Example Request

curl -X POST https://your-domain/api/v1/pdf/from-url \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: df_live_xxxxx" \
  -d '{"url": "https://example.com", "options": {"format": "A4"}}' \
  --output page.pdf
const response = await fetch('https://your-domain/api/v1/pdf/from-url', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-Api-Key': 'df_live_xxxxx'
  },
  body: JSON.stringify({
    url: 'https://example.com',
    options: { format: 'A4' }
  })
});

const blob = await response.blob();
import requests

response = requests.post(
    "https://your-domain/api/v1/pdf/from-url",
    headers={"X-Api-Key": "df_live_xxxxx"},
    json={"url": "https://example.com", "options": {"format": "A4"}}
)

with open("page.pdf", "wb") as f:
    f.write(response.content)

POST /api/v1/pdf/from-template

Generate a PDF from a saved template with dynamic data. Template variables use {{variableName}} syntax.

Request Body

ParameterTypeDescription
templateId requiredstringID of the saved template
dataobjectKey-value pairs to fill template variables
optionsobjectSame options as /pdf/from-html

Example Request

curl -X POST https://your-domain/api/v1/pdf/from-template \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: df_live_xxxxx" \
  -d '{
    "templateId": "tpl_invoice_v2",
    "data": {
      "customerName": "Acme Corp",
      "invoiceNumber": "INV-1042",
      "total": "$1,250.00",
      "items": [
        {"name": "API Pro Plan", "qty": 1, "price": "$1,250.00"}
      ]
    },
    "options": {"format": "A4"}
  }' \
  --output invoice.pdf
const response = await fetch('https://your-domain/api/v1/pdf/from-template', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-Api-Key': 'df_live_xxxxx'
  },
  body: JSON.stringify({
    templateId: 'tpl_invoice_v2',
    data: {
      customerName: 'Acme Corp',
      invoiceNumber: 'INV-1042',
      total: '$1,250.00'
    },
    options: { format: 'A4' }
  })
});
import requests

response = requests.post(
    "https://your-domain/api/v1/pdf/from-template",
    headers={"X-Api-Key": "df_live_xxxxx"},
    json={
        "templateId": "tpl_invoice_v2",
        "data": {
            "customerName": "Acme Corp",
            "invoiceNumber": "INV-1042",
            "total": "$1,250.00"
        },
        "options": {"format": "A4"}
    }
)

Image Endpoints

Generate screenshots and images from HTML, URLs, or templates. Supports PNG, JPEG, and WebP output formats.

POST /api/v1/image/from-html

Render HTML to an image. Useful for generating social cards, charts, and visual assets.

Request Body

ParameterTypeDescription
html requiredstringThe HTML content to render
options.formatstringOutput format: png, jpeg, or webp. Default: png
options.widthnumberViewport width in pixels. Default: 1280
options.heightnumberViewport height in pixels. Default: 720
options.scalenumberDevice scale factor (1-3). Default: 1
options.fullPagebooleanCapture the full scrollable page. Default: false
options.qualitynumberQuality 0-100 (JPEG/WebP only). Default: 80
options.cssstringAdditional CSS to inject
options.jsstringJavaScript to execute before capture
options.waitForSelectorstringWait for a CSS selector to appear
options.waitForTimeoutnumberWait N milliseconds before capture

Example Request

curl -X POST https://your-domain/api/v1/image/from-html \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: df_live_xxxxx" \
  -d '{
    "html": "<div style=\"padding:40px;background:#6366f1;color:white\"><h1>Hello</h1></div>",
    "options": {
      "format": "png",
      "width": 1200,
      "height": 630,
      "scale": 2
    }
  }' \
  --output social-card.png
const response = await fetch('https://your-domain/api/v1/image/from-html', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-Api-Key': 'df_live_xxxxx'
  },
  body: JSON.stringify({
    html: '<div style="padding:40px;background:#6366f1"><h1>Hello</h1></div>',
    options: { format: 'png', width: 1200, height: 630, scale: 2 }
  })
});

const blob = await response.blob();
import requests

response = requests.post(
    "https://your-domain/api/v1/image/from-html",
    headers={"X-Api-Key": "df_live_xxxxx"},
    json={
        "html": "<div style='padding:40px;background:#6366f1'><h1>Hello</h1></div>",
        "options": {"format": "png", "width": 1200, "height": 630}
    }
)

with open("social-card.png", "wb") as f:
    f.write(response.content)

Response

Returns the image as binary data with the appropriate Content-Type (image/png, image/jpeg, or image/webp).


POST /api/v1/image/from-url

Capture a screenshot of any URL as an image.

Request Body

ParameterTypeDescription
url requiredstringThe URL to capture
optionsobjectSame options as /image/from-html

Example Request

curl -X POST https://your-domain/api/v1/image/from-url \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: df_live_xxxxx" \
  -d '{"url": "https://example.com", "options": {"format": "png", "fullPage": true}}' \
  --output screenshot.png
const response = await fetch('https://your-domain/api/v1/image/from-url', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-Api-Key': 'df_live_xxxxx'
  },
  body: JSON.stringify({
    url: 'https://example.com',
    options: { format: 'png', fullPage: true }
  })
});
import requests

response = requests.post(
    "https://your-domain/api/v1/image/from-url",
    headers={"X-Api-Key": "df_live_xxxxx"},
    json={"url": "https://example.com", "options": {"format": "png", "fullPage": True}}
)

POST /api/v1/image/from-template

Render a saved template as an image with dynamic data.

Request Body

ParameterTypeDescription
templateId requiredstringID of the saved template
dataobjectKey-value pairs for template variables
optionsobjectSame options as /image/from-html

Example Request

curl -X POST https://your-domain/api/v1/image/from-template \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: df_live_xxxxx" \
  -d '{
    "templateId": "tpl_og_card",
    "data": {"title": "My Blog Post", "author": "John"},
    "options": {"format": "png", "width": 1200, "height": 630}
  }' \
  --output og-card.png
const response = await fetch('https://your-domain/api/v1/image/from-template', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-Api-Key': 'df_live_xxxxx'
  },
  body: JSON.stringify({
    templateId: 'tpl_og_card',
    data: { title: 'My Blog Post', author: 'John' },
    options: { format: 'png', width: 1200, height: 630 }
  })
});
import requests

response = requests.post(
    "https://your-domain/api/v1/image/from-template",
    headers={"X-Api-Key": "df_live_xxxxx"},
    json={
        "templateId": "tpl_og_card",
        "data": {"title": "My Blog Post", "author": "John"},
        "options": {"format": "png", "width": 1200, "height": 630}
    }
)

Templates

Save reusable HTML templates with {{variableName}} placeholders. Fill them with dynamic data when generating PDFs or images.

Template Variables
Use double curly braces for dynamic content: {{customerName}}, {{total}}, {{items}}. Variables are replaced at render time with values from the data object.
GET /api/v1/templates

List all templates for the authenticated user.

Example Response

{
  "success": true,
  "data": [
    {
      "id": "tpl_invoice_v2",
      "name": "Invoice Template",
      "variables": ["customerName", "invoiceNumber", "total"],
      "createdAt": "2026-03-15T10:30:00Z",
      "updatedAt": "2026-03-20T14:22:00Z"
    }
  ]
}

GET /api/v1/templates/:id

Get a single template by ID, including its full HTML content.

Example Response

{
  "success": true,
  "data": {
    "id": "tpl_invoice_v2",
    "name": "Invoice Template",
    "html": "<h1>Invoice {{invoiceNumber}}</h1><p>To: {{customerName}}</p>",
    "variables": ["customerName", "invoiceNumber", "total"],
    "createdAt": "2026-03-15T10:30:00Z",
    "updatedAt": "2026-03-20T14:22:00Z"
  }
}

POST /api/v1/templates

Create a new template. Requires JWT authentication.

Request Body

ParameterTypeDescription
name requiredstringTemplate display name
html requiredstringHTML content with {{variable}} placeholders

Example Request

curl -X POST https://your-domain/api/v1/templates \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <jwt_token>" \
  -d '{
    "name": "Invoice Template",
    "html": "<h1>Invoice {{invoiceNumber}}</h1><p>To: {{customerName}}</p><p>Total: {{total}}</p>"
  }'

PUT /api/v1/templates/:id

Update an existing template's name or HTML content.

Request Body

ParameterTypeDescription
namestringUpdated template name
htmlstringUpdated HTML content

Example Request

curl -X PUT https://your-domain/api/v1/templates/tpl_invoice_v2 \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <jwt_token>" \
  -d '{"name": "Invoice Template v3", "html": "<h1>Updated Invoice</h1>"}'

DELETE /api/v1/templates/:id

Permanently delete a template.

Example Request

curl -X DELETE https://your-domain/api/v1/templates/tpl_invoice_v2 \
  -H "Authorization: Bearer <jwt_token>"

Example Response

{
  "success": true,
  "message": "Template deleted successfully"
}

Error Handling

All errors follow a consistent JSON format. The HTTP status code and error body both indicate the problem.

Error Response Format

{
  "success": false,
  "error": {
    "code": "ERROR_CODE",
    "message": "Human readable description of what went wrong"
  }
}

Error Codes

CodeHTTP StatusDescription
UNAUTHORIZED401Missing or invalid API key / JWT token
FORBIDDEN403Valid credentials but insufficient permissions
NOT_FOUND404Requested resource (template, etc.) not found
BAD_REQUEST400Malformed request body or missing required fields
VALIDATION_ERROR422Input validation failed (invalid URL, bad options, etc.)
RATE_LIMIT_EXCEEDED429Too many requests per minute
QUOTA_EXCEEDED429Monthly render quota has been exceeded
RENDER_FAILED500The rendering engine failed to produce output
INTERNAL_ERROR500An unexpected server error occurred
Note
When you receive a RATE_LIMIT_EXCEEDED error, the response includes a Retry-After header indicating how many seconds to wait before retrying.

Rate Limits

API requests are rate-limited per API key. Monthly quotas depend on your plan.

Per-Minute Limit

All plans share the same per-minute rate limit: 100 requests per minute per API key.

Monthly Quotas

PlanMonthly RendersQuota
FreeFor testing and small projects100
StarterFor growing applications2,000
ProFor production workloads10,000
BusinessFor high-volume usage50,000

Response Headers

Every API response includes quota and performance headers:

HeaderTypeDescription
X-Quota-RemainingnumberRenders remaining in the current billing period
X-Quota-LimitnumberTotal renders allowed per billing period
X-Render-Time-MsnumberTime taken to render the document in milliseconds

SDKs

Official client libraries are in development. In the meantime, the REST API works with any HTTP client in any language.

JavaScript / TypeScript
npm install docforge
Coming Soon
Python
pip install docforge
Coming Soon
Go
go get docforge
Coming Soon
PHP
composer require docforge
Coming Soon
Want early access?
Join the waitlist for SDK beta access by reaching out through the dashboard or contacting support.