๐Ÿ“… let's chat! explore the endless possibilities creating industries that don't exist. click here

documenso-core-workflow-b

Implement Documenso template-based workflows and direct signing links. Use when creating reusable templates, generating documents from templates, or implementing direct signing experiences. Trigger with phrases like "documenso template", "signing link", "direct template", "reusable document", "template workflow". allowed-tools: Read, Write, Edit version: 1.0.0 license: MIT author: Jeremy Longshore <jeremy@intentsolutions.io>

Allowed Tools

No tools specified

Provided by Plugin

documenso-pack

Claude Code skill pack for Documenso (24 skills)

saas packs v1.0.0
View Plugin

Installation

This skill is included in the documenso-pack plugin:

/plugin install documenso-pack@claude-code-plugins-plus

Click to copy

Instructions

# Documenso Core Workflow B: Templates & Direct Signing ## Overview Create reusable templates, generate documents from templates, and implement direct signing experiences with Documenso. ## Prerequisites - Completed `documenso-core-workflow-a` - Understanding of template-based document generation - PDF template files ready ## Instructions ### Step 1: Create a Template ```typescript import { Documenso } from "@documenso/sdk-typescript"; import { openAsBlob } from "node:fs"; const documenso = new Documenso({ apiKey: process.env.DOCUMENSO_API_KEY ?? "", }); interface CreateTemplateInput { title: string; pdfPath: string; recipientRoles: Array<{ name: string; // e.g., "Employee", "Manager" role: "SIGNER" | "APPROVER" | "VIEWER" | "CC"; signingOrder?: number; }>; } async function createTemplate( input: CreateTemplateInput ): Promise { const pdfBlob = await openAsBlob(input.pdfPath); // Create the template const template = await documenso.templates.createV0({ title: input.title, file: pdfBlob, }); const templateId = template.templateId!; console.log(`Created template: ${templateId}`); // Add recipient placeholders for (const role of input.recipientRoles) { await documenso.templatesRecipients.createV0({ templateId, name: role.name, role: role.role, signingOrder: role.signingOrder, }); console.log(`Added role: ${role.name}`); } return templateId; } // Example: Create NDA template const templateId = await createTemplate({ title: "Non-Disclosure Agreement", pdfPath: "./templates/nda.pdf", recipientRoles: [ { name: "Disclosing Party", role: "SIGNER", signingOrder: 1 }, { name: "Receiving Party", role: "SIGNER", signingOrder: 2 }, ], }); ``` ### Step 2: Add Template Fields ```typescript interface TemplateFieldInput { recipientIndex: number; // Index of recipient in the roles array type: "SIGNATURE" | "INITIALS" | "NAME" | "EMAIL" | "DATE" | "TEXT"; page: number; x: number; y: number; width?: number; height?: number; } async function addTemplateFields( templateId: string, fields: TemplateFieldInput[] ): Promise { // Get template recipients to map indices to IDs const template = await documenso.templates.getV0({ templateId }); const recipientIds = template.recipients?.map(r => r.id!) ?? []; for (const field of fields) { const recipientId = recipientIds[field.recipientIndex]; if (!recipientId) { console.error(`No recipient at index ${field.recipientIndex}`); continue; } await documenso.templatesFields.createV0({ templateId, recipientId, type: field.type, page: field.page, positionX: field.x, positionY: field.y, width: field.width ?? 200, height: field.height ?? 60, }); console.log(`Added ${field.type} field for recipient ${field.recipientIndex}`); } } // Example: Add fields to NDA template await addTemplateFields(templateId, [ // Disclosing Party fields (index 0) { recipientIndex: 0, type: "SIGNATURE", page: 2, x: 100, y: 400 }, { recipientIndex: 0, type: "NAME", page: 2, x: 100, y: 350 }, { recipientIndex: 0, type: "DATE", page: 2, x: 350, y: 400 }, // Receiving Party fields (index 1) { recipientIndex: 1, type: "SIGNATURE", page: 2, x: 100, y: 200 }, { recipientIndex: 1, type: "NAME", page: 2, x: 100, y: 150 }, { recipientIndex: 1, type: "DATE", page: 2, x: 350, y: 200 }, ]); ``` ### Step 3: Generate Document from Template ```typescript interface UseTemplateInput { templateId: string; title?: string; recipients: Array<{ email: string; name: string; }>; sendImmediately?: boolean; } async function createFromTemplate( input: UseTemplateInput ): Promise<{ documentId: string }> { // Use the template to create a new document const result = await documenso.envelopes.useV0({ templateId: input.templateId, title: input.title, recipients: input.recipients.map((r, index) => ({ email: r.email, name: r.name, signerIndex: index, })), }); const documentId = result.envelopeId!; console.log(`Created document from template: ${documentId}`); // Send if requested if (input.sendImmediately) { await documenso.envelopes.distributeV0({ envelopeId: documentId, }); console.log("Document sent to recipients"); } return { documentId }; } // Example: Create NDA from template const document = await createFromTemplate({ templateId, title: "NDA - Acme Corp Partnership", recipients: [ { email: "legal@yourcompany.com", name: "Your Company Legal" }, { email: "partner@acme.com", name: "Acme Corp Representative" }, ], sendImmediately: true, }); ``` ### Step 4: Direct Template Links Direct templates allow signers to access and sign documents without pre-registration. ```typescript async function createDirectTemplateLink( templateId: string ): Promise<{ directLink: string }> { // Get template direct link settings const template = await documenso.templates.getV0({ templateId }); // The direct link is available when template is published const directLink = template.directLink; if (!directLink) { console.log("Template direct link not enabled. Enable in dashboard."); throw new Error("Direct link not available"); } return { directLink }; } // Example usage with direct link // Users can access: https://app.documenso.com/d/{directLinkToken} ``` ### Step 5: Embedding Signing Experience ```typescript // Get signing token for embedding async function getSigningToken( documentId: string, recipientEmail: string ): Promise<{ signingToken: string; signingUrl: string }> { // Get document with recipients const doc = await documenso.documents.getV0({ documentId }); const recipient = doc.recipients?.find(r => r.email === recipientEmail); if (!recipient) { throw new Error(`Recipient ${recipientEmail} not found`); } // The signing token can be used for embedding return { signingToken: recipient.signingToken!, signingUrl: recipient.signingUrl!, }; } // For React embedding, use @documenso/embed-react // npm install @documenso/embed-react // React component example: /* import { EmbedDirectTemplate } from '@documenso/embed-react'; function SigningComponent({ signingToken }) { return ( console.log('Ready')} onDocumentCompleted={() => console.log('Completed')} onDocumentError={(error) => console.error(error)} /> ); } */ ``` ### Step 6: Pre-fill Template Fields ```typescript interface PrefillInput { templateId: string; recipients: Array<{ email: string; name: string; prefillFields?: Array<{ fieldId: string; value: string; }>; }>; } async function createWithPrefill( input: PrefillInput ): Promise<{ documentId: string }> { const result = await documenso.envelopes.useV0({ templateId: input.templateId, recipients: input.recipients.map((r, index) => ({ email: r.email, name: r.name, signerIndex: index, prefillFields: r.prefillFields, })), }); return { documentId: result.envelopeId! }; } // Example: Pre-fill contract details await createWithPrefill({ templateId, recipients: [ { email: "client@example.com", name: "Client Name", prefillFields: [ { fieldId: "company_name_field", value: "Acme Corporation" }, { fieldId: "contract_amount_field", value: "$50,000" }, ], }, ], }); ``` ### Step 7: Duplicate and Modify Templates ```typescript async function duplicateTemplate( templateId: string, newTitle: string ): Promise { const duplicate = await documenso.templates.duplicateV0({ templateId, title: newTitle, }); console.log(`Duplicated template: ${duplicate.templateId}`); return duplicate.templateId!; } // Example: Create region-specific variants const usTemplateId = await duplicateTemplate(templateId, "NDA - US Version"); const euTemplateId = await duplicateTemplate(templateId, "NDA - EU Version"); ``` ## Template Workflow Patterns ### Pattern 1: Sales Contract Flow ```typescript // 1. Create template once const salesContractTemplate = await createTemplate({ title: "Sales Agreement", pdfPath: "./templates/sales-agreement.pdf", recipientRoles: [ { name: "Sales Rep", role: "SIGNER", signingOrder: 1 }, { name: "Customer", role: "SIGNER", signingOrder: 2 }, { name: "Legal Review", role: "APPROVER", signingOrder: 3 }, ], }); // 2. Use for each deal async function createSalesContract(deal: DealInfo) { return createFromTemplate({ templateId: salesContractTemplate, title: `Sales Agreement - ${deal.customerName}`, recipients: [ { email: deal.salesRepEmail, name: deal.salesRepName }, { email: deal.customerEmail, name: deal.customerName }, { email: "legal@company.com", name: "Legal Team" }, ], sendImmediately: true, }); } ``` ### Pattern 2: Self-Service Signing ```typescript // Customer visits your site, fills form, and signs async function selfServiceSigning(customerInfo: CustomerInfo) { // Create document from template with customer info pre-filled const doc = await createWithPrefill({ templateId: selfServiceTemplateId, recipients: [ { email: customerInfo.email, name: customerInfo.name, prefillFields: [ { fieldId: "customer_name", value: customerInfo.name }, { fieldId: "customer_address", value: customerInfo.address }, ], }, ], }); // Get signing URL for immediate redirect const { signingUrl } = await getSigningToken( doc.documentId, customerInfo.email ); return { signingUrl }; } ``` ## Output - Created reusable templates - Generated documents from templates - Direct signing links available - Embedded signing experience ready - Pre-filled field values ## Error Handling | Error | Cause | Solution | |-------|-------|----------| | Template not found | Invalid ID or deleted | Verify template exists | | Recipient mismatch | Wrong number of recipients | Match template roles | | Field not found | Invalid field ID for prefill | Get field IDs from template | | Direct link disabled | Feature not enabled | Enable in template settings | | Duplicate failed | Template in use | Try with different title | ## Resources - [Templates API](https://github.com/documenso/sdk-typescript/blob/main/docs/sdks/templates/README.md) - [Embedding Documentation](https://docs.documenso.com/developers/embedding) - [Direct Templates](https://docs.documenso.com/users/templates) ## Next Steps For error handling patterns, see `documenso-common-errors`.

Skill file: plugins/saas-packs/documenso-pack/skills/documenso-core-workflow-b/SKILL.md