documenso-debug-bundle
Comprehensive debugging toolkit for Documenso integrations. Use when troubleshooting complex issues, gathering diagnostic information, or creating support tickets for Documenso problems. Trigger with phrases like "debug documenso", "documenso diagnostics", "troubleshoot documenso", "documenso support ticket". allowed-tools: Read, Write, Edit, Bash(curl:*), Bash(node:*), Grep 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)
Installation
This skill is included in the documenso-pack plugin:
/plugin install documenso-pack@claude-code-plugins-plus
Click to copy
Instructions
# 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
```typescript
// 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 {
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
```typescript
// 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 ");
}
```
### Script 3: API Request Logger
```typescript
// 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
```typescript
// 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
```typescript
// 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 = {};
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
```bash
# 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
```bash
#!/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:
```markdown
## 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`.