mirror of
https://github.com/documenso/documenso.git
synced 2026-08-15 19:11:49 +10:00
Compare commits
5
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ddd0da1473 | ||
|
|
1e1e15a7dc | ||
|
|
4e87121bef | ||
|
|
f353706e24 | ||
|
|
eeae0e1e02 |
@@ -15,6 +15,8 @@ This guide provides a comprehensive troubleshooting matrix for the standard erro
|
|||||||
| `INVALID_REQUEST` | The overall request is malformed or invalid. | Review your API call parameters, including the URL, query parameters, and headers. Correct the request syntax. |
|
| `INVALID_REQUEST` | The overall request is malformed or invalid. | Review your API call parameters, including the URL, query parameters, and headers. Correct the request syntax. |
|
||||||
| `RECIPIENT_EXPIRED` | The signing link or recipient access has expired. | Generate and resend a new invitation to the affected recipient. |
|
| `RECIPIENT_EXPIRED` | The signing link or recipient access has expired. | Generate and resend a new invitation to the affected recipient. |
|
||||||
| `LIMIT_EXCEEDED` | Your account usage quota has been exceeded. | Check your current plan limits. Upgrade your subscription or wait until your billing cycle renews. |
|
| `LIMIT_EXCEEDED` | Your account usage quota has been exceeded. | Check your current plan limits. Upgrade your subscription or wait until your billing cycle renews. |
|
||||||
|
| `MISSING_ENV_VAR` | A required environment variable is not configured on the server (500). | Primarily affects self-hosted instances: set the environment variable named in the error message and restart. On Documenso Cloud, contact support. |
|
||||||
|
| `MISSING_SIGNATURE_FIELD` | A signer has no signature field placed on the document (400). Returned when distributing an envelope. | Add at least one signature field for every recipient with a signing role before calling `/envelope/distribute`. |
|
||||||
| `NOT_FOUND` | The requested resource could not be found (404). | Verify the resource ID (envelope, document, webhook) passed in the URL. Ensure the resource has not been deleted. |
|
| `NOT_FOUND` | The requested resource could not be found (404). | Verify the resource ID (envelope, document, webhook) passed in the URL. Ensure the resource has not been deleted. |
|
||||||
| `NOT_IMPLEMENTED` | The requested feature is not currently supported by the server. | Consult the API documentation to verify available methods. Do not use this endpoint at this time. |
|
| `NOT_IMPLEMENTED` | The requested feature is not currently supported by the server. | Consult the API documentation to verify available methods. Do not use this endpoint at this time. |
|
||||||
| `NOT_SETUP` | The required configuration for this action is incomplete. | Access your account or integration settings and complete the necessary configuration before retrying. |
|
| `NOT_SETUP` | The required configuration for this action is incomplete. | Access your account or integration settings and complete the necessary configuration before retrying. |
|
||||||
@@ -37,7 +39,28 @@ The following errors occur when attempting to perform actions on an envelope tha
|
|||||||
| `ENVELOPE_DRAFT` | The action cannot be performed because the envelope is still in a draft state. | Finalize the envelope configuration and transition it to the `PENDING` (sent) state before attempting this operation. |
|
| `ENVELOPE_DRAFT` | The action cannot be performed because the envelope is still in a draft state. | Finalize the envelope configuration and transition it to the `PENDING` (sent) state before attempting this operation. |
|
||||||
| `ENVELOPE_COMPLETED` | The action cannot be performed because the envelope is already completed. | No further modifications (e.g., adding signers, modifying documents) can be made to an envelope once the signing process is finished. |
|
| `ENVELOPE_COMPLETED` | The action cannot be performed because the envelope is already completed. | No further modifications (e.g., adding signers, modifying documents) can be made to an envelope once the signing process is finished. |
|
||||||
| `ENVELOPE_REJECTED` | The action cannot be performed because the envelope was rejected by a recipient. | The signing flow is permanently halted. Create a new envelope if you wish to resubmit the document. |
|
| `ENVELOPE_REJECTED` | The action cannot be performed because the envelope was rejected by a recipient. | The signing flow is permanently halted. Create a new envelope if you wish to resubmit the document. |
|
||||||
|
| `ENVELOPE_CANCELLED` | The action cannot be performed because the envelope was cancelled (400). | Create a new envelope if you need to restart the signing process. |
|
||||||
| `ENVELOPE_LEGACY` | The action cannot be performed because the envelope uses an obsolete format. | This envelope was created with a legacy version of the system. Recreate the envelope using the current API version to interact with it. |
|
| `ENVELOPE_LEGACY` | The action cannot be performed because the envelope uses an obsolete format. | This envelope was created with a legacy version of the system. Recreate the envelope using the current API version to interact with it. |
|
||||||
|
| `ENVELOPE_TSP_LOCKED` | An AES/QES envelope cannot be modified after it leaves the draft state (400). | Make changes while the envelope is in `DRAFT`, or create a new envelope. |
|
||||||
|
|
||||||
|
## CSC Signing Errors
|
||||||
|
|
||||||
|
These errors apply to Cloud Signature Consortium (CSC) signing flows.
|
||||||
|
|
||||||
|
| Error Code | Description | Recommended Action |
|
||||||
|
| :--- | :--- | :--- |
|
||||||
|
| `CSC_INSTANCE_MODE_MISMATCH` | The requested signature level does not match the instance's CSC mode (400). | Use the signature level supported by the instance's signing configuration. |
|
||||||
|
| `CSC_UNLICENSED` | CSC signing is not licensed for this instance (403). | Enable the CSC signing license before retrying. |
|
||||||
|
| `CSC_PROVIDER_INFO_FAILED` | The CSC provider's discovery request failed or returned unusable information (500). | Check the provider URL, availability, and OAuth configuration. |
|
||||||
|
| `CSC_PROVIDER_NO_TSA` | A timestamp authority is unavailable or unusable for CSC signing (500). | Configure `NEXT_PRIVATE_SIGNING_TIMESTAMP_AUTHORITY` and verify provider timestamp access. |
|
||||||
|
| `CSC_CREDENTIAL_LIST_EMPTY` | The CSC provider returned no signing credentials for the authenticated user (400). | Enrol a signing credential with the provider, then authenticate again. |
|
||||||
|
| `CSC_CERT_INVALID` | The selected signing certificate is missing, invalid, or outside its validity period (400). | Select or renew a valid certificate, then authenticate again. |
|
||||||
|
| `CSC_ALGORITHM_REFUSED` | The signing credential uses an unsupported key or digest algorithm (400). | Select a credential that satisfies the instance's CSC algorithm policy. |
|
||||||
|
| `CSC_SAD_EXPIRED_PRE_SIGN` | The signature activation data is missing, expired, or unreadable before signing (400). | Repeat the credential authorization flow. |
|
||||||
|
| `CSC_TSP_TIMEOUT` | The trust service provider did not complete the signing request before the timeout (408). | Retry the signing request after checking provider availability. |
|
||||||
|
| `CSC_EMBED_FAILED` | The returned CSC signature could not be embedded into the envelope items (400). | Restart the signing attempt. If it fails again, contact support. |
|
||||||
|
| `CSC_BASE_DOCUMENT_MUTATED` | The document changed between signature preparation and signing (500). | Restart signing from the current envelope state. |
|
||||||
|
| `CSC_REQUEST_FAILED` | A CSC provider request failed without a more specific CSC error (500). | Check provider availability and configuration, then retry. |
|
||||||
|
|
||||||
## See Also
|
## See Also
|
||||||
|
|
||||||
|
|||||||
@@ -60,8 +60,8 @@ Authorization: api_xxxxxxxxxxxxxxxx
|
|||||||
href="/docs/developers/api/templates"
|
href="/docs/developers/api/templates"
|
||||||
/>
|
/>
|
||||||
<Card
|
<Card
|
||||||
title="Teams"
|
title="Team-scoped access"
|
||||||
description="Manage teams and team members."
|
description="Use team-scoped API tokens with envelope endpoints."
|
||||||
href="/docs/developers/api/teams"
|
href="/docs/developers/api/teams"
|
||||||
/>
|
/>
|
||||||
</Cards>
|
</Cards>
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ description: Add and manage envelope recipients via API.
|
|||||||
import { Callout } from 'fumadocs-ui/components/callout';
|
import { Callout } from 'fumadocs-ui/components/callout';
|
||||||
import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
|
import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
|
||||||
|
|
||||||
|
<EnvelopeWarning />
|
||||||
|
|
||||||
<Callout type="warn">
|
<Callout type="warn">
|
||||||
This guide may not reflect the latest endpoints or parameters. For an always up-to-date reference,
|
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).
|
see the [OpenAPI Reference](https://openapi.documenso.com).
|
||||||
@@ -16,7 +18,7 @@ import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
|
|||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"id": 123,
|
"id": 123,
|
||||||
"envelopeId": "clu1abc2def3ghi4jkl",
|
"envelopeId": "envelope_abcdefhiklmnorst",
|
||||||
"email": "signer@example.com",
|
"email": "signer@example.com",
|
||||||
"name": "John Doe",
|
"name": "John Doe",
|
||||||
"role": "SIGNER",
|
"role": "SIGNER",
|
||||||
@@ -134,7 +136,7 @@ curl -X POST "https://app.documenso.com/api/v2/envelope/recipient/create-many" \
|
|||||||
-H "Authorization: api_xxxxxxxxxxxxxxxx" \
|
-H "Authorization: api_xxxxxxxxxxxxxxxx" \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
-d '{
|
-d '{
|
||||||
"envelopeId": "clu1abc2def3ghi4jkl",
|
"envelopeId": "envelope_abcdefhiklmnorst",
|
||||||
"data": [
|
"data": [
|
||||||
{
|
{
|
||||||
"email": "signer@example.com",
|
"email": "signer@example.com",
|
||||||
@@ -164,7 +166,7 @@ const response = await fetch(
|
|||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
envelopeId: 'clu1abc2def3ghi4jkl',
|
envelopeId: 'envelope_abcdefhiklmnorst',
|
||||||
data: [
|
data: [
|
||||||
{
|
{
|
||||||
email: 'signer@example.com',
|
email: 'signer@example.com',
|
||||||
@@ -196,7 +198,7 @@ const { data: recipients } = await response.json();
|
|||||||
"data": [
|
"data": [
|
||||||
{
|
{
|
||||||
"id": 789,
|
"id": 789,
|
||||||
"envelopeId": "clu1abc2def3ghi4jkl",
|
"envelopeId": "envelope_abcdefhiklmnorst",
|
||||||
"email": "signer@example.com",
|
"email": "signer@example.com",
|
||||||
"name": "John Doe",
|
"name": "John Doe",
|
||||||
"role": "SIGNER",
|
"role": "SIGNER",
|
||||||
@@ -209,7 +211,7 @@ const { data: recipients } = await response.json();
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 790,
|
"id": 790,
|
||||||
"envelopeId": "clu1abc2def3ghi4jkl",
|
"envelopeId": "envelope_abcdefhiklmnorst",
|
||||||
"email": "approver@example.com",
|
"email": "approver@example.com",
|
||||||
"name": "Jane Smith",
|
"name": "Jane Smith",
|
||||||
"role": "APPROVER",
|
"role": "APPROVER",
|
||||||
@@ -262,7 +264,7 @@ curl -X POST "https://app.documenso.com/api/v2/envelope/recipient/update-many" \
|
|||||||
-H "Authorization: api_xxxxxxxxxxxxxxxx" \
|
-H "Authorization: api_xxxxxxxxxxxxxxxx" \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
-d '{
|
-d '{
|
||||||
"envelopeId": "clu1abc2def3ghi4jkl",
|
"envelopeId": "envelope_abcdefhiklmnorst",
|
||||||
"data": [
|
"data": [
|
||||||
{
|
{
|
||||||
"id": 789,
|
"id": 789,
|
||||||
@@ -284,7 +286,7 @@ const response = await fetch(
|
|||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
envelopeId: 'clu1abc2def3ghi4jkl',
|
envelopeId: 'envelope_abcdefhiklmnorst',
|
||||||
data: [
|
data: [
|
||||||
{
|
{
|
||||||
id: 789,
|
id: 789,
|
||||||
@@ -387,7 +389,7 @@ const response = await fetch('https://app.documenso.com/api/v2/envelope/recipien
|
|||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
envelopeId: 'clu1abc2def3ghi4jkl',
|
envelopeId: 'envelope_abcdefhiklmnorst',
|
||||||
data: [
|
data: [
|
||||||
{
|
{
|
||||||
email: 'approver@example.com',
|
email: 'approver@example.com',
|
||||||
@@ -462,7 +464,7 @@ const response = await fetch('https://app.documenso.com/api/v2/envelope/recipien
|
|||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
envelopeId: 'clu1abc2def3ghi4jkl',
|
envelopeId: 'envelope_abcdefhiklmnorst',
|
||||||
data: [
|
data: [
|
||||||
{
|
{
|
||||||
email: 'signer@example.com',
|
email: 'signer@example.com',
|
||||||
|
|||||||
@@ -1,44 +1,29 @@
|
|||||||
---
|
---
|
||||||
title: Teams API
|
title: Team-Scoped API Access
|
||||||
description: Manage team resources, documents, and templates with team-scoped API tokens.
|
description: Use team-scoped API tokens with document and template envelopes.
|
||||||
---
|
---
|
||||||
|
|
||||||
import { Callout } from 'fumadocs-ui/components/callout';
|
import { Callout } from 'fumadocs-ui/components/callout';
|
||||||
import { Step, Steps } from 'fumadocs-ui/components/steps';
|
import { Step, Steps } from 'fumadocs-ui/components/steps';
|
||||||
import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
|
import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
|
||||||
|
|
||||||
|
<EnvelopeWarning />
|
||||||
|
|
||||||
<Callout type="warn">
|
<Callout type="warn">
|
||||||
This guide may not reflect the latest endpoints or parameters. For an always up-to-date reference,
|
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).
|
see the [OpenAPI Reference](https://openapi.documenso.com).
|
||||||
</Callout>
|
</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 |
|
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.
|
||||||
| `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"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Team-Scoped API Tokens
|
## Team-Scoped API Tokens
|
||||||
|
|
||||||
@@ -156,26 +141,26 @@ Retrieve all documents belonging to the team:
|
|||||||
<Tab value="curl">
|
<Tab value="curl">
|
||||||
```bash
|
```bash
|
||||||
# List all team documents
|
# 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"
|
-H "Authorization: api_team_xxxxxxxxxxxxxxxx"
|
||||||
|
|
||||||
# Filter by status
|
# 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"
|
-H "Authorization: api_team_xxxxxxxxxxxxxxxx"
|
||||||
````
|
````
|
||||||
|
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab value="TypeScript">
|
<Tab value="TypeScript">
|
||||||
```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',
|
method: 'GET',
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: TEAM_API_TOKEN,
|
Authorization: TEAM_API_TOKEN,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data, pagination } = await response.json();
|
const { data, count } = await response.json();
|
||||||
console.log(`Found ${pagination.totalItems} team documents`);
|
console.log(`Found ${count} team documents`);
|
||||||
|
|
||||||
````
|
````
|
||||||
</Tab>
|
</Tab>
|
||||||
@@ -190,10 +175,11 @@ Templates created with a team token are shared across the team.
|
|||||||
<Tabs items={['curl', 'TypeScript']}>
|
<Tabs items={['curl', 'TypeScript']}>
|
||||||
<Tab value="curl">
|
<Tab value="curl">
|
||||||
```bash
|
```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 "Authorization: api_team_xxxxxxxxxxxxxxxx" \
|
||||||
-H "Content-Type: multipart/form-data" \
|
-H "Content-Type: multipart/form-data" \
|
||||||
-F 'payload={
|
-F 'payload={
|
||||||
|
"type": "TEMPLATE",
|
||||||
"title": "NDA Template",
|
"title": "NDA Template",
|
||||||
"recipients": [
|
"recipients": [
|
||||||
{
|
{
|
||||||
@@ -223,6 +209,7 @@ curl -X POST "https://app.documenso.com/api/v2/template/create" \
|
|||||||
const form = new FormData();
|
const form = new FormData();
|
||||||
|
|
||||||
const payload = {
|
const payload = {
|
||||||
|
type: 'TEMPLATE',
|
||||||
title: 'NDA Template',
|
title: 'NDA Template',
|
||||||
recipients: [
|
recipients: [
|
||||||
{
|
{
|
||||||
@@ -249,7 +236,7 @@ form.append('files', fs.createReadStream('./nda-template.pdf'), {
|
|||||||
contentType: 'application/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',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: TEAM_API_TOKEN,
|
Authorization: TEAM_API_TOKEN,
|
||||||
@@ -257,8 +244,8 @@ const response = await fetch('https://app.documenso.com/api/v2/template/create',
|
|||||||
body: form,
|
body: form,
|
||||||
});
|
});
|
||||||
|
|
||||||
const template = await response.json();
|
const { id } = await response.json();
|
||||||
console.log('Created team template:', template.id);
|
console.log('Created team template envelope:', id);
|
||||||
````
|
````
|
||||||
</Tab>
|
</Tab>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
@@ -268,14 +255,14 @@ console.log('Created team template:', template.id);
|
|||||||
<Tabs items={['curl', 'TypeScript']}>
|
<Tabs items={['curl', 'TypeScript']}>
|
||||||
<Tab value="curl">
|
<Tab value="curl">
|
||||||
```bash
|
```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"
|
-H "Authorization: api_team_xxxxxxxxxxxxxxxx"
|
||||||
````
|
````
|
||||||
|
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab value="TypeScript">
|
<Tab value="TypeScript">
|
||||||
```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',
|
method: 'GET',
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: TEAM_API_TOKEN,
|
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;
|
const LEGAL_TEAM_TOKEN = process.env.LEGAL_TEAM_API_TOKEN;
|
||||||
|
|
||||||
// Get pending documents from sales team
|
// 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 },
|
headers: { Authorization: SALES_TEAM_TOKEN },
|
||||||
});
|
});
|
||||||
const salesDocs = await salesResponse.json();
|
const salesDocs = await salesResponse.json();
|
||||||
|
|
||||||
// Get completed documents from legal team
|
// 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 },
|
headers: { Authorization: LEGAL_TEAM_TOKEN },
|
||||||
});
|
});
|
||||||
const legalDocs = await legalResponse.json();
|
const legalDocs = await legalResponse.json();
|
||||||
|
|
||||||
console.log(`Sales team: ${salesDocs.pagination.totalItems} pending`);
|
console.log(`Sales team: ${salesDocs.count} pending`);
|
||||||
console.log(`Legal team: ${legalDocs.pagination.totalItems} completed`);
|
console.log(`Legal team: ${legalDocs.count} completed`);
|
||||||
```
|
```
|
||||||
|
|
||||||
## Error Responses
|
## Error Responses
|
||||||
|
|||||||
@@ -13,7 +13,194 @@ import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
|
|||||||
see the [OpenAPI Reference](https://openapi.documenso.com).
|
see the [OpenAPI Reference](https://openapi.documenso.com).
|
||||||
</Callout>
|
</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:
|
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.
|
Retrieve a paginated list of templates.
|
||||||
|
|
||||||
@@ -139,8 +326,8 @@ const response = await fetch(`${BASE_URL}/template`, {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data, pagination } = await response.json();
|
const { data, count } = await response.json();
|
||||||
console.log(`Found ${pagination.totalItems} templates`);
|
console.log(`Found ${count} templates`);
|
||||||
|
|
||||||
// Filter by type
|
// Filter by type
|
||||||
const privateResponse = await fetch(
|
const privateResponse = await fetch(
|
||||||
@@ -181,18 +368,16 @@ const privateTemplates = await privateResponse.json();
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"pagination": {
|
"count": 25,
|
||||||
"page": 1,
|
"currentPage": 1,
|
||||||
"perPage": 10,
|
"perPage": 10,
|
||||||
"totalPages": 3,
|
"totalPages": 3
|
||||||
"totalItems": 25
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Get Template
|
## Get Template (Deprecated)
|
||||||
|
|
||||||
Retrieve a single template by ID.
|
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">
|
<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.
|
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
|
### 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
|
```json
|
||||||
{
|
{
|
||||||
"id": "envelope_xyz789",
|
"id": 789,
|
||||||
"type": "DOCUMENT",
|
"envelopeId": "envelope_xyz789",
|
||||||
"status": "PENDING",
|
"status": "PENDING",
|
||||||
"title": "Employment Contract",
|
|
||||||
"source": "TEMPLATE",
|
"source": "TEMPLATE",
|
||||||
|
"title": "Employment Contract",
|
||||||
"externalId": "contract-2025-001",
|
"externalId": "contract-2025-001",
|
||||||
"recipients": [
|
"recipients": [
|
||||||
{
|
{
|
||||||
"id": 1,
|
"id": 1,
|
||||||
|
"envelopeId": "envelope_xyz789",
|
||||||
|
"documentId": 789,
|
||||||
|
"templateId": null,
|
||||||
"email": "john.doe@example.com",
|
"email": "john.doe@example.com",
|
||||||
"name": "John Doe",
|
"name": "John Doe",
|
||||||
"role": "SIGNER",
|
"role": "SIGNER",
|
||||||
"signingStatus": "NOT_SIGNED",
|
"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:
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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 |
|
| 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.
|
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}`,
|
subject: `Employment Contract for ${employeeData.name}`,
|
||||||
message: `Hi ${employeeData.name},\n\nPlease review and sign your employment contract.`,
|
message: `Hi ${employeeData.name},\n\nPlease review and sign your employment contract.`,
|
||||||
},
|
},
|
||||||
distributeDocument: true,
|
distributeDocument: false,
|
||||||
externalId: `emp-contract-${Date.now()}`,
|
externalId: `emp-contract-${Date.now()}`,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const document = await documentResponse.json();
|
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 {
|
return {
|
||||||
documentId: document.id,
|
envelopeId: document.envelopeId,
|
||||||
signingUrl: document.recipients[0].signingUrl,
|
signingUrl: distribution.recipients[0].signingUrl,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1018,7 +1241,7 @@ const result = await sendEmploymentContract({
|
|||||||
startDate: '2025-03-01',
|
startDate: '2025-03-01',
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log('Document created:', result.documentId);
|
console.log('Document created:', result.envelopeId);
|
||||||
console.log('Signing URL:', result.signingUrl);
|
console.log('Signing URL:', result.signingUrl);
|
||||||
````
|
````
|
||||||
|
|
||||||
|
|||||||
@@ -256,8 +256,11 @@ Use templates for repeatable document workflows. This example creates an employm
|
|||||||
Map template fields by label and build a <code>prefillFields</code> array
|
Map template fields by label and build a <code>prefillFields</code> array
|
||||||
</Step>
|
</Step>
|
||||||
<Step>
|
<Step>
|
||||||
Call <code>POST /template/use</code> with recipients, prefill data, and{' '}
|
Call <code>POST /template/use</code> with recipients and prefill data
|
||||||
<code>distributeDocument: true</code>
|
</Step>
|
||||||
|
<Step>
|
||||||
|
Distribute the returned envelope via <code>POST /envelope/distribute</code> and read its signing
|
||||||
|
links
|
||||||
</Step>
|
</Step>
|
||||||
</Steps>
|
</Steps>
|
||||||
|
|
||||||
@@ -291,7 +294,7 @@ type TemplateRecipient = {
|
|||||||
async function sendEmploymentContract(
|
async function sendEmploymentContract(
|
||||||
templateId: number,
|
templateId: number,
|
||||||
employee: EmployeeData,
|
employee: EmployeeData,
|
||||||
): Promise<{ documentId: string; signingUrl: string }> {
|
): Promise<{ documentId: number; signingUrl: string }> {
|
||||||
const templateResponse = await fetch(`${BASE_URL}/template/${templateId}`, {
|
const templateResponse = await fetch(`${BASE_URL}/template/${templateId}`, {
|
||||||
headers: { Authorization: API_TOKEN },
|
headers: { Authorization: API_TOKEN },
|
||||||
});
|
});
|
||||||
@@ -368,7 +371,6 @@ async function sendEmploymentContract(
|
|||||||
subject: `Your Employment Contract at ${employee.department}`,
|
subject: `Your Employment Contract at ${employee.department}`,
|
||||||
message: `Hi ${employee.name},\n\nPlease review and sign your employment contract for the ${employee.position} position.\n\nStart date: ${employee.startDate}`,
|
message: `Hi ${employee.name},\n\nPlease review and sign your employment contract for the ${employee.position} position.\n\nStart date: ${employee.startDate}`,
|
||||||
},
|
},
|
||||||
distributeDocument: true,
|
|
||||||
externalId: `emp-${Date.now()}-${employee.email.split('@')[0]}`,
|
externalId: `emp-${Date.now()}-${employee.email.split('@')[0]}`,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
@@ -380,9 +382,25 @@ async function sendEmploymentContract(
|
|||||||
|
|
||||||
const document = await createResponse.json();
|
const document = await createResponse.json();
|
||||||
|
|
||||||
|
const distributeResponse = await fetch(`${BASE_URL}/envelope/distribute`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
Authorization: API_TOKEN,
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ envelopeId: document.envelopeId }),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!distributeResponse.ok) {
|
||||||
|
const error = await distributeResponse.json();
|
||||||
|
throw new Error(`Failed to send document: ${error.message}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const distributeResult = await distributeResponse.json();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
documentId: document.id,
|
documentId: document.id,
|
||||||
signingUrl: document.recipients[0].signingUrl,
|
signingUrl: distributeResult.recipients[0].signingUrl,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -447,12 +465,17 @@ RESPONSE=$(curl -s -X POST "${BASE_URL}/template/use" \
|
|||||||
\"subject\": \"Your Employment Contract\",
|
\"subject\": \"Your Employment Contract\",
|
||||||
\"message\": \"Please review and sign your employment contract.\"
|
\"message\": \"Please review and sign your employment contract.\"
|
||||||
},
|
},
|
||||||
\"distributeDocument\": true,
|
|
||||||
\"externalId\": \"emp-$(date +%s)-alice\"
|
\"externalId\": \"emp-$(date +%s)-alice\"
|
||||||
}")
|
}")
|
||||||
|
|
||||||
echo "Document created:"
|
ENVELOPE_ID=$(echo $RESPONSE | jq -r '.envelopeId')
|
||||||
echo $RESPONSE | jq '{id, signingUrl: .recipients[0].signingUrl}'
|
DISTRIBUTE_RESPONSE=$(curl -s -X POST "${BASE_URL}/envelope/distribute" \
|
||||||
|
-H "Authorization: ${API_TOKEN}" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{\"envelopeId\": \"${ENVELOPE_ID}\"}")
|
||||||
|
|
||||||
|
echo "Document created: $(echo $RESPONSE | jq -r '.id')"
|
||||||
|
echo "Signing URL: $(echo $DISTRIBUTE_RESPONSE | jq -r '.recipients[0].signingUrl')"
|
||||||
````
|
````
|
||||||
|
|
||||||
</Tab>
|
</Tab>
|
||||||
@@ -470,8 +493,10 @@ Send the same document to multiple recipients in parallel. Useful for policy ack
|
|||||||
Fetch the template and get the signer recipient slot ID
|
Fetch the template and get the signer recipient slot ID
|
||||||
</Step>
|
</Step>
|
||||||
<Step>
|
<Step>
|
||||||
For each recipient, call <code>POST /template/use</code> with{' '}
|
For each recipient, call <code>POST /template/use</code>
|
||||||
<code>distributeDocument: true</code>
|
</Step>
|
||||||
|
<Step>
|
||||||
|
Distribute each returned envelope via <code>POST /envelope/distribute</code>
|
||||||
</Step>
|
</Step>
|
||||||
<Step>
|
<Step>
|
||||||
Process in batches with a short delay to respect rate limits (e.g. 1000 requests/minute)
|
Process in batches with a short delay to respect rate limits (e.g. 1000 requests/minute)
|
||||||
@@ -534,7 +559,6 @@ async function bulkSendFromTemplate(
|
|||||||
recipients: [
|
recipients: [
|
||||||
{ id: signerSlot.id, email: recipient.email, name: recipient.name },
|
{ id: signerSlot.id, email: recipient.email, name: recipient.name },
|
||||||
],
|
],
|
||||||
distributeDocument: true,
|
|
||||||
externalId: `bulk-${Date.now()}-${recipient.email}`,
|
externalId: `bulk-${Date.now()}-${recipient.email}`,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
@@ -545,10 +569,26 @@ async function bulkSendFromTemplate(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const document = await response.json();
|
const document = await response.json();
|
||||||
|
|
||||||
|
const distributeResponse = await fetch(`${BASE_URL}/envelope/distribute`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
Authorization: API_TOKEN,
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ envelopeId: document.envelopeId }),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!distributeResponse.ok) {
|
||||||
|
const error = await distributeResponse.json();
|
||||||
|
throw new Error(error.message || 'Failed to distribute document');
|
||||||
|
}
|
||||||
|
|
||||||
|
const distributeResult = await distributeResponse.json();
|
||||||
return {
|
return {
|
||||||
email: recipient.email,
|
email: recipient.email,
|
||||||
envelopeId: document.id,
|
envelopeId: document.envelopeId,
|
||||||
signingUrl: document.recipients[0].signingUrl,
|
signingUrl: distributeResult.recipients[0].signingUrl,
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
@@ -621,14 +661,24 @@ for RECIPIENT in "${RECIPIENTS[@]}"; do
|
|||||||
\"email\": \"${EMAIL}\",
|
\"email\": \"${EMAIL}\",
|
||||||
\"name\": \"${NAME}\"
|
\"name\": \"${NAME}\"
|
||||||
}],
|
}],
|
||||||
\"distributeDocument\": true,
|
|
||||||
\"externalId\": \"bulk-$(date +%s)-${EMAIL}\"
|
\"externalId\": \"bulk-$(date +%s)-${EMAIL}\"
|
||||||
}")
|
}")
|
||||||
|
|
||||||
if echo $RESPONSE | jq -e '.id' > /dev/null 2>&1; then
|
if echo $RESPONSE | jq -e '.envelopeId' > /dev/null 2>&1; then
|
||||||
echo " Success: $(echo $RESPONSE | jq -r '.id')"
|
ENVELOPE_ID=$(echo $RESPONSE | jq -r '.envelopeId')
|
||||||
|
DISTRIBUTE_RESPONSE=$(curl -s -X POST "${BASE_URL}/envelope/distribute" \
|
||||||
|
-H "Authorization: ${API_TOKEN}" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{\"envelopeId\": \"${ENVELOPE_ID}\"}")
|
||||||
|
|
||||||
|
if echo $DISTRIBUTE_RESPONSE | jq -e '.success' > /dev/null 2>&1; then
|
||||||
|
echo " Success: ${ENVELOPE_ID}"
|
||||||
|
echo " Signing URL: $(echo $DISTRIBUTE_RESPONSE | jq -r '.recipients[0].signingUrl')"
|
||||||
|
else
|
||||||
|
echo " Failed to distribute: $(echo $DISTRIBUTE_RESPONSE | jq -r '.message')"
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
echo " Failed: $(echo $RESPONSE | jq -r '.message')"
|
echo " Failed to create: $(echo $RESPONSE | jq -r '.message')"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Rate limiting delay
|
# Rate limiting delay
|
||||||
@@ -831,13 +881,15 @@ After a document is completed, download the signed PDF with all signatures embed
|
|||||||
</Step>
|
</Step>
|
||||||
</Steps>
|
</Steps>
|
||||||
|
|
||||||
|
The `version` query parameter accepts `original`, `pending`, or `signed`.
|
||||||
|
|
||||||
<Tabs items={['TypeScript', 'curl']}>
|
<Tabs items={['TypeScript', 'curl']}>
|
||||||
<Tab value="TypeScript">
|
<Tab value="TypeScript">
|
||||||
```typescript
|
```typescript
|
||||||
const API_TOKEN = process.env.DOCUMENSO_API_TOKEN;
|
const API_TOKEN = process.env.DOCUMENSO_API_TOKEN;
|
||||||
const BASE_URL = 'https://app.documenso.com/api/v2';
|
const BASE_URL = 'https://app.documenso.com/api/v2';
|
||||||
|
|
||||||
type DownloadVersion = 'signed' | 'original';
|
type DownloadVersion = 'original' | 'pending' | 'signed';
|
||||||
|
|
||||||
async function downloadDocument(
|
async function downloadDocument(
|
||||||
envelopeId: string,
|
envelopeId: string,
|
||||||
@@ -891,7 +943,7 @@ async function downloadAllCompletedDocuments(outputDir: string): Promise<void> {
|
|||||||
{ headers: { Authorization: API_TOKEN } },
|
{ headers: { Authorization: API_TOKEN } },
|
||||||
);
|
);
|
||||||
|
|
||||||
const { data, pagination } = await response.json();
|
const { data, count, currentPage, perPage, totalPages } = await response.json();
|
||||||
|
|
||||||
for (const envelope of data) {
|
for (const envelope of data) {
|
||||||
try {
|
try {
|
||||||
@@ -905,8 +957,8 @@ async function downloadAllCompletedDocuments(outputDir: string): Promise<void> {
|
|||||||
await new Promise((resolve) => setTimeout(resolve, 500));
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
||||||
}
|
}
|
||||||
|
|
||||||
hasMore = page < pagination.totalPages;
|
hasMore = currentPage < totalPages;
|
||||||
page++;
|
page = currentPage + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,20 +24,18 @@ import { Step, Steps } from 'fumadocs-ui/components/steps';
|
|||||||
{/* prettier-ignore */}
|
{/* prettier-ignore */}
|
||||||
<Steps>
|
<Steps>
|
||||||
<Step>
|
<Step>
|
||||||
### Open settings
|
### Select a team
|
||||||
|
|
||||||
- Log in to your Documenso account
|
Log in to Documenso and open the team that the integration should access. API tokens are scoped to a
|
||||||
- Click your avatar in the top right corner
|
team.
|
||||||
- Select **Settings** from the dropdown menu
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
</Step>
|
</Step>
|
||||||
|
|
||||||
<Step>
|
<Step>
|
||||||
### Navigate to the API Tokens tab
|
### Open API Tokens
|
||||||
|
|
||||||
Go to **Settings** and open the **API Tokens** tab.
|
Go to **Team Settings** → **API Tokens**, or open
|
||||||
|
`/t/{teamUrl}/settings/tokens` after replacing `{teamUrl}` with your team's URL.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
@@ -48,7 +46,7 @@ Go to **Settings** and open the **API Tokens** tab.
|
|||||||
|
|
||||||
- Click **Create Token**
|
- Click **Create Token**
|
||||||
- Enter a descriptive name (e.g., `production-backend`, `zapier-integration`)
|
- Enter a descriptive name (e.g., `production-backend`, `zapier-integration`)
|
||||||
- Select an expiration period: never expires, 7 days, 1 month, 3 months, 6 months, or 1 year
|
- Select an expiration period: 7 days, 1 month, 3 months, 6 months, 12 months, or Never
|
||||||
- Click **Create Token**
|
- Click **Create Token**
|
||||||
|
|
||||||
</Step>
|
</Step>
|
||||||
@@ -75,21 +73,21 @@ Include the token in the `Authorization` header of your HTTP requests.
|
|||||||
### cURL
|
### cURL
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl https://app.documenso.com/api/v2/document \
|
curl https://app.documenso.com/api/v2/envelope \
|
||||||
-H "Authorization: api_xxxxxxxxxxxxxxxx"
|
-H "Authorization: api_xxxxxxxxxxxxxxxx"
|
||||||
```
|
```
|
||||||
|
|
||||||
### JavaScript / TypeScript
|
### JavaScript / TypeScript
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
const response = await fetch('https://app.documenso.com/api/v2/document', {
|
const response = await fetch('https://app.documenso.com/api/v2/envelope', {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: 'api_xxxxxxxxxxxxxxxx',
|
Authorization: 'api_xxxxxxxxxxxxxxxx',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const documents = await response.json();
|
const envelopes = await response.json();
|
||||||
```
|
```
|
||||||
|
|
||||||
### Using the TypeScript SDK
|
### Using the TypeScript SDK
|
||||||
@@ -129,7 +127,7 @@ SDKs are available for [TypeScript](https://github.com/documenso/sdk-typescript)
|
|||||||
|
|
||||||
## Token Security
|
## Token Security
|
||||||
|
|
||||||
API tokens grant full access to your account. Follow these practices to keep them secure:
|
API tokens grant full API access to the team they were created for. Follow these practices to keep them secure:
|
||||||
|
|
||||||
- **Never commit tokens to version control.** Use environment variables instead.
|
- **Never commit tokens to version control.** Use environment variables instead.
|
||||||
- **Use descriptive names.** Names like `zapier-prod` or `backend-staging` help you identify token usage.
|
- **Use descriptive names.** Names like `zapier-prod` or `backend-staging` help you identify token usage.
|
||||||
@@ -155,12 +153,11 @@ const client = new Documenso({
|
|||||||
|
|
||||||
## Token Scope
|
## Token Scope
|
||||||
|
|
||||||
API tokens have full access to your account, including:
|
API tokens have full API access to the team they were created for, including:
|
||||||
|
|
||||||
- Creating, reading, updating, and deleting documents
|
- Creating, reading, updating, and deleting documents
|
||||||
- Managing recipients and fields
|
- Managing recipients and fields
|
||||||
- Accessing templates
|
- Accessing templates
|
||||||
- Managing team resources (if the token owner has team access)
|
|
||||||
|
|
||||||
There is currently no way to create tokens with limited scopes or permissions.
|
There is currently no way to create tokens with limited scopes or permissions.
|
||||||
|
|
||||||
@@ -171,7 +168,7 @@ To revoke a token:
|
|||||||
{/* prettier-ignore */}
|
{/* prettier-ignore */}
|
||||||
<Steps>
|
<Steps>
|
||||||
<Step>
|
<Step>
|
||||||
Go to **Settings** > **API Tokens**
|
Go to **Team Settings** → **API Tokens**
|
||||||
</Step>
|
</Step>
|
||||||
<Step>
|
<Step>
|
||||||
Find the token you want to revoke
|
Find the token you want to revoke
|
||||||
@@ -194,7 +191,7 @@ Revoked tokens stop working immediately. Any integrations using that token will
|
|||||||
</Accordion>
|
</Accordion>
|
||||||
<Accordion title="401 Unauthorized — Expired token">Create a new token in settings.</Accordion>
|
<Accordion title="401 Unauthorized — Expired token">Create a new token in settings.</Accordion>
|
||||||
<Accordion title="403 Forbidden — Token doesn't have access to the resource">
|
<Accordion title="403 Forbidden — Token doesn't have access to the resource">
|
||||||
Ensure you're accessing resources owned by the token's account.
|
Ensure you're accessing resources owned by the token's team.
|
||||||
</Accordion>
|
</Accordion>
|
||||||
</Accordions>
|
</Accordions>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user