API Reference

All DokJet v1 endpoints. Authentication: X-API-Key header on every request.

POST /v1/generate Generate from template

Generate a PDF from a DokJet template identified by template_id. Returns the PDF binary stream (sync) or a task_id (async).

Request Body

Parameter Type Required Description
template_idstringrequiredTemplate identifier (e.g. invoices/invoice). See GET /v1/templates.
dataobjectrequiredTemplate variables. Unknown keys are silently ignored.
optionsobjectoptionalRendering options. See options object below.
goDokModebooleanoptionalEnable AI optimization (+1 Dok). With attached file: +2 Doks. Default: false.
async_modebooleanoptionalfalse (default): returns PDF. true: returns a task_id (HTTP 202).
return_typestringoptionalbinary (default) | url. Sync mode only.
webhook_urlstring (uri)optionalURL called via POST JSON when the job completes. Async mode only.
metadataobjectoptionalFree key-value object returned in /v1/status and the webhook.
options object
ParameterTypeDescription
paperstringA4 | A3 | A5 | Letter | Legal. Default: A4
orientationstringportrait | landscape. Default: portrait
scalefloatZoom factor. Default: 1.0
margin_top / bottom / left / rightfloatMargins in inches.
header_htmlstringHTML shown in header of every page (inline styles required). Free.
footer_htmlstringHTML shown in footer of every page. Free.
omit_backgroundsbooleanDisable CSS backgrounds. Free.
pdf_formatstringPDF/A-1a | PDF/A-1b | PDF/A-2b | PDF/A-3b. Free.
passwordstringAES encryption. Free on paid plans. Blocked on Free plan (HTTP 403).
compressbooleanqpdf compression. +1 Dok.
factur_xbooleanForce PDF/A-3b and prepare Factur-X. +1 Dok.
embed_filesstring[]URLs of files to embed as invisible attachments. +1 Dok (flat fee).
attachmentsstring[]PDF URLs to merge. +1 Dok per file.

Code examples

curl -X POST https://dokjet.ptitlabo.xyz/v1/generate \
  -H "X-API-Key: dk_live_••••••••••••" \
  -H "Content-Type: application/json" \
  -d '{
    "template_id": "invoices/invoice",
    "data": { "client": "Acme Corp", "total": "€1 240" },
    "options": { "paper": "A4", "compress": true },
    "return_type": "url"
  }'
const res = await fetch('https://dokjet.ptitlabo.xyz/v1/generate', {
  method: 'POST',
  headers: { 'X-API-Key': 'dk_live_••••••••••••',
             'Content-Type': 'application/json' },
  body: JSON.stringify({
    template_id: 'invoices/invoice',
    data: { client: 'Acme Corp', total: '€1 240' },
    options: { paper: 'A4', compress: true },
    return_type: 'url',
  }),
});
const data = await res.json();
$ch = curl_init('https://dokjet.ptitlabo.xyz/v1/generate');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_POST           => true,
  CURLOPT_HTTPHEADER     => ['X-API-Key: dk_live_••••••••••••',
                             'Content-Type: application/json'],
  CURLOPT_POSTFIELDS     => json_encode([
    'template_id' => 'invoices/invoice',
    'data'        => ['client' => 'Acme Corp', 'total' => '€1 240'],
    'options'     => ['paper' => 'A4', 'compress' => true],
    'return_type' => 'url',
  ]),
]);
$data = json_decode(curl_exec($ch), true);
import requests

data = requests.post(
    'https://dokjet.ptitlabo.xyz/v1/generate',
    headers={'X-API-Key': 'dk_live_••••••••••••'},
    json={
        'template_id': 'invoices/invoice',
        'data':        {'client': 'Acme Corp', 'total': '€1 240'},
        'options':     {'paper': 'A4', 'compress': True},
        'return_type': 'url',
    }
).json()

Response

200 application/pdf — PDF binary
200 application/json {url, credits_left, response_time_ms}
202 — async: {task_id, status, check_status_url}
400 — missing template_id
401 — invalid API key
402 — insufficient Doks
404 — template not found
POST /v1/transform Convert raw HTML

Convert raw HTML directly to PDF, without a DokJet template. Ideal for layouts you fully control client-side.

goDokMode defaults to true on /v1/transform. Pass goDokMode: false to convert at 1 Dok.

Request Body

ParameterTypeRequiredDescription
htmlstringrequiredComplete standalone HTML document (<html>, <head>, <body>).
cssstringoptionalAdditional CSS injected into <head>.
optionsobjectoptionalSame options object as /v1/generate.
goDokModebooleanoptionaltrue by default on this endpoint. Pass false for 1 Dok instead of 2.
async_modebooleanoptionalDefault: false (sync).
return_typestringoptionalbinary | url. Sync mode.
webhook_urlstringoptionalAsync mode only.
metadataobjectoptionalFree object returned in the webhook.
curl -X POST https://dokjet.ptitlabo.xyz/v1/transform \
  -H "X-API-Key: dk_live_••••••••••••" \
  -H "Content-Type: application/json" \
  -d '{
    "html": "<html><body><h1>Hello World</h1></body></html>",
    "goDokMode": false,
    "return_type": "url"
  }'
const res = await fetch('https://dokjet.ptitlabo.xyz/v1/transform', {
  method: 'POST',
  headers: { 'X-API-Key': 'dk_live_••••••••••••',
             'Content-Type': 'application/json' },
  body: JSON.stringify({
    html: '<html><body><h1>Hello World</h1></body></html>',
    goDokMode: false,
    return_type: 'url',
  }),
});
$data = json_decode(
  file_get_contents('https://dokjet.ptitlabo.xyz/v1/transform', false,
    stream_context_create(['http' => [
      'method'  => 'POST',
      'header'  => "X-API-Key: dk_live_••••••••••••\r\nContent-Type: application/json\r\n",
      'content' => json_encode([
        'html'        => '<html><body><h1>Hello</h1></body></html>',
        'goDokMode'   => false,
        'return_type' => 'url',
      ]),
    ]])
  ), true
);
import requests

data = requests.post(
    'https://dokjet.ptitlabo.xyz/v1/transform',
    headers={'X-API-Key': 'dk_live_••••••••••••'},
    json={
        'html':        '<html><body><h1>Hello World</h1></body></html>',
        'goDokMode':   False,
        'return_type': 'url',
    }
).json()
POST /v1/studio/{slug} Pre-configured Studio endpoint

Generate a PDF from a pre-configured Studio endpoint identified by its slug. The endpoint configuration (template, options) applies automatically. data values override defaults.

Path Parameters

ParameterTypeDescription
slugstringStudio endpoint slug. See GET /v1/endpoints.

Request Body

ParameterTypeRequiredDescription
dataobjectoptionalVariables to inject. Override endpoint defaults.
optionsobjectoptionalOverride the endpoint rendering options.
goDokModebooleanoptionalOverride the endpoint goDokMode parameter. +1 Dok.
async_modebooleanoptionalDefault: false.
webhook_url / return_type / metadataoptionalSame as /v1/generate.
curl -X POST https://dokjet.ptitlabo.xyz/v1/studio/mes-factures \
  -H "X-API-Key: dk_live_••••••••••••" \
  -H "Content-Type: application/json" \
  -d '{ "data": { "client": "Acme Corp", "total": "€1 240" } }'
const res = await fetch('https://dokjet.ptitlabo.xyz/v1/studio/mes-factures', {
  method: 'POST',
  headers: { 'X-API-Key': 'dk_live_••••••••••••',
             'Content-Type': 'application/json' },
  body: JSON.stringify({ data: { client: 'Acme Corp', total: '€1 240' }}),
});
$ch = curl_init('https://dokjet.ptitlabo.xyz/v1/studio/mes-factures');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_POST           => true,
  CURLOPT_HTTPHEADER     => ['X-API-Key: dk_live_••••••••••••',
                             'Content-Type: application/json'],
  CURLOPT_POSTFIELDS     => json_encode([
    'data' => ['client' => 'Acme Corp', 'total' => '€1 240'],
  ]),
]);
import requests

data = requests.post(
    'https://dokjet.ptitlabo.xyz/v1/studio/mes-factures',
    headers={'X-API-Key': 'dk_live_••••••••••••'},
    json={'data': {'client': 'Acme Corp', 'total': '€1 240'}}
).json()
POST /v1/batch Async batch

Submit multiple PDF jobs in a single request. Exclusively asynchronous.

Batch mode is exclusively asynchronous — async_mode must be true.
Batch entry limits depend on your plan: Free = 3, Pro/Max = 10 entries per batch.

Request Body

ParameterTypeRequiredDescription
endpointstringrequiredgenerate | transform | {slug}. Endpoint type applied to all entries.
entriesarrayrequiredArray of payloads. Each entry follows the corresponding endpoint schema. Max 3 (Free) / 10 (Pro+).
async_modebooleanoptionalMust be true or omitted. Passing false → HTTP 400.
webhook_urlstringoptionalDefault webhook for all entries (overridable per entry).

Webhook payload (per job)

POST {webhook_url}
{
  "task_id":      "job_a1b2c3d4e5f6g7h8",
  "status":       "completed",
  "download_url": "https://dokjet.ptitlabo.xyz/upload/.../doc.pdf",
  "metadata":     {}
}
curl -X POST https://dokjet.ptitlabo.xyz/v1/batch \
  -H "X-API-Key: dk_live_••••••••••••" \
  -H "Content-Type: application/json" \
  -d '{
    "endpoint": "generate",
    "webhook_url": "https://your-app.com/webhooks/dokjet",
    "entries": [
      { "template_id": "invoices/invoice", "data": { "client": "Acme" } },
      { "template_id": "invoices/invoice", "data": { "client": "Beta Corp" } }
    ]
  }'
const res = await fetch('https://dokjet.ptitlabo.xyz/v1/batch', {
  method: 'POST',
  headers: { 'X-API-Key': 'dk_live_••••••••••••',
             'Content-Type': 'application/json' },
  body: JSON.stringify({
    endpoint:    'generate',
    webhook_url: 'https://your-app.com/webhooks/dokjet',
    entries: [
      { template_id: 'invoices/invoice', data: { client: 'Acme' }},
      { template_id: 'invoices/invoice', data: { client: 'Beta Corp' }},
    ],
  }),
});
const { batch_id, tasks } = await res.json();
// Using Guzzle
$response = $client->post('https://dokjet.ptitlabo.xyz/v1/batch', [
  'headers' => ['X-API-Key' => 'dk_live_••••••••••••'],
  'json'    => [
    'endpoint'    => 'generate',
    'webhook_url' => 'https://your-app.com/webhooks/dokjet',
    'entries'     => [
      ['template_id' => 'invoices/invoice', 'data' => ['client' => 'Acme']],
      ['template_id' => 'invoices/invoice', 'data' => ['client' => 'Beta Corp']],
    ],
  ],
]);
import requests

result = requests.post(
    'https://dokjet.ptitlabo.xyz/v1/batch',
    headers={'X-API-Key': 'dk_live_••••••••••••'},
    json={
        'endpoint':    'generate',
        'webhook_url': 'https://your-app.com/webhooks/dokjet',
        'entries': [
            {'template_id': 'invoices/invoice', 'data': {'client': 'Acme'}},
            {'template_id': 'invoices/invoice', 'data': {'client': 'Beta Corp'}},
        ],
    }
).json()

Response

202 {batch_id, count, tasks[]}
400 — async_mode: false
402 — insufficient Doks
422 — plan limit exceeded
GET /v1/status/{task_id} Async job status

Returns the state of a job created in async mode. Lifecycle: pending → processing → completed | failed.

Poll every 2–5 seconds. Prefer webhooks to avoid polling in production.

Path Parameters

ParameterTypeDescription
task_idstringtask_id returned by a generation endpoint in async mode.
curl https://dokjet.ptitlabo.xyz/v1/status/job_a1b2c3d4e5f6g7h8 \
  -H "X-API-Key: dk_live_••••••••••••"
→  200 OK
{
  "task_id":      "job_a1b2c3d4e5f6g7h8",
  "status":       "completed",
  "download_url": "https://dokjet.ptitlabo.xyz/upload/.../doc.pdf"
}
const poll = async (taskId) => {
  let status;
  do {
    await new Promise(r => setTimeout(r, 3000));
    const res = await fetch(`https://dokjet.ptitlabo.xyz/v1/status/${taskId}`, {
      headers: { 'X-API-Key': 'dk_live_••••••••••••' },
    });
    ({ status } = await res.json());
  } while (status === 'pending' || status === 'processing');
  return status;
};
$status = 'pending';
while (in_array($status, ['pending', 'processing'])) {
  sleep(3);
  $r = json_decode(file_get_contents(
    'https://dokjet.ptitlabo.xyz/v1/status/' . $taskId,
    false,
    stream_context_create(['http' => [
      'header' => "X-API-Key: dk_live_••••••••••••\r\n"
    ]])), true);
  $status = $r['status'];
}
import time, requests

def poll(task_id):
    while True:
        time.sleep(3)
        r = requests.get(
            f'https://dokjet.ptitlabo.xyz/v1/status/{task_id}',
            headers={'X-API-Key': 'dk_live_••••••••••••'}
        ).json()
        if r['status'] not in ('pending', 'processing'):
            return r
GET /v1/templates List templates

Returns the full catalog of DokJet templates usable in POST /v1/generate via their template_id.

curl https://dokjet.ptitlabo.xyz/v1/templates \
  -H "X-API-Key: dk_live_••••••••••••"
→  [{ "id": "invoices/invoice", "label": "Invoice", "category": "invoices", "orientation": "portrait" }, ...]
const templates = await fetch('https://dokjet.ptitlabo.xyz/v1/templates', {
  headers: { 'X-API-Key': 'dk_live_••••••••••••' },
}).then(r => r.json());
$templates = json_decode(file_get_contents(
  'https://dokjet.ptitlabo.xyz/v1/templates', false,
  stream_context_create(['http' => [
    'header' => "X-API-Key: dk_live_••••••••••••\r\n"
  ]])
), true);
templates = requests.get(
    'https://dokjet.ptitlabo.xyz/v1/templates',
    headers={'X-API-Key': 'dk_live_••••••••••••'}
).json()
GET /v1/endpoints List Studio endpoints

Returns all Studio endpoints in your workspace. Use their slug with POST /v1/studio/{slug}.

GET /v1/endpoints
→  200 OK
[{
  "name":      "Mes factures",
  "slug":      "mes-factures",
  "type":      "template",
  "express":   false,
  "variables": ["client", "total", "invoice_number"]
}]
GET /v1/credits Credit balance

Returns the Dok balance for your account and the name of the active plan.

GET /v1/credits
curl https://dokjet.ptitlabo.xyz/v1/credits \
  -H "X-API-Key: dk_live_••••••••••••"
→  200 OK
{
  "credits_left": 42,
  "plan":         "Free"
}