mirror of
https://github.com/documenso/documenso.git
synced 2026-08-16 11:31:51 +10:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a43d09be9b |
@@ -6,6 +6,8 @@ description: Add signature and form fields to documents via API.
|
||||
import { Callout } from 'fumadocs-ui/components/callout';
|
||||
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).
|
||||
@@ -62,7 +64,7 @@ import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
|
||||
| Type | Description | Auto-filled |
|
||||
| ---------------- | ----------------------------------------- | ----------- |
|
||||
| `SIGNATURE` | Drawn, typed, or uploaded signature | No |
|
||||
| `FREE_SIGNATURE` | Unrestricted signature without validation | No |
|
||||
| `FREE_SIGNATURE` | Legacy free-form signature. Accepted by the v2 create schema but rejected by the v1 API and unsupported in the signing UI — avoid in new integrations | No |
|
||||
| `INITIALS` | Recipient's initials | No |
|
||||
| `NAME` | Recipient's full name | Yes |
|
||||
| `EMAIL` | Recipient's email address | Yes |
|
||||
@@ -140,6 +142,8 @@ POST /envelope/field/create-many
|
||||
| `envelopeId` | string | Yes | The envelope ID |
|
||||
| `data` | array | Yes | Array of field configurations |
|
||||
|
||||
Each entry in `data` requires a `type`, a `recipientId`, and a position — either explicit coordinates (`page`, `positionX`, `positionY`, `width`, `height`) or a [text placeholder](#placeholder-based-field-positioning) (`placeholder` with optional `width`, `height`, and `matchAll`). Optional per-entry properties: `envelopeItemId` (which PDF in the envelope to place the field on; defaults to the first item) and `fieldMeta`.
|
||||
|
||||
### Code Examples
|
||||
|
||||
<Tabs items={['curl', 'TypeScript']}>
|
||||
@@ -335,6 +339,8 @@ POST /envelope/field/update-many
|
||||
| `envelopeId` | string | Yes | The envelope ID |
|
||||
| `data` | array | Yes | Array of field update objects |
|
||||
|
||||
Each entry in `data` requires the field `id` and `type`. Position properties (`page`, `positionX`, `positionY`, `width`, `height`), `envelopeItemId`, and `fieldMeta` are optional — only supplied values are updated. Placeholder positioning is not supported when updating; use coordinates.
|
||||
|
||||
### Code Examples
|
||||
|
||||
<Tabs items={['curl', 'TypeScript']}>
|
||||
@@ -551,6 +557,33 @@ This approach is useful when generating PDFs programmatically or using templates
|
||||
|
||||
See the [PDF Placeholders](/docs/users/documents/advanced/pdf-placeholders) guide for the full placeholder format reference, including supported field types, recipient identifiers, and field options.
|
||||
|
||||
### Placeholder Positioning via the API
|
||||
|
||||
`POST /envelope/field/create-many` accepts a placeholder position in place of coordinates. Instead of `page`, `positionX`, `positionY`, `width`, and `height`, pass:
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
| ------------- | ------- | -------- | ------------------------------------------------------------------------------------------------------------ |
|
||||
| `placeholder` | string | Yes | Text to search for in the PDF (e.g. `{{name}}`). The field is placed at the bounding box of the first match. |
|
||||
| `width` | number | No | Override the field width. Defaults to the width of the matched text. |
|
||||
| `height` | number | No | Override the field height. Defaults to the height of the matched text. |
|
||||
| `matchAll` | boolean | No | Create a field at every occurrence of the placeholder instead of only the first. |
|
||||
|
||||
```json
|
||||
{
|
||||
"envelopeId": "envelope_abcdefhiklmnorst",
|
||||
"data": [
|
||||
{
|
||||
"type": "SIGNATURE",
|
||||
"recipientId": 456,
|
||||
"placeholder": "{{signature}}",
|
||||
"matchAll": true
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
`POST /envelope/field/update-many` does not accept placeholders — field updates are coordinate-only.
|
||||
|
||||
---
|
||||
|
||||
## Field Meta Options
|
||||
|
||||
@@ -78,10 +78,12 @@ A successful response returns a list of your documents (envelopes):
|
||||
"createdAt": "2025-01-15T10:30:00.000Z"
|
||||
}
|
||||
],
|
||||
"count": 1,
|
||||
"currentPage": 1,
|
||||
"perPage": 10,
|
||||
"totalPages": 1
|
||||
"pagination": {
|
||||
"page": 1,
|
||||
"perPage": 10,
|
||||
"totalPages": 1,
|
||||
"totalItems": 1
|
||||
}
|
||||
}
|
||||
````
|
||||
|
||||
@@ -226,12 +228,9 @@ 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/distribute" \
|
||||
curl -X POST "https://app.documenso.com/api/v2/envelope/envelope_abc123/distribute" \
|
||||
-H "Authorization: YOUR_API_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"envelopeId": "envelope_abc123"
|
||||
}'
|
||||
-H "Content-Type: application/json"
|
||||
````
|
||||
|
||||
</Tab>
|
||||
@@ -239,14 +238,16 @@ curl -X POST "https://app.documenso.com/api/v2/envelope/distribute" \
|
||||
```javascript
|
||||
const envelopeId = 'envelope_abc123';
|
||||
|
||||
const response = await fetch('https://app.documenso.com/api/v2/envelope/distribute', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: 'YOUR_API_TOKEN',
|
||||
'Content-Type': 'application/json',
|
||||
const response = await fetch(
|
||||
`https://app.documenso.com/api/v2/envelope/${envelopeId}/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);
|
||||
@@ -336,14 +337,16 @@ 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/distribute`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': API_TOKEN,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ envelopeId: envelope.id }),
|
||||
});
|
||||
const distributeResponse = await fetch(
|
||||
`${BASE_URL}/envelope/${envelope.id}/distribute`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': API_TOKEN,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
if (!distributeResponse.ok) {
|
||||
const error = await distributeResponse.json();
|
||||
@@ -419,12 +422,9 @@ echo "Created envelope: ${ENVELOPE_ID}"
|
||||
# Step 2: Send the document for signing
|
||||
|
||||
echo "Sending document..."
|
||||
curl -s -X POST "${BASE_URL}/envelope/distribute" \
|
||||
curl -s -X POST "${BASE_URL}/envelope/${ENVELOPE_ID}/distribute" \
|
||||
-H "Authorization: ${API_TOKEN}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{
|
||||
\"envelopeId\": \"${ENVELOPE_ID}\"
|
||||
}"
|
||||
-H "Content-Type: application/json"
|
||||
|
||||
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 for the duration in the `Retry-After` header |
|
||||
| `429` | Rate limited - wait 60 seconds and retry |
|
||||
| `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. 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.
|
||||
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:
|
||||
|
||||
```javascript
|
||||
async function fetchWithRetry(url, options, maxRetries = 3) {
|
||||
@@ -493,9 +493,8 @@ async function fetchWithRetry(url, options, maxRetries = 3) {
|
||||
const response = await fetch(url, options);
|
||||
|
||||
if (response.status === 429) {
|
||||
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));
|
||||
console.log('Rate limited, waiting 60 seconds...');
|
||||
await new Promise((resolve) => setTimeout(resolve, 60000));
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user