Documenso Debug Bundle
Overview
Comprehensive debugging tools and diagnostic scripts for Documenso integration issues.
Prerequisites
- Documenso SDK installed
- Access to logs and configuration
- curl for API testing
Debug Scripts
Script 1: Connection Diagnostic
// scripts/documenso-diagnostic.ts
import { Documenso } from "@documenso/sdk-typescript";
interface DiagnosticResult {
timestamp: string;
environment: {
nodeVersion: string;
sdkVersion: string;
apiKeyPresent: boolean;
apiKeyPrefix: string;
baseUrl: string;
};
connectivity: {
canConnect: boolean;
latencyMs: number;
error?: string;
};
account: {
documentsCount?: number;
templatesCount?: number;
error?: string;
};
}
async function runDiagnostic(): Promise<DiagnosticResult> {
const result: DiagnosticResult = {
timestamp: new Date().toISOString(),
environment: {
nodeVersion: process.version,
sdkVersion: "latest", // Get from package.json
apiKeyPresent: !!process.env.DOCUMENSO_API_KEY,
apiKeyPrefix: process.env.DOCUMENSO_API_KEY?.substring(0, 7) ?? "missing",
baseUrl: process.env.DOCUMENSO_BASE_URL ?? "https://app.documenso.com/api/v2/",
},
connectivity: {
canConnect: false,
latencyMs: 0,
},
account: {},
};
if (!process.env.DOCUMENSO_API_KEY) {
result.connectivity.error = "DOCUMENSO_API_KEY not set";
return result;
}
const client = new Documenso({
apiKey: process.env.DOCUMENSO_API_KEY,
serverURL: process.env.DOCUMENSO_BASE_URL,
});
// Test connectivity
const startTime = Date.now();
try {
const docs = await client.documents.findV0({ perPage: 1 });
result.connectivity.canConnect = true;
result.connectivity.latencyMs = Date.now() - startTime;
result.account.documentsCount = docs.totalPages ?? 0;
} catch (error: any) {
result.connectivity.error = `${error.statusCode}: ${error.message}`;
result.connectivity.latencyMs = Date.now() - startTime;
}
// Test templates access
try {
const templates = await client.templates.findV0({ perPage: 1 });
result.account.templatesCount = templates.totalPages ?? 0;
} catch (error: any) {
result.account.error = error.message;
}
return result;
}
// Run and output
runDiagnostic().then(result => {
console.log("\n=== Documenso Diagnostic Report ===\n");
console.log(JSON.stringify(result, null, 2));
// Summary
console.log("\n=== Summary ===");
if (result.connectivity.canConnect) {
console.log("Connection: OK");
console.log(`Latency: ${result.connectivity.latencyMs}ms`);
} else {
console.log("Connection: FAILED");
console.log(`Error: ${result.connectivity.error}`);
}
});
Script 2: Document Inspector
// scripts/inspect-document.ts
import { Documenso } from "@documenso/sdk-typescript";
async function inspectDocument(documentId: string) {
const client = new Documenso({
apiKey: process.env.DOCUMENSO_API_KEY ?? "",
});
console.log(`\n=== Inspecting Document: ${documentId} ===\n`);
try {
const doc = await client.documents.getV0({ documentId });
console.log("Document Details:");
console.log(` ID: ${doc.id}`);
console.log(` Title: ${doc.title}`);
console.log(` Status: ${doc.status}`);
console.log(` Created: ${doc.createdAt}`);
console.log(` Updated: ${doc.updatedAt}`);
console.log("\nRecipients:");
for (const recipient of doc.recipients ?? []) {
console.log(` - ${recipient.email}`);
console.log(` Name: ${recipient.name}`);
console.log(` Role: ${recipient.role}`);
console.log(` Status: ${recipient.signingStatus}`);
console.log(` Signing Order: ${recipient.signingOrder}`);
}
console.log("\nFields:");
for (const field of doc.fields ?? []) {
console.log(` - Type: ${field.type}`);
console.log(` Page: ${field.page}`);
console.log(` Position: (${field.positionX}, ${field.positionY})`);
console.log(` Size: ${field.width}x${field.height}`);
console.log(` Recipient: ${field.recipientId}`);
}
return doc;
} catch (error: any) {
console.error(`Failed to inspect document: ${error.message}`);
console.error(`Status: ${error.statusCode}`);
throw error;
}
}
// Usage: npx tsx scripts/inspect-document.ts doc_abc123
const documentId = process.argv[2];
if (documentId) {
inspectDocument(documentId);
} else {
console.log("Usage: npx tsx scripts/inspect-document.ts <documentId>");
}
Script 3: API Request Logger
// scripts/logged-client.ts
import { Documenso } from "@documenso/sdk-typescript";
// Create a logged wrapper
function createLoggedClient(): Documenso {
const client = new Documenso({
apiKey: process.env.DOCUMENSO_API_KEY ?? "",
serverURL: process.env.DOCUMENSO_BASE_URL,
debugLogger: {
log: (...args) => {
const timestamp = new Date().toISOString();
console.log(`[${timestamp}] DEBUG:`, ...args);
},
warn: (...args) => {
const timestamp = new Date().toISOString();
console.warn(`[${timestamp}] WARN:`, ...args);
},
error: (...args) => {
const timestamp = new Date().toISOString();
console.error(`[${timestamp}] ERROR:`, ...args);
},
},
});
return client;
}
export { createLoggedClient };
Script 4: Webhook Tester
// scripts/test-webhook.ts
import express from "express";
import crypto from "crypto";
const app = express();
// Log all incoming requests
app.use((req, res, next) => {
console.log(`\n=== Incoming Request ===`);
console.log(`Time: ${new Date().toISOString()}`);
console.log(`Method: ${req.method}`);
console.log(`Path: ${req.path}`);
console.log(`Headers:`, JSON.stringify(req.headers, null, 2));
next();
});
// Parse raw body for signature verification
app.use(express.raw({ type: "application/json" }));
app.post("/webhook/documenso", (req, res) => {
const secret = req.headers["x-documenso-secret"];
const expectedSecret = process.env.DOCUMENSO_WEBHOOK_SECRET;
console.log(`\n=== Webhook Received ===`);
console.log(`Secret Header: ${secret ? "present" : "missing"}`);
console.log(`Secret Valid: ${secret === expectedSecret}`);
try {
const payload = JSON.parse(req.body.toString());
console.log(`Event: ${payload.event}`);
console.log(`Document ID: ${payload.payload?.id}`);
console.log(`Status: ${payload.payload?.status}`);
console.log(`Full Payload:`, JSON.stringify(payload, null, 2));
res.status(200).json({ received: true });
} catch (error) {
console.error(`Failed to parse webhook:`, error);
res.status(400).json({ error: "Invalid JSON" });
}
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Webhook test server running on port ${PORT}`);
console.log(`Endpoint: POST http://localhost:${PORT}/webhook/documenso`);
console.log(`\nUse ngrok to expose: ngrok http ${PORT}`);
});
Script 5: Bulk Document Status Check
// scripts/check-document-status.ts
import { Documenso } from "@documenso/sdk-typescript";
async function checkAllDocuments() {
const client = new Documenso({
apiKey: process.env.DOCUMENSO_API_KEY ?? "",
});
console.log("Fetching all documents...\n");
const statusCounts: Record<string, number> = {};
const pendingDocs: Array<{ id: string; title: string; age: string }> = [];
let page = 1;
let hasMore = true;
while (hasMore) {
const result = await client.documents.findV0({
page,
perPage: 100,
});
for (const doc of result.documents ?? []) {
const status = doc.status ?? "UNKNOWN";
statusCounts[status] = (statusCounts[status] ?? 0) + 1;
// Track pending documents
if (status === "PENDING") {
const createdAt = new Date(doc.createdAt!);
const age = getAge(createdAt);
pendingDocs.push({
id: doc.id!,
title: doc.title ?? "Untitled",
age,
});
}
}
hasMore = (result.documents?.length ?? 0) === 100;
page++;
}
console.log("=== Document Status Summary ===");
for (const [status, count] of Object.entries(statusCounts)) {
console.log(`${status}: ${count}`);
}
if (pendingDocs.length > 0) {
console.log("\n=== Pending Documents ===");
for (const doc of pendingDocs.slice(0, 10)) {
console.log(`- ${doc.title} (${doc.id}) - ${doc.age} old`);
}
if (pendingDocs.length > 10) {
console.log(`... and ${pendingDocs.length - 10} more`);
}
}
}
function getAge(date: Date): string {
const now = new Date();
const diffMs = now.getTime() - date.getTime();
const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));
if (diffDays === 0) return "< 1 day";
if (diffDays === 1) return "1 day";
if (diffDays < 7) return `${diffDays} days`;
if (diffDays < 30) return `${Math.floor(diffDays / 7)} weeks`;
return `${Math.floor(diffDays / 30)} months`;
}
checkAllDocuments().catch(console.error);
curl Debug Commands
# Test API connectivity
curl -v -H "Authorization: Bearer $DOCUMENSO_API_KEY" \
https://app.documenso.com/api/v2/documents
# Get specific document
curl -H "Authorization: Bearer $DOCUMENSO_API_KEY" \
https://app.documenso.com/api/v2/documents/{documentId}
# List templates
curl -H "Authorization: Bearer $DOCUMENSO_API_KEY" \
https://app.documenso.com/api/v2/templates
# Test webhook endpoint
curl -X POST http://localhost:3000/webhook/documenso \
-H "Content-Type: application/json" \
-H "X-Documenso-Secret: your-secret" \
-d '{"event":"document.completed","payload":{"id":"test"}}'
Environment Checklist
#!/bin/bash
# scripts/check-env.sh
echo "=== Documenso Environment Check ==="
# Check API key
if [ -z "$DOCUMENSO_API_KEY" ]; then
echo "DOCUMENSO_API_KEY: NOT SET"
else
echo "DOCUMENSO_API_KEY: SET (${DOCUMENSO_API_KEY:0:7}...)"
fi
# Check base URL
if [ -z "$DOCUMENSO_BASE_URL" ]; then
echo "DOCUMENSO_BASE_URL: NOT SET (using default)"
else
echo "DOCUMENSO_BASE_URL: $DOCUMENSO_BASE_URL"
fi
# Check webhook secret
if [ -z "$DOCUMENSO_WEBHOOK_SECRET" ]; then
echo "DOCUMENSO_WEBHOOK_SECRET: NOT SET"
else
echo "DOCUMENSO_WEBHOOK_SECRET: SET"
fi
# Test connectivity
echo ""
echo "Testing connectivity..."
response=$(curl -s -o /dev/null -w "%{http_code}" \
-H "Authorization: Bearer $DOCUMENSO_API_KEY" \
${DOCUMENSO_BASE_URL:-https://app.documenso.com/api/v2/}documents?perPage=1)
if [ "$response" = "200" ]; then
echo "API Connection: OK"
elif [ "$response" = "401" ]; then
echo "API Connection: UNAUTHORIZED (check API key)"
else
echo "API Connection: FAILED (HTTP $response)"
fi
Support Ticket Template
When creating a support ticket, include:
## Documenso Support Request
### Environment
- SDK Version: @documenso/sdk-typescript@x.x.x
- Node.js Version: v20.x.x
- Environment: Production / Staging
- API Base URL: https://app.documenso.com/api/v2/
### Issue Description
[Describe what you expected vs what happened]
### Steps to Reproduce
1. [Step 1]
2. [Step 2]
3. [Step 3]
### Error Details
[Paste error message and stack trace]
### Diagnostic Output
```json
[Paste output from documenso-diagnostic.ts]
Document IDs (if applicable)
- Document ID: doc_xxx
- Template ID: tmpl_xxx
Request/Response (if applicable)
[Paste relevant API request and response]
## Output
- Diagnostic scripts ready
- Environment validated
- Debug logging enabled
- Support ticket template prepared
## Resources
- [Documenso GitHub Issues](https://github.com/documenso/documenso/issues)
- [Documenso Discord](https://documenso.com/discord)
- [API Status](https://status.documenso.com)
## Next Steps
For rate limit handling, see `documenso-rate-limits`.