Templates API
Create documents from reusable templates via API.
This guide may not reflect the latest endpoints or parameters. For an always up-to-date reference, see the OpenAPI Reference.
Use a Template Envelope
New integrations should create a document from a template envelope with the Envelope API.
POST /envelope/use
Content-Type: multipart/form-dataThe request uses multipart/form-data:
| Part | Type | Required | Description |
|---|---|---|---|
payload | JSON | Yes | Template envelope ID, recipient details, and document settings |
files | File(s) | No | Replacement PDFs referenced by entries in customDocumentData |
Payload Schema
| Field | Type | Required | Description |
|---|---|---|---|
envelopeId | string | Yes | ID of the template envelope |
externalId | string | No | Your identifier for the created document envelope |
recipients | array | No | Recipient details mapped to recipients in the template |
distributeDocument | boolean | No | If true, create the document as pending and distribute it |
customDocumentData | array | No | Maps uploaded replacement PDFs to template envelope items |
folderId | string | No | Folder in which to create the document |
prefillFields | array | No | Field values to prefill before distribution |
override | object | No | Template values to override for the created document |
attachments | array | No | Link attachments to add to the document |
formValues | object | No | PDF form values to apply |
Each recipient entry accepts the following fields:
| Field | Type | Required | Description |
|---|---|---|---|
id | number | Yes | Recipient ID from the template envelope |
email | string | Yes | Recipient email address |
name | string | No | Recipient display name |
signingOrder | number | No | Recipient position in sequential signing |
Each customDocumentData entry maps an uploaded file to a template item:
| Field | Type | Required | Description |
|---|---|---|---|
identifier | string | number | Yes | Uploaded filename or zero-based file index |
envelopeItemId | string | Yes | Template envelope item whose PDF the uploaded file replaces |
Code Examples
curl -X POST "https://app.documenso.com/api/v2/envelope/use" \
-H "Authorization: api_xxxxxxxxxxxxxxxx" \
-F 'payload={
"envelopeId": "envelope_template123",
"externalId": "contract-2025-001",
"recipients": [
{
"id": 1,
"email": "john.doe@example.com",
"name": "John Doe"
}
],
"prefillFields": [
{
"id": 101,
"type": "text",
"value": "Senior Software Engineer"
}
],
"distributeDocument": false
}'Response
{
"id": "envelope_document123",
"recipients": [
{
"id": 1,
"name": "John Doe",
"email": "john.doe@example.com",
"token": "recipient_token",
"role": "SIGNER",
"signingOrder": 1,
"signingUrl": "https://app.documenso.com/sign/recipient_token"
}
]
}Distribute the Created Envelope
If you leave distributeDocument unset or set it to false, distribute the created document with
POST /envelope/distribute. Its response confirms delivery and includes each recipient's signing URL.
const distributionResponse = await fetch(
'https://app.documenso.com/api/v2/envelope/distribute',
{
method: 'POST',
headers: {
Authorization: 'api_xxxxxxxxxxxxxxxx',
'Content-Type': 'application/json',
},
body: JSON.stringify({
envelopeId: document.id,
}),
},
);
const distribution = await distributionResponse.json();
console.log('Signing URL:', distribution.recipients[0].signingUrl);{
"success": true,
"id": "envelope_document123",
"recipients": [
{
"id": 1,
"name": "John Doe",
"email": "john.doe@example.com",
"token": "recipient_token",
"role": "SIGNER",
"signingOrder": 1,
"signingUrl": "https://app.documenso.com/sign/recipient_token"
}
]
}Deprecated Template Endpoint Reference
Every /template/* endpoint below is deprecated. Use the Envelope API for new integrations and
follow Migrating to Envelopes to replace existing calls.
The legacy reference remains here to support migrations.
Legacy Template Object
A template object contains the following properties:
| Property | Type | Description |
|---|---|---|
id | number | Unique template identifier |
envelopeId | string | Associated envelope ID |
type | string | Template type: PRIVATE or PUBLIC |
visibility | string | Who can view: EVERYONE, ADMIN, MANAGER_AND_ABOVE |
title | string | Template title |
externalId | string | null | Your custom identifier |
publicTitle | string | null | Public-facing title (for public templates) |
publicDescription | string | null | Public-facing description (for public templates) |
userId | number | Owner's user ID |
teamId | number | null | Team ID if team-owned |
folderId | string | null | Folder containing the template |
createdAt | string | ISO 8601 timestamp |
updatedAt | string | ISO 8601 timestamp |
recipients | array | Predefined recipients with roles and fields |
fields | array | Signature and form fields on the template |
templateMeta | object | Email settings, signing options, redirect URL |
directLink | object | null | Direct link configuration if enabled |
Example Template Object
{
"id": 123,
"envelopeId": "envelope_abc123xyz",
"type": "PRIVATE",
"visibility": "EVERYONE",
"title": "Employment Contract",
"externalId": "template-emp-001",
"publicTitle": null,
"publicDescription": null,
"userId": 1,
"teamId": 5,
"folderId": null,
"createdAt": "2025-01-10T08:00:00.000Z",
"updatedAt": "2025-01-10T08:30:00.000Z",
"recipients": [
{
"id": 1,
"email": "employee@example.com",
"name": "Employee",
"role": "SIGNER",
"signingOrder": 1
},
{
"id": 2,
"email": "hr@company.com",
"name": "HR Manager",
"role": "SIGNER",
"signingOrder": 2
}
],
"fields": [
{
"id": 101,
"type": "SIGNATURE",
"page": 1,
"positionX": 10,
"positionY": 80,
"width": 30,
"height": 5,
"recipientId": 1
}
],
"templateMeta": {
"subject": "Your Employment Contract",
"message": "Please review and sign your employment contract.",
"redirectUrl": "https://example.com/welcome"
},
"directLink": null
}List Templates (Deprecated)
Retrieve a paginated list of templates.
GET /templateQuery Parameters
| Parameter | Type | Description |
|---|---|---|
page | integer | Page number (default: 1) |
perPage | integer | Results per page (default: 10, max: 100) |
type | string | Filter by type: PRIVATE or PUBLIC |
folderId | string | Filter by folder ID |
orderByColumn | string | Sort field (only createdAt supported) |
orderByDirection | string | Sort direction: asc or desc (default: desc) |
Code Examples
# List all templates
curl -X GET "https://app.documenso.com/api/v2/template" \
-H "Authorization: api_xxxxxxxxxxxxxxxx"
# Filter by type and paginate
curl -X GET "https://app.documenso.com/api/v2/template?type=PRIVATE&page=1&perPage=20" \
-H "Authorization: api_xxxxxxxxxxxxxxxx"
Response
{
"data": [
{
"id": 123,
"envelopeId": "envelope_abc123",
"type": "PRIVATE",
"title": "Employment Contract",
"createdAt": "2025-01-10T08:00:00.000Z",
"updatedAt": "2025-01-10T08:30:00.000Z",
"recipients": [
{
"id": 1,
"email": "employee@example.com",
"name": "Employee",
"role": "SIGNER"
}
]
}
],
"count": 25,
"currentPage": 1,
"perPage": 10,
"totalPages": 3
}Get Template (Deprecated)
Retrieve a single template by ID.
GET /template/{templateId}Path Parameters
| Parameter | Type | Description |
|---|---|---|
templateId | number | The template ID |
Code Examples
curl -X GET "https://app.documenso.com/api/v2/template/123" \
-H "Authorization: api_xxxxxxxxxxxxxxxx"Response
Returns the full template object including recipients, fields, and metadata.
Create Document from Template (Deprecated)
Create a new document using the deprecated template endpoint.
This endpoint does not support PDF placeholder parsing. Use POST /envelope/create for placeholder-based field positioning.
POST /template/use
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
templateId | number | Yes | The template ID to use |
recipients | array | Yes | Recipient details (maps to template recipients) |
distributeDocument | boolean | No | If true, immediately send the document to recipients |
externalId | string | No | Your custom identifier for the created document |
folderId | string | No | Folder ID to create the document in |
prefillFields | array | No | Pre-fill field values before sending |
override | object | No | Override template settings for this document |
formValues | object | No | PDF form values to insert |
Recipients Array
Each recipient object must include:
| Field | Type | Required | Description |
|---|---|---|---|
id | number | Yes | The recipient ID from the template |
email | string | Yes | Recipient's email address |
name | string | No | Recipient's display name |
Code Examples
# Create document from template
curl -X POST "https://app.documenso.com/api/v2/template/use" \
-H "Authorization: api_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"templateId": 123,
"recipients": [
{
"id": 1,
"email": "john.doe@example.com",
"name": "John Doe"
},
{
"id": 2,
"email": "jane.smith@company.com",
"name": "Jane Smith"
}
],
"distributeDocument": true,
"externalId": "contract-2025-001"
}'
# Create document with field prefilling
curl -X POST "https://app.documenso.com/api/v2/template/use" \
-H "Authorization: api_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"templateId": 123,
"recipients": [
{
"id": 1,
"email": "john.doe@example.com",
"name": "John Doe"
}
],
"prefillFields": [
{
"id": 101,
"type": "text",
"value": "Senior Software Engineer"
},
{
"id": 102,
"type": "number",
"value": "85000"
},
{
"id": 103,
"type": "date",
"value": "2025-02-01"
}
],
"distributeDocument": true
}'Response
The endpoint returns the full legacy document object. The selected fields below show both the numeric
legacy id and canonical envelopeId. Recipient entries do not include a signingUrl.
{
"id": 789,
"envelopeId": "envelope_xyz789",
"status": "PENDING",
"source": "TEMPLATE",
"title": "Employment Contract",
"externalId": "contract-2025-001",
"recipients": [
{
"id": 1,
"envelopeId": "envelope_xyz789",
"documentId": 789,
"templateId": null,
"email": "john.doe@example.com",
"name": "John Doe",
"role": "SIGNER",
"signingStatus": "NOT_SIGNED",
"signingOrder": 1
}
]
}To send a document created with distributeDocument: false and receive signing links, call
POST /envelope/distribute with its envelopeId:
const document = await response.json();
const distributionResponse = await fetch(`${BASE_URL}/envelope/distribute`, {
method: 'POST',
headers: {
Authorization: API_TOKEN,
'Content-Type': 'application/json',
},
body: JSON.stringify({
envelopeId: document.envelopeId,
}),
});
const distribution = await distributionResponse.json();
console.log('Signing URL:', distribution.recipients[0].signingUrl);Override Template Settings (Deprecated)
When creating a document from a template, you can override various settings:
const response = await fetch(`${BASE_URL}/template/use`, {
method: 'POST',
headers: {
Authorization: API_TOKEN,
'Content-Type': 'application/json',
},
body: JSON.stringify({
templateId: 123,
recipients: [{ id: 1, email: 'signer@example.com', name: 'Signer' }],
override: {
title: 'Custom Document Title',
subject: 'Custom email subject',
message: 'Custom email message body',
timezone: 'America/New_York',
dateFormat: 'MM/dd/yyyy',
redirectUrl: 'https://example.com/custom-redirect',
language: 'de',
typedSignatureEnabled: true,
uploadSignatureEnabled: false,
drawSignatureEnabled: true,
},
distributeDocument: true,
}),
});Override Options
| Field | Type | Description |
|---|---|---|
title | string | Document title |
subject | string | Email subject line |
message | string | Email body message |
timezone | string | Timezone for date fields |
dateFormat | string | Date format string |
redirectUrl | string | URL to redirect after signing |
language | string | Document language code |
typedSignatureEnabled | boolean | Allow typed signatures |
uploadSignatureEnabled | boolean | Allow uploaded signature images |
drawSignatureEnabled | boolean | Allow drawn signatures |
Prefill Fields (Deprecated)
Prefill field values when creating a document from a template. This is useful for populating known data before sending.
Supported Field Types
| Type | Value Format | Description |
|---|---|---|
text | string | Text field value |
number | string | Numeric value as string |
date | string (ISO 8601) | Date in YYYY-MM-DD format |
radio | string | Selected option value |
checkbox | array of strings | Array of checked option values |
dropdown | string | Selected dropdown value |
Prefill Field Schema
type PrefillField = {
id: number; // Field ID from template
type: string; // Field type (must match template field)
label?: string; // Optional label override
placeholder?: string; // Optional placeholder (text/number only)
value: string | string[]; // Value to prefill
};Example: Prefill Multiple Field Types
const response = await fetch(`${BASE_URL}/template/use`, {
method: 'POST',
headers: {
Authorization: API_TOKEN,
'Content-Type': 'application/json',
},
body: JSON.stringify({
templateId: 123,
recipients: [{ id: 1, email: 'signer@example.com', name: 'Signer' }],
prefillFields: [
// Text field
{
id: 101,
type: 'text',
value: 'John Doe',
},
// Number field
{
id: 102,
type: 'number',
value: '50000',
},
// Date field
{
id: 103,
type: 'date',
value: '2025-03-15',
},
// Radio field (select one option)
{
id: 104,
type: 'radio',
value: 'full-time',
},
// Checkbox field (select multiple options)
{
id: 105,
type: 'checkbox',
value: ['health', 'dental', '401k'],
},
// Dropdown field
{
id: 106,
type: 'dropdown',
value: 'engineering',
},
],
distributeDocument: true,
}),
});The field type in prefillFields must match the actual field type in the template. A mismatch
will result in an error.
Update Template (Deprecated)
Update a template's properties.
POST /template/updateRequest Body
| Field | Type | Required | Description |
|---|---|---|---|
templateId | number | Yes | Template ID |
data | object | No | Template properties to update |
meta | object | No | Email and signing settings to update |
Code Examples
curl -X POST "https://app.documenso.com/api/v2/template/update" \
-H "Authorization: api_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"templateId": 123,
"data": {
"title": "Updated Employment Contract",
"visibility": "ADMIN"
},
"meta": {
"subject": "Updated: Your Employment Contract",
"redirectUrl": "https://example.com/updated-redirect"
}
}'Duplicate Template (Deprecated)
Create a copy of an existing template.
POST /template/duplicate
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
templateId | number | Yes | Template ID |
Code Examples
curl -X POST "https://app.documenso.com/api/v2/template/duplicate" \
-H "Authorization: api_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"templateId": 123
}'Delete Template (Deprecated)
Delete a template.
POST /template/delete
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
templateId | number | Yes | Template ID |
Code Examples
curl -X POST "https://app.documenso.com/api/v2/template/delete" \
-H "Authorization: api_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"templateId": 123
}'Response
{
"success": true
}Direct Link Templates (Deprecated)
Direct link templates allow recipients to create and sign documents without requiring you to explicitly create each document. When a recipient visits the direct link, a new document is automatically created from the template.
Create Direct Link
POST /template/direct/create| Field | Type | Required | Description |
|---|---|---|---|
templateId | number | Yes | Template ID |
directRecipientId | number | No | Recipient ID to use as the direct link signer |
curl -X POST "https://app.documenso.com/api/v2/template/direct/create" \
-H "Authorization: api_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"templateId": 123,
"directRecipientId": 1
}'Response
{
"id": 456,
"token": "abc123xyz",
"templateId": 123,
"directTemplateRecipientId": 1,
"enabled": true,
"createdAt": "2025-01-15T10:00:00.000Z"
}Toggle Direct Link
Enable or disable an existing direct link.
POST /template/direct/togglecurl -X POST "https://app.documenso.com/api/v2/template/direct/toggle" \
-H "Authorization: api_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"templateId": 123,
"enabled": false
}'Delete Direct Link
POST /template/direct/delete
curl -X POST "https://app.documenso.com/api/v2/template/direct/delete" \
-H "Authorization: api_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"templateId": 123
}'Custom Document Data (Deprecated)
When creating a document from a template, you can replace the template's PDF with a custom PDF by using the customDocumentData parameter. This is useful when you need to generate the PDF dynamically while reusing the template's recipient and field configuration.
To use custom document data:
- Retrieve the template to get the
envelopeItemIdof the PDF you want to replace - Include
customDocumentDatain yourtemplate/userequest, mapping eachenvelopeItemIdto a new file
The field positions from the template are preserved on the new PDF. Ensure the replacement PDF has the same page layout to maintain accurate field placement.
See the OpenAPI Reference for the full request schema.
Template Types (Legacy)
| Type | Description |
|---|---|
PRIVATE | Only accessible by owner and team members |
PUBLIC | Can be shared publicly with a direct link |
Complete Legacy Example: Contract Workflow (Deprecated)
This example demonstrates a complete workflow for using templates to send contracts.
const API_TOKEN = process.env.DOCUMENSO_API_TOKEN;
const BASE_URL = 'https://app.documenso.com/api/v2';
async function sendEmploymentContract(employeeData: {
email: string;
name: string;
position: string;
salary: number;
startDate: string;
}) {
// 1. Get the template to find recipient and field IDs
const templateResponse = await fetch(`${BASE_URL}/template/456`, {
headers: { Authorization: API_TOKEN },
});
const template = await templateResponse.json();
// 2. Find the employee recipient slot
const employeeRecipient = template.recipients.find(
(r) => r.role === 'SIGNER' && r.signingOrder === 1
);
// 3. Find fields to prefill
const positionField = template.fields.find(
(f) => f.fieldMeta?.label === 'Position'
);
const salaryField = template.fields.find(
(f) => f.fieldMeta?.label === 'Salary'
);
const startDateField = template.fields.find(
(f) => f.type === 'DATE'
);
// 4. Create document from template with prefilled data
const documentResponse = await fetch(`${BASE_URL}/template/use`, {
method: 'POST',
headers: {
Authorization: API_TOKEN,
'Content-Type': 'application/json',
},
body: JSON.stringify({
templateId: 456,
recipients: [
{
id: employeeRecipient.id,
email: employeeData.email,
name: employeeData.name,
},
],
prefillFields: [
{
id: positionField.id,
type: 'text',
value: employeeData.position,
},
{
id: salaryField.id,
type: 'number',
value: employeeData.salary.toString(),
},
{
id: startDateField.id,
type: 'date',
value: employeeData.startDate,
},
],
override: {
subject: `Employment Contract for ${employeeData.name}`,
message: `Hi ${employeeData.name},\n\nPlease review and sign your employment contract.`,
},
distributeDocument: false,
externalId: `emp-contract-${Date.now()}`,
}),
});
const document = await documentResponse.json();
// 5. Distribute the envelope and get recipient signing links
const distributionResponse = await fetch(`${BASE_URL}/envelope/distribute`, {
method: 'POST',
headers: {
Authorization: API_TOKEN,
'Content-Type': 'application/json',
},
body: JSON.stringify({
envelopeId: document.envelopeId,
}),
});
const distribution = await distributionResponse.json();
return {
envelopeId: document.envelopeId,
signingUrl: distribution.recipients[0].signingUrl,
};
}
// Usage
const result = await sendEmploymentContract({
email: 'john.doe@example.com',
name: 'John Doe',
position: 'Senior Engineer',
salary: 120000,
startDate: '2025-03-01',
});
console.log('Document created:', result.envelopeId);
console.log('Signing URL:', result.signingUrl);See Also
- Documents API - Work with created documents
- Recipients API - Manage document recipients
- Fields API - Work with signature and form fields
- Webhooks - Get notified when documents are signed