Skip to main content

Templates

Upload and reuse document templates (PDF, Word, Excel) to automatically fill them with data.

Overview

Templates allow you to treat documents as reusable forms. You upload a document once, and DocuDevs analyzes it to find fillable fields. You can then fill these templates repeatedly with new data via the API.

For PDFs, there are two distinct workflows:

  • Template workflow: upload a reusable AcroForm PDF, inspect field names, and fill it repeatedly.
  • Metadata workflow: inspect AcroForm fields, widgets, and page coordinates for an existing PDF without creating a reusable template. See AcroForm Metadata for Existing PDFs.
  • Conversion workflow: start from a normal PDF, run the pdf-acroform operation to generate a fillable AcroForm PDF, inspect editable field definitions, and optionally regenerate the PDF after review. See PDF AcroForm Conversion.

Supported Formats:

  • PDF Forms: Standard AcroForms.
  • Word Documents: .docx files with placeholders or content controls.
  • Excel Spreadsheets: .xlsx files.
  • PowerPoint Presentations: .pptx files.

Managing Templates

Uploading a Template

Upload a document to create a new template. DocuDevs stores the template immediately, then prepares PDF field metadata in the background when the file is an AcroForm PDF.

from docudevs import DocuDevsClient
import os
import asyncio

client = DocuDevsClient(token=os.getenv('API_KEY'))

async def upload_invoice_template():
with open('invoice_template.pdf', 'rb') as f:
response = await client.upload_template(
name="invoice",
document=f.read(),
file_name="invoice_template.pdf",
mime_type="application/pdf"
)

print(f"Upload status: {response.status_code}")

fields = await client.wait_for_template_metadata(
"invoice",
timeout=60,
poll_interval=1,
)
print(fields)

# asyncio.run(upload_invoice_template())

Listing Templates

Get a list of all available templates in your organization.

templates = await client.list_templates()
for template in templates:
print(f"Name: {template.name}, Created: {template.created_at}")

Inspecting Template Metadata

Retrieve details about a specific template, including its fillable fields.

For PDF templates, GET /template/metadata/{name} returns 202 Accepted with Retry-After: 1 while field extraction is still pending. The Python SDK helper wait_for_template_metadata(...) handles this polling for you.

fields = await client.wait_for_template_metadata(
"invoice",
timeout=60,
poll_interval=1,
)

for field in fields:
print(f"- {field['name']} ({field['type']})")

Deleting a Template

Remove a template when it is no longer needed.

await client.delete_template("invoice")

Filling Templates

Once a template is uploaded, you can fill it with data. The data structure depends on the template type.

If you fill a template immediately after upload, prefer fill_with_retry(...) in the Python SDK. It retries transient readiness races while background template preparation finishes.

Filling a PDF Form

PDF forms typically use a flat dictionary of field names and values.

from docudevs.models import TemplateFillRequest

async def fill_invoice():
fill_request = TemplateFillRequest(
fields={
"customerName": "Acme Corp",
"invoiceNumber": "INV-2024-001",
"totalAmount": "1500.00",
"paid": True
}
)

response = await client.fill_with_retry(
name="invoice",
body=fill_request,
timeout=30,
poll_interval=1,
)

# Save the filled PDF
with open("filled_invoice.pdf", "wb") as f:
f.write(response.content)

# asyncio.run(fill_invoice())

Filling a Word Template with Tables

Word templates support nested data structures, allowing you to fill tables and repeated sections.

async def fill_report():
fill_request = TemplateFillRequest(
fields={
"reportTitle": "Quarterly Sales",
"date": "2024-04-01",
"items": [
{"product": "Widget A", "sales": 100, "revenue": 5000},
{"product": "Widget B", "sales": 200, "revenue": 8000},
{"product": "Widget C", "sales": 50, "revenue": 2500}
],
"summary": {
"totalRevenue": 15500,
"growth": "15%"
}
}
)

response = await client.fill(name="sales_report", body=fill_request)

with open("filled_report.docx", "wb") as f:
f.write(response.content)

AcroForm Metadata for Existing PDFs

Use AcroForm metadata when you need field IDs, widget IDs, page numbers, or page-anchor coordinates from an existing fillable PDF.

  • Use the direct metadata endpoint when you only need the AcroForm structure.
  • Use the async job flow when you also need processed-job images, source locations, extraction, or overlays tied to a job GUID.

The direct endpoint accepts PDF uploads only. Non-PDF uploads return 400 Bad Request. A normal PDF without an AcroForm still returns 200 OK with fields: [].

If the source PDF is visually form-like but fields comes back empty, the document does not already contain embedded AcroForm widgets. In that case, use the pdf-acroform operation to generate a new fillable PDF and inspect its editable field definitions. The full conversion and review loop is documented in Operations.

import json

with open("fillable-form.pdf", "rb") as f:
pdf_bytes = f.read()

direct_metadata = await client.extract_acroform_metadata(
document=pdf_bytes,
file_name="fillable-form.pdf",
mime_type="application/pdf",
)

print(f"Direct fields: {len(direct_metadata.get('fields', []))}")
print(json.dumps(direct_metadata.get("fields", [])[:3], indent=2))

job_guid = await client.submit_and_process_document(
document=pdf_bytes,
document_mime_type="application/pdf",
acro_form_metadata=True,
source_locations=True,
source_location_granularity="block",
)

job_metadata = await client.get_acroform_metadata(job_guid)
source_locations = await client.get_source_locations(job_guid)

print(f"Async metadata fields: {len(job_metadata.get('fields', []))}")
print(source_locations)

For OCR-backed evidence overlays on the same job, combine acro_form_metadata=True with source_locations=True and then read Source Locations.

Best Practices

  • Field Naming: Use clear, consistent names for your form fields (e.g., camelCase like customerName).
  • Testing: Upload your template and inspect the metadata to ensure all fields are detected correctly.
  • Data Types: Ensure the data you send matches the expected type (e.g., booleans for checkboxes).
  • Configurations: Combine templates with Named Configurations to standardize the filling process if you have complex logic.