documenso-data-handling
Handle document data, signatures, and PII in Documenso integrations. Use when managing document lifecycle, handling signed PDFs, or implementing data retention policies. Trigger with phrases like "documenso data", "signed document", "document retention", "documenso PII", "download signed pdf".
Install
mkdir -p .claude/skills/documenso-data-handling && curl -L -o skill.zip "https://mcp.directory/api/skills/download/7424" && unzip -o skill.zip -d .claude/skills/documenso-data-handling && rm skill.zipInstalls to .claude/skills/documenso-data-handling
About this skill
Documenso Data Handling
Overview
Best practices for handling documents, signatures, and PII in Documenso integrations. Covers downloading signed PDFs, data retention, GDPR compliance, and secure storage. Note: Documenso cloud stores documents in PostgreSQL by default; self-hosted gives you full control.
Prerequisites
- Understanding of data protection regulations (GDPR, CCPA)
- Secure storage infrastructure (S3, GCS, or local encrypted storage)
- Completed
documenso-install-authsetup
Document Lifecycle
DRAFT ──send()──→ PENDING ──all sign──→ COMPLETED
│
├──reject()──→ REJECTED
└──cancel()──→ CANCELLED
Data handling implications:
- DRAFT: mutable, can delete freely
- PENDING: immutable document, but status changes
- COMPLETED: signed PDF available for download, archive
- REJECTED/CANCELLED: cleanup candidate
Instructions
Step 1: Download Signed Documents
import { Documenso } from "@documenso/sdk-typescript";
import { writeFile } from "node:fs/promises";
const client = new Documenso({ apiKey: process.env.DOCUMENSO_API_KEY! });
async function downloadSignedPdf(documentId: number, outputPath: string) {
// Verify document is completed
const doc = await client.documents.getV0(documentId);
if (doc.status !== "COMPLETED") {
throw new Error(`Document ${documentId} is ${doc.status}, not COMPLETED`);
}
// Download via v1 REST API (SDK may not expose download directly)
const res = await fetch(
`https://app.documenso.com/api/v1/documents/${documentId}/download`,
{ headers: { Authorization: `Bearer ${process.env.DOCUMENSO_API_KEY}` } }
);
if (!res.ok) throw new Error(`Download failed: ${res.status}`);
const buffer = Buffer.from(await res.arrayBuffer());
await writeFile(outputPath, buffer);
console.log(`Saved signed PDF: ${outputPath} (${buffer.length} bytes)`);
}
Step 2: PII Handling
// Identify PII in Documenso data
interface RecipientPII {
email: string; // PII — must be protected
name: string; // PII — must be protected
role: string; // Not PII
signingStatus: string; // Not PII
}
// Sanitize before logging
function sanitizeForLogging(payload: any): any {
const sanitized = { ...payload };
if (sanitized.recipients) {
sanitized.recipients = sanitized.recipients.map((r: any) => ({
...r,
email: r.email.replace(/^(.{2}).*(@.*)$/, "$1***$2"),
name: "[REDACTED]",
}));
}
return sanitized;
}
// Usage: safe to log
console.log("Webhook received:", JSON.stringify(sanitizeForLogging(payload)));
// Output: { email: "ja***@example.com", name: "[REDACTED]" }
Step 3: Data Retention Policy
// src/retention/documenso-cleanup.ts
import { Documenso } from "@documenso/sdk-typescript";
interface RetentionPolicy {
draftMaxAgeDays: number; // Delete abandoned drafts
completedArchiveDays: number; // Archive completed docs
retainCompletedDays: number; // Keep completed in Documenso
}
const POLICY: RetentionPolicy = {
draftMaxAgeDays: 30,
completedArchiveDays: 7, // Archive to S3 within 7 days
retainCompletedDays: 365, // Keep in Documenso for 1 year
};
async function enforceRetention(client: Documenso) {
const { documents } = await client.documents.findV0({ page: 1, perPage: 100 });
const now = Date.now();
for (const doc of documents) {
const ageDays = (now - new Date(doc.createdAt).getTime()) / (1000 * 60 * 60 * 24);
// Delete old drafts
if (doc.status === "DRAFT" && ageDays > POLICY.draftMaxAgeDays) {
await client.documents.deleteV0(doc.id);
console.log(`Deleted abandoned draft: ${doc.title} (${ageDays.toFixed(0)} days old)`);
}
// Archive completed documents
if (doc.status === "COMPLETED" && ageDays > POLICY.completedArchiveDays) {
await archiveToS3(doc.id, doc.title);
console.log(`Archived: ${doc.title}`);
}
}
}
Step 4: GDPR Data Subject Requests
// Handle GDPR access and erasure requests
async function handleDataSubjectRequest(
client: Documenso,
type: "access" | "erasure",
subjectEmail: string
) {
const { documents } = await client.documents.findV0({ page: 1, perPage: 100 });
// Find all documents involving this person
const subjectDocs = documents.filter((doc: any) =>
doc.recipients?.some((r: any) => r.email === subjectEmail)
);
if (type === "access") {
// Return all data associated with this person
return {
documentsCount: subjectDocs.length,
documents: subjectDocs.map((d: any) => ({
title: d.title,
status: d.status,
createdAt: d.createdAt,
role: d.recipients.find((r: any) => r.email === subjectEmail)?.role,
})),
};
}
if (type === "erasure") {
// Delete/anonymize where legally permissible
// Note: completed, signed documents may need to be retained for legal compliance
const deletable = subjectDocs.filter((d: any) => d.status === "DRAFT");
for (const doc of deletable) {
await client.documents.deleteV0(doc.id);
}
return {
deleted: deletable.length,
retained: subjectDocs.length - deletable.length,
retainedReason: "Completed documents retained for legal compliance",
};
}
}
Step 5: Secure Storage for Downloaded PDFs
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
import crypto from "crypto";
const s3 = new S3Client({ region: "us-east-1" });
async function archiveToS3(documentId: number, title: string) {
// Download signed PDF
const res = await fetch(
`https://app.documenso.com/api/v1/documents/${documentId}/download`,
{ headers: { Authorization: `Bearer ${process.env.DOCUMENSO_API_KEY}` } }
);
const buffer = Buffer.from(await res.arrayBuffer());
// Upload with server-side encryption
const key = `signed-documents/${documentId}-${Date.now()}.pdf`;
await s3.send(new PutObjectCommand({
Bucket: process.env.ARCHIVE_BUCKET!,
Key: key,
Body: buffer,
ContentType: "application/pdf",
ServerSideEncryption: "aws:kms",
Metadata: {
documentId: String(documentId),
title,
archivedAt: new Date().toISOString(),
checksum: crypto.createHash("sha256").update(buffer).digest("hex"),
},
}));
console.log(`Archived to s3://${process.env.ARCHIVE_BUCKET}/${key}`);
}
Data Classification
| Data Type | Classification | Retention | Handling |
|---|---|---|---|
| Signed PDF | Legal record | Per regulation (often 7+ years) | Encrypted archive |
| Recipient email/name | PII | Duration of business relationship | Sanitize in logs |
| API keys | Secret | Active use only | Secret manager, never logged |
| Webhook payloads | Contains PII | 30 days max | Anonymize after processing |
| Audit trail | Compliance record | Per regulation | Immutable storage |
Error Handling
| Data Issue | Cause | Solution |
|---|---|---|
| Download failed | Document not COMPLETED | Check status before download |
| Storage permission denied | Wrong bucket policy | Verify IAM permissions |
| GDPR request incomplete | Pagination not handled | Iterate all pages of documents |
| Retention job failed | API error during deletion | Retry with backoff, log failures |
Resources
Next Steps
For enterprise RBAC, see documenso-enterprise-rbac.
More by jeremylongshore
View all skills by jeremylongshore →You might also like
flutter-development
aj-geddes
Build beautiful cross-platform mobile apps with Flutter and Dart. Covers widgets, state management with Provider/BLoC, navigation, API integration, and material design.
drawio-diagrams-enhanced
jgtolentino
Create professional draw.io (diagrams.net) diagrams in XML format (.drawio files) with integrated PMP/PMBOK methodologies, extensive visual asset libraries, and industry-standard professional templates. Use this skill when users ask to create flowcharts, swimlane diagrams, cross-functional flowcharts, org charts, network diagrams, UML diagrams, BPMN, project management diagrams (WBS, Gantt, PERT, RACI), risk matrices, stakeholder maps, or any other visual diagram in draw.io format. This skill includes access to custom shape libraries for icons, clipart, and professional symbols.
ui-ux-pro-max
nextlevelbuilder
"UI/UX design intelligence. 50 styles, 21 palettes, 50 font pairings, 20 charts, 8 stacks (React, Next.js, Vue, Svelte, SwiftUI, React Native, Flutter, Tailwind). Actions: plan, build, create, design, implement, review, fix, improve, optimize, enhance, refactor, check UI/UX code. Projects: website, landing page, dashboard, admin panel, e-commerce, SaaS, portfolio, blog, mobile app, .html, .tsx, .vue, .svelte. Elements: button, modal, navbar, sidebar, card, table, form, chart. Styles: glassmorphism, claymorphism, minimalism, brutalism, neumorphism, bento grid, dark mode, responsive, skeuomorphism, flat design. Topics: color palette, accessibility, animation, layout, typography, font pairing, spacing, hover, shadow, gradient."
godot
bfollington
This skill should be used when working on Godot Engine projects. It provides specialized knowledge of Godot's file formats (.gd, .tscn, .tres), architecture patterns (component-based, signal-driven, resource-based), common pitfalls, validation tools, code templates, and CLI workflows. The `godot` command is available for running the game, validating scripts, importing resources, and exporting builds. Use this skill for tasks involving Godot game development, debugging scene/resource files, implementing game systems, or creating new Godot components.
nano-banana-pro
garg-aayush
Generate and edit images using Google's Nano Banana Pro (Gemini 3 Pro Image) API. Use when the user asks to generate, create, edit, modify, change, alter, or update images. Also use when user references an existing image file and asks to modify it in any way (e.g., "modify this image", "change the background", "replace X with Y"). Supports both text-to-image generation and image-to-image editing with configurable resolution (1K default, 2K, or 4K for high resolution). DO NOT read the image file first - use this skill directly with the --input-image parameter.
fastapi-templates
wshobson
Create production-ready FastAPI projects with async patterns, dependency injection, and comprehensive error handling. Use when building new FastAPI applications or setting up backend API projects.
Related MCP Servers
Browse all serversConnect Claude with Vectorize.io's vector database to extract text from images and enable advanced retrieval for researc
Unlock AI-ready web data with Firecrawl: scrape any website, handle dynamic content, and automate web scraping for resea
Optimize your codebase for AI with Repomix—transform, compress, and secure repos for easier analysis with modern AI tool
Connect Supabase projects to AI with Supabase MCP Server. Standardize LLM communication for secure, efficient developmen
pg-aiguide — Version-aware PostgreSQL docs and best practices tailored for AI coding assistants. Improve queries, migrat
Transform any OpenAPI specification into callable tools. Easily test an API, handle authentication, and generate schemas
Stay ahead of the MCP ecosystem
Get weekly updates on new skills and servers.