Doklavio documentation

Learn how to turn a document you design once into ready-to-use PDFs for every customer, employee, project or transaction.

Start here

Doklavio combines a reusable document design with changing business data. You build the layout, connect the parts that should change and then create one PDF or a complete batch.

1Create the design

Start with a blank page, import a PDF you already use or open a Doklavio template file.

2Connect your data

Upload CSV or JSON data and place its fields into the document.

3Check each record

Move through the live preview and confirm that names, totals and layouts look right.

4Generate the PDFs

Select the records you need and download separate PDFs or one combined file.

Your workspace

The workspace is where you create, find and manage templates. It also shows your account, team and monthly document usage.

Start with a blank page

Open an empty document and build the complete layout inside the editor.

Import a PDF

Bring in an existing form, invoice, certificate or other PDF and continue working from that design.

Open a template file

Open a .doklavio file that you previously saved to your computer.

Find saved templates

Search by template or owner. Use the filter to show team templates, your templates, personal templates or templates from one team member.

Each saved template card shows its owner and whether it is available to the team or private. Select Open to continue editing it.

Template actions

ActionWhat it does
OpenLoads the editable template in the editor.
Make personalRemoves your template from the shared team view. Only you can see it.
Share with teamMakes your template available to every current team member.
Share by emailSends a template invitation that the recipient must accept.
DeletePermanently removes your template. This action cannot be undone.

The action menu appears only on templates you own. A teammate can open a shared team template but cannot change its privacy or delete it.

Create a template

Start from a blank page

Use a blank page when you want full control over the document. Add text, tables, images, shapes and other blocks from the Elements panel. You can add more pages, choose the page size and adjust page margins from the toolbar.

Import an existing PDF

Importing a PDF keeps the original page design as the visual base and extracts embedded text into editable regions. You can change that text, cover old content and place data fields over the design.

Import a PDF in the workspace and Upload PDF in the editor use the same import tool. Importing replaces the current page design after confirmation. The status reports how many pages and editable text regions were found. Extracted text behaves like other editable blocks and can be moved, resized or changed.

Use more than one page

Select + Page in the editor toolbar to add pages. Use the page selector to move between them. Page numbers can be added from the Elements panel.

Know the editor

The editor is split into four working areas. Each one has a different job.

Tools

Upload data and PDFs, browse available fields, add images and choose document elements.

Canvas

Build the actual page. Move, resize, rotate and edit the content placed here.

Properties

Control the selected block's appearance, position, size, alignment, layer order and data behavior.

Preview

See the finished document with the current record's real values in place.

Add and format content

  • Add headings, body text, labels, callouts, information cards, amount blocks, quotes and signatures.
  • Upload images and reuse them from your image library across templates.
  • Add tables, rectangles, circles, lines, arrows, symbols and other shapes.
  • Use the toolbar to change fonts, sizes, colors, alignment, lists and line spacing.
  • Select several blocks to align or group them. Use layer controls when elements overlap.

When you are signed in, new image uploads are saved to the billing owner's shared team image library. Every active team member can reuse those images across templates and browser sessions. If a member leaves the team or their seat is suspended, they lose access to that library. Images already placed in a saved template remain part of that template.

Select a block on the page to see its available controls in Properties. The options change based on whether you selected text, a table, an image or a shape.

Under Style, switch Background or Border off when a block should be transparent or borderless. When enabled, you can choose the colors, border thickness, rounded corners and overall opacity.

Select, move and arrange blocks

  • Click a block once to select it. Drag the block to move it on the page.
  • Use the resize handles around the selected block to change its width or height.
  • Use the rotation control in Properties when an element needs to sit at an angle.
  • Hold Shift while clicking to select several blocks. Select Group when they should move together.
  • Use Send backward and Bring forward when shapes, images or text overlap.
  • Use the X, Y, Width and Height values in Properties when exact placement matters.
  • Right-click a block for its common actions. In Layers, double-click a name to rename it.
  • Use the View menu to show or hide Tools, Properties, Layers and Preview when you need more canvas space.

Keep blocks below changing content

Select a block, open Properties, then Layout and choose another block under Keep below another block. Set the vertical gap you want. When the connected block grows—for example, when a repeating table renders more rows—the lower block moves down automatically in Preview, browser exports and API-generated PDFs.

You can connect several blocks in a chain, such as table → divider → totals → footer. A connected block can still be dragged horizontally, while its vertical position remains controlled by its anchor. Choose Free position to disconnect it. Connections stay on their current page; they do not automatically create another page.

Work with tables

Add a table from the top toolbar. After selecting it, Properties lets you add or remove rows and columns, change borders, align text, show or hide the header, alternate row colors and adjust cell spacing.

Connect data and fields

Open the Data tab under Tools and choose one or more Excel, CSV or JSON files. Doklavio reads them inside your browser and creates a searchable list of fields. The files and their values are not uploaded or included when you save the template.

Excel files

Choose the worksheet to import. Use one record per row, or group related rows into documents with a repeating item list.

CSV files

The first row contains field names. Every following row becomes one document record.

JSON objects

A single object becomes one record. Nested values appear as grouped fields.

JSON arrays

An array at the top level becomes multiple records. Arrays inside a record can create repeating table rows.

Multiple files

Records from the uploaded files are added to the same batch, ready for preview and selection.

How Excel files are read

Upload an .xlsx file directly — there is no need to export it to CSV first. Choose which worksheet to import. Its first row supplies field names and, by default, every following row becomes one document record. Numbers, dates and true/false cells keep their type; dates are read as plain YYYY-MM-DD values. Formula cells import the value already calculated by your spreadsheet app, not the formula itself; a formula your spreadsheet app couldn't compute imports as an empty cell.

Group spreadsheet rows into documents

Turn on Group rows into documents when several rows belong to the same output, such as invoice lines. Choose the document ID column, enter the repeating list name (normally items), and select the columns that describe each item. Doklavio creates one document record for every unique ID and places the selected values inside the repeating list.

Columns outside the repeating list must stay the same for every row in a group. If, for example, a customer name changes inside one invoice number, import stops and identifies the conflicting column instead of silently using the wrong value.

Grouped worksheetExample data
invoice_number,customer_name,description,quantity
DEMO-001,Demo Client One,Setup,1
DEMO-001,Demo Client One,Review,2
DEMO-002,Demo Client Two,Export,1

Group by invoice_number, use items as the list name, and select description and quantity as item columns. The first two rows become one record with two items; the last row becomes a second record.

How CSV files are read

The filename does not matter. The first row supplies the field names and every following row becomes one record. A CSV must contain a header row and at least one data row. Quoted values may contain commas. Doklavio recognizes plain text, numbers, true or false values and empty cells.

CSV structureExample data
invoice_number,customer_name,issue_date,total
DEMO-001,Demo Client One,YYYY-MM-DD,100.00
DEMO-002,Demo Client Two,YYYY-MM-DD,200.00

How JSON files are read

A top-level object becomes one record. A top-level array becomes several records. Nested objects are shown as groups in the Fields panel, with paths such as customer.name. An array inside a record is shown as a repeatable data source that can be connected to a table.

JSON structureExample data
[
  {
    "customer": { "name": "Demo Client One" },
    "invoice": { "number": "DEMO-001", "total": 100 },
    "items": [
      { "description": "Consulting", "quantity": 4, "price": 120 }
    ]
  }
]

Place a field in the document

  1. Find the field in the Data panel.
  2. Drag it onto the page, into a text block or into a table cell.
  3. Move through the Preview records to check the result with different values.

Format a field

Click the block that contains the field, open Properties, Data behavior, then click the exact field you want to change. Formatting is saved with the template and is applied consistently in preview, browser exports and API-generated PDFs.

Dates

Display a YYYY-MM-DD value as 24.08.2026, 24/08/2026, 24 Aug 2026 or August 24, 2026.

Numbers

Choose plain, 1,234.50 or 1 234,50 formatting. Currency fields support EUR, USD and GBP with either symbol placement.

Text

Use uppercase, lowercase or title case, then add an optional prefix, suffix or maximum character length.

Empty values

Enter replacement text that is used only when the source field is missing or empty.

Render data as images, QR codes or barcodes

Open Elements, add a Data image, QR code or Barcode, then select the source field under Properties, Data behavior. The visual changes with every record and is rendered the same way in the preview, browser exports and API-generated PDFs.

Data images

Use an inline PNG or JPEG data URL, such as data:image/png;base64,.... This is useful for product images, employee photos and record-specific signatures.

QR codes

Encode a URL, identifier or short text value. QR values may contain up to 134 UTF-8 bytes.

Barcodes

Create a Code 128 barcode from 1–120 printable ASCII characters and choose whether the value appears below the bars.

Handle changing data

  • Repeating rows: drag an array field such as items onto the page to create a repeating table, or select an existing table and choose the array under Properties, Data behavior, Repeat rows from.
  • Conditional blocks: select a block, choose a field under Properties, Data behavior, Show this block when, then choose whether it must have a value, be empty, equal text or pass a numeric comparison such as greater than, at least, less than or at most.
  • Fallback values: select a placed data field and enter replacement text for empty values. For example, show Not provided when customer.phone is empty.

Preview and generate PDFs

The Preview panel shows one record at a time. Use the arrow buttons to move through your records and check how each finished document will look.

Before generating

  • Check long names, addresses and descriptions for wrapping.
  • Confirm that empty fields and conditional blocks behave as expected.
  • Check repeating tables with records that contain different numbers of rows.
  • Resolve any missing or unrecognized fields shown by the editor.

Choose the output

Open the Share menu and select Export PDF to open the record queue. Choose which records to include, then download them as separate PDF files or as one combined PDF.

For separate files, set a naming pattern such as invoice-{{invoice.number}}. Use {{index}} when you only need a running number. When several separate PDFs are generated, Doklavio downloads them together in a ZIP file.

Record queue controls

  • Include: controls whether a record is part of the current export.
  • Separate files: creates one PDF for each selected record. Several files are downloaded together as a ZIP.
  • Single file: combines all selected records into one PDF.
  • File naming: builds filenames from fixed text, {{index}} or an uploaded data field such as {{invoice.number}}.
  • Generate ready PDFs: creates the selected output and counts each selected record toward monthly document usage.

Save and open templates

Save to your workspace

When creating a template, choose Local only, Personal or Team. Local only does not enable cloud autosave. Personal stores the template in your account for you alone, while Team stores a shared cloud template for current team members. You can also open the Share menu and choose Save to account later. Saved templates include their pages, elements, field connections, page settings and uploaded image assets. CSV and JSON records are not saved.

Save to your computer

From the Share menu, choose Download file to save a .doklavio template file. Local template files are encrypted and tied to the account that created them. Sign in with that same account when opening the file again.

The editable design is sent over HTTPS to Doklavio's authenticated encryption service when the local file is encrypted or opened, but it is not saved as a cloud template. Uploaded CSV, Excel and JSON records are excluded from that request and from the template file.

How automatic saving works

Automatic saving never turns a local template into a cloud template. A template opened from a .doklavio file remains local until you explicitly choose Save to account. Cloud templates periodically save unsaved design changes to the account, and shared Team templates also synchronize core canvas edits between current collaborators. Download the local file again when you want an updated copy on your computer.

Open a saved template

Open cloud templates from the workspace. For a local template file, select Open template file and choose the .doklavio file from your computer.

Teams, sharing and privacy

When you use the editor, customer data from CSV and JSON files stays in the current browser session. Opening a saved template starts without customer data, so you choose the data needed for that session. Imported PDF pages and image assets form part of the saved design, but Doklavio does not keep the original PDF as a separate upload.

API integrations send records to Doklavio over HTTPS for server-side processing. Synchronous input is processed in memory; async job input is held privately only while queued or processing. Generated PDFs are cached privately for idempotent replay and authenticated job download. Job input and output become eligible for cleanup within 24 hours. See API security and data handling for details.

A team uses one shared plan and document allowance. The team owner manages billing and seats. Members can work with team templates without maintaining separate copies.

Team templates

Visible to every current team member. Team members can open and edit the shared template.

Personal templates

Visible only to their creator. Other team members cannot find or open them, including the team owner.

Invite a member

The team owner sends an invitation by email. The person joins the team after accepting it in their workspace.

Share by email

Template sharing sends an invitation. The template is added only after the recipient accepts it.

Every team member can create templates. When starting with a blank page or importing a PDF, choose Local only, Personal or Team. A Local only template stays on that computer and cannot be collaboratively edited. A Personal template is visible only to its creator, not even the team owner. A Team template is available to everyone on the team. Cloud templates use the team owner's plan and usage limits. Only the creator can change access, share it by email or delete it while they remain a member.

If a member leaves or is removed, their Team templates are transferred to the team owner so the team keeps its shared work. Their Personal templates stay in their own account. The removed member receives a notice and can no longer open the team copies.

The owner can grant individual members permission to manage team members or API keys. These permissions do not transfer billing ownership and can be removed at any time.

PermissionYou own itAnother member owns it
View a team templateYesYes
Edit a team templateYesYes
View a personal templateYesNo
Make it personal or sharedYesNo
Share by emailYesNo
Delete the templateYesNo

Work on a template together

Several current team members can open the same shared cloud template at once. Doklavio shows who else is present and sends core canvas changes between their editors, including adding, deleting, moving, resizing and rotating objects. Finished text edits are also synchronized.

Presence

Collaborator avatars show who currently has the template open.

Object locks

When one person selects or edits an object, it is temporarily locked for everyone else and identifies who is working on it.

Cloud templates only

Live collaboration works on saved Team templates in the cloud. Local .doklavio files do not start a collaboration session.

Team access required

Only current members of the template's team can join. Personal templates remain private to their creator.

Plans and document usage

Your plan controls the number of templates, documents per month, records in one batch and available team seats. Current usage appears in the account panel.

  • One generated PDF record counts as one document.
  • A batch of 10 records counts as 10 documents.
  • Saving or editing a template does not use document allowance.
  • Team members use the team owner's shared document allowance.
  • The team owner can see how many documents each member generated during the current month.
  • Only the team owner can manage the team's plan and billing.

Open Usage & billing from account settings to compare monthly and annual plans, start an upgrade, manage an active Stripe subscription, buy a one-time document pack or control automatic API overage billing when the current plan supports it. Browser and editor generation never creates an automatic overage charge.

After a cancellation or downgrade

A scheduled cancellation keeps the paid plan active until the end of its current billing period. When the lower plan takes effect, Doklavio keeps existing templates, team membership and API-key records rather than deleting them automatically, but access is reduced to the new plan's limits.

  • API keys remain visible to the billing owner, but API requests are suspended while the plan does not include API access.
  • The team owner remains active. Members above the new seat limit are suspended and cannot use team templates or the owner's document allowance, but they can still open Team settings and leave.
  • Upgrading again restores eligible suspended seats and unexpired, non-revoked API keys. The owner can remove retained members or revoke retained keys at any time.

See the current plan limits on the pricing section.

Doklavio API v1

Use the REST API to list reusable templates and generate documents without opening the editor. Synchronous requests return one combined PDF; asynchronous jobs can instead return a ZIP containing one PDF per record. API access is available on Team and Business plans. Team is intended for normal team automation; Business is intended for production integrations that generate documents more often or from another product.

Base URLHTTPS only
https://api.doklavio.com/v1

Account isolation

Every key belongs to the billing owner's team. It can use the owner's templates and templates that current members explicitly share with that team, but never personal templates or another company's templates.

Synchronous PDFs

Send one record or a batch to POST /documents. A successful request returns one combined PDF in the response.

Asynchronous jobs

Send a larger batch to POST /jobs, poll its status and download the result after completion. An optional signed webhook can notify your server.

The API domain terminates TLS at a protected load-balancer edge with abuse throttling. The underlying Function origin does not accept direct internet traffic.

API quickstart

This server-side Node.js example completes the full integration flow: list accessible templates, select one, generate a PDF and save it locally. Use Node.js 18 or newer and provide the API key through your deployment platform's secrets manager.

EnvironmentDo not commit this value
DOKLAVIO_API_KEY=your_key_from_the_workspace
generate-document.mjsNode.js
import { randomUUID } from "node:crypto";
import { writeFile } from "node:fs/promises";

const baseUrl = "https://api.doklavio.com/v1";
const authorization = `Bearer ${process.env.DOKLAVIO_API_KEY}`;

const templatesResponse = await fetch(`${baseUrl}/templates?limit=25`, {
  headers: { Authorization: authorization }
});
if (!templatesResponse.ok) throw new Error(await templatesResponse.text());

const { templates } = await templatesResponse.json();
const template = templates[0];
if (!template) throw new Error("No API-accessible template is available.");

const body = JSON.stringify({
  template_id: template.id,
  template_owner_id: template.owner_id,
  data: {
    invoice_number: "DEMO-001",
    customer_name: "Demo Client One",
    total: 100
  }
});

const documentResponse = await fetch(`${baseUrl}/documents`, {
  method: "POST",
  headers: {
    Authorization: authorization,
    "Content-Type": "application/json",
    "Idempotency-Key": randomUUID()
  },
  body
});
if (!documentResponse.ok) throw new Error(await documentResponse.text());

await writeFile("invoice.pdf", Buffer.from(await documentResponse.arrayBuffer()));
console.log("Created invoice.pdf", documentResponse.headers.get("x-request-id"));

In production, select the intended template by a configured id and owner_id rather than taking the first result. Keep the same serialized request body and idempotency key when retrying an interrupted generation.

Security and API keys

The billing owner manages API keys by default and can grant selected members permission to create, rename, extend and revoke the team's keys. Creating and using a key requires an active Team or Business plan. After a downgrade to a plan without API access, existing keys remain visible and revocable but API authentication is suspended until an eligible plan is active again. An account can have up to 10 active keys. A key expires after 90 days by default; the workspace also offers 30, 180 and 365-day lifetimes.

ActionSecurity behavior
CreateName the integration and choose its lifetime. The complete key is shown once and cannot be recovered later.
ListShows safe metadata such as the key name, hint, status, creation, expiration and last use. It never returns the secret.
RevokeImmediately rejects the key. Revocation cannot be undone.

Protect every key

  • Store keys in a managed secrets service and inject them into the server process at runtime.
  • Never commit a key, place it in a URL, expose it to browser or mobile code, or write it to logs and error reports.
  • Use a separate named key for each deployed integration so one system can be rotated or revoked without affecting another.
  • Send the key only over HTTPS in the Authorization header.
Authentication headerEvery request
Authorization: Bearer ${DOKLAVIO_API_KEY}

Rendering and data handling

Before rendering, Doklavio sanitizes the stored template and escapes values from API records. Rendering runs in an isolated service with no access to your account data, database or stored credentials. JavaScript is disabled, and sanitization, Content Security Policy and request interception block the rendered document from loading an external script, image, font or other resource. Inline API-rendered images are limited to bounded PNG and JPEG rasters; animated formats are rejected.

Synchronous input records are processed in memory and are not persisted. An asynchronous job stores its validated input in private server storage only while it is queued or processing, then removes it when processing finishes; abandoned job input becomes eligible for cleanup after 24 hours. Generated PDFs are cached privately for replay and authenticated job download, become eligible for deletion after 24 hours and are never readable through Firebase client rules. Treat API output as temporary and retain your own copy for as long as your business requires it.

Secure onboarding

  1. Have the billing owner open API keys in the workspace account panel, then create a named key and choose an appropriate lifetime.
  2. Copy the key once into the integration's secrets manager.
  3. Call GET /templates and retain both the template id and owner_id from the response.
  4. Generate a test PDF with a unique Idempotency-Key, then retain the request ID for support and audit logs.

List templates

GET /templates returns templates owned by the billing owner plus member-owned templates explicitly shared with the team. Personal member templates and templates from other teams are excluded.

Query parameterUse
limitOptional page size from 1 to 100. The default is 50.
page_tokenOptional opaque token returned as next_page_token by the previous page. Pass it back unchanged.
Requestcurl
curl --fail-with-body \
  --url "https://api.doklavio.com/v1/templates?limit=25" \
  --header "Authorization: Bearer ${DOKLAVIO_API_KEY}"
Response200 JSON
{
  "templates": [
    {
      "id": "invoice_standard",
      "owner_id": "usr_example_member",
      "name": "Standard invoice",
      "page_count": 1,
      "updated_at": "2026-08-20T12:00:00.000Z"
    }
  ],
  "next_page_token": null
}

Generate PDFs

POST /documents accepts uncompressed JSON no larger than 1 MiB and returns a combined PDF synchronously. Compressed request bodies are not accepted. Send exactly one of data or records.

HeaderRequirement
AuthorizationBearer followed by the API key.
Idempotency-KeyA unique value of 8 to 128 characters using letters, numbers, ., _, ~ or -.
Content-TypeMust be application/json.
JSON fieldRequirement
template_idRequired template ID returned by GET /templates.
template_owner_idThe corresponding owner_id returned by GET /templates. Optional only for templates owned by the billing owner.
dataOne JSON object. Required when records is omitted.
recordsA non-empty array of JSON objects. Required when data is omitted and limited by plan.
filenameOptional PDF filename. Doklavio removes unsafe path and control characters.

One record

request.jsonJSON
{
  "template_id": "invoice_standard",
  "template_owner_id": "usr_example_member",
  "data": {
    "invoice": { "number": "DEMO-001", "currency": "EUR", "total": "100.00" },
    "customer": { "name": "Demo Client One" },
    "items": [
      { "description": "Example item", "quantity": 1, "price": "100.00", "total": "100.00" }
    ]
  }
}

Batch

A Team API request can contain up to 25 records and can run one PDF generation at a time. A Business API request can contain up to 100 records and can run two PDF generations at a time. This API request limit is separate from your plan's browser/editor batch size, which is much larger — see the pricing section for both numbers. Every record counts as one generated document and one API-generated document. Team includes 1,000 API-generated documents per month, Business includes 5,000. By default, going over returns 429 api_quota_exceeded until the period resets. From your workspace account panel, the billing owner can either buy a one-time document pack (100–1,000 documents, $0.02 each) to top up the current period instantly, or opt in to automatic overage billing: once enabled, extra documents are billed at $0.02 each with no per-request approval step, up to a monthly overage cap (500 extra for Team, 2,500 extra for Business). Reaching the cap returns 429 api_quota_exceeded again for the rest of the period — contact us to raise it.

request.jsonJSON
{
  "template_id": "invoice_standard",
  "template_owner_id": "usr_example_member",
  "records": [
    {
      "invoice": { "number": "DEMO-001", "currency": "EUR", "total": "100.00" },
      "customer": { "name": "Demo Client One" },
      "items": [{ "description": "Example item one", "quantity": 1, "price": "100.00", "total": "100.00" }]
    },
    {
      "invoice": { "number": "DEMO-002", "currency": "EUR", "total": "200.00" },
      "customer": { "name": "Demo Client Two" },
      "items": [{ "description": "Example item two", "quantity": 2, "price": "100.00", "total": "200.00" }]
    }
  ]
}
Generate and savecurl
curl --fail-with-body \
  --request POST \
  --url "https://api.doklavio.com/v1/documents" \
  --header "Authorization: Bearer ${DOKLAVIO_API_KEY}" \
  --header "Idempotency-Key: example-document-001" \
  --header "Content-Type: application/json" \
  --data-binary @request.json \
  --output invoices.pdf

A successful response has status 200 and content type application/pdf. The maximum output size is 25 MiB, and one request cannot render more than 500 pages. Non-success responses produced by the Doklavio API handler use the JSON error format below.

Idempotent retries

Use a new idempotency key for each logical generation. Repeating the request with the same API key, idempotency key and byte-identical body within 24 hours returns the privately cached PDF without generating or charging for the records again and sets X-Idempotent-Replay: true. Reusing that idempotency key with a different body returns 409 Conflict.

Asynchronous jobs and webhooks

Use POST /jobs when the caller should not hold one HTTP connection open while Doklavio renders. Job submissions accept the same template and data fields as POST /documents, plus optional output and webhook settings. A job can contain up to 500 records, while the finished result remains limited to 500 rendered pages and 25 MiB.

Choose the output

outputResultFilename behavior
combined_pdfOne PDF containing every record. This is the default.filename names the PDF.
zipOne ZIP containing a separate PDF for every record.filename names the ZIP. filename_pattern names each PDF.

A ZIP filename pattern can contain {{index}} or a scalar record path such as {{invoice.number}}. Unsafe filename characters are replaced, values cannot create folders, and duplicate names receive a numeric suffix.

Create a job

Requestcurl
curl --fail-with-body \
  --request POST \
  --url "https://api.doklavio.com/v1/jobs" \
  --header "Authorization: Bearer ${DOKLAVIO_API_KEY}" \
  --header "Idempotency-Key: example-async-job-001" \
  --header "Content-Type: application/json" \
  --data-binary @request.json
request.jsonReplace the example webhook host
{
  "template_id": "invoice_standard",
  "template_owner_id": "usr_example_member",
  "records": [
    { "invoice": { "number": "EXAMPLE-001", "total": "100.00" } },
    { "invoice": { "number": "EXAMPLE-002", "total": "200.00" } }
  ],
  "output": "zip",
  "filename": "example-invoices.zip",
  "filename_pattern": "invoice-{{invoice.number}}",
  "webhook_url": "https://hooks.your-domain.example/doklavio"
}

The response is 202 Accepted. Its Location header points to the status endpoint. If a webhook was requested, webhook_secret is returned with the job response; keep that per-job secret in server-side protected storage and use it to verify delivery signatures.

Response202 JSON
{
  "id": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "object": "document_job",
  "status": "queued",
  "progress": 0,
  "record_count": 2,
  "filename": "example-invoices.zip",
  "output": "zip",
  "webhook_configured": true,
  "webhook_secret": "whsec_store_this_per_job_secret"
}

Poll and download

Call GET /jobs/{job_id} with the API key. Status moves through queued, processing, then completed or failed. A completed response includes result_url. Download that URL with the same Authorization header; it is not a public signed link. The response is application/pdf for combined_pdf and application/zip for zip.

Poll and downloadcurl
curl --fail-with-body \
  --url "https://api.doklavio.com/v1/jobs/${JOB_ID}" \
  --header "Authorization: Bearer ${DOKLAVIO_API_KEY}"

curl --fail-with-body \
  --url "https://api.doklavio.com/v1/jobs/${JOB_ID}/result" \
  --header "Authorization: Bearer ${DOKLAVIO_API_KEY}" \
  --output example-invoices.zip

The result endpoint returns 409 job_not_complete while work is queued or processing, and 409 job_failed after a failed job. Repeating a failed submission with the same body and idempotency key returns the same failed job without reserving quota again; use a new idempotency key only when intentionally starting a new attempt. Job status, input and output become eligible for deletion after 24 hours.

Webhook requirements

  • The URL must use HTTPS on port 443, contain no embedded username, password or fragment, and resolve only to public IP addresses. Redirects are not followed.
  • Return a 2xx response within 10 seconds. Doklavio attempts a failed delivery up to three times.
  • Read the unmodified request bytes before parsing JSON. Verify Doklavio-Signature, which contains t=timestamp,v1=signature, using HMAC-SHA256 over timestamp + "." + rawBody.
  • Reject stale timestamps according to your own replay window and compare signatures with a constant-time function.
  • The Doklavio-Event header is document_job.completed or document_job.failed. Webhook bodies contain job metadata but never the API key or input records.
Verify a webhookNode.js
import { createHmac, timingSafeEqual } from "node:crypto";

function verifyDoklavioWebhook(rawBody, signatureHeader, secret) {
  const values = Object.fromEntries(signatureHeader.split(",").map(part => part.split("=")));
  const timestamp = Number(values.t);
  if (!Number.isFinite(timestamp) || Math.abs(Date.now() / 1000 - timestamp) > 300) return false;

  const expected = createHmac("sha256", secret)
    .update(`${values.t}.`)
    .update(rawBody)
    .digest("hex");
  const actual = Buffer.from(values.v1 || "", "hex");
  const trusted = Buffer.from(expected, "hex");
  return actual.length === trusted.length && timingSafeEqual(actual, trusted);
}

Errors, retries and rate limits

Every error produced by the Doklavio API handler has the same envelope. Include its request ID when contacting support, but do not include the API key or customer data.

Error responseJSON
{
  "error": {
    "code": "invalid_request",
    "message": "Provide exactly one of data or records.",
    "request_id": "00000000-0000-4000-8000-000000000000"
  }
}
StatusMeaningRetry
400The query, headers or JSON body are invalid.Correct the request.
401The key is missing, malformed, expired or revoked.Use a current key.
403The account does not have active API access on its current plan.Do not retry unchanged.
404The route or an accessible template was not found.Check the URL or template ID.
405The HTTP method is not supported by the route.Use the documented method.
409An idempotency key conflicts, a synchronous request is still processing, or an async result is not available.For request_in_progress or job_not_complete, wait for Retry-After. For idempotency_conflict, use a new key only for a new operation. Inspect the job status after job_failed.
413The request body or generated PDF/ZIP exceeds its byte limit.Reduce the request or output.
415The content type or content encoding is unsupported.Send uncompressed application/json.
422The saved template cannot be rendered safely through the API.Correct and resave the template.
429The durable request rate limit, monthly document quota, or the monthly API document allowance was reached.For rate_limit_exceeded, wait for Retry-After. For quota_exceeded, wait for the allowance to reset or change plans. For api_quota_exceeded, you've used your included API documents (and, if automatic overage billing is enabled, the overage cap too) — wait for the period to reset, enable overage billing from your workspace account panel, or contact us to raise the cap.
500 or 503Doklavio could not complete the request safely.Retry with bounded exponential backoff.

Doklavio's network edge can reject or terminate a request before it reaches the API handler. Those edge or network failures might be non-JSON and might not include X-Request-Id. Treat the result of an interrupted POST as indeterminate and retry with the identical API key, raw body and Idempotency-Key; never invent a new key for an ambiguous retry.

Per-minute limits

Durable counters apply to both the individual key and its billing-owner account. Creating a PDF counts against both the total request limit and the smaller generation limit. Business has higher API throughput because production integrations can create more renderer load than normal workspace use.

PlanAll API requestsPDF generations
Team60 per minute10 per minute
Business240 per minute30 per minute
PlanIncluded API-generated documentsSynchronous batchAsync job batchConcurrent renders
Team1,000 per month25 records500 records1
Business5,000 per month100 records500 records2

To keep rendering capacity fair between companies, a Team account can run one PDF generation at a time and a Business account can run two. An additional synchronous generation receives 429 render_concurrency_exceeded with Retry-After; accepted async jobs wait in the queue instead. Template-list and job-status requests remain available while a PDF is rendering.

Response headers

HeaderUse
X-Request-IdUnique request identifier returned on every response. Keep it in operational logs.
X-RateLimit-LimitOne-minute limit applied to the current request.
X-RateLimit-RemainingRequests remaining in the current window.
X-RateLimit-ResetWindow reset time as a Unix timestamp in seconds.
Retry-AfterSeconds to wait after rate_limit_exceeded or request_in_progress.
X-Idempotent-ReplaySet to true when a successful PDF is returned from the private replay cache.

For a document retry, keep the original API key, raw body bytes and Idempotency-Key. A different credential has a separate replay scope, while changing the body under the original credential causes a conflict.

Rotate and revoke keys

  1. Create a second named key before the current key expires.
  2. Store the replacement in the integration's secrets manager and deploy it to every instance.
  3. Let in-flight retries finish, then confirm the replacement is being used and the old key's last-used time has stopped changing.
  4. Revoke the old key and verify that it now receives 401.

The replay cache is scoped to the API key. Repeating an old request under the replacement credential creates a new generation and consumes document allowance again.

Production checklist

  • Keep the credential in a secrets manager with access limited to the integration runtime.
  • Alert well before the key expiration date and rotate on a regular schedule.
  • Use request IDs in operational logs while excluding Authorization headers and document data.
  • Set explicit request timeouts and stream the PDF response directly to its approved destination.
  • Retry only the documented statuses, honor Retry-After and use the same idempotency key and body for a replay.
  • For async jobs, protect the per-job webhook secret, verify the raw-body signature and timestamp before acting, and download results from your backend with Authorization.

Common questions

Why is a data field missing?

Check that the field exists in the uploaded CSV header or JSON structure. If you changed the data file, upload the latest version and search the field list again.

Why can I not edit text from an imported PDF?

The PDF may be a scanned image or its text may have been converted to outlines. Keep the page as the visual base and add editable text or fields over it.

Why is a team template not visible?

Refresh the workspace and make sure the template is marked Team rather than Personal. Personal templates are visible only to their creator, including when another person owns the team.

Can several team members edit one template at the same time?

Yes, when it is a shared Team template saved in the cloud. Doklavio shows active collaborators, synchronizes core canvas changes and temporarily locks an object while someone is working on it. Local .doklavio files and Personal templates do not provide team collaboration.

Who can use an uploaded image?

Signed-in uploads are saved to the billing owner's shared team image library. Every active member can reuse them across team and personal templates while they belong to that team. Removing an image from the library does not remove copies already placed inside saved templates.

How do dynamic images, QR codes and barcodes work?

Add the visual from Elements and choose its source field under Properties, Data behavior. Dynamic images accept inline PNG or JPEG data URLs only; QR codes accept up to 134 UTF-8 bytes; Code 128 barcodes accept 1–120 printable ASCII characters. All three change for each record and work in browser and API output.

Can I try Doklavio without creating an account?

Yes. Choose Try the live demo on the homepage. It uses sample invoice data and can export up to three documents at a time. PDF creation runs locally in the browser without calling the Doklavio API, reading account templates or consuming server-side document quota.

What happens to members and API keys after a downgrade?

Doklavio retains them so a temporary downgrade does not destroy the setup. Seats above the new limit and API access are suspended. Suspended members can still open Team settings and leave. The owner can remove members or revoke keys, and an upgrade restores eligible seats and unexpired keys.

Why is PDF generation unavailable?

Make sure at least one record is selected and that the account still has documents available for the current month.

Does saving overwrite the finished PDFs?

No. Templates and generated PDFs are separate. Saving updates the reusable template, while exporting creates new finished files.

Which templates can an API key use?

An API key can use templates owned by its billing owner and templates that current members explicitly mark as Team. It cannot use Personal member templates or anything belonging to another team. Use both id and owner_id from GET /templates when selecting a member-owned template.

Why does the API return 401?

The key is missing, malformed, expired or revoked. Doklavio deliberately returns the same generic response for these cases. Create or deploy a current key, and never send it in a URL or browser application.

Why does the API return 409?

request_in_progress means the original request is still running; wait for Retry-After and retry with the identical key and body. idempotency_conflict means the same Idempotency-Key was used with different request bytes.

How should an interrupted API generation be retried?

Keep the original API key, exact serialized body and Idempotency-Key. A platform or network interruption can make the outcome uncertain, so do not invent a new idempotency key. Use bounded exponential backoff and retain the returned X-Request-Id.

How long is an API-generated PDF retained?

The private copy exists only for idempotent replay and authenticated async-job download. It becomes eligible for deletion after 24 hours and scheduled cleanup removes expired output. Save the successful response in your own approved destination.

Can Doklavio call our webhook when a PDF is ready?

Yes. Submit the generation through POST /jobs with a public HTTPS webhook_url, store the returned per-job webhook secret and verify every raw-body signature before trusting the event. You can also poll GET /jobs/{job_id} without configuring a webhook.

Where can I find Doklavio's legal and data-processing information?

The site footer links to the Privacy Policy, Terms of Use, Cookie Policy and Data Processing Agreement.