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.
Start with a blank page, import a PDF you already use or open a Doklavio template file.
Upload CSV or JSON data and place its fields into the document.
Move through the live preview and confirm that names, totals and layouts look right.
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
| Action | What it does |
|---|---|
| Open | Loads the editable template in the editor. |
| Make personal | Removes your template from the shared team view. Only you can see it. |
| Share with team | Makes your template available to every current team member. |
| Share by email | Sends a template invitation that the recipient must accept. |
| Delete | Permanently 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.
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.
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.
[
{
"customer": { "name": "Demo Client One" },
"invoice": { "number": "DEMO-001", "total": 100 },
"items": [
{ "description": "Consulting", "quantity": 4, "price": 120 }
]
}
]
Place a field in the document
- Find the field in the Data panel.
- Drag it onto the page, into a text block or into a table cell.
- 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
itemsonto 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.phoneis 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.
| Permission | You own it | Another member owns it |
|---|---|---|
| View a team template | Yes | Yes |
| Edit a team template | Yes | Yes |
| View a personal template | Yes | No |
| Make it personal or shared | Yes | No |
| Share by email | Yes | No |
| Delete the template | Yes | No |
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.
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.
DOKLAVIO_API_KEY=your_key_from_the_workspace
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.
| Action | Security behavior |
|---|---|
| Create | Name the integration and choose its lifetime. The complete key is shown once and cannot be recovered later. |
| List | Shows safe metadata such as the key name, hint, status, creation, expiration and last use. It never returns the secret. |
| Revoke | Immediately 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
Authorizationheader.
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
- Have the billing owner open API keys in the workspace account panel, then create a named key and choose an appropriate lifetime.
- Copy the key once into the integration's secrets manager.
- Call
GET /templatesand retain both the templateidandowner_idfrom the response. - 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 parameter | Use |
|---|---|
limit | Optional page size from 1 to 100. The default is 50. |
page_token | Optional opaque token returned as next_page_token by the previous page. Pass it back unchanged. |
curl --fail-with-body \
--url "https://api.doklavio.com/v1/templates?limit=25" \
--header "Authorization: Bearer ${DOKLAVIO_API_KEY}"
{
"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.
| Header | Requirement |
|---|---|
Authorization | Bearer followed by the API key. |
Idempotency-Key | A unique value of 8 to 128 characters using letters, numbers, ., _, ~ or -. |
Content-Type | Must be application/json. |
| JSON field | Requirement |
|---|---|
template_id | Required template ID returned by GET /templates. |
template_owner_id | The corresponding owner_id returned by GET /templates. Optional only for templates owned by the billing owner. |
data | One JSON object. Required when records is omitted. |
records | A non-empty array of JSON objects. Required when data is omitted and limited by plan. |
filename | Optional PDF filename. Doklavio removes unsafe path and control characters. |
One record
{
"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.
{
"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" }]
}
]
}
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
output | Result | Filename behavior |
|---|---|---|
combined_pdf | One PDF containing every record. This is the default. | filename names the PDF. |
zip | One 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
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
{
"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.
{
"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.
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
2xxresponse within 10 seconds. Doklavio attempts a failed delivery up to three times. - Read the unmodified request bytes before parsing JSON. Verify
Doklavio-Signature, which containst=timestamp,v1=signature, using HMAC-SHA256 overtimestamp + "." + rawBody. - Reject stale timestamps according to your own replay window and compare signatures with a constant-time function.
- The
Doklavio-Eventheader isdocument_job.completedordocument_job.failed. Webhook bodies contain job metadata but never the API key or input records.
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": {
"code": "invalid_request",
"message": "Provide exactly one of data or records.",
"request_id": "00000000-0000-4000-8000-000000000000"
}
}
| Status | Meaning | Retry |
|---|---|---|
| 400 | The query, headers or JSON body are invalid. | Correct the request. |
| 401 | The key is missing, malformed, expired or revoked. | Use a current key. |
| 403 | The account does not have active API access on its current plan. | Do not retry unchanged. |
| 404 | The route or an accessible template was not found. | Check the URL or template ID. |
| 405 | The HTTP method is not supported by the route. | Use the documented method. |
| 409 | An 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. |
| 413 | The request body or generated PDF/ZIP exceeds its byte limit. | Reduce the request or output. |
| 415 | The content type or content encoding is unsupported. | Send uncompressed application/json. |
| 422 | The saved template cannot be rendered safely through the API. | Correct and resave the template. |
| 429 | The 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 503 | Doklavio 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.
| Plan | All API requests | PDF generations |
|---|---|---|
| Team | 60 per minute | 10 per minute |
| Business | 240 per minute | 30 per minute |
| Plan | Included API-generated documents | Synchronous batch | Async job batch | Concurrent renders |
|---|---|---|---|---|
| Team | 1,000 per month | 25 records | 500 records | 1 |
| Business | 5,000 per month | 100 records | 500 records | 2 |
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
| Header | Use |
|---|---|
X-Request-Id | Unique request identifier returned on every response. Keep it in operational logs. |
X-RateLimit-Limit | One-minute limit applied to the current request. |
X-RateLimit-Remaining | Requests remaining in the current window. |
X-RateLimit-Reset | Window reset time as a Unix timestamp in seconds. |
Retry-After | Seconds to wait after rate_limit_exceeded or request_in_progress. |
X-Idempotent-Replay | Set 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
- Create a second named key before the current key expires.
- Store the replacement in the integration's secrets manager and deploy it to every instance.
- Let in-flight retries finish, then confirm the replacement is being used and the old key's last-used time has stopped changing.
- 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-Afterand 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.