Documenso Local Dev Loop
Overview
Configure a productive local development environment for Documenso integrations with fast iteration cycles.
Prerequisites
- Completed
documenso-install-authsetup - Node.js 18+ or Python 3.10+
- Docker (optional, for self-hosted testing)
- Code editor with TypeScript support
Instructions
Step 1: Project Structure
my-documenso-project/
├── src/
│ ├── documenso/
│ │ ├── client.ts # SDK client wrapper
│ │ ├── config.ts # Environment configuration
│ │ └── types.ts # Custom TypeScript types
│ ├── services/
│ │ └── signing.ts # Signing service layer
│ └── index.ts # Main entry point
├── tests/
│ ├── unit/
│ │ └── signing.test.ts
│ └── integration/
│ └── documenso.test.ts
├── fixtures/
│ └── sample.pdf # Test PDF files
├── .env.development
├── .env.test
└── package.json
Step 2: Environment Configuration
.env.development:
# Use staging API for development
DOCUMENSO_API_KEY=your-dev-api-key
DOCUMENSO_BASE_URL=https://stg-app.documenso.com/api/v2/
# Test recipient (use your own email for testing)
TEST_RECIPIENT_EMAIL=developer@yourcompany.com
TEST_RECIPIENT_NAME=Dev Tester
.env.test:
# Use staging with test-specific key
DOCUMENSO_API_KEY=your-test-api-key
DOCUMENSO_BASE_URL=https://stg-app.documenso.com/api/v2/
# CI test recipient
TEST_RECIPIENT_EMAIL=ci-test@yourcompany.com
Step 3: Client Wrapper with Dev Helpers
// src/documenso/client.ts
import { Documenso } from "@documenso/sdk-typescript";
interface DocumensoConfig {
apiKey: string;
baseUrl?: string;
debug?: boolean;
}
let clientInstance: Documenso | null = null;
export function getDocumensoClient(config?: DocumensoConfig): Documenso {
if (!clientInstance) {
const apiKey = config?.apiKey ?? process.env.DOCUMENSO_API_KEY;
const baseUrl = config?.baseUrl ?? process.env.DOCUMENSO_BASE_URL;
if (!apiKey) {
throw new Error("DOCUMENSO_API_KEY is required");
}
clientInstance = new Documenso({
apiKey,
serverURL: baseUrl,
debugLogger: config?.debug ? console : undefined,
});
}
return clientInstance;
}
// Helper for testing - reset singleton
export function resetClient(): void {
clientInstance = null;
}
// Development helper - create test document quickly
export async function createTestDocument(
title = "Test Document"
): Promise<{ documentId: string }> {
const client = getDocumensoClient();
const doc = await client.documents.createV0({ title });
return { documentId: doc.documentId! };
}
Step 4: Development Scripts
package.json:
{
"scripts": {
"dev": "tsx watch src/index.ts",
"test": "vitest",
"test:integration": "vitest run tests/integration/",
"test:watch": "vitest watch",
"documenso:verify": "tsx scripts/verify-connection.ts",
"documenso:cleanup": "tsx scripts/cleanup-test-docs.ts"
}
}
Step 5: Quick Verification Script
// scripts/verify-connection.ts
import { getDocumensoClient } from "../src/documenso/client";
async function verify() {
console.log("Verifying Documenso connection...");
console.log(`Base URL: ${process.env.DOCUMENSO_BASE_URL || "default"}`);
try {
const client = getDocumensoClient({ debug: true });
const result = await client.documents.findV0({ perPage: 1 });
console.log("Connection successful!");
console.log(`Total documents in account: ${result.totalPages ?? 0} pages`);
return true;
} catch (error: any) {
console.error("Connection failed!");
console.error(`Error: ${error.message}`);
if (error.statusCode === 401) {
console.error("Hint: Check your DOCUMENSO_API_KEY");
}
return false;
}
}
verify().then(success => process.exit(success ? 0 : 1));
Step 6: Test Cleanup Script
// scripts/cleanup-test-docs.ts
import { getDocumensoClient } from "../src/documenso/client";
async function cleanup() {
const client = getDocumensoClient();
const testPrefix = "Test Document";
console.log("Finding test documents to clean up...");
const docs = await client.documents.findV0({});
const testDocs = docs.documents?.filter(d =>
d.title?.startsWith(testPrefix)
) ?? [];
console.log(`Found ${testDocs.length} test documents`);
for (const doc of testDocs) {
try {
await client.documents.deleteV0({ documentId: doc.id! });
console.log(`Deleted: ${doc.title} (${doc.id})`);
} catch (error: any) {
console.error(`Failed to delete ${doc.id}: ${error.message}`);
}
}
console.log("Cleanup complete!");
}
cleanup().catch(console.error);
Step 7: Integration Test Example
// tests/integration/documenso.test.ts
import { describe, it, expect, beforeAll, afterAll } from "vitest";
import { getDocumensoClient, resetClient } from "../../src/documenso/client";
describe("Documenso Integration", () => {
let testDocumentId: string;
beforeAll(() => {
resetClient();
});
afterAll(async () => {
// Clean up test document
if (testDocumentId) {
const client = getDocumensoClient();
await client.documents.deleteV0({ documentId: testDocumentId });
}
});
it("should create a document", async () => {
const client = getDocumensoClient();
const doc = await client.documents.createV0({
title: "Test Document - Integration",
});
expect(doc.documentId).toBeDefined();
testDocumentId = doc.documentId!;
});
it("should add a recipient", async () => {
const client = getDocumensoClient();
const recipient = await client.documentsRecipients.createV0({
documentId: testDocumentId,
email: process.env.TEST_RECIPIENT_EMAIL!,
name: process.env.TEST_RECIPIENT_NAME ?? "Test User",
role: "SIGNER",
});
expect(recipient.recipientId).toBeDefined();
});
it("should retrieve document details", async () => {
const client = getDocumensoClient();
const doc = await client.documents.getV0({
documentId: testDocumentId,
});
expect(doc.title).toBe("Test Document - Integration");
expect(doc.recipients?.length).toBeGreaterThan(0);
});
});
Self-Hosted Local Development
For testing against a local Documenso instance:
# Clone Documenso
git clone https://github.com/documenso/documenso.git
cd documenso
# Start with Docker Compose
docker-compose up -d
# Your local instance is now at http://localhost:3000
.env.local (for self-hosted):
DOCUMENSO_API_KEY=your-local-api-key
DOCUMENSO_BASE_URL=http://localhost:3000/api/v2/
Output
- Configured development environment
- Verification script passing
- Integration tests running against staging
- Cleanup script for test documents
Error Handling
| Issue | Cause | Solution | |-------|-------|----------| | Connection refused | Wrong base URL | Check DOCUMENSO_BASE_URL | | 401 on staging | Wrong API key | Get staging-specific key | | Tests failing | Stale test data | Run cleanup script | | Rate limited | Too many requests | Add delays between tests |
Resources
Next Steps
Apply patterns in documenso-sdk-patterns for production-ready code.
Scan to join WeChat group