mirror of
https://github.com/documenso/documenso.git
synced 2026-08-17 03:51:52 +10:00
Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f353706e24 | ||
|
|
eeae0e1e02 | ||
|
|
3c9c490505 | ||
|
|
905e68fdea | ||
|
|
ced5af4d5a | ||
|
|
b076a70d98 | ||
|
|
6ace46fefd |
@@ -32,9 +32,9 @@ A document object contains the following properties:
|
||||
| --------------- | -------------- | -------------------------------------------------------------- |
|
||||
| `id` | string | Unique identifier (e.g., `envelope_abc123`) |
|
||||
| `type` | string | `DOCUMENT` or `TEMPLATE` |
|
||||
| `status` | string | Current status: `DRAFT`, `PENDING`, `COMPLETED`, or `REJECTED` |
|
||||
| `status` | string | Current status: `DRAFT`, `PENDING`, `COMPLETED`, `REJECTED`, or `CANCELLED` |
|
||||
| `title` | string | Document title |
|
||||
| `source` | string | How the document was created: `DOCUMENT`, `TEMPLATE`, `API` |
|
||||
| `source` | string | How the document was created: `DOCUMENT`, `TEMPLATE`, `TEMPLATE_DIRECT_LINK` |
|
||||
| `visibility` | string | Who can view: `EVERYONE`, `ADMIN`, `MANAGER_AND_ABOVE` |
|
||||
| `externalId` | string \| null | Your custom identifier for the document |
|
||||
| `createdAt` | string | ISO 8601 timestamp |
|
||||
@@ -53,7 +53,7 @@ A document object contains the following properties:
|
||||
"id": "envelope_abc123xyz",
|
||||
"type": "DOCUMENT",
|
||||
"status": "PENDING",
|
||||
"source": "API",
|
||||
"source": "DOCUMENT",
|
||||
"visibility": "EVERYONE",
|
||||
"title": "Service Agreement",
|
||||
"externalId": "contract-2025-001",
|
||||
@@ -73,13 +73,13 @@ A document object contains the following properties:
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"id": "field_123",
|
||||
"id": 123,
|
||||
"type": "SIGNATURE",
|
||||
"page": 1,
|
||||
"positionX": 10,
|
||||
"positionY": 80,
|
||||
"width": 30,
|
||||
"height": 5,
|
||||
"positionX": "10",
|
||||
"positionY": "80",
|
||||
"width": "30",
|
||||
"height": "5",
|
||||
"recipientId": 1
|
||||
}
|
||||
],
|
||||
@@ -99,6 +99,8 @@ A document object contains the following properties:
|
||||
}
|
||||
```
|
||||
|
||||
Field position and size values are stored as decimals and serialized as strings in API responses.
|
||||
|
||||
## List Documents
|
||||
|
||||
Retrieve a paginated list of documents.
|
||||
@@ -114,7 +116,7 @@ GET /envelope
|
||||
| `page` | integer | Page number (default: 1) |
|
||||
| `perPage` | integer | Results per page (default: 10, max: 100) |
|
||||
| `type` | string | Filter by `DOCUMENT` or `TEMPLATE` |
|
||||
| `status` | string | Filter by status: `DRAFT`, `PENDING`, `COMPLETED`, `REJECTED` |
|
||||
| `status` | string | Filter by status: `DRAFT`, `PENDING`, `COMPLETED`, `REJECTED`, `CANCELLED` |
|
||||
| `source` | string | Filter by creation source |
|
||||
| `folderId` | string | Filter by folder ID |
|
||||
| `orderByColumn` | string | Sort field (only `createdAt` supported) |
|
||||
@@ -154,8 +156,8 @@ const response = await fetch(`${BASE_URL}/envelope`, {
|
||||
},
|
||||
});
|
||||
|
||||
const { data, pagination } = await response.json();
|
||||
console.log(`Found ${pagination.totalItems} documents`);
|
||||
const { data, count } = await response.json();
|
||||
console.log(`Found ${count} documents`);
|
||||
|
||||
// Filter by status
|
||||
const pendingResponse = await fetch(
|
||||
@@ -197,12 +199,10 @@ const pendingDocs = await pendingResponse.json();
|
||||
]
|
||||
}
|
||||
],
|
||||
"pagination": {
|
||||
"page": 1,
|
||||
"perPage": 10,
|
||||
"totalPages": 5,
|
||||
"totalItems": 42
|
||||
}
|
||||
"count": 42,
|
||||
"currentPage": 1,
|
||||
"perPage": 10,
|
||||
"totalPages": 5
|
||||
}
|
||||
```
|
||||
|
||||
@@ -628,6 +628,72 @@ The response includes signing URLs for each recipient:
|
||||
|
||||
---
|
||||
|
||||
## Cancel Document
|
||||
|
||||
Cancel a pending document. This changes its status from `PENDING` to `CANCELLED`.
|
||||
|
||||
```
|
||||
POST /envelope/cancel
|
||||
```
|
||||
|
||||
### Request Body
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
| ------------ | ------ | -------- | ----------------------------------- |
|
||||
| `envelopeId` | string | Yes | Document ID |
|
||||
| `reason` | string | No | Reason for cancelling the document |
|
||||
|
||||
### Code Examples
|
||||
|
||||
<Tabs items={['curl', 'TypeScript']}>
|
||||
<Tab value="curl">
|
||||
```bash
|
||||
curl -X POST "https://app.documenso.com/api/v2/envelope/cancel" \
|
||||
-H "Authorization: api_xxxxxxxxxxxxxxxx" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"envelopeId": "envelope_abc123",
|
||||
"reason": "The agreement is no longer needed."
|
||||
}'
|
||||
```
|
||||
</Tab>
|
||||
<Tab value="TypeScript">
|
||||
```typescript
|
||||
const response = await fetch('https://app.documenso.com/api/v2/envelope/cancel', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: 'api_xxxxxxxxxxxxxxxx',
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
envelopeId: 'envelope_abc123',
|
||||
reason: 'The agreement is no longer needed.',
|
||||
}),
|
||||
});
|
||||
|
||||
const { success } = await response.json();
|
||||
```
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
### Response
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true
|
||||
}
|
||||
```
|
||||
|
||||
### Behavior
|
||||
|
||||
- Only documents in `PENDING` status can be cancelled. Other statuses return `400`.
|
||||
- Cancellation is not idempotent. Cancelling the same document again returns `400`.
|
||||
- The document owner and team members with `MANAGER` or higher permissions can cancel it. Requests for documents you cannot view return `404`; requests for visible documents without sufficient permissions return `401`.
|
||||
- A successful cancellation fires the `DOCUMENT_CANCELLED` webhook.
|
||||
- Cancellation emails are sent only to eligible non-CC, non-rejected recipients who were sent or opened the document.
|
||||
|
||||
---
|
||||
|
||||
## Delete Document
|
||||
|
||||
Delete a document. Completed documents cannot be deleted.
|
||||
@@ -670,7 +736,7 @@ const response = await fetch('https://app.documenso.com/api/v2/envelope/delete',
|
||||
|
||||
const { success } = await response.json();
|
||||
|
||||
````
|
||||
```
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
@@ -680,7 +746,7 @@ const { success } = await response.json();
|
||||
{
|
||||
"success": true
|
||||
}
|
||||
````
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -694,9 +760,11 @@ POST /envelope/get-many
|
||||
|
||||
### Request Body
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
| ------------- | ----- | -------- | --------------------- |
|
||||
| `envelopeIds` | array | Yes | Array of document IDs |
|
||||
| Field | Type | Required | Description |
|
||||
| ---------- | ------ | -------- | ---------------------------------------------------------------------------- |
|
||||
| `ids` | object | Yes | ID selector containing `type` and `ids` |
|
||||
| `ids.type` | string | Yes | `envelopeId`, `documentId`, or `templateId` |
|
||||
| `ids.ids` | array | Yes | 1-20 IDs: strings for `envelopeId`; numbers for `documentId` or `templateId` |
|
||||
|
||||
### Code Examples
|
||||
|
||||
@@ -707,12 +775,17 @@ curl -X POST "https://app.documenso.com/api/v2/envelope/get-many" \
|
||||
-H "Authorization: api_xxxxxxxxxxxxxxxx" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"envelopeIds": ["envelope_abc123", "envelope_def456", "envelope_ghi789"]
|
||||
"ids": {
|
||||
"type": "envelopeId",
|
||||
"ids": ["envelope_abc123", "envelope_def456", "envelope_ghi789"]
|
||||
}
|
||||
}'
|
||||
```
|
||||
</Tab>
|
||||
<Tab value="TypeScript">
|
||||
```typescript
|
||||
const requestedIds = ['envelope_abc123', 'envelope_def456', 'envelope_ghi789'];
|
||||
|
||||
const response = await fetch('https://app.documenso.com/api/v2/envelope/get-many', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
@@ -720,16 +793,36 @@ const response = await fetch('https://app.documenso.com/api/v2/envelope/get-many
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
envelopeIds: ['envelope_abc123', 'envelope_def456', 'envelope_ghi789'],
|
||||
ids: {
|
||||
type: 'envelopeId',
|
||||
ids: requestedIds,
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
const documents = await response.json();
|
||||
const { data } = await response.json();
|
||||
|
||||
````
|
||||
```
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
### Response
|
||||
|
||||
```json
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"id": "envelope_abc123",
|
||||
"type": "DOCUMENT",
|
||||
"status": "PENDING",
|
||||
"title": "Service Agreement"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
The endpoint silently omits envelopes you cannot access instead of returning `404`. Compare `data.length` with `requestedIds.length` to detect omissions.
|
||||
|
||||
---
|
||||
|
||||
## Document Statuses
|
||||
@@ -740,6 +833,7 @@ const documents = await response.json();
|
||||
| `PENDING` | Document has been sent. Waiting for recipients to sign. |
|
||||
| `COMPLETED` | All recipients have signed. Document is sealed. |
|
||||
| `REJECTED` | A recipient rejected the document. |
|
||||
| `CANCELLED` | The document was cancelled by its owner or a team member with `MANAGER` or higher permissions. |
|
||||
|
||||
### Status Transitions
|
||||
|
||||
@@ -747,11 +841,13 @@ const documents = await response.json();
|
||||
flowchart LR
|
||||
DRAFT --> PENDING --> COMPLETED
|
||||
PENDING --> REJECTED
|
||||
PENDING --> CANCELLED
|
||||
```
|
||||
|
||||
- **DRAFT to PENDING**: Call the distribute endpoint
|
||||
- **PENDING to COMPLETED**: All recipients complete their signing
|
||||
- **PENDING to REJECTED**: A recipient rejects the document
|
||||
- **PENDING to CANCELLED**: The document owner or a team member with `MANAGER` or higher permissions cancels the document
|
||||
|
||||
<Callout type="warn">
|
||||
You cannot modify recipients or fields after a document moves to `PENDING` status.
|
||||
@@ -773,8 +869,8 @@ flowchart LR
|
||||
| Parameter | Values | Description |
|
||||
| ---------- | ------------------------------------------- | ------------------------- |
|
||||
| `type` | `DOCUMENT`, `TEMPLATE` | Filter by envelope type |
|
||||
| `status` | `DRAFT`, `PENDING`, `COMPLETED`, `REJECTED` | Filter by status |
|
||||
| `source` | `DOCUMENT`, `TEMPLATE`, `API` | Filter by creation source |
|
||||
| `status` | `DRAFT`, `PENDING`, `COMPLETED`, `REJECTED`, `CANCELLED` | Filter by status |
|
||||
| `source` | `DOCUMENT`, `TEMPLATE`, `TEMPLATE_DIRECT_LINK` | Filter by creation source |
|
||||
| `folderId` | string | Filter by folder |
|
||||
|
||||
### Sorting
|
||||
@@ -800,10 +896,10 @@ async function getAllPendingDocuments() {
|
||||
},
|
||||
);
|
||||
|
||||
const { data, pagination } = await response.json();
|
||||
const { data, currentPage, totalPages } = await response.json();
|
||||
documents.push(...data);
|
||||
|
||||
hasMore = page < pagination.totalPages;
|
||||
hasMore = currentPage < totalPages;
|
||||
page++;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,13 +19,13 @@ import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
|
||||
| `secondaryId` | string | Secondary identifier for audit logs |
|
||||
| `type` | string | Field type (see [Field Types](#field-types)) |
|
||||
| `recipientId` | number | ID of the recipient assigned to this field |
|
||||
| `envelopeId` | number | ID of the parent envelope |
|
||||
| `envelopeId` | string | ID of the parent envelope |
|
||||
| `envelopeItemId` | string | ID of the PDF item the field is placed on |
|
||||
| `page` | number | Page number (1-indexed) |
|
||||
| `positionX` | number | X coordinate as percentage (0-100) |
|
||||
| `positionY` | number | Y coordinate as percentage (0-100) |
|
||||
| `width` | number | Width as percentage of page (0-100) |
|
||||
| `height` | number | Height as percentage of page (0-100) |
|
||||
| `positionX` | string | X coordinate as percentage (0-100), a decimal serialized as a string |
|
||||
| `positionY` | string | Y coordinate as percentage (0-100), a decimal serialized as a string |
|
||||
| `width` | string | Width as percentage of page (0-100), a decimal serialized as a string |
|
||||
| `height` | string | Height as percentage of page (0-100), a decimal serialized as a string |
|
||||
| `customText` | string | Value entered by the recipient |
|
||||
| `inserted` | boolean | Whether the field has been completed |
|
||||
| `fieldMeta` | object \| null | Type-specific configuration options |
|
||||
@@ -38,18 +38,19 @@ import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
|
||||
"secondaryId": "field_abc123",
|
||||
"type": "SIGNATURE",
|
||||
"recipientId": 123,
|
||||
"envelopeId": 789,
|
||||
"envelopeItemId": "envelope_item_xyz",
|
||||
"envelopeId": "envelope_abcdefhiklmnorst",
|
||||
"envelopeItemId": "envelope_item_abcdefhiklmnorst",
|
||||
"page": 1,
|
||||
"positionX": 10,
|
||||
"positionY": 80,
|
||||
"width": 30,
|
||||
"height": 5,
|
||||
"positionX": "10",
|
||||
"positionY": "80",
|
||||
"width": "30",
|
||||
"height": "5",
|
||||
"customText": "",
|
||||
"inserted": false,
|
||||
"fieldMeta": {
|
||||
"type": "signature",
|
||||
"required": true
|
||||
"required": true,
|
||||
"overflow": "auto"
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -134,10 +135,10 @@ POST /envelope/field/create-many
|
||||
|
||||
### Request Body
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
| ----------- | ------ | -------- | ------------------------------- |
|
||||
| `documentId`| number | Yes | The document ID |
|
||||
| `fields` | array | Yes | Array of field configurations |
|
||||
| Field | Type | Required | Description |
|
||||
| ------------ | ------ | -------- | ------------------------------- |
|
||||
| `envelopeId` | string | Yes | The envelope ID |
|
||||
| `data` | array | Yes | Array of field configurations |
|
||||
|
||||
### Code Examples
|
||||
|
||||
@@ -148,32 +149,32 @@ curl -X POST "https://app.documenso.com/api/v2/envelope/field/create-many" \
|
||||
-H "Authorization: api_xxxxxxxxxxxxxxxx" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"documentId": 123,
|
||||
"fields": [
|
||||
"envelopeId": "envelope_abcdefhiklmnorst",
|
||||
"data": [
|
||||
{
|
||||
"type": "SIGNATURE",
|
||||
"recipientId": 456,
|
||||
"pageNumber": 1,
|
||||
"pageX": 10,
|
||||
"pageY": 80,
|
||||
"page": 1,
|
||||
"positionX": 10,
|
||||
"positionY": 80,
|
||||
"width": 30,
|
||||
"height": 5
|
||||
},
|
||||
{
|
||||
"type": "DATE",
|
||||
"recipientId": 456,
|
||||
"pageNumber": 1,
|
||||
"pageX": 50,
|
||||
"pageY": 80,
|
||||
"page": 1,
|
||||
"positionX": 50,
|
||||
"positionY": 80,
|
||||
"width": 20,
|
||||
"height": 3
|
||||
},
|
||||
{
|
||||
"type": "TEXT",
|
||||
"recipientId": 456,
|
||||
"pageNumber": 1,
|
||||
"pageX": 10,
|
||||
"pageY": 70,
|
||||
"page": 1,
|
||||
"positionX": 10,
|
||||
"positionY": 70,
|
||||
"width": 40,
|
||||
"height": 4,
|
||||
"fieldMeta": {
|
||||
@@ -199,32 +200,32 @@ const response = await fetch(
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
documentId: 123,
|
||||
fields: [
|
||||
envelopeId: 'envelope_abcdefhiklmnorst',
|
||||
data: [
|
||||
{
|
||||
type: 'SIGNATURE',
|
||||
recipientId: 456,
|
||||
pageNumber: 1,
|
||||
pageX: 10,
|
||||
pageY: 80,
|
||||
page: 1,
|
||||
positionX: 10,
|
||||
positionY: 80,
|
||||
width: 30,
|
||||
height: 5,
|
||||
},
|
||||
{
|
||||
type: 'DATE',
|
||||
recipientId: 456,
|
||||
pageNumber: 1,
|
||||
pageX: 50,
|
||||
pageY: 80,
|
||||
page: 1,
|
||||
positionX: 50,
|
||||
positionY: 80,
|
||||
width: 20,
|
||||
height: 3,
|
||||
},
|
||||
{
|
||||
type: 'TEXT',
|
||||
recipientId: 456,
|
||||
pageNumber: 1,
|
||||
pageX: 10,
|
||||
pageY: 70,
|
||||
page: 1,
|
||||
positionX: 10,
|
||||
positionY: 70,
|
||||
width: 40,
|
||||
height: 4,
|
||||
fieldMeta: {
|
||||
@@ -239,8 +240,8 @@ const response = await fetch(
|
||||
}
|
||||
);
|
||||
|
||||
const { fields } = await response.json();
|
||||
console.log(`Created ${fields.length} fields`);
|
||||
const { data } = await response.json();
|
||||
console.log(`Created ${data.length} fields`);
|
||||
|
||||
````
|
||||
</Tab>
|
||||
@@ -250,36 +251,68 @@ console.log(`Created ${fields.length} fields`);
|
||||
|
||||
```json
|
||||
{
|
||||
"fields": [
|
||||
"data": [
|
||||
{
|
||||
"id": 101,
|
||||
"secondaryId": "field_abc123",
|
||||
"envelopeId": "envelope_abcdefhiklmnorst",
|
||||
"envelopeItemId": "envelope_item_abcdefhiklmnorst",
|
||||
"type": "SIGNATURE",
|
||||
"recipientId": 456,
|
||||
"page": 1,
|
||||
"positionX": 10,
|
||||
"positionY": 80,
|
||||
"width": 30,
|
||||
"height": 5
|
||||
"positionX": "10",
|
||||
"positionY": "80",
|
||||
"width": "30",
|
||||
"height": "5",
|
||||
"customText": "",
|
||||
"inserted": false,
|
||||
"fieldMeta": {
|
||||
"type": "signature",
|
||||
"fontSize": 18,
|
||||
"overflow": "auto"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 102,
|
||||
"secondaryId": "field_def456",
|
||||
"envelopeId": "envelope_abcdefhiklmnorst",
|
||||
"envelopeItemId": "envelope_item_abcdefhiklmnorst",
|
||||
"type": "DATE",
|
||||
"recipientId": 456,
|
||||
"page": 1,
|
||||
"positionX": 50,
|
||||
"positionY": 80,
|
||||
"width": 20,
|
||||
"height": 3
|
||||
"positionX": "50",
|
||||
"positionY": "80",
|
||||
"width": "20",
|
||||
"height": "3",
|
||||
"customText": "",
|
||||
"inserted": false,
|
||||
"fieldMeta": {
|
||||
"type": "date",
|
||||
"fontSize": 12,
|
||||
"textAlign": "left",
|
||||
"overflow": "auto"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 103,
|
||||
"secondaryId": "field_ghi789",
|
||||
"envelopeId": "envelope_abcdefhiklmnorst",
|
||||
"envelopeItemId": "envelope_item_abcdefhiklmnorst",
|
||||
"type": "TEXT",
|
||||
"recipientId": 456,
|
||||
"page": 1,
|
||||
"positionX": 10,
|
||||
"positionY": 70,
|
||||
"width": 40,
|
||||
"height": 4
|
||||
"positionX": "10",
|
||||
"positionY": "70",
|
||||
"width": "40",
|
||||
"height": "4",
|
||||
"customText": "",
|
||||
"inserted": false,
|
||||
"fieldMeta": {
|
||||
"type": "text",
|
||||
"label": "Job Title",
|
||||
"placeholder": "Enter your job title",
|
||||
"required": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -299,8 +332,8 @@ POST /envelope/field/update-many
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
| ------------ | ------ | -------- | ----------------------------- |
|
||||
| `documentId` | number | Yes | The document ID |
|
||||
| `fields` | array | Yes | Array of field update objects |
|
||||
| `envelopeId` | string | Yes | The envelope ID |
|
||||
| `data` | array | Yes | Array of field update objects |
|
||||
|
||||
### Code Examples
|
||||
|
||||
@@ -311,17 +344,17 @@ curl -X POST "https://app.documenso.com/api/v2/envelope/field/update-many" \
|
||||
-H "Authorization: api_xxxxxxxxxxxxxxxx" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"documentId": 123,
|
||||
"fields": [
|
||||
"envelopeId": "envelope_abcdefhiklmnorst",
|
||||
"data": [
|
||||
{
|
||||
"id": 101,
|
||||
"type": "SIGNATURE",
|
||||
"pageY": 85
|
||||
"positionY": 85
|
||||
},
|
||||
{
|
||||
"id": 102,
|
||||
"type": "DATE",
|
||||
"pageY": 85
|
||||
"positionY": 85
|
||||
}
|
||||
]
|
||||
}'
|
||||
@@ -338,16 +371,16 @@ const response = await fetch(
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
documentId: 123,
|
||||
fields: [
|
||||
{ id: 101, type: 'SIGNATURE', pageY: 85 },
|
||||
{ id: 102, type: 'DATE', pageY: 85 },
|
||||
envelopeId: 'envelope_abcdefhiklmnorst',
|
||||
data: [
|
||||
{ id: 101, type: 'SIGNATURE', positionY: 85 },
|
||||
{ id: 102, type: 'DATE', positionY: 85 },
|
||||
],
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
||||
const { fields } = await response.json();
|
||||
const { data } = await response.json();
|
||||
|
||||
````
|
||||
</Tab>
|
||||
@@ -357,9 +390,48 @@ const { fields } = await response.json();
|
||||
|
||||
```json
|
||||
{
|
||||
"fields": [
|
||||
{ "id": 101, "type": "SIGNATURE", "positionY": 85 },
|
||||
{ "id": 102, "type": "DATE", "positionY": 85 }
|
||||
"data": [
|
||||
{
|
||||
"id": 101,
|
||||
"secondaryId": "field_abc123",
|
||||
"envelopeId": "envelope_abcdefhiklmnorst",
|
||||
"envelopeItemId": "envelope_item_abcdefhiklmnorst",
|
||||
"type": "SIGNATURE",
|
||||
"recipientId": 456,
|
||||
"page": 1,
|
||||
"positionX": "10",
|
||||
"positionY": "85",
|
||||
"width": "30",
|
||||
"height": "5",
|
||||
"customText": "",
|
||||
"inserted": false,
|
||||
"fieldMeta": {
|
||||
"type": "signature",
|
||||
"fontSize": 18,
|
||||
"overflow": "auto"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 102,
|
||||
"secondaryId": "field_def456",
|
||||
"envelopeId": "envelope_abcdefhiklmnorst",
|
||||
"envelopeItemId": "envelope_item_abcdefhiklmnorst",
|
||||
"type": "DATE",
|
||||
"recipientId": 456,
|
||||
"page": 1,
|
||||
"positionX": "50",
|
||||
"positionY": "85",
|
||||
"width": "20",
|
||||
"height": "3",
|
||||
"customText": "",
|
||||
"inserted": false,
|
||||
"fieldMeta": {
|
||||
"type": "date",
|
||||
"fontSize": 12,
|
||||
"textAlign": "left",
|
||||
"overflow": "auto"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
````
|
||||
@@ -443,8 +515,8 @@ Fields use percentage-based coordinates relative to the PDF page dimensions.
|
||||
(0,0) ─────────────────────────── (100,0)
|
||||
│ │
|
||||
│ ┌─────────┐ │
|
||||
│ │ Field │ (pageX: 10, │
|
||||
│ │ │ pageY: 20, │
|
||||
│ │ Field │ (positionX: 10, │
|
||||
│ │ │ positionY: 20, │
|
||||
│ └─────────┘ width: 30, │
|
||||
│ height: 5) │
|
||||
│ │
|
||||
@@ -457,9 +529,9 @@ Fields use percentage-based coordinates relative to the PDF page dimensions.
|
||||
const field = {
|
||||
type: 'SIGNATURE',
|
||||
recipientId: 123,
|
||||
pageNumber: 1,
|
||||
pageX: 60, // 60% from left
|
||||
pageY: 85, // 85% from top (near bottom)
|
||||
page: 1,
|
||||
positionX: 60, // 60% from left
|
||||
positionY: 85, // 85% from top (near bottom)
|
||||
width: 30, // 30% of page width
|
||||
height: 8, // 8% of page height
|
||||
};
|
||||
@@ -643,15 +715,15 @@ All field types support these base options:
|
||||
Create a document with a signature block containing multiple field types:
|
||||
|
||||
```typescript
|
||||
async function addSignatureBlock(documentId: number, recipientId: number) {
|
||||
const fields = [
|
||||
async function addSignatureBlock(envelopeId: string, recipientId: number) {
|
||||
const data = [
|
||||
// Signature
|
||||
{
|
||||
type: 'SIGNATURE',
|
||||
recipientId,
|
||||
pageNumber: 1,
|
||||
pageX: 10,
|
||||
pageY: 80,
|
||||
page: 1,
|
||||
positionX: 10,
|
||||
positionY: 80,
|
||||
width: 30,
|
||||
height: 8,
|
||||
fieldMeta: {
|
||||
@@ -663,9 +735,9 @@ async function addSignatureBlock(documentId: number, recipientId: number) {
|
||||
{
|
||||
type: 'NAME',
|
||||
recipientId,
|
||||
pageNumber: 1,
|
||||
pageX: 10,
|
||||
pageY: 90,
|
||||
page: 1,
|
||||
positionX: 10,
|
||||
positionY: 90,
|
||||
width: 30,
|
||||
height: 4,
|
||||
fieldMeta: {
|
||||
@@ -677,9 +749,9 @@ async function addSignatureBlock(documentId: number, recipientId: number) {
|
||||
{
|
||||
type: 'DATE',
|
||||
recipientId,
|
||||
pageNumber: 1,
|
||||
pageX: 50,
|
||||
pageY: 80,
|
||||
page: 1,
|
||||
positionX: 50,
|
||||
positionY: 80,
|
||||
width: 20,
|
||||
height: 4,
|
||||
fieldMeta: {
|
||||
@@ -691,9 +763,9 @@ async function addSignatureBlock(documentId: number, recipientId: number) {
|
||||
{
|
||||
type: 'TEXT',
|
||||
recipientId,
|
||||
pageNumber: 1,
|
||||
pageX: 50,
|
||||
pageY: 90,
|
||||
page: 1,
|
||||
positionX: 50,
|
||||
positionY: 90,
|
||||
width: 30,
|
||||
height: 4,
|
||||
fieldMeta: {
|
||||
@@ -710,7 +782,7 @@ async function addSignatureBlock(documentId: number, recipientId: number) {
|
||||
Authorization: 'api_xxxxxxxxxxxxxxxx',
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ documentId, fields }),
|
||||
body: JSON.stringify({ envelopeId, data }),
|
||||
});
|
||||
|
||||
return response.json();
|
||||
|
||||
@@ -60,8 +60,8 @@ Authorization: api_xxxxxxxxxxxxxxxx
|
||||
href="/docs/developers/api/templates"
|
||||
/>
|
||||
<Card
|
||||
title="Teams"
|
||||
description="Manage teams and team members."
|
||||
title="Team-scoped access"
|
||||
description="Use team-scoped API tokens with envelope endpoints."
|
||||
href="/docs/developers/api/teams"
|
||||
/>
|
||||
</Cards>
|
||||
|
||||
@@ -119,7 +119,7 @@ Full reference in the [V2 OpenAPI reference](https://openapi.documenso.com).
|
||||
| ------------------------------------------------- | ----------------------------------------------------- |
|
||||
| `GET /api/v2/document` | `GET /api/v2/envelope` |
|
||||
| `GET /api/v2/document/{documentId}` | `GET /api/v2/envelope/{envelopeId}` |
|
||||
| `POST /api/v2/document/get-many` | `POST /api/v2/envelope/get-many` |
|
||||
| `POST /api/v2/document/get-many` | `POST /api/v2/envelope/get-many` (body changes from `documentIds: number[]` to `ids: { type: "documentId"; ids: number[] }`) |
|
||||
| `POST /api/v2/document/create` | `POST /api/v2/envelope/create` |
|
||||
| `POST /api/v2/document/create/beta` | `POST /api/v2/envelope/create` |
|
||||
| `POST /api/v2/document/update` | `POST /api/v2/envelope/update` |
|
||||
@@ -140,7 +140,7 @@ Full reference in the [V2 OpenAPI reference](https://openapi.documenso.com).
|
||||
| ------------------------------------- | ------------------------------------------------ |
|
||||
| `GET /api/v2/template` | `GET /api/v2/envelope` (with `type=TEMPLATE`) |
|
||||
| `GET /api/v2/template/{templateId}` | `GET /api/v2/envelope/{envelopeId}` |
|
||||
| `POST /api/v2/template/get-many` | `POST /api/v2/envelope/get-many` |
|
||||
| `POST /api/v2/template/get-many` | `POST /api/v2/envelope/get-many` (body changes from `templateIds: number[]` to `ids: { type: "templateId"; ids: number[] }`) |
|
||||
| `POST /api/v2/template/create` | `POST /api/v2/envelope/create` (`type=TEMPLATE`) |
|
||||
| `POST /api/v2/template/create/beta` | `POST /api/v2/envelope/create` (`type=TEMPLATE`) |
|
||||
| `POST /api/v2/template/update` | `POST /api/v2/envelope/update` |
|
||||
|
||||
@@ -1,44 +1,29 @@
|
||||
---
|
||||
title: Teams API
|
||||
description: Manage team resources, documents, and templates with team-scoped API tokens.
|
||||
title: Team-Scoped API Access
|
||||
description: Use team-scoped API tokens with document and template envelopes.
|
||||
---
|
||||
|
||||
import { Callout } from 'fumadocs-ui/components/callout';
|
||||
import { Step, Steps } from 'fumadocs-ui/components/steps';
|
||||
import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
|
||||
|
||||
<EnvelopeWarning />
|
||||
|
||||
<Callout type="warn">
|
||||
This guide may not reflect the latest endpoints or parameters. For an always up-to-date reference,
|
||||
see the [OpenAPI Reference](https://openapi.documenso.com).
|
||||
</Callout>
|
||||
|
||||
## Team Object
|
||||
## Team Context
|
||||
|
||||
A team object contains the following properties:
|
||||
<Callout type="info">
|
||||
The V2 REST API does not expose `/team/*` endpoints. Create and manage teams, members, and team
|
||||
settings in the Documenso web application. This page explains how a team-scoped token applies
|
||||
that team context to supported API resources.
|
||||
</Callout>
|
||||
|
||||
| Property | Type | Description |
|
||||
| ----------------- | -------------- | --------------------------------------------------- |
|
||||
| `id` | number | Unique team identifier |
|
||||
| `name` | string | Team display name |
|
||||
| `url` | string | Unique team URL slug |
|
||||
| `createdAt` | string | ISO 8601 timestamp |
|
||||
| `avatarImageId` | string \| null | ID of the team's avatar image |
|
||||
| `organisationId` | string | ID of the parent organisation |
|
||||
| `currentTeamRole` | string | Your role in the team: `ADMIN`, `MANAGER`, `MEMBER` |
|
||||
|
||||
### Example Team Object
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 123,
|
||||
"name": "Engineering",
|
||||
"url": "engineering",
|
||||
"createdAt": "2025-01-15T10:30:00.000Z",
|
||||
"avatarImageId": null,
|
||||
"organisationId": "org_abc123",
|
||||
"currentTeamRole": "ADMIN"
|
||||
}
|
||||
```
|
||||
The API resolves the team from your token. You do not pass a team ID when creating, listing, or
|
||||
using envelopes. The token's team ID determines which resources the request can access.
|
||||
|
||||
## Team-Scoped API Tokens
|
||||
|
||||
@@ -156,26 +141,26 @@ Retrieve all documents belonging to the team:
|
||||
<Tab value="curl">
|
||||
```bash
|
||||
# List all team documents
|
||||
curl -X GET "https://app.documenso.com/api/v2/envelope" \
|
||||
curl -X GET "https://app.documenso.com/api/v2/envelope?type=DOCUMENT" \
|
||||
-H "Authorization: api_team_xxxxxxxxxxxxxxxx"
|
||||
|
||||
# Filter by status
|
||||
curl -X GET "https://app.documenso.com/api/v2/envelope?status=PENDING" \
|
||||
curl -X GET "https://app.documenso.com/api/v2/envelope?type=DOCUMENT&status=PENDING" \
|
||||
-H "Authorization: api_team_xxxxxxxxxxxxxxxx"
|
||||
````
|
||||
|
||||
</Tab>
|
||||
<Tab value="TypeScript">
|
||||
```typescript
|
||||
const response = await fetch('https://app.documenso.com/api/v2/envelope', {
|
||||
const response = await fetch('https://app.documenso.com/api/v2/envelope?type=DOCUMENT', {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
Authorization: TEAM_API_TOKEN,
|
||||
},
|
||||
});
|
||||
|
||||
const { data, pagination } = await response.json();
|
||||
console.log(`Found ${pagination.totalItems} team documents`);
|
||||
const { data, count } = await response.json();
|
||||
console.log(`Found ${count} team documents`);
|
||||
|
||||
````
|
||||
</Tab>
|
||||
@@ -190,10 +175,11 @@ Templates created with a team token are shared across the team.
|
||||
<Tabs items={['curl', 'TypeScript']}>
|
||||
<Tab value="curl">
|
||||
```bash
|
||||
curl -X POST "https://app.documenso.com/api/v2/template/create" \
|
||||
curl -X POST "https://app.documenso.com/api/v2/envelope/create" \
|
||||
-H "Authorization: api_team_xxxxxxxxxxxxxxxx" \
|
||||
-H "Content-Type: multipart/form-data" \
|
||||
-F 'payload={
|
||||
"type": "TEMPLATE",
|
||||
"title": "NDA Template",
|
||||
"recipients": [
|
||||
{
|
||||
@@ -223,6 +209,7 @@ curl -X POST "https://app.documenso.com/api/v2/template/create" \
|
||||
const form = new FormData();
|
||||
|
||||
const payload = {
|
||||
type: 'TEMPLATE',
|
||||
title: 'NDA Template',
|
||||
recipients: [
|
||||
{
|
||||
@@ -249,7 +236,7 @@ form.append('files', fs.createReadStream('./nda-template.pdf'), {
|
||||
contentType: 'application/pdf',
|
||||
});
|
||||
|
||||
const response = await fetch('https://app.documenso.com/api/v2/template/create', {
|
||||
const response = await fetch('https://app.documenso.com/api/v2/envelope/create', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: TEAM_API_TOKEN,
|
||||
@@ -257,8 +244,8 @@ const response = await fetch('https://app.documenso.com/api/v2/template/create',
|
||||
body: form,
|
||||
});
|
||||
|
||||
const template = await response.json();
|
||||
console.log('Created team template:', template.id);
|
||||
const { id } = await response.json();
|
||||
console.log('Created team template envelope:', id);
|
||||
````
|
||||
</Tab>
|
||||
</Tabs>
|
||||
@@ -268,14 +255,14 @@ console.log('Created team template:', template.id);
|
||||
<Tabs items={['curl', 'TypeScript']}>
|
||||
<Tab value="curl">
|
||||
```bash
|
||||
curl -X GET "https://app.documenso.com/api/v2/template" \
|
||||
curl -X GET "https://app.documenso.com/api/v2/envelope?type=TEMPLATE" \
|
||||
-H "Authorization: api_team_xxxxxxxxxxxxxxxx"
|
||||
````
|
||||
|
||||
</Tab>
|
||||
<Tab value="TypeScript">
|
||||
```typescript
|
||||
const response = await fetch('https://app.documenso.com/api/v2/template', {
|
||||
const response = await fetch('https://app.documenso.com/api/v2/envelope?type=TEMPLATE', {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
Authorization: TEAM_API_TOKEN,
|
||||
@@ -330,19 +317,19 @@ const SALES_TEAM_TOKEN = process.env.SALES_TEAM_API_TOKEN;
|
||||
const LEGAL_TEAM_TOKEN = process.env.LEGAL_TEAM_API_TOKEN;
|
||||
|
||||
// Get pending documents from sales team
|
||||
const salesResponse = await fetch('https://app.documenso.com/api/v2/envelope?status=PENDING', {
|
||||
const salesResponse = await fetch('https://app.documenso.com/api/v2/envelope?type=DOCUMENT&status=PENDING', {
|
||||
headers: { Authorization: SALES_TEAM_TOKEN },
|
||||
});
|
||||
const salesDocs = await salesResponse.json();
|
||||
|
||||
// Get completed documents from legal team
|
||||
const legalResponse = await fetch('https://app.documenso.com/api/v2/envelope?status=COMPLETED', {
|
||||
const legalResponse = await fetch('https://app.documenso.com/api/v2/envelope?type=DOCUMENT&status=COMPLETED', {
|
||||
headers: { Authorization: LEGAL_TEAM_TOKEN },
|
||||
});
|
||||
const legalDocs = await legalResponse.json();
|
||||
|
||||
console.log(`Sales team: ${salesDocs.pagination.totalItems} pending`);
|
||||
console.log(`Legal team: ${legalDocs.pagination.totalItems} completed`);
|
||||
console.log(`Sales team: ${salesDocs.count} pending`);
|
||||
console.log(`Legal team: ${legalDocs.count} completed`);
|
||||
```
|
||||
|
||||
## Error Responses
|
||||
|
||||
@@ -13,7 +13,194 @@ import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
|
||||
see the [OpenAPI Reference](https://openapi.documenso.com).
|
||||
</Callout>
|
||||
|
||||
## Template Object
|
||||
## 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-data
|
||||
```
|
||||
|
||||
The 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
|
||||
|
||||
<Tabs items={['curl', 'TypeScript']}>
|
||||
<Tab value="curl">
|
||||
```bash
|
||||
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
|
||||
}'
|
||||
```
|
||||
</Tab>
|
||||
<Tab value="TypeScript">
|
||||
```typescript
|
||||
const form = new FormData();
|
||||
|
||||
form.append(
|
||||
'payload',
|
||||
JSON.stringify({
|
||||
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,
|
||||
}),
|
||||
);
|
||||
|
||||
const response = await fetch('https://app.documenso.com/api/v2/envelope/use', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: 'api_xxxxxxxxxxxxxxxx',
|
||||
},
|
||||
body: form,
|
||||
});
|
||||
|
||||
const document = await response.json();
|
||||
console.log('Created document envelope:', document.id);
|
||||
```
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
### Response
|
||||
|
||||
```json
|
||||
{
|
||||
"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.
|
||||
|
||||
```typescript
|
||||
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);
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"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
|
||||
|
||||
<Callout type="warn">
|
||||
Every `/template/*` endpoint below is deprecated. Use the Envelope API for new integrations and
|
||||
follow [Migrating to Envelopes](/docs/developers/api/migrate-to-envelopes) to replace existing calls.
|
||||
The legacy reference remains here to support migrations.
|
||||
</Callout>
|
||||
|
||||
## Legacy Template Object
|
||||
|
||||
A template object contains the following properties:
|
||||
|
||||
@@ -91,7 +278,7 @@ A template object contains the following properties:
|
||||
}
|
||||
```
|
||||
|
||||
## List Templates
|
||||
## List Templates (Deprecated)
|
||||
|
||||
Retrieve a paginated list of templates.
|
||||
|
||||
@@ -139,8 +326,8 @@ const response = await fetch(`${BASE_URL}/template`, {
|
||||
},
|
||||
});
|
||||
|
||||
const { data, pagination } = await response.json();
|
||||
console.log(`Found ${pagination.totalItems} templates`);
|
||||
const { data, count } = await response.json();
|
||||
console.log(`Found ${count} templates`);
|
||||
|
||||
// Filter by type
|
||||
const privateResponse = await fetch(
|
||||
@@ -181,18 +368,16 @@ const privateTemplates = await privateResponse.json();
|
||||
]
|
||||
}
|
||||
],
|
||||
"pagination": {
|
||||
"page": 1,
|
||||
"perPage": 10,
|
||||
"totalPages": 3,
|
||||
"totalItems": 25
|
||||
}
|
||||
"count": 25,
|
||||
"currentPage": 1,
|
||||
"perPage": 10,
|
||||
"totalPages": 3
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Get Template
|
||||
## Get Template (Deprecated)
|
||||
|
||||
Retrieve a single template by ID.
|
||||
|
||||
@@ -238,9 +423,9 @@ Returns the full template object including recipients, fields, and metadata.
|
||||
|
||||
---
|
||||
|
||||
## Create Document from Template
|
||||
## Create Document from Template (Deprecated)
|
||||
|
||||
Create a new document using a template. This is the primary way to use templates programmatically.
|
||||
Create a new document using the deprecated template endpoint.
|
||||
|
||||
<Callout type="info">
|
||||
This endpoint does not support [PDF placeholder parsing](/docs/users/documents/advanced/pdf-placeholders). Use `POST /envelope/create` for placeholder-based field positioning.
|
||||
@@ -415,32 +600,57 @@ const prefilledDocument = await prefillResponse.json();
|
||||
|
||||
### Response
|
||||
|
||||
Returns the created document object with recipients and signing URLs.
|
||||
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`.
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "envelope_xyz789",
|
||||
"type": "DOCUMENT",
|
||||
"id": 789,
|
||||
"envelopeId": "envelope_xyz789",
|
||||
"status": "PENDING",
|
||||
"title": "Employment Contract",
|
||||
"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",
|
||||
"signingUrl": "https://app.documenso.com/sign/abc123"
|
||||
"signingOrder": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
````
|
||||
```
|
||||
|
||||
To send a document created with `distributeDocument: false` and receive signing links, call
|
||||
`POST /envelope/distribute` with its `envelopeId`:
|
||||
|
||||
```typescript
|
||||
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
|
||||
## Override Template Settings (Deprecated)
|
||||
|
||||
When creating a document from a template, you can override various settings:
|
||||
|
||||
@@ -488,7 +698,7 @@ const response = await fetch(`${BASE_URL}/template/use`, {
|
||||
|
||||
---
|
||||
|
||||
## Prefill Fields
|
||||
## Prefill Fields (Deprecated)
|
||||
|
||||
Prefill field values when creating a document from a template. This is useful for populating known data before sending.
|
||||
|
||||
@@ -577,7 +787,7 @@ const response = await fetch(`${BASE_URL}/template/use`, {
|
||||
|
||||
---
|
||||
|
||||
## Update Template
|
||||
## Update Template (Deprecated)
|
||||
|
||||
Update a template's properties.
|
||||
|
||||
@@ -643,7 +853,7 @@ const template = await response.json();
|
||||
|
||||
---
|
||||
|
||||
## Duplicate Template
|
||||
## Duplicate Template (Deprecated)
|
||||
|
||||
Create a copy of an existing template.
|
||||
|
||||
@@ -695,7 +905,7 @@ console.log('New template ID:', duplicatedTemplate.id);
|
||||
|
||||
---
|
||||
|
||||
## Delete Template
|
||||
## Delete Template (Deprecated)
|
||||
|
||||
Delete a template.
|
||||
|
||||
@@ -754,7 +964,7 @@ const { success } = await response.json();
|
||||
|
||||
---
|
||||
|
||||
## Direct Link Templates
|
||||
## 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.
|
||||
|
||||
@@ -898,7 +1108,7 @@ const { success } = await response.json();
|
||||
|
||||
---
|
||||
|
||||
## Custom Document Data
|
||||
## 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.
|
||||
|
||||
@@ -913,7 +1123,7 @@ See the [OpenAPI Reference](https://openapi.documenso.com) for the full request
|
||||
|
||||
---
|
||||
|
||||
## Template Types
|
||||
## Template Types (Legacy)
|
||||
|
||||
| Type | Description |
|
||||
| --------- | ------------------------------------------------------------------ |
|
||||
@@ -922,7 +1132,7 @@ See the [OpenAPI Reference](https://openapi.documenso.com) for the full request
|
||||
|
||||
---
|
||||
|
||||
## Complete Example: Contract Workflow
|
||||
## Complete Legacy Example: Contract Workflow (Deprecated)
|
||||
|
||||
This example demonstrates a complete workflow for using templates to send contracts.
|
||||
|
||||
@@ -996,16 +1206,29 @@ async function sendEmploymentContract(employeeData: {
|
||||
subject: `Employment Contract for ${employeeData.name}`,
|
||||
message: `Hi ${employeeData.name},\n\nPlease review and sign your employment contract.`,
|
||||
},
|
||||
distributeDocument: true,
|
||||
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 {
|
||||
documentId: document.id,
|
||||
signingUrl: document.recipients[0].signingUrl,
|
||||
envelopeId: document.envelopeId,
|
||||
signingUrl: distribution.recipients[0].signingUrl,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1018,7 +1241,7 @@ const result = await sendEmploymentContract({
|
||||
startDate: '2025-03-01',
|
||||
});
|
||||
|
||||
console.log('Document created:', result.documentId);
|
||||
console.log('Document created:', result.envelopeId);
|
||||
console.log('Signing URL:', result.signingUrl);
|
||||
````
|
||||
|
||||
|
||||
@@ -78,12 +78,10 @@ A successful response returns a list of your documents (envelopes):
|
||||
"createdAt": "2025-01-15T10:30:00.000Z"
|
||||
}
|
||||
],
|
||||
"pagination": {
|
||||
"page": 1,
|
||||
"perPage": 10,
|
||||
"totalPages": 1,
|
||||
"totalItems": 1
|
||||
}
|
||||
"count": 1,
|
||||
"currentPage": 1,
|
||||
"perPage": 10,
|
||||
"totalPages": 1
|
||||
}
|
||||
````
|
||||
|
||||
@@ -228,9 +226,12 @@ After creating a document, it's in `DRAFT` status. To send it to recipients, use
|
||||
<Tabs items={['curl', 'JavaScript']}>
|
||||
<Tab value="curl">
|
||||
```bash
|
||||
curl -X POST "https://app.documenso.com/api/v2/envelope/envelope_abc123/distribute" \
|
||||
curl -X POST "https://app.documenso.com/api/v2/envelope/distribute" \
|
||||
-H "Authorization: YOUR_API_TOKEN" \
|
||||
-H "Content-Type: application/json"
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"envelopeId": "envelope_abc123"
|
||||
}'
|
||||
````
|
||||
|
||||
</Tab>
|
||||
@@ -238,16 +239,14 @@ curl -X POST "https://app.documenso.com/api/v2/envelope/envelope_abc123/distribu
|
||||
```javascript
|
||||
const envelopeId = 'envelope_abc123';
|
||||
|
||||
const response = await fetch(
|
||||
`https://app.documenso.com/api/v2/envelope/${envelopeId}/distribute`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: 'YOUR_API_TOKEN',
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
const response = await fetch('https://app.documenso.com/api/v2/envelope/distribute', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: 'YOUR_API_TOKEN',
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
);
|
||||
body: JSON.stringify({ envelopeId }),
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
console.log('Document sent:', data);
|
||||
@@ -337,16 +336,14 @@ async function createAndSendDocument(pdfPath, recipientEmail, recipientName) {
|
||||
console.log('Created envelope:', envelope.id);
|
||||
|
||||
// Step 2: Send the document for signing
|
||||
const distributeResponse = await fetch(
|
||||
`${BASE_URL}/envelope/${envelope.id}/distribute`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': API_TOKEN,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
}
|
||||
);
|
||||
const distributeResponse = await fetch(`${BASE_URL}/envelope/distribute`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': API_TOKEN,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ envelopeId: envelope.id }),
|
||||
});
|
||||
|
||||
if (!distributeResponse.ok) {
|
||||
const error = await distributeResponse.json();
|
||||
@@ -422,9 +419,12 @@ echo "Created envelope: ${ENVELOPE_ID}"
|
||||
# Step 2: Send the document for signing
|
||||
|
||||
echo "Sending document..."
|
||||
curl -s -X POST "${BASE_URL}/envelope/${ENVELOPE_ID}/distribute" \
|
||||
curl -s -X POST "${BASE_URL}/envelope/distribute" \
|
||||
-H "Authorization: ${API_TOKEN}" \
|
||||
-H "Content-Type: application/json"
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{
|
||||
\"envelopeId\": \"${ENVELOPE_ID}\"
|
||||
}"
|
||||
|
||||
echo "Document sent for signing!"
|
||||
|
||||
@@ -441,7 +441,7 @@ The API returns standard HTTP status codes and JSON error responses:
|
||||
| `400` | Bad request - check your request payload |
|
||||
| `401` | Unauthorized - invalid or missing API token |
|
||||
| `404` | Not found - resource doesn't exist |
|
||||
| `429` | Rate limited - wait 60 seconds and retry |
|
||||
| `429` | Rate limited - wait for the duration in the `Retry-After` header |
|
||||
| `500` | Server error - retry or contact support |
|
||||
|
||||
### Error Response Format
|
||||
@@ -485,7 +485,7 @@ The API returns standard HTTP status codes and JSON error responses:
|
||||
|
||||
### Handling Rate Limits
|
||||
|
||||
The API allows 1000 requests per minute per IP address. Your organisation may have its own lower rate limits. When rate limited, wait at least 60 seconds before retrying:
|
||||
The API allows 1000 requests per minute per IP address. Your organisation may have its own lower rate limits. Every response includes `X-RateLimit-Remaining` and `X-RateLimit-Reset` (an epoch timestamp in seconds). When you receive a `429` response, read the `Retry-After` header and wait for that many seconds before retrying. See [Error Handling Patterns](/docs/developers/examples/common-workflows#error-handling-patterns) for a more complete retry strategy.
|
||||
|
||||
```javascript
|
||||
async function fetchWithRetry(url, options, maxRetries = 3) {
|
||||
@@ -493,8 +493,9 @@ async function fetchWithRetry(url, options, maxRetries = 3) {
|
||||
const response = await fetch(url, options);
|
||||
|
||||
if (response.status === 429) {
|
||||
console.log('Rate limited, waiting 60 seconds...');
|
||||
await new Promise((resolve) => setTimeout(resolve, 60000));
|
||||
const retryAfterSeconds = Number.parseInt(response.headers.get('Retry-After') ?? '1', 10);
|
||||
console.log(`Rate limited, waiting ${retryAfterSeconds} seconds...`);
|
||||
await new Promise((resolve) => setTimeout(resolve, retryAfterSeconds * 1000));
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,13 +8,14 @@ export const cancelEnvelopeMeta: TrpcRouteMeta = {
|
||||
method: 'POST',
|
||||
path: '/envelope/cancel',
|
||||
summary: 'Cancel envelope',
|
||||
description: 'Cancel a pending envelope',
|
||||
tags: ['Envelope'],
|
||||
},
|
||||
};
|
||||
|
||||
export const ZCancelEnvelopeRequestSchema = z.object({
|
||||
envelopeId: z.string(),
|
||||
reason: z.string().optional(),
|
||||
envelopeId: z.string().describe('The ID of the envelope to cancel.'),
|
||||
reason: z.string().describe('The reason for cancelling the envelope.').optional(),
|
||||
});
|
||||
|
||||
export const ZCancelEnvelopeResponseSchema = ZSuccessResponseSchema;
|
||||
|
||||
@@ -8,12 +8,13 @@ export const deleteEnvelopeMeta: TrpcRouteMeta = {
|
||||
method: 'POST',
|
||||
path: '/envelope/delete',
|
||||
summary: 'Delete envelope',
|
||||
description: 'Delete an envelope',
|
||||
tags: ['Envelope'],
|
||||
},
|
||||
};
|
||||
|
||||
export const ZDeleteEnvelopeRequestSchema = z.object({
|
||||
envelopeId: z.string(),
|
||||
envelopeId: z.string().describe('The ID of the envelope to delete.'),
|
||||
});
|
||||
|
||||
export const ZDeleteEnvelopeResponseSchema = ZSuccessResponseSchema;
|
||||
|
||||
@@ -29,7 +29,17 @@ export const updateEnvelopeFieldsRoute = authenticatedProcedure
|
||||
id: envelopeId,
|
||||
},
|
||||
type: null,
|
||||
fields,
|
||||
fields: fields.map((field) => ({
|
||||
id: field.id,
|
||||
type: field.type,
|
||||
pageNumber: field.page,
|
||||
pageX: field.positionX,
|
||||
pageY: field.positionY,
|
||||
width: field.width,
|
||||
height: field.height,
|
||||
fieldMeta: field.fieldMeta,
|
||||
envelopeItemId: field.envelopeItemId,
|
||||
})),
|
||||
requestMetadata: ctx.metadata,
|
||||
});
|
||||
|
||||
|
||||
@@ -12,24 +12,32 @@ export const updateEnvelopeMeta: TrpcRouteMeta = {
|
||||
method: 'POST',
|
||||
path: '/envelope/update',
|
||||
summary: 'Update envelope',
|
||||
description: 'Update envelope properties and settings',
|
||||
tags: ['Envelope'],
|
||||
},
|
||||
};
|
||||
|
||||
export const ZUpdateEnvelopeRequestSchema = z.object({
|
||||
envelopeId: z.string(),
|
||||
envelopeId: z.string().describe('The ID of the envelope to update.'),
|
||||
data: z
|
||||
.object({
|
||||
title: ZDocumentTitleSchema.optional(),
|
||||
externalId: ZDocumentExternalIdSchema.nullish(),
|
||||
visibility: ZDocumentVisibilitySchema.optional(),
|
||||
globalAccessAuth: z.array(ZDocumentAccessAuthTypesSchema).optional(),
|
||||
globalActionAuth: z.array(ZDocumentActionAuthTypesSchema).optional(),
|
||||
folderId: z.string().nullish(),
|
||||
templateType: z.nativeEnum(TemplateType).optional(),
|
||||
globalAccessAuth: z
|
||||
.array(ZDocumentAccessAuthTypesSchema)
|
||||
.describe('The authentication methods required to access the envelope.')
|
||||
.optional(),
|
||||
globalActionAuth: z
|
||||
.array(ZDocumentActionAuthTypesSchema)
|
||||
.describe('The authentication methods required to sign the envelope.')
|
||||
.optional(),
|
||||
folderId: z.string().describe('The ID of the folder containing the envelope.').nullish(),
|
||||
templateType: z.nativeEnum(TemplateType).describe('The template type.').optional(),
|
||||
})
|
||||
.describe('The envelope properties to update.')
|
||||
.optional(),
|
||||
meta: ZDocumentMetaUpdateSchema.optional(),
|
||||
meta: ZDocumentMetaUpdateSchema.describe('The email and signing settings to update.').optional(),
|
||||
});
|
||||
|
||||
export const ZUpdateEnvelopeResponseSchema = ZEnvelopeLiteSchema;
|
||||
|
||||
Reference in New Issue
Block a user