Compare commits
4 Commits
chore/tran
...
feat/add-a
| Author | SHA1 | Date | |
|---|---|---|---|
| 01ff304e6e | |||
| 90e40e4368 | |||
| 2c89b0805a | |||
| f53fad8cd7 |
@ -13,10 +13,6 @@ NEXT_PRIVATE_ENCRYPTION_SECONDARY_KEY="DEADBEEF"
|
||||
# https://docs.documenso.com/developers/self-hosting/setting-up-oauth-providers#google-oauth-gmail
|
||||
NEXT_PRIVATE_GOOGLE_CLIENT_ID=""
|
||||
NEXT_PRIVATE_GOOGLE_CLIENT_SECRET=""
|
||||
# Find documentation on setting up Microsoft OAuth here:
|
||||
# https://docs.documenso.com/developers/self-hosting/setting-up-oauth-providers#microsoft-oauth-azure-ad
|
||||
NEXT_PRIVATE_MICROSOFT_CLIENT_ID=""
|
||||
NEXT_PRIVATE_MICROSOFT_CLIENT_SECRET=""
|
||||
|
||||
NEXT_PRIVATE_OIDC_WELL_KNOWN=""
|
||||
NEXT_PRIVATE_OIDC_CLIENT_ID=""
|
||||
@ -29,10 +25,6 @@ NEXT_PUBLIC_WEBAPP_URL="http://localhost:3000"
|
||||
# URL used by the web app to request itself (e.g. local background jobs)
|
||||
NEXT_PRIVATE_INTERNAL_WEBAPP_URL="http://localhost:3000"
|
||||
|
||||
# [[SERVER]]
|
||||
# OPTIONAL: The port the server will listen on. Defaults to 3000.
|
||||
PORT=3000
|
||||
|
||||
# [[DATABASE]]
|
||||
NEXT_PRIVATE_DATABASE_URL="postgres://documenso:password@127.0.0.1:54320/documenso"
|
||||
# Defines the URL to use for the database when running migrations and other commands that won't work with a connection pool.
|
||||
|
||||
692
CODE_STYLE.md
@ -1,692 +0,0 @@
|
||||
# Documenso Code Style Guide
|
||||
|
||||
This document captures the code style, patterns, and conventions used in the Documenso codebase. It covers both enforceable rules and subjective "taste" elements that make our code consistent and maintainable.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
1. [General Principles](#general-principles)
|
||||
2. [TypeScript Conventions](#typescript-conventions)
|
||||
3. [Imports & Dependencies](#imports--dependencies)
|
||||
4. [Functions & Methods](#functions--methods)
|
||||
5. [React & Components](#react--components)
|
||||
6. [Error Handling](#error-handling)
|
||||
7. [Async/Await Patterns](#asyncawait-patterns)
|
||||
8. [Whitespace & Formatting](#whitespace--formatting)
|
||||
9. [Naming Conventions](#naming-conventions)
|
||||
10. [Pattern Matching](#pattern-matching)
|
||||
11. [Database & Prisma](#database--prisma)
|
||||
12. [TRPC Patterns](#trpc-patterns)
|
||||
|
||||
---
|
||||
|
||||
## General Principles
|
||||
|
||||
- **Functional over Object-Oriented**: Prefer functional programming patterns over classes
|
||||
- **Explicit over Implicit**: Be explicit about types, return values, and error cases
|
||||
- **Early Returns**: Use guard clauses and early returns to reduce nesting
|
||||
- **Immutability**: Favor `const` over `let`; avoid mutation where possible
|
||||
|
||||
---
|
||||
|
||||
## TypeScript Conventions
|
||||
|
||||
### Type Definitions
|
||||
|
||||
```typescript
|
||||
// ✅ Prefer `type` over `interface`
|
||||
type CreateDocumentOptions = {
|
||||
templateId: number;
|
||||
userId: number;
|
||||
recipients: Recipient[];
|
||||
};
|
||||
|
||||
// ❌ Avoid interfaces unless absolutely necessary
|
||||
interface CreateDocumentOptions {
|
||||
templateId: number;
|
||||
}
|
||||
```
|
||||
|
||||
### Type Imports
|
||||
|
||||
```typescript
|
||||
// ✅ Use `type` keyword for type-only imports
|
||||
import type { Document, Recipient } from '@prisma/client';
|
||||
import { DocumentStatus } from '@prisma/client';
|
||||
|
||||
// Types in function signatures
|
||||
export const findDocuments = async ({ userId, teamId }: FindDocumentsOptions) => {
|
||||
// ...
|
||||
};
|
||||
```
|
||||
|
||||
### Inline Types for Function Parameters
|
||||
|
||||
```typescript
|
||||
// ✅ Extract inline types to named types
|
||||
type FinalRecipient = Pick<Recipient, 'name' | 'email' | 'role' | 'authOptions'> & {
|
||||
templateRecipientId: number;
|
||||
fields: Field[];
|
||||
};
|
||||
|
||||
const finalRecipients: FinalRecipient[] = [];
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Imports & Dependencies
|
||||
|
||||
### Import Organization
|
||||
|
||||
Imports should be organized in the following order with blank lines between groups:
|
||||
|
||||
```typescript
|
||||
// 1. React imports
|
||||
import { useCallback, useEffect, useMemo } from 'react';
|
||||
|
||||
// 2. Third-party library imports (alphabetically)
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { Trans } from '@lingui/react/macro';
|
||||
import type { Document, Recipient } from '@prisma/client';
|
||||
import { DocumentStatus, RecipientRole } from '@prisma/client';
|
||||
import { match } from 'ts-pattern';
|
||||
|
||||
// 3. Internal package imports (from @documenso/*)
|
||||
import { AppError } from '@documenso/lib/errors/app-error';
|
||||
import { prisma } from '@documenso/prisma';
|
||||
import { Button } from '@documenso/ui/primitives/button';
|
||||
|
||||
// 4. Relative imports
|
||||
import { getTeamById } from '../team/get-team';
|
||||
import type { FindResultResponse } from './types';
|
||||
```
|
||||
|
||||
### Destructuring Imports
|
||||
|
||||
```typescript
|
||||
// ✅ Destructure specific exports
|
||||
// ✅ Use type imports for types
|
||||
import type { Document } from '@prisma/client';
|
||||
|
||||
import { Button } from '@documenso/ui/primitives/button';
|
||||
import { Input } from '@documenso/ui/primitives/input';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Functions & Methods
|
||||
|
||||
### Arrow Functions
|
||||
|
||||
```typescript
|
||||
// ✅ Always use arrow functions for functions
|
||||
export const createDocument = async ({
|
||||
userId,
|
||||
title,
|
||||
}: CreateDocumentOptions) => {
|
||||
// ...
|
||||
};
|
||||
|
||||
// ✅ Callbacks and handlers
|
||||
const onSubmit = useCallback(async () => {
|
||||
// ...
|
||||
}, [dependencies]);
|
||||
|
||||
// ❌ Avoid regular function declarations
|
||||
function createDocument() {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
### Function Parameters
|
||||
|
||||
```typescript
|
||||
// ✅ Use destructured object parameters for multiple params
|
||||
export const findDocuments = async ({
|
||||
userId,
|
||||
teamId,
|
||||
status = ExtendedDocumentStatus.ALL,
|
||||
page = 1,
|
||||
perPage = 10,
|
||||
}: FindDocumentsOptions) => {
|
||||
// ...
|
||||
};
|
||||
|
||||
// ✅ Destructure on separate line when needed
|
||||
const onFormSubmit = form.handleSubmit(onSubmit);
|
||||
|
||||
// ✅ Deconstruct nested properties explicitly
|
||||
const { user } = ctx;
|
||||
const { templateId } = input;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## React & Components
|
||||
|
||||
### Component Definition
|
||||
|
||||
```typescript
|
||||
// ✅ Use const with arrow function
|
||||
export const AddSignersFormPartial = ({
|
||||
documentFlow,
|
||||
recipients,
|
||||
fields,
|
||||
onSubmit,
|
||||
}: AddSignersFormProps) => {
|
||||
// ...
|
||||
};
|
||||
|
||||
// ❌ Never use classes
|
||||
class MyComponent extends React.Component {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
### Hooks
|
||||
|
||||
```typescript
|
||||
// ✅ Group related hooks together with blank line separation
|
||||
const { _ } = useLingui();
|
||||
const { toast } = useToast();
|
||||
|
||||
const { currentStep, totalSteps, previousStep } = useStep();
|
||||
|
||||
const form = useForm<TFormSchema>({
|
||||
resolver: zodResolver(ZFormSchema),
|
||||
defaultValues: {
|
||||
// ...
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### Event Handlers
|
||||
|
||||
```typescript
|
||||
// ✅ Use arrow functions with descriptive names
|
||||
const onFormSubmit = async () => {
|
||||
await form.trigger();
|
||||
// ...
|
||||
};
|
||||
|
||||
const onFieldCopy = useCallback(
|
||||
(event?: KeyboardEvent | null) => {
|
||||
event?.preventDefault();
|
||||
// ...
|
||||
},
|
||||
[dependencies],
|
||||
);
|
||||
|
||||
// ✅ Inline handlers for simple operations
|
||||
<Button onClick={() => setOpen(false)}>Close</Button>
|
||||
```
|
||||
|
||||
### State Management
|
||||
|
||||
```typescript
|
||||
// ✅ Descriptive state names with auxiliary verbs
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [hasError, setHasError] = useState(false);
|
||||
const [showAdvancedSettings, setShowAdvancedSettings] = useState(false);
|
||||
|
||||
// ✅ Complex state in single useState when related
|
||||
const [coords, setCoords] = useState({
|
||||
x: 0,
|
||||
y: 0,
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Error Handling
|
||||
|
||||
### Try-Catch Blocks
|
||||
|
||||
```typescript
|
||||
// ✅ Use try-catch for operations that might fail
|
||||
try {
|
||||
const document = await getDocumentById({
|
||||
documentId: Number(documentId),
|
||||
userId: user.id,
|
||||
});
|
||||
|
||||
return {
|
||||
status: 200,
|
||||
body: document,
|
||||
};
|
||||
} catch (err) {
|
||||
return {
|
||||
status: 404,
|
||||
body: {
|
||||
message: 'Document not found',
|
||||
},
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### Throwing Errors
|
||||
|
||||
```typescript
|
||||
// ✅ Use AppError for application errors
|
||||
throw new AppError(AppErrorCode.NOT_FOUND, {
|
||||
message: 'Template not found',
|
||||
});
|
||||
|
||||
// ✅ Use descriptive error messages
|
||||
if (!template) {
|
||||
throw new AppError(AppErrorCode.NOT_FOUND, {
|
||||
message: `Template with ID ${templateId} not found`,
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
### Error Parsing on Frontend
|
||||
|
||||
```typescript
|
||||
// ✅ Parse errors on the frontend
|
||||
try {
|
||||
await updateOrganisation({ organisationId, data });
|
||||
} catch (err) {
|
||||
const error = AppError.parseError(err);
|
||||
console.error(error);
|
||||
|
||||
toast({
|
||||
title: t`An error occurred`,
|
||||
description: error.message,
|
||||
variant: 'destructive',
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Async/Await Patterns
|
||||
|
||||
### Async Function Definitions
|
||||
|
||||
```typescript
|
||||
// ✅ Mark async functions clearly
|
||||
export const createDocument = async ({
|
||||
userId,
|
||||
title,
|
||||
}: Options): Promise<Document> => {
|
||||
// ...
|
||||
};
|
||||
|
||||
// ✅ Use await for promises
|
||||
const document = await prisma.document.create({ data });
|
||||
|
||||
// ✅ Use Promise.all for parallel operations
|
||||
const [document, recipients] = await Promise.all([
|
||||
getDocumentById({ documentId }),
|
||||
getRecipientsForDocument({ documentId }),
|
||||
]);
|
||||
```
|
||||
|
||||
### Void for Fire-and-Forget
|
||||
|
||||
```typescript
|
||||
// ✅ Use void for intentionally unwaited promises
|
||||
void handleAutoSave();
|
||||
|
||||
// ✅ Or in event handlers
|
||||
onClick={() => void onFormSubmit()}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Whitespace & Formatting
|
||||
|
||||
### Blank Lines Between Concepts
|
||||
|
||||
```typescript
|
||||
// ✅ Blank line after imports
|
||||
import { prisma } from '@documenso/prisma';
|
||||
|
||||
export const findDocuments = async () => {
|
||||
// ...
|
||||
};
|
||||
|
||||
// ✅ Blank line between logical sections
|
||||
const user = await prisma.user.findFirst({ where: { id: userId } });
|
||||
|
||||
let team = null;
|
||||
|
||||
if (teamId !== undefined) {
|
||||
team = await getTeamById({ userId, teamId });
|
||||
}
|
||||
|
||||
// ✅ Blank line before return statements
|
||||
const result = await someOperation();
|
||||
|
||||
return result;
|
||||
```
|
||||
|
||||
### Function/Method Spacing
|
||||
|
||||
```typescript
|
||||
// ✅ No blank lines between chained methods in same operation
|
||||
const documents = await prisma.document
|
||||
.findMany({ where: { userId } })
|
||||
.then((docs) => docs.map(maskTokens));
|
||||
|
||||
// ✅ Blank line between different operations
|
||||
const document = await createDocument({ userId });
|
||||
|
||||
await sendDocument({ documentId: document.id });
|
||||
|
||||
return document;
|
||||
```
|
||||
|
||||
### Object and Array Formatting
|
||||
|
||||
```typescript
|
||||
// ✅ Multi-line when complex
|
||||
const options = {
|
||||
userId,
|
||||
teamId,
|
||||
status: ExtendedDocumentStatus.ALL,
|
||||
page: 1,
|
||||
};
|
||||
|
||||
// ✅ Single line when simple
|
||||
const coords = { x: 0, y: 0 };
|
||||
|
||||
// ✅ Array items on separate lines when objects
|
||||
const recipients = [
|
||||
{
|
||||
name: 'John',
|
||||
email: 'john@example.com',
|
||||
},
|
||||
{
|
||||
name: 'Jane',
|
||||
email: 'jane@example.com',
|
||||
},
|
||||
];
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Naming Conventions
|
||||
|
||||
### Variables
|
||||
|
||||
```typescript
|
||||
// ✅ camelCase for variables and functions
|
||||
const documentId = 123;
|
||||
const onSubmit = () => {};
|
||||
|
||||
// ✅ Descriptive names with auxiliary verbs for booleans
|
||||
const isLoading = false;
|
||||
const hasError = false;
|
||||
const canEdit = true;
|
||||
const shouldRender = true;
|
||||
|
||||
// ✅ Prefix with $ for DOM elements
|
||||
const $page = document.querySelector('.page');
|
||||
const $inputRef = useRef<HTMLInputElement>(null);
|
||||
```
|
||||
|
||||
### Types and Schemas
|
||||
|
||||
```typescript
|
||||
// ✅ PascalCase for types
|
||||
type CreateDocumentOptions = {
|
||||
userId: number;
|
||||
};
|
||||
|
||||
// ✅ Prefix Zod schemas with Z
|
||||
const ZCreateDocumentSchema = z.object({
|
||||
title: z.string(),
|
||||
});
|
||||
|
||||
// ✅ Prefix type from Zod schema with T
|
||||
type TCreateDocumentSchema = z.infer<typeof ZCreateDocumentSchema>;
|
||||
```
|
||||
|
||||
### Constants
|
||||
|
||||
```typescript
|
||||
// ✅ UPPER_SNAKE_CASE for true constants
|
||||
const DEFAULT_DOCUMENT_DATE_FORMAT = 'dd/MM/yyyy';
|
||||
const MAX_FILE_SIZE = 1024 * 1024 * 5;
|
||||
|
||||
// ✅ camelCase for const variables that aren't "constants"
|
||||
const userId = await getUserId();
|
||||
```
|
||||
|
||||
### Functions
|
||||
|
||||
```typescript
|
||||
// ✅ Verb-based names for functions
|
||||
const createDocument = async () => {};
|
||||
const findDocuments = async () => {};
|
||||
const updateDocument = async () => {};
|
||||
const deleteDocument = async () => {};
|
||||
|
||||
// ✅ On prefix for event handlers
|
||||
const onSubmit = () => {};
|
||||
const onClick = () => {};
|
||||
const onFieldCopy = () => {}; // 'on' is also acceptable
|
||||
```
|
||||
|
||||
### Clarity Over Brevity
|
||||
|
||||
```typescript
|
||||
// ✅ Prefer descriptive names over abbreviations
|
||||
const superLongMethodThatIsCorrect = () => {};
|
||||
const recipientAuthenticationOptions = {};
|
||||
const documentMetadata = {};
|
||||
|
||||
// ❌ Avoid abbreviations that sacrifice clarity
|
||||
const supLongMethThatIsCorrect = () => {};
|
||||
const recipAuthOpts = {};
|
||||
const docMeta = {};
|
||||
|
||||
// ✅ Common abbreviations that are widely understood are acceptable
|
||||
const userId = 123;
|
||||
const htmlElement = document.querySelector('div');
|
||||
const apiResponse = await fetch('/api');
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Pattern Matching
|
||||
|
||||
### Using ts-pattern
|
||||
|
||||
```typescript
|
||||
import { match } from 'ts-pattern';
|
||||
|
||||
// ✅ Use match for complex conditionals
|
||||
const result = match(status)
|
||||
.with(ExtendedDocumentStatus.DRAFT, () => ({
|
||||
status: 'draft',
|
||||
}))
|
||||
.with(ExtendedDocumentStatus.PENDING, () => ({
|
||||
status: 'pending',
|
||||
}))
|
||||
.with(ExtendedDocumentStatus.COMPLETED, () => ({
|
||||
status: 'completed',
|
||||
}))
|
||||
.exhaustive();
|
||||
|
||||
// ✅ Use .otherwise() for default case when not exhaustive
|
||||
const value = match(type)
|
||||
.with('text', () => 'Text field')
|
||||
.with('number', () => 'Number field')
|
||||
.otherwise(() => 'Unknown field');
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Database & Prisma
|
||||
|
||||
### Query Structure
|
||||
|
||||
```typescript
|
||||
// ✅ Destructure commonly used fields
|
||||
const { id, email, name } = user;
|
||||
|
||||
// ✅ Use select to limit returned fields
|
||||
const user = await prisma.user.findFirst({
|
||||
where: { id: userId },
|
||||
select: {
|
||||
id: true,
|
||||
email: true,
|
||||
name: true,
|
||||
},
|
||||
});
|
||||
|
||||
// ✅ Use include for relations
|
||||
const document = await prisma.document.findFirst({
|
||||
where: { id: documentId },
|
||||
include: {
|
||||
recipients: true,
|
||||
fields: true,
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### Transactions
|
||||
|
||||
```typescript
|
||||
// ✅ Use transactions for related operations
|
||||
return await prisma.$transaction(async (tx) => {
|
||||
const document = await tx.document.create({ data });
|
||||
|
||||
await tx.field.createMany({ data: fieldsData });
|
||||
|
||||
await tx.documentAuditLog.create({ data: auditData });
|
||||
|
||||
return document;
|
||||
});
|
||||
```
|
||||
|
||||
### Where Clauses
|
||||
|
||||
```typescript
|
||||
// ✅ Build complex where clauses separately
|
||||
const whereClause: Prisma.DocumentWhereInput = {
|
||||
AND: [
|
||||
{ userId: user.id },
|
||||
{ deletedAt: null },
|
||||
{ status: { in: [DocumentStatus.DRAFT, DocumentStatus.PENDING] } },
|
||||
],
|
||||
};
|
||||
|
||||
const documents = await prisma.document.findMany({
|
||||
where: whereClause,
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## TRPC Patterns
|
||||
|
||||
### Router Structure
|
||||
|
||||
```typescript
|
||||
// ✅ Destructure context and input at start
|
||||
.query(async ({ input, ctx }) => {
|
||||
const { teamId } = ctx;
|
||||
const { templateId } = input;
|
||||
|
||||
ctx.logger.info({
|
||||
input: { templateId },
|
||||
});
|
||||
|
||||
return await getTemplateById({
|
||||
id: templateId,
|
||||
userId: ctx.user.id,
|
||||
teamId,
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### Request/Response Schemas
|
||||
|
||||
```typescript
|
||||
// ✅ Name schemas clearly
|
||||
const ZCreateDocumentRequestSchema = z.object({
|
||||
title: z.string(),
|
||||
recipients: z.array(ZRecipientSchema),
|
||||
});
|
||||
|
||||
const ZCreateDocumentResponseSchema = z.object({
|
||||
documentId: z.number(),
|
||||
status: z.string(),
|
||||
});
|
||||
```
|
||||
|
||||
### Error Handling in TRPC
|
||||
|
||||
```typescript
|
||||
// ✅ Catch and transform errors appropriately
|
||||
try {
|
||||
const result = await createDocument({ userId, data });
|
||||
|
||||
return result;
|
||||
} catch (err) {
|
||||
return AppError.toRestAPIError(err);
|
||||
}
|
||||
|
||||
// ✅ Or throw AppError directly
|
||||
if (!template) {
|
||||
throw new AppError(AppErrorCode.NOT_FOUND, {
|
||||
message: 'Template not found',
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Additional Patterns
|
||||
|
||||
### Optional Chaining
|
||||
|
||||
```typescript
|
||||
// ✅ Use optional chaining for potentially undefined values
|
||||
const email = user?.email;
|
||||
const recipientToken = recipient?.token ?? '';
|
||||
|
||||
// ✅ Use nullish coalescing for defaults
|
||||
const pageSize = perPage ?? 10;
|
||||
const status = documentStatus ?? DocumentStatus.DRAFT;
|
||||
```
|
||||
|
||||
### Array Operations
|
||||
|
||||
```typescript
|
||||
// ✅ Use functional array methods
|
||||
const activeRecipients = recipients.filter((r) => r.signingStatus === 'SIGNED');
|
||||
const recipientEmails = recipients.map((r) => r.email);
|
||||
const hasSignedRecipients = recipients.some((r) => r.signingStatus === 'SIGNED');
|
||||
|
||||
// ✅ Use find instead of filter + [0]
|
||||
const recipient = recipients.find((r) => r.id === recipientId);
|
||||
```
|
||||
|
||||
### Conditional Rendering
|
||||
|
||||
```typescript
|
||||
// ✅ Use && for conditional rendering
|
||||
{isLoading && <Loader />}
|
||||
|
||||
// ✅ Use ternary for either/or
|
||||
{isLoading ? <Loader /> : <Content />}
|
||||
|
||||
// ✅ Extract complex conditions to variables
|
||||
const shouldShowAdvanced = isAdmin && hasPermission && !isDisabled;
|
||||
{shouldShowAdvanced && <AdvancedSettings />}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## When in Doubt
|
||||
|
||||
- **Consistency**: Follow the patterns you see in similar files
|
||||
- **Readability**: Favor code that's easy to read over clever one-liners
|
||||
- **Explicitness**: Be explicit rather than implicit
|
||||
- **Whitespace**: Use blank lines to separate logical sections
|
||||
- **Early Returns**: Use guard clauses to reduce nesting
|
||||
- **Functional**: Prefer functional patterns over imperative ones
|
||||
@ -44,7 +44,7 @@ Before using the `EmbedCreateDocument` component, you'll need to obtain a presig
|
||||
You can create a presign token by making a request to:
|
||||
|
||||
```
|
||||
POST /api/v2/embedding/create-presign-token
|
||||
POST /api/v2-beta/embedding/create-presign-token
|
||||
```
|
||||
|
||||
This API endpoint requires authentication with your Documenso API key. The token has a default expiration of 1 hour, but you can customize this duration based on your security requirements.
|
||||
@ -134,7 +134,7 @@ import { unstable_EmbedCreateDocument as EmbedCreateDocument } from '@documenso/
|
||||
|
||||
function DocumentCreator() {
|
||||
// In a real application, you would fetch this token from your backend
|
||||
// using your API key at /api/v2/embedding/create-presign-token
|
||||
// using your API key at /api/v2-beta/embedding/create-presign-token
|
||||
const presignToken = 'YOUR_PRESIGN_TOKEN';
|
||||
const [documentId, setDocumentId] = useState<number | null>(null);
|
||||
|
||||
|
||||
@ -9,11 +9,11 @@ Documenso uses API keys for authentication. An API key is a unique token that is
|
||||
|
||||
## Creating an API Key
|
||||
|
||||
To create an API key, navigate to the user settings page. Click on your avatar in the top right corner of the dashboard and select "Team Settings" from the dropdown menu.
|
||||
To create an API key, navigate to the user settings page. Click on your avatar in the top right corner of the dashboard and select "**[User settings](https://app.documenso.com/settings)**" from the dropdown menu.
|
||||
|
||||

|
||||
|
||||
Once you're on the settings page, navigate to the **API Tokens** tab. This page lists your existing keys and enables you to create new ones.
|
||||
Once you're on the user settings page, navigate to the "**[API Tokens](https://app.documenso.com/settings/tokens)**" tab. The "API Token" page lists your existing keys and enables you to create new ones.
|
||||
|
||||

|
||||
|
||||
@ -37,17 +37,31 @@ You must include the API key in the `Authorization` request header to authentica
|
||||
Here's a sample API request using cURL:
|
||||
|
||||
```bash
|
||||
curl --location 'https://app.documenso.com/api/v2/envelope/create' \
|
||||
--header 'Authorization: api_xxxxxxxxxxxxxxxx' \
|
||||
--form 'payload={ "title": "Some Title", "type": "DOCUMENT" }'
|
||||
curl --location 'https://app.documenso.com/api/v1/documents?page=1&perPage=1' \
|
||||
--header 'Authorization: api_xxxxxxxxxxxxxxxx'
|
||||
```
|
||||
|
||||
Here's a sample response from the API based on the above cURL request:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "envelope_xxxxxxxxxxxxx"
|
||||
"documents": [
|
||||
{
|
||||
"id": 11,
|
||||
"userId": 2,
|
||||
"teamId": null,
|
||||
"title": "documenso",
|
||||
"status": "PENDING",
|
||||
"documentDataId": "ab2ecm1npk11rt5sp398waf7h",
|
||||
"createdAt": "2024-04-25T11:05:18.420Z",
|
||||
"updatedAt": "2024-04-25T11:05:36.328Z",
|
||||
"completedAt": null
|
||||
}
|
||||
],
|
||||
"totalPages": 1
|
||||
}
|
||||
```
|
||||
|
||||
The API key has access to your account and all its resources. Please keep it secure and do not share it with others. If you suspect your key has been compromised, you can revoke it from the same page you created it from.
|
||||

|
||||
|
||||
The API key has access to your account and all its resources. Please keep it secure and do not share it with others. If you suspect your key has been compromised, you can revoke it from the "API Tokens" page in your user settings.
|
||||
|
||||
@ -9,13 +9,19 @@ import { Callout, Steps } from 'nextra/components';
|
||||
|
||||
Documenso provides a public REST API enabling you to interact with your documents programmatically. The API exposes various HTTP endpoints that allow you to perform operations such as:
|
||||
|
||||
- Retrieving, uploading, deleting, and sending documents for signing
|
||||
- Creating, updating, and deleting recipients
|
||||
- Creating, updating, and deleting document fields
|
||||
- retrieving, uploading, deleting, and sending documents for signing
|
||||
- creating, updating, and deleting recipients
|
||||
- creating, updating, and deleting document fields
|
||||
|
||||
The documentation walks you through creating API keys and using them to authenticate your API requests. You'll also learn about the available endpoints, request and response formats, and how to use the API.
|
||||
|
||||
## API V2 - Stable
|
||||
## API V1 - Stable
|
||||
|
||||
Check out the [API V1 documentation](https://app.documenso.com/api/v1/openapi) for details about the API endpoints, request parameters, response formats, and authentication methods.
|
||||
|
||||
## API V2 - Beta
|
||||
|
||||
<Callout type="warning">API V2 is currently beta, and will be subject to breaking changes</Callout>
|
||||
|
||||
Check out the [API V2 documentation](https://documen.so/api-v2-docs) for details about the API endpoints, request parameters, response formats, and authentication methods.
|
||||
|
||||
@ -26,15 +32,18 @@ Our new API V2 supports the following typed SDKs:
|
||||
- [Go](https://github.com/documenso/sdk-go)
|
||||
|
||||
<Callout type="info">
|
||||
For the staging API, please use the following base URL: `https://stg-app.documenso.com/api/v2/`
|
||||
For the staging API, please use the following base URL:
|
||||
`https://stg-app.documenso.com/api/v2-beta/`
|
||||
</Callout>
|
||||
|
||||
## API V1 - Deprecated
|
||||
|
||||
Check out the [API V1 documentation](https://app.documenso.com/api/v1/openapi) for details about the API endpoints, request parameters, response formats, and authentication methods.
|
||||
🚀 [V2 Announcement](https://documen.so/sdk-blog)
|
||||
|
||||
📖 [Documentation](https://documen.so/api-v2-docs)
|
||||
|
||||
💬 [Leave Feedback](https://documen.so/sdk-feedback)
|
||||
|
||||
🔔 [Breaking Changes](https://documen.so/sdk-breaking)
|
||||
|
||||
## Availability
|
||||
|
||||
The API is available to individual users, teams and higher plans. [Fair Use](https://documen.so/fair) applies.
|
||||
|
||||
@ -7,246 +7,550 @@ import { Callout, Steps } from 'nextra/components';
|
||||
|
||||
# API Reference
|
||||
|
||||
On this page we will refer to both Documents and Templates as Envelopes for convenience, unless otherwise specified.
|
||||
The Swagger UI for the API is available at [/api/v1/openapi](https://app.documenso.com/api/v1/openapi). This page provides detailed information about the API endpoints, request and response formats, and authentication requirements.
|
||||
|
||||
<Callout type="info">
|
||||
This page is used to demonstrate some of the endpoints and how to use them. For the full API
|
||||
reference, please see the [API Reference](https://openapi.documenso.com/).
|
||||
</Callout>
|
||||
## Upload a Document
|
||||
|
||||
## Get Envelope
|
||||
Uploading a document to your Documenso account requires a two-step process.
|
||||
|
||||
For the vast majority of use cases, you will need to retrieve the envelope to get details for further operations.
|
||||
<Steps>
|
||||
|
||||
The main details you generally want to extract are the following:
|
||||
### Create Document
|
||||
|
||||
- **Recipients** - The individuals who will be signing the document
|
||||
- **Fields** - The fields the user will sign
|
||||
- **Items** - The PDF files the user will see and sign
|
||||
|
||||
This is done by doing a the following GET [request](https://openapi.documenso.com/reference#tag/envelope/POST/envelope/create)
|
||||
|
||||
```sh
|
||||
curl -X GET "https://app.documenso.com/api/v2/envelope/envelope_xxxxxxxxxxxxx" \
|
||||
-H "Authorization: api_xxxxxxxxxxxxxx"
|
||||
```
|
||||
|
||||
A successful response looks as follows:
|
||||
First, you need to make a `POST` request to the `/api/v1/documents` endpoint, which takes a JSON payload with the following fields:
|
||||
|
||||
```json
|
||||
{
|
||||
"internalVersion": 2,
|
||||
"type": "TEMPLATE",
|
||||
"status": "DRAFT",
|
||||
"source": "TEMPLATE",
|
||||
"visibility": "EVERYONE",
|
||||
"templateType": "PRIVATE",
|
||||
"id": "envelope_xxxxxxxxxxxxxxxx",
|
||||
"secondaryId": "template_9",
|
||||
"externalId": null,
|
||||
"createdAt": "2025-11-12T11:36:38.391Z",
|
||||
"updatedAt": "2025-11-12T11:36:55.648Z",
|
||||
"completedAt": null,
|
||||
"deletedAt": null,
|
||||
"title": "Title",
|
||||
"title": "string",
|
||||
"externalId": "string",
|
||||
"recipients": [
|
||||
{
|
||||
"envelopeId": "envelope_xxxxxxxxxxxxxxxx",
|
||||
"name": "string",
|
||||
"email": "user@example.com",
|
||||
"role": "SIGNER",
|
||||
"readStatus": "NOT_OPENED",
|
||||
"signingStatus": "NOT_SIGNED",
|
||||
"sendStatus": "NOT_SENT",
|
||||
"id": 0,
|
||||
"email": "recipient+1@documenso.com",
|
||||
"name": "",
|
||||
"token": "cxH2Ss79Hj94M1U3PxRAG",
|
||||
"documentDeletedAt": null,
|
||||
"expired": null,
|
||||
"signedAt": null,
|
||||
"authOptions": {
|
||||
"accessAuth": [],
|
||||
"actionAuth": []
|
||||
},
|
||||
"signingOrder": 1,
|
||||
"rejectionReason": null
|
||||
}
|
||||
]
|
||||
"envelopeItems": [
|
||||
{
|
||||
"envelopeId": "envelope_xxxxxxxxxxxxxxxx",
|
||||
"id": "envelope_item_xxxxxxxxxxxxxxxxx",
|
||||
"title": "FileOne",
|
||||
"order": 1
|
||||
"signingOrder": 0
|
||||
}
|
||||
],
|
||||
// Other attributes
|
||||
}
|
||||
```
|
||||
|
||||
## Create Envelope
|
||||
|
||||
This example request will create a document with the following:
|
||||
|
||||
- Two PDF files
|
||||
- Two recipients with one field each
|
||||
|
||||
You will need to:
|
||||
|
||||
- Replace api_xxxxxxxxxxxxxx with your API key
|
||||
- Replace the file paths with the actual paths to your files
|
||||
|
||||
Note that the identifier on a field is linking to the files you upload. It can either be the index of the file or the filename. In this example it uses the index of the file.
|
||||
|
||||
```sh
|
||||
curl -X POST "https://app.documenso.com/api/v2/envelope/create" \
|
||||
-H "Authorization: api_xxxxxxxxxxxxxx" \
|
||||
-H "Content-Type: multipart/form-data" \
|
||||
-F 'payload={
|
||||
"type": "DOCUMENT",
|
||||
"title": "Envelope Full Field Test",
|
||||
"recipients": [
|
||||
{
|
||||
"email": "recipient+1@example.com",
|
||||
"name": "Recipient One",
|
||||
"role": "SIGNER",
|
||||
"fields": [
|
||||
{
|
||||
"identifier": 0,
|
||||
"type": "SIGNATURE",
|
||||
"page": 1,
|
||||
"positionX": 0,
|
||||
"positionY": 0,
|
||||
"width": 50,
|
||||
"height": 50
|
||||
}
|
||||
]
|
||||
"meta": {
|
||||
"subject": "string",
|
||||
"message": "string",
|
||||
"timezone": "Etc/UTC",
|
||||
"dateFormat": "yyyy-MM-dd hh:mm a",
|
||||
"redirectUrl": "string",
|
||||
"signingOrder": "PARALLEL"
|
||||
},
|
||||
{
|
||||
"email": "recipient-2@example.com",
|
||||
"name": "Recipient Two",
|
||||
"role": "SIGNER",
|
||||
"fields": [
|
||||
{
|
||||
"identifier": 1,
|
||||
"type": "SIGNATURE",
|
||||
"page": 1,
|
||||
"positionX": 0,
|
||||
"positionY": 0,
|
||||
"width": 50,
|
||||
"height": 50
|
||||
"authOptions": {
|
||||
"globalAccessAuth": "ACCOUNT",
|
||||
"globalActionAuth": "ACCOUNT"
|
||||
},
|
||||
"formValues": {
|
||||
"additionalProp1": "string",
|
||||
"additionalProp2": "string",
|
||||
"additionalProp3": "string"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}' \
|
||||
-F "files=@./field-font-alignment.pdf;type=application/pdf" \
|
||||
-F "files=@./field-meta.pdf;type=application/pdf"
|
||||
```
|
||||
|
||||
- `title` _(required)_ - This represents the document's title.
|
||||
- `externalId` - This is an optional field that you can use to store an external identifier for the document. This can be useful for tracking the document in your system.
|
||||
- `recipients` _(required)_ - This is an array of recipient objects. Each recipient object has the following fields:
|
||||
- `name` - The name of the recipient.
|
||||
- `email` - The email address of the recipient.
|
||||
- `role` - The role of the recipient. See the [available roles](/users/signing-documents#roles).
|
||||
- `signingOrder` - The order in which the recipient should sign the document. This is an integer value starting from 0.
|
||||
- `meta` - This object contains additional metadata for the document. It has the following fields:
|
||||
- `subject` - The subject of the email that will be sent to the recipients.
|
||||
- `message` - The message of the email that will be sent to the recipients.
|
||||
- `timezone` - The timezone in which the document should be signed.
|
||||
- `dateFormat` - The date format that should be used in the document.
|
||||
- `redirectUrl` - The URL to which the user should be redirected after signing the document.
|
||||
- `signingOrder` - The signing order for the document. This can be either `SEQUENTIAL` or `PARALLEL`.
|
||||
- `authOptions` - This object contains authentication options for the document. It has the following fields:
|
||||
- `globalAccessAuth` - The authentication level required to access the document. This can be either `ACCOUNT` or `null`.
|
||||
- If the document is set to `ACCOUNT`, all recipients must authenticate with their Documenso account to access it.
|
||||
- The document can be accessed without a Documenso account if it's set to `null`.
|
||||
- `globalActionAuth` - The authentication level required to perform actions on the document. This can be `ACCOUNT`, `PASSKEY`, `TWO_FACTOR_AUTH`, or `null`.
|
||||
- If the document is set to `ACCOUNT`, all recipients must authenticate with their Documenso account to perform actions on the document.
|
||||
- If it's set to `PASSKEY`, all recipients must have the passkey active to perform actions on the document.
|
||||
- If it's set to `TWO_FACTOR_AUTH`, all recipients must have the two-factor authentication active to perform actions on the document.
|
||||
- If it's set to `null`, all the recipients can perform actions on the document without any authentication.
|
||||
- `formValues` - This object contains additional form values for the document. This property only works with native PDF fields and accepts three types: number, text and boolean.
|
||||
|
||||
<Callout type="info">
|
||||
See the full request and response formats for the create endpoint
|
||||
[here](https://openapi.documenso.com/reference#tag/envelope/POST/envelope/create)
|
||||
The `globalActionAuth` property is only available for Enterprise accounts.
|
||||
</Callout>
|
||||
|
||||
## Use Template
|
||||
Here's an example of the JSON payload for uploading a document:
|
||||
|
||||
```json
|
||||
{
|
||||
"title": "my-document.pdf",
|
||||
"externalId": "12345",
|
||||
"recipients": [
|
||||
{
|
||||
"name": "Alex Blake",
|
||||
"email": "alexblake@email.com",
|
||||
"role": "SIGNER",
|
||||
"signingOrder": 1
|
||||
},
|
||||
{
|
||||
"name": "Ash Drew",
|
||||
"email": "ashdrew@email.com",
|
||||
"role": "SIGNER",
|
||||
"signingOrder": 0
|
||||
}
|
||||
],
|
||||
"meta": {
|
||||
"subject": "Sign the document",
|
||||
"message": "Hey there, please sign this document.",
|
||||
"timezone": "Europe/London",
|
||||
"dateFormat": "Day, Month Year",
|
||||
"redirectUrl": "https://mysite.com/welcome",
|
||||
"signingOrder": "SEQUENTIAL"
|
||||
},
|
||||
"authOptions": {
|
||||
"globalAccessAuth": "ACCOUNT",
|
||||
"globalActionAuth": "PASSKEY"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Upload to S3
|
||||
|
||||
A successful API call to the `/api/v1/documents` endpoint returns a JSON response containing the upload URL, document ID, and recipient information.
|
||||
|
||||
The upload URL is a pre-signed S3 URL that you can use to upload the document to the Documenso (or your) S3 bucket. You need to make a `PUT` request to this URL to upload the document.
|
||||
|
||||
```json
|
||||
{
|
||||
"uploadUrl": "https://<url>/<bucket-name>/<id>/my-document.pdf?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=<credentials>&X-Amz-Date=<date>&X-Amz-Expires=3600&X-Amz-Signature=<signature>&X-Amz-SignedHeaders=host&x-id=PutObject",
|
||||
"documentId": 51,
|
||||
"recipients": [
|
||||
{
|
||||
"recipientId": 11,
|
||||
"name": "Alex Blake",
|
||||
"email": "alexblake@email.com",
|
||||
"token": "<unique-signer-token>",
|
||||
"role": "SIGNER",
|
||||
"signingOrder": 1,
|
||||
"signingUrl": "https://app.documenso.com/sign/<unique-signer-token>"
|
||||
},
|
||||
{
|
||||
"recipientId": 12,
|
||||
"name": "Ash Drew",
|
||||
"email": "ashdrew@email.com",
|
||||
"token": "<unique-signer-token>",
|
||||
"role": "SIGNER",
|
||||
"signingOrder": 0,
|
||||
"signingUrl": "https://app.documenso.com/sign/<unique-signer-token>"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
When you make the `PUT` request to the pre-signed URL, you need to include the document file you want to upload. The image below shows how to upload a document to the S3 bucket via Postman.
|
||||
|
||||

|
||||
|
||||
Here's an example of how to upload a document using cURL:
|
||||
|
||||
```bash
|
||||
curl --location --request PUT 'https://<url>/<bucket-name>/<id>/my-document.pdf?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=<credentials>&X-Amz-Date=<date>&X-Amz-Expires=3600&X-Amz-Signature=<signature>&X-Amz-SignedHeaders=host&x-id=PutObject' \
|
||||
--form '=@"/Users/my-user/Documents/documenso.pdf"'
|
||||
```
|
||||
|
||||
Once the document is successfully uploaded, you can access it in your Documenso account dashboard. The screenshot below shows the document that was uploaded via the API.
|
||||
|
||||

|
||||
|
||||
</Steps>
|
||||
|
||||
## Generate Document From Template
|
||||
|
||||
Documenso allows you to generate documents from templates. This is useful when you have a standard document format you want to reuse.
|
||||
|
||||
The API endpoint for generating a document from a template is `/api/v2/envelopes/use`, and it takes a JSON payload with the following fields:
|
||||
The API endpoint for generating a document from a template is `/api/v1/templates/{templateId}/generate-document`, and it takes a JSON payload with the following fields:
|
||||
|
||||
<Callout type="info">
|
||||
See the full request and response formats for the use endpoint
|
||||
[here](https://openapi.documenso.com/reference#tag/envelope/POST/envelope/use)
|
||||
</Callout>
|
||||
```json
|
||||
{
|
||||
"title": "string",
|
||||
"externalId": "string",
|
||||
"recipients": [
|
||||
{
|
||||
"id": 0,
|
||||
"name": "string",
|
||||
"email": "user@example.com",
|
||||
"signingOrder": 0
|
||||
}
|
||||
],
|
||||
"meta": {
|
||||
"subject": "string",
|
||||
"message": "string",
|
||||
"timezone": "string",
|
||||
"dateFormat": "string",
|
||||
"redirectUrl": "string",
|
||||
"signingOrder": "PARALLEL"
|
||||
},
|
||||
"authOptions": {
|
||||
"globalAccessAuth": "ACCOUNT",
|
||||
"globalActionAuth": "ACCOUNT"
|
||||
},
|
||||
"formValues": {
|
||||
"additionalProp1": "string",
|
||||
"additionalProp2": "string",
|
||||
"additionalProp3": "string"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The JSON payload is identical to the payload for uploading a document, so you can read more about the fields in the [Create Document](/developers/public-api/reference#create-document) step. For this API endpoint, the `recipients` property is required.
|
||||
|
||||
<Steps>
|
||||
|
||||
### Grab the Template ID
|
||||
|
||||
The first step is to retrieve the ID of the template you want to use. This can be done via the API or from the Documenso UI.
|
||||
The first step is to retrieve the template ID from the Documenso dashboard. You can find the template ID in the URL by navigating to the template details page.
|
||||
|
||||
You can get the ID by navigating to the template page and looking at the URL. The ID is the last part of the URL which looks like this "envelope_xxxxxxxx"
|
||||

|
||||
|
||||
In this case, the template ID is "99999".
|
||||
|
||||
### Retrieve the Recipient(s) ID(s)
|
||||
|
||||
Once you have the template ID, you will want to retrieve the full template so you can see the recipients.
|
||||
Once you have the template ID, the next step involves retrieving the ID(s) of the recipient(s) from the template. You can do this by making a GET request to `/api/v1/templates/{template-id}`.
|
||||
|
||||
This is optional, and you only will want to do this if you want to modify the recipient details prior to creating the new document.
|
||||
|
||||
See the [Get Envelope](#get-envelope) section for more details on how to retrieve the envelope.
|
||||
|
||||
### Generate the Document
|
||||
|
||||
To generate a document from the template, you need to make a POST request to the [`/api/v2/envelope/use`](https://openapi.documenso.com/reference#tag/envelope/POST/envelope/use) endpoint.
|
||||
|
||||
You will need to replace the following:
|
||||
|
||||
- `api_xxxxxxxxxxxxxx` with your API key
|
||||
- `envelope_xxxxxxxxxxxxxxx` with the template ID
|
||||
- `RECIPIENT_ID_HERE` with the recipient ID you want to modify prior to sending
|
||||
- `RECIPIENT_EMAIL_HERE` with the new recipient email you want to use
|
||||
- `RECIPIENT_NAME_HERE` with the new recipient name you want to use
|
||||
|
||||
If you want to send the document immediately, you can add the `distributeDocument` parameter to the payload.
|
||||
|
||||
```sh
|
||||
curl -X POST "https://app.documenso.com/api/v2/envelope/use" \
|
||||
-H "Authorization: api_xxxxxxxxxxxxxx" \
|
||||
-H "Content-Type: multipart/form-data" \
|
||||
-F 'payload={
|
||||
"envelopeId": "envelope_xxxxxxxxxxxxxxx",
|
||||
"recipients": [
|
||||
{
|
||||
"id": RECIPIENT_ID_HERE,
|
||||
"email": "RECIPIENT_EMAIL_HERE",
|
||||
"name": "RECIPIENT_NAME_HERE"
|
||||
}
|
||||
]
|
||||
}'
|
||||
```
|
||||
|
||||
#### Generate the Document with Custom Files
|
||||
|
||||
You can also generate a document from a template using custom PDF files to replace the template's default PDF files.
|
||||
|
||||
To do this, you will need to grab the `envelopeItemId` of the item you want to replace, this is found in the GET request in the previous step.
|
||||
|
||||
You will need to replace the following:
|
||||
|
||||
- `CUSTOM_FILE_NAME_HERE.pdf` with the custom file name
|
||||
- `envelope_item_xxxxxxxxxxxxxxxxx` with the `envelopeItemId` of the item you want to replace
|
||||
|
||||
```sh
|
||||
curl -X POST "https://app.documenso.com/api/v2/envelope/use" \
|
||||
-H "Authorization: api_xxxxxxxxxxxxxx" \
|
||||
-H "Content-Type: multipart/form-data" \
|
||||
-F 'payload={
|
||||
"envelopeId": "envelope_xxxxxxxxxxxxxxx",
|
||||
"recipients": [
|
||||
{
|
||||
"id": RECIPIENT_ID_HERE,
|
||||
"email": "RECIPIENT_EMAIL_HERE",
|
||||
"name": "RECIPIENT_NAME_HERE"
|
||||
}
|
||||
],
|
||||
"customDocumentData": [
|
||||
{
|
||||
"identifier": "CUSTOM_FILE_NAME_HERE.pdf",
|
||||
"envelopeItemId": "envelope_item_xxxxxxxxxxxxxxxxx"
|
||||
}
|
||||
]
|
||||
}' \
|
||||
-F "files=@./CUSTOM_FILE_NAME_HERE.pdf;type=application/pdf"
|
||||
```
|
||||
|
||||
You can now access the document in your Documenso account dashboard.
|
||||
|
||||
#### Pre-fill Fields On Document Creation
|
||||
|
||||
The API allows you to pre-fill fields on document creation. This is useful when you want to create a document from an existing template and pre-fill the fields with specific values.
|
||||
A successful response looks as follows:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 0,
|
||||
"externalId": "string",
|
||||
"type": "PUBLIC",
|
||||
"title": "string",
|
||||
"userId": 0,
|
||||
"teamId": 0,
|
||||
"templateDocumentDataId": "string",
|
||||
"createdAt": "2024-10-11T08:46:58.247Z",
|
||||
"updatedAt": "2024-10-11T08:46:58.247Z",
|
||||
"templateMeta": {
|
||||
"id": "string",
|
||||
"subject": "string",
|
||||
"message": "string",
|
||||
"timezone": "string",
|
||||
"dateFormat": "string",
|
||||
"templateId": 0,
|
||||
"redirectUrl": "string",
|
||||
"signingOrder": "PARALLEL"
|
||||
},
|
||||
"directLink": {
|
||||
"token": "string",
|
||||
"enabled": true
|
||||
},
|
||||
"templateDocumentData": {
|
||||
"id": "string",
|
||||
"type": "S3_PATH",
|
||||
"data": "string"
|
||||
},
|
||||
"Field": [
|
||||
{
|
||||
"id": 0,
|
||||
"recipientId": 0,
|
||||
"type": "SIGNATURE",
|
||||
"page": 0,
|
||||
"positionX": "string",
|
||||
"positionY": "string",
|
||||
"width": "string",
|
||||
"height": "string"
|
||||
}
|
||||
],
|
||||
"Recipient": [
|
||||
{
|
||||
"id": 0,
|
||||
"email": "user@example.com",
|
||||
"name": "string",
|
||||
"signingOrder": 0,
|
||||
"authOptions": "string",
|
||||
"role": "CC"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
You'll need the recipient(s) ID(s) for the next step.
|
||||
|
||||
### Generate the Document
|
||||
|
||||
To generate a document from the template, you need to make a POST request to the `/api/v1/templates/{template-id}/generate-document` endpoint.
|
||||
|
||||
At the minimum, you must provide the `recipients` array in the JSON payload. Here's an example of the JSON payload:
|
||||
|
||||
```json
|
||||
{
|
||||
"recipients": [
|
||||
{
|
||||
"id": 0,
|
||||
"name": "Ash Drew",
|
||||
"email": "ashdrew@email.com",
|
||||
"signingOrder": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Filling the `recipients` array with the corresponding recipient for each template placeholder recipient is recommended. For example, if the template has two placeholders, you should provide at least two recipients in the `recipients` array. Otherwise, the document will be sent to inexistent recipients such as `<recipient.1@documenso.com>`. However, the recipients can always be edited via the API or the web app.
|
||||
|
||||
A successful response will contain the document ID and recipient(s) information.
|
||||
|
||||
```json
|
||||
{
|
||||
"documentId": 999,
|
||||
"recipients": [
|
||||
{
|
||||
"recipientId": 0,
|
||||
"name": "Ash Drew",
|
||||
"email": "ashdrew@email.com",
|
||||
"token": "<signing-token>",
|
||||
"role": "SIGNER",
|
||||
"signingOrder": null,
|
||||
"signingUrl": "https://app.documenso.com/sign/<signing-token>"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
You can now access the document in your Documenso account dashboard. The screenshot below shows the document that was generated from the template.
|
||||
|
||||

|
||||
|
||||
</Steps>
|
||||
|
||||
## Add Fields to Document
|
||||
|
||||
The API allows you to add fields to a document via the `/api/v1/documents/{documentId}/fields` endpoint. This is useful when you want to add fields to a document before sending it to recipients.
|
||||
|
||||
To add fields to a document, you need to make a `POST` request with a JSON payload containing the field(s) information.
|
||||
|
||||
```json
|
||||
{
|
||||
"recipientId": 0,
|
||||
"type": "SIGNATURE",
|
||||
"pageNumber": 0,
|
||||
"pageX": 0,
|
||||
"pageY": 0,
|
||||
"pageWidth": 0,
|
||||
"pageHeight": 0,
|
||||
"fieldMeta": {
|
||||
"label": "string",
|
||||
"placeholder": "string",
|
||||
"required": true,
|
||||
"readOnly": true,
|
||||
"type": "text",
|
||||
"text": "string",
|
||||
"characterLimit": 0
|
||||
}
|
||||
}
|
||||
|
||||
// or
|
||||
|
||||
[
|
||||
{
|
||||
"recipientId": 0,
|
||||
"type": "SIGNATURE",
|
||||
"pageNumber": 0,
|
||||
"pageX": 0,
|
||||
"pageY": 0,
|
||||
"pageWidth": 0,
|
||||
"pageHeight": 0
|
||||
},
|
||||
{
|
||||
"recipientId": 0,
|
||||
"type": "TEXT",
|
||||
"pageNumber": 0,
|
||||
"pageX": 0,
|
||||
"pageY": 0,
|
||||
"pageWidth": 0,
|
||||
"pageHeight": 0,
|
||||
"fieldMeta": {
|
||||
"label": "string",
|
||||
"placeholder": "string",
|
||||
"required": true,
|
||||
"readOnly": true,
|
||||
"type": "text",
|
||||
"text": "string",
|
||||
"characterLimit": 0
|
||||
}
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
<Callout type="info">This endpoint accepts either one field or an array of fields.</Callout>
|
||||
|
||||
Before adding fields to a document, you need each recipient's ID. If the document already has recipients, you can query the document to retrieve the recipient's details. If the document has no recipients, you need to add a recipient via the UI or API before adding a field.
|
||||
|
||||
<Steps>
|
||||
|
||||
### Retrieve the Recipient(s) ID(s)
|
||||
|
||||
Perform a `GET` request to the `/api/v1/documents/{id}` to retrieve the details of a specific document, including the recipient's information.
|
||||
|
||||
An example response would look like this:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 137,
|
||||
"externalId": null,
|
||||
"userId": 3,
|
||||
"teamId": null,
|
||||
"title": "documenso.pdf",
|
||||
"status": "DRAFT",
|
||||
"documentDataId": "<document-data-id>",
|
||||
"createdAt": "2024-10-11T12:29:12.725Z",
|
||||
"updatedAt": "2024-10-11T12:29:12.725Z",
|
||||
"completedAt": null,
|
||||
"recipients": [
|
||||
{
|
||||
"id": 55,
|
||||
"documentId": 137,
|
||||
"email": "ashdrew@email.com",
|
||||
"name": "Ash Drew",
|
||||
"role": "SIGNER",
|
||||
"signingOrder": null,
|
||||
"token": "<signing-token>",
|
||||
"signedAt": null,
|
||||
"readStatus": "NOT_OPENED",
|
||||
"signingStatus": "NOT_SIGNED",
|
||||
"sendStatus": "NOT_SENT",
|
||||
"signingUrl": "https://app.documenso.com/sign/<signing-token>"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
From this response, you'll only need the recipient ID, which is `55` in this case.
|
||||
|
||||
### (OR) Add a Recipient
|
||||
|
||||
If the document doesn't already have recipient(s), you can add recipient(s) via the API. Make a `POST` request to the `/api/v1/documents/{documentId}/recipients` endpoint with the recipient information. This endpoint takes the following JSON payload:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "string",
|
||||
"email": "user@example.com",
|
||||
"role": "SIGNER",
|
||||
"signingOrder": 0,
|
||||
"authOptions": {
|
||||
"actionAuth": "ACCOUNT"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<Callout type="info">The `authOptions` property is only available for Enterprise accounts.</Callout>
|
||||
|
||||
Here's an example of the JSON payload for adding a recipient:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "Ash Drew",
|
||||
"email": "ashdrew@email.com",
|
||||
"role": "SIGNER",
|
||||
"signingOrder": 0
|
||||
}
|
||||
```
|
||||
|
||||
A successful request will return a JSON response with the newly added recipient. You can now use the recipient ID to add fields to the document.
|
||||
|
||||
### Add Field(s)
|
||||
|
||||
Now you can make a `POST` request to the `/api/v1/documents/{documentId}/fields` endpoint with the field(s) information. Here's an example:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"recipientId": 55,
|
||||
"type": "SIGNATURE",
|
||||
"pageNumber": 1,
|
||||
"pageX": 50,
|
||||
"pageY": 20,
|
||||
"pageWidth": 25,
|
||||
"pageHeight": 5
|
||||
},
|
||||
{
|
||||
"recipientId": 55,
|
||||
"type": "TEXT",
|
||||
"pageNumber": 1,
|
||||
"pageX": 20,
|
||||
"pageY": 50,
|
||||
"pageWidth": 30,
|
||||
"pageHeight": 7.5,
|
||||
"fieldMeta": {
|
||||
"label": "Address",
|
||||
"placeholder": "32 New York Street, 41241",
|
||||
"required": true,
|
||||
"readOnly": false,
|
||||
"type": "text",
|
||||
"text": "32 New York Street, 41241",
|
||||
"characterLimit": 40
|
||||
}
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
<Callout type="info">
|
||||
The `text` field represents the default value of the field. If the user doesn't provide any other
|
||||
value, this is the value that will be used to sign the field.
|
||||
</Callout>
|
||||
|
||||
<Callout type="warning">
|
||||
It's important to pass the `type` in the `fieldMeta` property for the advanced fields. [Read more
|
||||
here](#a-note-on-advanced-fields)
|
||||
</Callout>
|
||||
|
||||
A successful request will return a JSON response with the newly added fields. The image below illustrates the fields added to the document via the API.
|
||||
|
||||

|
||||
|
||||
</Steps>
|
||||
|
||||
#### A Note on Advanced Fields
|
||||
|
||||
The advanced fields are: text, checkbox, radio, number, and select. Whenever you append any of these advanced fields to a document, you need to pass the `type` in the `fieldMeta` property:
|
||||
|
||||
```json
|
||||
...
|
||||
"fieldMeta": {
|
||||
"type": "text",
|
||||
}
|
||||
...
|
||||
```
|
||||
|
||||
Replace the `text` value with the corresponding field type:
|
||||
|
||||
- For the `TEXT` field it should be `text`.
|
||||
- For the `CHECKBOX` field it should be `checkbox`.
|
||||
- For the `RADIO` field it should be `radio`.
|
||||
- For the `NUMBER` field it should be `number`.
|
||||
- For the `SELECT` field it should be `select`. (check this before merge)
|
||||
|
||||
You must pass this property at all times, even if you don't need to set any other properties. If you don't, the endpoint will throw an error.
|
||||
|
||||
## Pre-fill Fields On Document Creation
|
||||
|
||||
The API allows you to pre-fill fields on document creation. This is useful when you want to create a document from an existing template and pre-fill the fields with specific values.
|
||||
|
||||
To pre-fill a field, you need to make a `POST` request to the `/api/v1/templates/{templateId}/generate-document` endpoint with the field information. Here's an example:
|
||||
|
||||
```json
|
||||
{
|
||||
"title": "my-document.pdf",
|
||||
"recipients": [
|
||||
{
|
||||
"id": 3,
|
||||
"name": "Example User",
|
||||
"email": "example@documenso.com",
|
||||
"signingOrder": 1,
|
||||
"role": "SIGNER"
|
||||
}
|
||||
],
|
||||
"prefillFields": [
|
||||
{
|
||||
"id": 21,
|
||||
@ -270,96 +574,51 @@ The API allows you to pre-fill fields on document creation. This is useful when
|
||||
"value": ["option-1", "option-2"]
|
||||
}
|
||||
]
|
||||
// Other payload properties...
|
||||
}
|
||||
```
|
||||
|
||||
</Steps>
|
||||
Check out the endpoint in the [API V1 documentation](https://app.documenso.com/api/v1/openapi#:~:text=/%7BtemplateId%7D/-,generate,-%2Ddocument).
|
||||
|
||||
## Add Recipients
|
||||
### API V2
|
||||
|
||||
The API allows you to add recipients to an envelope via the [`/api/v2/envelope/recipient/create-many`](https://openapi.documenso.com/reference#tag/envelope-recipients/POST/envelope/recipient/create-many) endpoint.
|
||||
For API V2, you need to make a `POST` request to the `/api/v2-beta/template/use` endpoint with the field(s) information. Here's an example:
|
||||
|
||||
The following is an example of a request which creates 2 new recipients on the envelope.
|
||||
|
||||
```sh
|
||||
curl https://app.documenso.com/api/v2/envelope/recipient/create-many \
|
||||
--request POST \
|
||||
--header 'Authorization: api_xxxxxxxxxxxxxx' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data '{
|
||||
"envelopeId": "envelope_brxkyaxywuxkyeuv",
|
||||
"data": [
|
||||
```json
|
||||
{
|
||||
"name": "Recipient Name",
|
||||
"templateId": 111,
|
||||
"recipients": [
|
||||
{
|
||||
"id": 3,
|
||||
"name": "Example User",
|
||||
"email": "example@documenso.com",
|
||||
"signingOrder": 1,
|
||||
"role": "SIGNER"
|
||||
}
|
||||
],
|
||||
"prefillFields": [
|
||||
{
|
||||
"id": 21,
|
||||
"type": "text",
|
||||
"label": "my-label",
|
||||
"placeholder": "my-placeholder",
|
||||
"value": "my-value"
|
||||
},
|
||||
{
|
||||
"name": "Recipient Two",
|
||||
"email": "example+2@documenso.com",
|
||||
"role": "APPROVER"
|
||||
}
|
||||
]
|
||||
}'
|
||||
```
|
||||
|
||||
## Add Fields
|
||||
|
||||
The API allows you to add fields to an envelope via the [`/api/v2/envelope/field/create-many`](https://openapi.documenso.com/reference#tag/envelope-fields/POST/envelope/field/create-many) endpoint.
|
||||
|
||||
Before adding fields to an envelope, you will need the following details:
|
||||
|
||||
- **Envelope ID** - Which envelope the field will be added to
|
||||
- **Recipient ID** - Which recipient the field will be added to
|
||||
- **Envelope Item ID** - Which file the field will be added to. If blank, the field will be added to the first file.
|
||||
|
||||
See the [Get Envelope](#get-envelope) section for more details on how to retrieve these details.
|
||||
|
||||
The following is an example of a request which creates 2 new fields on the first page of the envelope.
|
||||
|
||||
Note that width, height, positionX and positionY are percentage numbers between 0 and 100, which scale the field relative to the size of the PDF.
|
||||
|
||||
```sh
|
||||
curl https://app.documenso.com/api/v2/envelope/field/create-many \
|
||||
--request POST \
|
||||
--header 'Authorization: api_xxxxxxxxxxxxxx' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data '{
|
||||
"envelopeId": "envelope_xxxxxxxxxx",
|
||||
"data": [
|
||||
{
|
||||
"recipientId": recipient_id_here,
|
||||
"envelopeItemId": "envelope_item_id_here",
|
||||
"type": "TEXT",
|
||||
"page": 1,
|
||||
"positionX": 0,
|
||||
"positionY": 0,
|
||||
"width": 50,
|
||||
"height": 50,
|
||||
"fieldMeta": {
|
||||
"type": "text",
|
||||
"label": "First test field"
|
||||
}
|
||||
"id": 22,
|
||||
"type": "number",
|
||||
"label": "my-label",
|
||||
"placeholder": "my-placeholder",
|
||||
"value": "123"
|
||||
},
|
||||
{
|
||||
"recipientId": recipient_id_here,
|
||||
"envelopeItemId": "envelope_item_id_here",
|
||||
"type": "TEXT",
|
||||
"page": 1,
|
||||
"positionX": 50,
|
||||
"positionY": 50,
|
||||
"width": 50,
|
||||
"height": 50,
|
||||
"fieldMeta": {
|
||||
"type": "text",
|
||||
"label": "Second test field"
|
||||
}
|
||||
"id": 23,
|
||||
"type": "checkbox",
|
||||
"label": "my-label",
|
||||
"placeholder": "my-placeholder",
|
||||
"value": ["option-1", "option-2"]
|
||||
}
|
||||
]
|
||||
}'
|
||||
}
|
||||
```
|
||||
|
||||
Field meta allows you to further configure fields, for example it will allow you to add multiple items for checkboxes or radios.
|
||||
|
||||
A successful request will return a JSON response with the newly added fields.
|
||||
Check out the endpoint in the [API V2 documentation](https://openapi.documenso.com/reference#tag/template/POST/template/use).
|
||||
|
||||
@ -9,9 +9,9 @@ import { Callout } from 'nextra/components';
|
||||
|
||||
Documenso uses API versioning to manage changes to the public API. This allows us to introduce new features, fix bugs, and make other changes without breaking existing integrations.
|
||||
|
||||
<Callout type="info">The current version of the API is `v2`.</Callout>
|
||||
<Callout type="info">The current version of the API is `v1`.</Callout>
|
||||
|
||||
The API version is specified in the URL. For example, the base URL for the `v2` API is `https://app.documenso.com/api/v2`.
|
||||
The API version is specified in the URL. For example, the base URL for the `v1` API is `https://app.documenso.com/api/v1`.
|
||||
|
||||
We may make changes to the API without incrementing the version number. We will always try to avoid breaking changes, but in some cases, it may be necessary to make changes that are not backward compatible. In these cases, we will increment the version number and provide information about the changes in the release notes.
|
||||
|
||||
|
||||
@ -27,33 +27,3 @@ NEXT_PRIVATE_GOOGLE_CLIENT_SECRET=<your-client-secret>
|
||||
```
|
||||
|
||||
Finally verify the signing in with Google works by signing in with your Google account and checking the email address in your profile.
|
||||
|
||||
## Microsoft OAuth (Azure AD)
|
||||
|
||||
To use Microsoft OAuth, you will need to create an Azure AD application registration in the Microsoft Azure portal. This will allow users to sign in with their Microsoft accounts.
|
||||
|
||||
### Create and configure a new Azure AD application
|
||||
|
||||
1. Go to the [Azure Portal](https://portal.azure.com/)
|
||||
2. Navigate to **Azure Active Directory** (or **Microsoft Entra ID** in newer Azure portals)
|
||||
3. In the left sidebar, click **App registrations**
|
||||
4. Click **New registration**
|
||||
5. Enter a name for your application (e.g., "Documenso")
|
||||
6. Under **Supported account types**, select **Accounts in any organizational directory (Any Azure AD directory - Multitenant) and personal Microsoft accounts (e.g. Skype, Xbox)** to allow any Microsoft account to sign in
|
||||
7. Under **Redirect URI**, select **Web** and enter: `https://<documenso-domain>/api/auth/callback/microsoft`
|
||||
8. Click **Register**
|
||||
|
||||
### Configure the application
|
||||
|
||||
1. After registration, you'll be taken to the app's overview page
|
||||
2. Copy the **Application (client) ID** - this will be your `NEXT_PRIVATE_MICROSOFT_CLIENT_ID`
|
||||
3. In the left sidebar, click **Certificates & secrets**
|
||||
4. Under **Client secrets**, click **New client secret**
|
||||
5. Add a description and select an expiration period
|
||||
6. Click **Add** and copy the **Value** (not the Secret ID) - this will be your `NEXT_PRIVATE_MICROSOFT_CLIENT_SECRET`
|
||||
7. In the Documenso environment variables, set the following:
|
||||
|
||||
```
|
||||
NEXT_PRIVATE_MICROSOFT_CLIENT_ID=<your-application-client-id>
|
||||
NEXT_PRIVATE_MICROSOFT_CLIENT_SECRET=<your-client-secret-value>
|
||||
```
|
||||
|
||||
@ -11,76 +11,120 @@ Learn about the different fields you can add to your documents in Documenso and
|
||||
|
||||
The signature field collects the signer's signature. It's required for each recipient with the "Signer" role.
|
||||
|
||||
### Document Editor View
|
||||
|
||||
The field doesn't have any additional settings. You just need to place it on the document where you want the signer to sign.
|
||||
|
||||

|
||||
|
||||
The signature field settings include:
|
||||
### Document Signing View
|
||||
|
||||
- **Font size** - The typed signature font size. You can disable typed signatures in the document settings.
|
||||
The recipient will see the signature field when they open the document to sign.
|
||||
|
||||
The recipient must click on the signature field to open the signing view, where they can sign using their mouse, touchpad, or touchscreen.
|
||||
|
||||

|
||||
|
||||
The image below shows the signature field signed by the recipient.
|
||||
|
||||

|
||||
|
||||
After signing, the recipient can click the "Complete" button to complete the signing process.
|
||||
|
||||
## Email Field
|
||||
|
||||
The email field is used to collect the signer's email address. This will be the email address you entered when you created the recipients.
|
||||
The email field is used to collect the signer's email address.
|
||||
|
||||
### Document Editor View
|
||||
|
||||
The field doesn't have any additional settings. You just need to place it on the document where you want the signer to sign.
|
||||
|
||||

|
||||
|
||||
The email field settings include:
|
||||
### Document Signing View
|
||||
|
||||
- **Font Size** - The font size of the email address.
|
||||
- **Text Align** - The horizontal text alignment of the email address.
|
||||
When the recipient opens the document to sign, they will see the email field.
|
||||
|
||||
The recipient must click on the email field to automatically sign the field with the email associated with their account.
|
||||
|
||||

|
||||
|
||||
The image below shows the email field signed by the recipient.
|
||||
|
||||

|
||||
|
||||
After entering their email address, the recipient can click the "Complete" button to complete the signing process.
|
||||
|
||||
## Name Field
|
||||
|
||||
The name field is used to collect the signer's name.
|
||||
|
||||
### Document Editor View
|
||||
|
||||
The field doesn't have any additional settings. You just need to place it on the document where you want the signer to sign.
|
||||
|
||||

|
||||
|
||||
The name field settings include:
|
||||
### Document Signing View
|
||||
|
||||
- **Font Size** - The font size of the name.
|
||||
- **Text Align** - The horizontal text alignment of the name.
|
||||
When the recipient opens the document to sign, they will see the name field.
|
||||
|
||||
## Initials Field
|
||||
The recipient must click on the name field, which will automatically sign the field with the name associated with their account.
|
||||
|
||||
The initials field is used to collect the signer's initials. This is generally the first and last name initials.
|
||||

|
||||
|
||||

|
||||
The image below shows the name field signed by the recipient.
|
||||
|
||||
The initials field settings include:
|
||||

|
||||
|
||||
- **Font Size** - The font size of the initials.
|
||||
- **Text Align** - The horizontal text alignment of the initials.
|
||||
After entering their name, the recipient can click the "Complete" button to complete the signing process.
|
||||
|
||||
## Date Field
|
||||
|
||||
The date field is used to collect the date of the signature. You can change the date format in the document settings.
|
||||
The date field is used to collect the date of the signature.
|
||||
|
||||
### Document Editor View
|
||||
|
||||
The field doesn't have any additional settings. You just need to place it on the document where you want the signer to sign.
|
||||
|
||||

|
||||
|
||||
The date field settings include:
|
||||
### Document Signing View
|
||||
|
||||
- **Font Size** - The font size of the date.
|
||||
- **Text Align** - The horizontal text alignment of the date.
|
||||
When the recipient opens the document to sign, they will see the date field.
|
||||
|
||||
The recipient must click on the date field to automatically sign the field with the current date and time.
|
||||
|
||||

|
||||
|
||||
The image below shows the date field signed by the recipient.
|
||||
|
||||

|
||||
|
||||
After entering the date, the recipient can click the "Complete" button to complete the signing process.
|
||||
|
||||
## Text Field
|
||||
|
||||
The text field is used to collect text input from the signer.
|
||||
|
||||
### Document Editor View
|
||||
|
||||
Place the text field on the document where you want the signer to enter text. The text field comes with additional settings that can be configured.
|
||||
|
||||

|
||||
|
||||
To open the settings, click on the text field and then on the "Sliders" icon. That opens the settings panel on the right side of the screen.
|
||||
|
||||

|
||||
|
||||
The text field settings include:
|
||||
|
||||
- **Label** - The label displayed in the field when the user opens the document to sign
|
||||
- **Placeholder** - The placeholder text displayed in the field. The signer will see this prior to signing.
|
||||
- **Text** - The text which will be prefilled into the field. The signer can change this text unless the field is read-only.
|
||||
- **Label** - The label displayed in the field.
|
||||
- **Placeholder** - The placeholder text displayed in the field.
|
||||
- **Text** - The default text displayed in the field.
|
||||
- **Character limit** - The maximum number of characters allowed in the field.
|
||||
- **Required** - Whether the field is required or not.
|
||||
- **Read only** - Whether the field is read-only or not.
|
||||
- **Text Align** - The horizontal text alignment of the text in the field.
|
||||
- **Vertical Align** - The vertical text alignment of the text in the field.
|
||||
- **Line height** - The line height of the text in the field. Useful for multi-line text fields.
|
||||
- **Letter spacing** - The spacing between each character in the text in the field.
|
||||
|
||||
It also comes with a couple of rules:
|
||||
|
||||
@ -89,26 +133,71 @@ It also comes with a couple of rules:
|
||||
- The signer must fill out a required field.
|
||||
- The text field characters count can't exceed the character limit.
|
||||
- The signer can't modify a read-only field.
|
||||
- The field will be inserted automatically into the document if there is a default text value.
|
||||
- The field auto-signs if there is a default text value.
|
||||
|
||||
Let's look at the following example.
|
||||
|
||||

|
||||
|
||||
The field is configured as follows:
|
||||
|
||||
- Label: "Address"
|
||||
- Placeholder: "Your office address"
|
||||
- Default Text: "Signing Street 1, 241245"
|
||||
- Character Limit: 35
|
||||
- Required: False
|
||||
- Read Only: False
|
||||
|
||||
Since the field has a label set, the label is displayed instead of the default text field value - "Add text".
|
||||
|
||||
### Document Signing View
|
||||
|
||||
What the recipient sees when they open the document to sign depends on the settings configured by the sender.
|
||||
|
||||
In this case, the recipient sees the text field signed with the default value.
|
||||
|
||||

|
||||
|
||||
The recipient can modify the text field value since the field is not read-only. To change the value, the recipient must click the field to un-sign it.
|
||||
|
||||
Once it's unsigned, the field uses the label set by the sender.
|
||||
|
||||

|
||||
|
||||
To sign the field with a different value, the recipient needs to click on the field and enter the new value.
|
||||
|
||||

|
||||
|
||||
Since the text field has a character limit, the recipient must enter a value that doesn't exceed the limit. Otherwise, an error message will appear, and the field will not be signed.
|
||||
|
||||
The image below illustrates the text field signed with a new value.
|
||||
|
||||

|
||||
|
||||
After signing the field, the recipient can click the "Complete" button to complete the signing process.
|
||||
|
||||
## Number Field
|
||||
|
||||
The number field is used for collecting a number input from the signer.
|
||||
|
||||
### Document Editor View
|
||||
|
||||
Place the number field on the document where you want the signer to enter a number. The number field comes with additional settings that can be configured.
|
||||
|
||||

|
||||
|
||||
To open the settings, click on the number field and then on the "Sliders" icon. That opens the settings panel on the right side of the screen.
|
||||
|
||||

|
||||
|
||||
The number field settings include:
|
||||
|
||||
- **Label** - The label displayed is the field.
|
||||
- **Placeholder** - The placeholder text displayed in the field.
|
||||
- **Value** - The value which will be prefilled into the field. The signer can change this value unless the field is read-only.
|
||||
- **Value** - The default number displayed in the field.
|
||||
- **Number format** - The format of the number.
|
||||
- **Required** - Whether the field is required or not.
|
||||
- **Read only** - Whether the field is read-only or not.
|
||||
- **Text Align** - The horizontal text alignment of the number in the field.
|
||||
- **Vertical Align** - The vertical text alignment of the number in the field.
|
||||
- **Line height** - The line height of the number in the field. Useful for multi-line number fields.
|
||||
- **Letter spacing** - The spacing between each character in the number in the field.
|
||||
- **Validation** - The validation rules for the field.
|
||||
|
||||
It also comes with a couple of rules:
|
||||
@ -121,18 +210,66 @@ It also comes with a couple of rules:
|
||||
- If the default number and a min value are set, the default number must be greater than the min value.
|
||||
- The value must match the number format if a number format is set.
|
||||
|
||||
In this example, the number field is configured as follows:
|
||||
|
||||
- Label: "Quantity"
|
||||
- Placeholder: "Enter the preferred quantity"
|
||||
- Default Value: 12
|
||||
- Number Format: "123,456,789.00"
|
||||
- Required: False
|
||||
- Read Only: False
|
||||
- Validation:
|
||||
- Min value: 5, Max value: 50
|
||||
|
||||

|
||||
|
||||
Since the field has a label set, the label is displayed instead of the default number field value - "Add number".
|
||||
|
||||
### Document Signing View
|
||||
|
||||
What the recipient sees when they open the document to sign depends on the settings configured by the sender.
|
||||
|
||||
The recipient sees the number field signed with the default value in this case.
|
||||
|
||||

|
||||
|
||||
Since the number field is not read-only, the recipient can modify its value. To change the value, the recipient must click the field to un-sign it.
|
||||
|
||||
Once it's unsigned, the field uses the label set by the sender.
|
||||
|
||||

|
||||
|
||||
To sign the field with a different value, the recipient needs to click on the field and enter the new value.
|
||||
|
||||

|
||||
|
||||
Since the number field has a validation rule set, the recipient must enter a value that meets the rules. In this example, the value needs to be between 5 and 50. Otherwise, an error message will appear, and the field will not be signed.
|
||||
|
||||
The image below illustrates the text field signed with a new value.
|
||||
|
||||

|
||||
|
||||
After signing the field, the recipient can click the "Complete" button to complete the signing process.
|
||||
|
||||
## Radio Field
|
||||
|
||||
The radio field is used to collect a single choice from the signer.
|
||||
|
||||
### Document Editor View
|
||||
|
||||
Place the radio field on the document where you want the signer to select a choice. The radio field comes with additional settings that can be configured.
|
||||
|
||||

|
||||
|
||||
To open the settings, click on the radio field and then on the "Sliders" icon. That opens the settings panel on the right side of the screen.
|
||||
|
||||

|
||||
|
||||
The radio field settings include:
|
||||
|
||||
- **Required** - Whether the field is required or not.
|
||||
- **Read only** - Whether the field is read-only or not.
|
||||
- **Values** - The list of choices for the field.
|
||||
- **Direction** - The direction of the radio field. Can be "Vertical" or "Horizontal".
|
||||
|
||||
It also comes with a couple of rules:
|
||||
|
||||
@ -145,22 +282,57 @@ It also comes with a couple of rules:
|
||||
- It should contain at least one option.
|
||||
- The field can't have more than one option selected.
|
||||
|
||||
In this example, the radio field is configured as follows:
|
||||
|
||||
- Required: False
|
||||
- Read Only: False
|
||||
- Options:
|
||||
- Option 1
|
||||
- Option 2
|
||||
- Empty value
|
||||
- Empty value
|
||||
- Option 3
|
||||
|
||||

|
||||
|
||||
Since the field contains radio options, it displays them instead of the default radio field value, "Radio".
|
||||
|
||||
### Document Signing View
|
||||
|
||||
What the recipient sees when they open the document to sign depends on the settings configured by the sender.
|
||||
|
||||
In this case, the recipient sees the radio field unsigned because the sender didn't select a value.
|
||||
|
||||

|
||||
|
||||
The recipient can select one of the options by clicking on the radio button next to the option.
|
||||
|
||||

|
||||
|
||||
After signing the field, the recipient can click the "Complete" button to complete the signing process.
|
||||
|
||||
## Checkbox Field
|
||||
|
||||
The checkbox field is used to collect multiple choices from the signer.
|
||||
|
||||
### Document Editor View
|
||||
|
||||
Place the checkbox field on the document where you want the signer to select choices. The checkbox field comes with additional settings that can be configured.
|
||||
|
||||

|
||||

|
||||
|
||||
To open the settings, click on the checkbox field and then on the "Sliders" icon. That opens the settings panel on the right side of the screen.
|
||||
|
||||

|
||||
|
||||
The checkbox field settings include the following:
|
||||
|
||||
- **Validation** - The validation rules for the field.
|
||||
- **Rule** - The rule specifies "At least", "At most", and "Exactly".
|
||||
- **Number** - The number of choices that must be selected.
|
||||
- **Required** - Whether the field is required or not.
|
||||
- **Read only** - Whether the field is read-only or not.
|
||||
- **Options** - The list of choices for the field.
|
||||
- **Direction** - The direction of the checkbox field. Can be "Vertical" or "Horizontal".
|
||||
- **Validation Rule** - The rule specifies "At least", "At most", and "Exactly".
|
||||
- **Validation Number** - The number of choices that must be selected.
|
||||
|
||||
It also comes with a couple of rules:
|
||||
|
||||
@ -172,20 +344,67 @@ It also comes with a couple of rules:
|
||||
- The signer can't modify the field if it's read-only.
|
||||
- It should contain at least one option.
|
||||
|
||||
In this example, the checkbox field is configured as follows:
|
||||
|
||||
- No validation rules
|
||||
- Required: True
|
||||
- Read Only: False
|
||||
- Options:
|
||||
- Option 1
|
||||
- Empty value (checked)
|
||||
- Option 2
|
||||
- Option 3 (checked)
|
||||
- Empty value
|
||||
|
||||

|
||||
|
||||
Since the field contains checkbox options, it displays them instead of the default checkbox field value, "Checkbox".
|
||||
|
||||
### Document Signing View
|
||||
|
||||
What the recipient sees when they open the document to sign depends on the settings configured by the sender.
|
||||
|
||||
In this case, the recipient sees the checkbox field signed with the values selected by the sender.
|
||||
|
||||

|
||||
|
||||
Since the field is required, the recipient can either sign with the values selected by the sender or modify the values.
|
||||
|
||||
The values can be modified in 2 ways:
|
||||
|
||||
- Click on the options you want to select or deselect.
|
||||
- Hover over the field and click the "X" button to clear all the selected values.
|
||||
|
||||
The image below illustrates the checkbox field with the values cleared by the recipient. Since the field is required, it has a red border instead of the yellow one (non-required fields).
|
||||
|
||||

|
||||
|
||||
Then, the recipient can select values other than the ones chosen by the sender.
|
||||
|
||||

|
||||
|
||||
After signing the field, the recipient can click the "Complete" button to complete the signing process.
|
||||
|
||||
## Dropdown/Select Field
|
||||
|
||||
The dropdown/select field collects a single choice from a list of options.
|
||||
|
||||
### Document Editor View
|
||||
|
||||
Place the dropdown/select field on the document where you want the signer to select a choice. The dropdown/select field comes with additional settings that can be configured.
|
||||
|
||||

|
||||

|
||||
|
||||
To open the settings, click on the dropdown/select field and then on the "Sliders" icon. That opens the settings panel on the right side of the screen.
|
||||
|
||||

|
||||
|
||||
The dropdown/select field settings include:
|
||||
|
||||
- **Required** - Whether the field is required or not.
|
||||
- **Read only** - Whether the field is read-only or not.
|
||||
- **Options** - The list of choices for the field.
|
||||
- **Default Value** - The default value selected in the field.
|
||||
- **Default** value - The default value selected in the field.
|
||||
|
||||
It also comes with a couple of rules:
|
||||
|
||||
@ -197,3 +416,31 @@ It also comes with a couple of rules:
|
||||
- The field can't be signed with a value not in the options list.
|
||||
- The signer can't modify the field if it's read-only.
|
||||
- It should contain at least one option.
|
||||
|
||||
In this example, the dropdown/select field is configured as follows:
|
||||
|
||||
- Required: False
|
||||
- Read Only: False
|
||||
- Default Value: None
|
||||
- Options:
|
||||
- Document
|
||||
- Template
|
||||
- Other
|
||||
|
||||
### Document Signing View
|
||||
|
||||
What the recipient sees when they open the document to sign depends on the settings configured by the sender.
|
||||
|
||||
In this case, the recipient sees the dropdown/select field with the default label, "-- Select ---" since the sender has not set a default value.
|
||||
|
||||

|
||||
|
||||
The recipient can modify the dropdown/select field value since the field is not read-only. To change the value, the recipient must click on the field for the dropdown list to appear.
|
||||
|
||||

|
||||
|
||||
The recipient can select one of the options from the list. The image below illustrates the dropdown/select field signed with a new value.
|
||||
|
||||

|
||||
|
||||
After signing the field, the recipient can click the "Complete" button to complete the signing process.
|
||||
|
||||
@ -9,85 +9,90 @@ import { Callout, Steps } from 'nextra/components';
|
||||
|
||||
This guide will walk you through the process of sending a document out for signing. You will learn how to upload a document, add recipients, place signature fields, and send the document for signing.
|
||||
|
||||
## Uploading a Document
|
||||
|
||||
<Steps>
|
||||
### Log In to Your Account
|
||||
### Login Into Your Account
|
||||
|
||||
The guide assumes you have a Documenso account. If you don't, you can create a free account [here](https://documen.so/free-docs).
|
||||
|
||||
### Upload Document
|
||||
|
||||
Navigate to the [Documenso dashboard](https://app.documenso.com/documents) and click on the "Upload Document" button located at the top right of the page. Select the documents you want to upload and wait for the upload to complete.
|
||||
Navigate to the [Documenso dashboard](https://app.documenso.com/documents) and click on the "Add a document" button. Select the document you want to upload and wait for the upload to complete.
|
||||
|
||||
<Callout type="info">
|
||||
The maximum file size for uploaded documents is 150MB in production. You can upload up to 5
|
||||
documents at a time on standard plans. In staging, the limit is 50MB.
|
||||
The maximum file size for uploaded documents is 150MB in production. In staging, the limit is
|
||||
50MB.
|
||||
</Callout>
|
||||
|
||||

|
||||
|
||||
After the upload is complete, you will be redirected to the editor. You can configure the document's settings and add recipients and fields here.
|
||||
After the upload is complete, you will be redirected to the document's page. You can configure the document's settings and add recipients and fields here.
|
||||
|
||||
</Steps>
|
||||

|
||||
|
||||
## Configuring and Sending Document
|
||||
### (Optional) Advanced Options
|
||||
|
||||
The Documenso editor allows you to create and configure documents or templates. The editor consists of three sections that guide you through the process of preparing your document.
|
||||
Click on the "Advanced options" button to access additional settings for the document. You can set an external ID, date format, time zone, and the redirect URL.
|
||||
|
||||
1. **Document & Recipients** - Upload files and add recipients
|
||||
2. **Add Fields** - Add fields to the document
|
||||
3. **Preview** - Preview the document before sending
|
||||

|
||||
|
||||
You can click each section to navigate to it, and the current section will be highlighted in the sidebar.
|
||||
The external ID allows you to set a custom ID for the document that can be used to identify the document in your external system(s).
|
||||
|
||||

|
||||
The date format and time zone settings allow you to customize how the date and time are displayed in the document.
|
||||
|
||||
There is also a quick actions section on the left-hand side which allows you to:
|
||||
The redirect URL allows you to specify a URL where the signer will be redirected after signing the document.
|
||||
|
||||
- **Document Settings** - Configure general settings, emails, or security settings for the document
|
||||
- **Send Document** - Send the document to the recipients
|
||||
- **Duplicate** - Duplicate the document
|
||||
- **Download** - Download the document PDF
|
||||
- **Delete** - Delete the document
|
||||
### (Optional) Document Access
|
||||
|
||||
The header contains some notable items:
|
||||
Documenso enables you to set up access control for your documents. You can require authentication for viewing the document.
|
||||
|
||||
- **Title** - You can edit the title in the top-left corner of the header by clicking on the text
|
||||
- **Status** - You can see the current status of the document next to the title
|
||||
- **Attachments** - You can configure the attachments on the right-hand side of the header
|
||||
The available options are:
|
||||
|
||||
<Steps>
|
||||
- **Require account** - The recipient must be signed in to view the document.
|
||||
- **None** - The document can be accessed directly by the URL sent to the recipient.
|
||||
|
||||
### Upload Documents and Add Recipients
|
||||
|
||||
The first step in the editor is to upload your document and add recipients.
|
||||
|
||||

|
||||
|
||||
#### Upload Document
|
||||
|
||||
You can upload documents by either clicking the "Add a document" dropzone, or dragging and dropping files into the dropzone.
|
||||

|
||||
|
||||
<Callout type="info">
|
||||
The maximum file size for uploaded documents is 150MB in production. You can upload up to 5
|
||||
documents at a time on standard plans. In staging, the limit is 50MB.
|
||||
The "Document Access" feature is only available for Enterprise accounts.
|
||||
</Callout>
|
||||
|
||||
#### Add Recipients
|
||||
### (Optional) Recipient Authentication
|
||||
|
||||
Click the "+ Add Signer" button to add a new recipient. For each recipient you can configure the following:
|
||||
The "Recipient Authentication" feature allows you to specify the authentication method required for recipients to sign the signature field.
|
||||
|
||||
- **Email address** - The recipient's email address
|
||||
- **Name** - The recipient's name
|
||||
- **Order** - The sequence in which the recipient should sign the document. Only available if the "Enable Signing Order" checkbox is enabled
|
||||
- **Role** - As seen below
|
||||
The available options are:
|
||||
|
||||
Documenso has 5 roles for recipients with different permissions and actions.
|
||||
- **Require passkey** - The recipient must have an account and passkey configured via their settings.
|
||||
- **Require 2FA** - The recipient must have an account and 2FA enabled via their settings.
|
||||
- **None** - No authentication required.
|
||||
|
||||

|
||||
|
||||
This can be overridden by setting the authentication requirements directly for each recipient in the next step.
|
||||
|
||||
<Callout type="info">
|
||||
The "Recipient Authentication" feature is only available for Enterprise accounts.
|
||||
</Callout>
|
||||
|
||||
### Recipients
|
||||
|
||||
Click the "+ Add Signer" button to add a new recipient. You can configure the recipient's email address, name, role, and authentication method on this page.
|
||||
|
||||
You can choose any option from the ["Recipient Authentication"](#optional-recipient-authentication) section, or you can set it to "Inherit authentication method" to use the global action signing authentication method configured in the "General Settings" step.
|
||||
|
||||

|
||||
|
||||
You can also set the recipient's role, which determines their actions and permissions in the document.
|
||||
|
||||

|
||||
|
||||
#### Roles
|
||||
|
||||
Documenso has 4 roles for recipients with different permissions and actions.
|
||||
|
||||
| Role | Function | Action required | Signature |
|
||||
| :-------: | :-----------------------------------------------------------------------------: | :-------------: | :-------: |
|
||||
| Signer | Needs to sign signature fields assigned to them. | Yes | Yes |
|
||||
| Signer | Needs to sign signatures fields assigned to them. | Yes | Yes |
|
||||
| Approver | Needs to approve the document as a whole. Signature optional. | Yes | Optional |
|
||||
| Viewer | Needs to confirm they viewed the document. | Yes | No |
|
||||
| Assistant | Can help prepare the document by filling in fields on behalf of other signers. | Yes | No |
|
||||
@ -95,20 +100,15 @@ Documenso has 5 roles for recipients with different permissions and actions.
|
||||
|
||||
### Fields
|
||||
|
||||
Documenso supports 10 different field types that can be added to the document. Each field type collects various information from the recipients when they sign the document.
|
||||
|
||||
To create a field, you can either click and drag to draw a field on the document or drag and drop the field type from the sidebar.
|
||||
Documenso supports 9 different field types that can be added to the document. Each field type collects various information from the recipients when they sign the document.
|
||||
|
||||

|
||||
|
||||
The field created will be assigned to the currently selected recipient. You can change the recipient by clicking on the recipient's name in the right sidebar.
|
||||
|
||||
The available field types are:
|
||||
|
||||
- **Signature** - Collects the signer's signature
|
||||
- **Email** - Collects the signer's email address
|
||||
- **Name** - Collects the signer's name
|
||||
- **Initials** - Collects the signer's initials
|
||||
- **Date** - Collects the date of the signature
|
||||
- **Text** - Collects text input from the signer
|
||||
- **Number** - Collects a number input from the signer
|
||||
@ -123,11 +123,11 @@ All fields can be placed anywhere on the document and resized as needed.
|
||||
page](/users/documents/fields).
|
||||
</Callout>
|
||||
|
||||
### Preview
|
||||
#### Signature Required
|
||||
|
||||
In this section, you can preview what the document will look like once it is fully signed. This uses placeholder data for the fields.
|
||||
Signer Roles require at least 1 signature field. You will get an error message if you try to send a document without a signature field.
|
||||
|
||||

|
||||

|
||||
|
||||
### Email Settings
|
||||
|
||||
@ -156,54 +156,3 @@ https://app.documenso.com/sign/12ACP777zxQLO52hjj_vCB
|
||||
```
|
||||
|
||||
</Steps>
|
||||
|
||||
## Document Settings
|
||||
|
||||
To access the document settings, click the "Document Settings" button in the quick actions section.
|
||||
|
||||
### General Settings
|
||||
|
||||

|
||||
|
||||
- **Language** - The language that the emails will be sent in
|
||||
- **Allowed Signature Types** - The signature types that the recipient will be allowed to use
|
||||
- **Date Format** - The date format that will be used for date fields
|
||||
- **Time Zone** - The time zone that will be used for date fields
|
||||
- **External ID** - A custom ID for the document that can be used to identify the document in your external system(s)
|
||||
- **Redirect URL** - The URL where the signer will be redirected after signing the document
|
||||
- **Document Distribution Method** - Whether to use emails to send the document, or none (which we will generate signing links for manual distribution)
|
||||
|
||||
### Email Settings
|
||||
|
||||

|
||||
|
||||
- **Reply To** - The email address that will be used as the reply to email address
|
||||
- **Subject** - The subject of the email
|
||||
- **Message** - The message of the email
|
||||
- **Checkboxes** - You can select which emails should be sent during the document signing process
|
||||
|
||||
### Security Settings
|
||||
|
||||
Documenso enables you to set up access control for your documents. You can require authentication for viewing the document.
|
||||
|
||||
The available options are:
|
||||
|
||||
- **Require account** - The recipient must be signed in to view the document.
|
||||
- **Require 2FA** - The recipient must use 2FA to sign the document.
|
||||
- **None** - The document can be accessed directly by the URL sent to the recipient.
|
||||
|
||||

|
||||
|
||||
The "Recipient Authentication" feature allows you to specify the authentication method required for recipients to sign the signature field.
|
||||
|
||||
The available options are:
|
||||
|
||||
- **Require passkey** - The recipient must have an account and passkey configured via their settings.
|
||||
- **Require 2FA** - The recipient must have an account and 2FA enabled via their settings.
|
||||
- **None** - No authentication required.
|
||||
|
||||
This can be overridden by setting the authentication requirements directly for each recipient in the next step.
|
||||
|
||||
<Callout type="info">
|
||||
The "Recipient Authentication" feature is only available for Enterprise accounts.
|
||||
</Callout>
|
||||
|
||||
@ -8,43 +8,82 @@ Documenso allows you to create templates, which are reusable documents. Template
|
||||
|
||||
### Create New Template
|
||||
|
||||
To create a new template, navigate to the "Templates" page and click on the "Upload Template" button.
|
||||
To create a new template, navigate to the ["Templates" page](https://app.documenso.com/templates) and click on the "New Template" button.
|
||||
|
||||

|
||||
|
||||
You can select multiple files at once to upload into the template. Once the upload is complete you will be redirected to the editor.
|
||||
Clicking on the "New Template" button opens a new modal to upload the document you want to use as a template. Select the document and wait for Documenso to upload it to your account.
|
||||
|
||||

|
||||

|
||||
|
||||
See the [documents](/users/documents/sending-documents) page for more information on how to use the editor.
|
||||
Once the upload is complete, Documenso opens the template configuration page.
|
||||
|
||||

|
||||
|
||||
You can then configure the template by adding recipients, fields, and other options.
|
||||
|
||||
### (Optional) Email options
|
||||
|
||||
When you send a document for signing, Documenso emails the recipients with a link to the document. The email contains a subject, message, and the document.
|
||||
|
||||
Documenso uses a generic subject and message but also allows you to customize them for each document and template.
|
||||
|
||||

|
||||
|
||||
To configure the email options, click the "Email Options" tab and fill in the subject and message fields. Every time you use this template for signing, Documenso will use the custom subject and message you provided. They can also be overridden before sending the document.
|
||||
|
||||
### (Optional) Advanced Options
|
||||
|
||||
The template also has advanced options that you can configure. These options include settings such as the external ID, date format, time zone and the redirect URL.
|
||||
|
||||

|
||||
|
||||
The external ID allows you to set a custom ID for the document that can be used to identify the document in your external system(s).
|
||||
|
||||
The date format and time zone settings allow you to customize how the date and time are displayed in the document.
|
||||
|
||||
The redirect URL allows you to specify a URL where the signer will be redirected after signing the document.
|
||||
|
||||
### Add Placeholders or Recipients
|
||||
|
||||
When adding recipients, you can use dummy recipients which can be replaced with actual recipients when you use a template, which we will explain in the next section.
|
||||
You can add placeholders for the template recipients. Placeholders specify where the recipient's name, email, and other information should be in the document.
|
||||
|
||||
For example, the following has two recipients:
|
||||
|
||||
- placeholder@documenso.com
|
||||
- me@documenso.com
|
||||
You can also add recipients directly to the template. Recipients are the people who will receive the document for signing.
|
||||
|
||||

|
||||
|
||||
You can then place fields for each recipient.
|
||||
If you add placeholders to the template, you must replace them with actual recipients when creating a document from it. See the modal from the ["Use a Template"](#use-a-template) section.
|
||||
|
||||
### Add Fields
|
||||
|
||||
The last step involves adding fields to the document. These fields collect information from the recipients when they sign the document.
|
||||
|
||||
Documenso provides the following field types:
|
||||
|
||||
- **Signature** - Collects the signer's signature
|
||||
- **Email** - Collects the signer's email address
|
||||
- **Name** - Collects the signer's name
|
||||
- **Date** - Collects the date of the signature
|
||||
- **Text** - Collects text input from the signer
|
||||
- **Number** - Collects a number input from the signer
|
||||
- **Radio** - Collects a single choice from the signer
|
||||
- **Checkbox** - Collects multiple choices from the signer
|
||||
- **Dropdown/Select** - Collects a single choice from a list of choices
|
||||
|
||||

|
||||
|
||||
After adding the fields, press the "Save Template" button to save the template.
|
||||
|
||||
<Callout type="info">
|
||||
Learn more about the available field types and how to use them on the [Fields
|
||||
page](/users/documents/fields).
|
||||
page](signing-documents/fields).
|
||||
</Callout>
|
||||
|
||||
### Use a Template
|
||||
|
||||
Once you're ready to use the template, you can click the "Use Template" button in the top right corner.
|
||||
Click on the "Use Template" button to create a new document from the template. Before creating the document, you are asked to fill in the recipients for the placeholders you added to the template.
|
||||
|
||||
Here you can choose to use the template as is, or you can replace the emails or names with different recipients as you require.
|
||||
|
||||
You can now decide whether to create the document as a draft, or immediately send it to the recipients for signing.
|
||||
After filling in the recipients, click the "Create Document" button to create the document in your account.
|
||||
|
||||

|
||||
|
||||
@ -52,7 +91,7 @@ You can also send the document straight to the recipients for signing by checkin
|
||||
|
||||
### (Optional) Create A Direct Signing Link
|
||||
|
||||
A direct signing link allows you to create a shareable link for document signing, where recipients can fill in their information and sign the document.
|
||||
A direct signing link allows you to create a shareable link for document signing, where recipients can fill in their information and sign the document. See the "Create Direct Link" button in the image from [step 4](#add-placeholders-or-recipients).
|
||||
|
||||
<Callout type="info">
|
||||
Check out the [Direct Signing Links](/users/direct-links) section for more information.
|
||||
|
||||
|
After Width: | Height: | Size: 123 KiB |
|
After Width: | Height: | Size: 106 KiB |
|
After Width: | Height: | Size: 96 KiB |
|
After Width: | Height: | Size: 92 KiB |
|
After Width: | Height: | Size: 65 KiB |
|
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 66 KiB |
|
Before Width: | Height: | Size: 82 KiB After Width: | Height: | Size: 91 KiB |
|
Before Width: | Height: | Size: 69 KiB After Width: | Height: | Size: 189 KiB |
|
After Width: | Height: | Size: 70 KiB |
|
After Width: | Height: | Size: 69 KiB |
|
After Width: | Height: | Size: 74 KiB |
|
After Width: | Height: | Size: 72 KiB |
|
Before Width: | Height: | Size: 88 KiB |
|
After Width: | Height: | Size: 71 KiB |
|
After Width: | Height: | Size: 72 KiB |
|
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 72 KiB |
|
After Width: | Height: | Size: 66 KiB |
|
After Width: | Height: | Size: 68 KiB |
|
After Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 101 KiB After Width: | Height: | Size: 78 KiB |
|
Before Width: | Height: | Size: 112 KiB After Width: | Height: | Size: 54 KiB |
|
After Width: | Height: | Size: 78 KiB |
|
After Width: | Height: | Size: 85 KiB |
|
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 57 KiB |
|
Before Width: | Height: | Size: 100 KiB |
|
Before Width: | Height: | Size: 104 KiB |
|
Before Width: | Height: | Size: 71 KiB |
|
Before Width: | Height: | Size: 92 KiB |
|
After Width: | Height: | Size: 51 KiB |
|
After Width: | Height: | Size: 46 KiB |
|
After Width: | Height: | Size: 54 KiB |
|
After Width: | Height: | Size: 50 KiB |
|
After Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 84 KiB |
|
Before Width: | Height: | Size: 109 KiB |
|
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 73 KiB |
|
After Width: | Height: | Size: 67 KiB |
|
Before Width: | Height: | Size: 76 KiB |
|
Before Width: | Height: | Size: 80 KiB After Width: | Height: | Size: 73 KiB |
|
After Width: | Height: | Size: 66 KiB |
|
After Width: | Height: | Size: 68 KiB |
|
After Width: | Height: | Size: 67 KiB |
|
Before Width: | Height: | Size: 80 KiB After Width: | Height: | Size: 60 KiB |
|
After Width: | Height: | Size: 69 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 67 KiB |
|
After Width: | Height: | Size: 67 KiB |
|
After Width: | Height: | Size: 68 KiB |
|
After Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 73 KiB |
|
After Width: | Height: | Size: 72 KiB |
|
After Width: | Height: | Size: 71 KiB |
|
After Width: | Height: | Size: 73 KiB |
|
After Width: | Height: | Size: 64 KiB |
|
After Width: | Height: | Size: 73 KiB |
|
After Width: | Height: | Size: 67 KiB |
|
After Width: | Height: | Size: 72 KiB |
|
After Width: | Height: | Size: 71 KiB |
|
After Width: | Height: | Size: 66 KiB |
|
Before Width: | Height: | Size: 82 KiB After Width: | Height: | Size: 71 KiB |
|
After Width: | Height: | Size: 55 KiB |
|
After Width: | Height: | Size: 69 KiB |
|
After Width: | Height: | Size: 64 KiB |
|
After Width: | Height: | Size: 60 KiB |
|
After Width: | Height: | Size: 69 KiB |
|
Before Width: | Height: | Size: 80 KiB After Width: | Height: | Size: 75 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 69 KiB |
|
After Width: | Height: | Size: 68 KiB |
|
After Width: | Height: | Size: 65 KiB |
|
After Width: | Height: | Size: 135 KiB |
|
Before Width: | Height: | Size: 71 KiB After Width: | Height: | Size: 70 KiB |
|
After Width: | Height: | Size: 137 KiB |
|
Before Width: | Height: | Size: 87 KiB After Width: | Height: | Size: 60 KiB |
|
After Width: | Height: | Size: 61 KiB |
|
Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 61 KiB |
BIN
apps/documentation/public/teams/team-branding-preferences.webp
Normal file
|
After Width: | Height: | Size: 79 KiB |
|
After Width: | Height: | Size: 128 KiB |
|
After Width: | Height: | Size: 91 KiB |
|
After Width: | Height: | Size: 47 KiB |
|
After Width: | Height: | Size: 55 KiB |
|
After Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 84 KiB After Width: | Height: | Size: 58 KiB |
|
After Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 49 KiB |
|
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 104 KiB After Width: | Height: | Size: 44 KiB |
@ -1,4 +1,4 @@
|
||||
import { DocumentStatus, EnvelopeType } from '@prisma/client';
|
||||
import { DocumentStatus } from '@prisma/client';
|
||||
import { DateTime } from 'luxon';
|
||||
|
||||
import { kyselyPrisma, sql } from '@documenso/prisma';
|
||||
@ -7,19 +7,18 @@ import { addZeroMonth } from '../add-zero-month';
|
||||
|
||||
export const getCompletedDocumentsMonthly = async (type: 'count' | 'cumulative' = 'count') => {
|
||||
const qb = kyselyPrisma.$kysely
|
||||
.selectFrom('Envelope')
|
||||
.selectFrom('Document')
|
||||
.select(({ fn }) => [
|
||||
fn<Date>('DATE_TRUNC', [sql.lit('MONTH'), 'Envelope.updatedAt']).as('month'),
|
||||
fn<Date>('DATE_TRUNC', [sql.lit('MONTH'), 'Document.updatedAt']).as('month'),
|
||||
fn.count('id').as('count'),
|
||||
fn
|
||||
.sum(fn.count('id'))
|
||||
// Feels like a bug in the Kysely extension but I just can not do this orderBy in a type-safe manner
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions, @typescript-eslint/no-explicit-any
|
||||
.over((ob) => ob.orderBy(fn('DATE_TRUNC', [sql.lit('MONTH'), 'Envelope.updatedAt']) as any))
|
||||
.over((ob) => ob.orderBy(fn('DATE_TRUNC', [sql.lit('MONTH'), 'Document.updatedAt']) as any))
|
||||
.as('cume_count'),
|
||||
])
|
||||
.where(() => sql`"Envelope"."status" = ${DocumentStatus.COMPLETED}::"DocumentStatus"`)
|
||||
.where(() => sql`"Envelope"."type" = ${EnvelopeType.DOCUMENT}::"EnvelopeType"`)
|
||||
.where(() => sql`"Document"."status" = ${DocumentStatus.COMPLETED}::"DocumentStatus"`)
|
||||
.groupBy('month')
|
||||
.orderBy('month', 'desc')
|
||||
.limit(12);
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
"scripts": {
|
||||
"dev": "next dev -p 3003",
|
||||
"build": "next build",
|
||||
"start": "next start -p 3003",
|
||||
"start": "next start",
|
||||
"lint:fix": "next lint --fix",
|
||||
"clean": "rimraf .next && rimraf node_modules"
|
||||
},
|
||||
|
||||