documenso-sdk-patterns

Apply production-ready Documenso SDK patterns for TypeScript and Python. Use when implementing Documenso integrations, refactoring SDK usage, or establishing team coding standards for Documenso. Trigger with phrases like "documenso SDK patterns", "documenso best practices", "documenso code patterns", "idiomatic documenso".

25 stars

Best use case

documenso-sdk-patterns is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Apply production-ready Documenso SDK patterns for TypeScript and Python. Use when implementing Documenso integrations, refactoring SDK usage, or establishing team coding standards for Documenso. Trigger with phrases like "documenso SDK patterns", "documenso best practices", "documenso code patterns", "idiomatic documenso".

Teams using documenso-sdk-patterns should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/documenso-sdk-patterns/SKILL.md --create-dirs "https://raw.githubusercontent.com/ComeOnOliver/skillshub/main/skills/jeremylongshore/claude-code-plugins-plus-skills/documenso-sdk-patterns/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/documenso-sdk-patterns/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How documenso-sdk-patterns Compares

Feature / Agentdocumenso-sdk-patternsStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Apply production-ready Documenso SDK patterns for TypeScript and Python. Use when implementing Documenso integrations, refactoring SDK usage, or establishing team coding standards for Documenso. Trigger with phrases like "documenso SDK patterns", "documenso best practices", "documenso code patterns", "idiomatic documenso".

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

Related Guides

SKILL.md Source

# Documenso SDK Patterns

## Overview

Production-ready patterns for the Documenso TypeScript SDK (`@documenso/sdk-typescript`) and Python SDK. Covers singleton clients, typed wrappers, error handling, retry logic, and testing patterns.

## Prerequisites

- Completed `documenso-install-auth` setup
- Familiarity with async/await and TypeScript generics
- Understanding of error handling best practices

## Instructions

### Pattern 1: Singleton Client with Configuration

```typescript
// src/documenso/client.ts
import { Documenso } from "@documenso/sdk-typescript";

interface DocumensoConfig {
  apiKey: string;
  baseUrl?: string;
  timeout?: number;
}

let instance: Documenso | null = null;

export function getDocumensoClient(config?: DocumensoConfig): Documenso {
  if (!instance) {
    const apiKey = config?.apiKey ?? process.env.DOCUMENSO_API_KEY;
    if (!apiKey) throw new Error("DOCUMENSO_API_KEY is required");

    instance = new Documenso({
      apiKey,
      ...(config?.baseUrl && { serverURL: config.baseUrl }),
    });
  }
  return instance;
}

// Reset for testing
export function resetClient(): void {
  instance = null;
}
```

### Pattern 2: Typed Document Service

```typescript
// src/documenso/documents.ts
import { getDocumensoClient } from "./client";

export interface CreateDocumentInput {
  title: string;
  pdfPath: string;
  signers: Array<{
    email: string;
    name: string;
    fields: Array<{
      type: "SIGNATURE" | "INITIALS" | "NAME" | "EMAIL" | "DATE" | "TEXT";
      pageNumber: number;
      pageX: number;
      pageY: number;
      pageWidth?: number;
      pageHeight?: number;
    }>;
  }>;
}

export interface DocumentResult {
  documentId: number;
  recipientIds: number[];
  status: "DRAFT" | "PENDING" | "COMPLETED";
}

export async function createAndSendDocument(
  input: CreateDocumentInput
): Promise<DocumentResult> {
  const client = getDocumensoClient();
  const { readFileSync } = await import("fs");

  // Create document
  const doc = await client.documents.createV0({ title: input.title });

  // Upload PDF
  const pdfBuffer = readFileSync(input.pdfPath);
  await client.documents.setFileV0(doc.documentId, {
    file: new Blob([pdfBuffer], { type: "application/pdf" }),
  });

  // Add recipients and fields
  const recipientIds: number[] = [];
  for (const signer of input.signers) {
    const recipient = await client.documentsRecipients.createV0(doc.documentId, {
      email: signer.email,
      name: signer.name,
      role: "SIGNER",
    });
    recipientIds.push(recipient.recipientId);

    for (const field of signer.fields) {
      await client.documentsFields.createV0(doc.documentId, {
        recipientId: recipient.recipientId,
        type: field.type,
        pageNumber: field.pageNumber,
        pageX: field.pageX,
        pageY: field.pageY,
        pageWidth: field.pageWidth ?? 20,
        pageHeight: field.pageHeight ?? 5,
      });
    }
  }

  // Send
  await client.documents.sendV0(doc.documentId);

  return { documentId: doc.documentId, recipientIds, status: "PENDING" };
}
```

### Pattern 3: Error Handling Wrapper

```typescript
// src/documenso/errors.ts

export class DocumensoError extends Error {
  constructor(
    message: string,
    public statusCode?: number,
    public retryable: boolean = false
  ) {
    super(message);
    this.name = "DocumensoError";
  }
}

export async function withErrorHandling<T>(
  operation: string,
  fn: () => Promise<T>
): Promise<T> {
  try {
    return await fn();
  } catch (err: any) {
    const status = err.statusCode ?? err.status;
    switch (status) {
      case 401:
        throw new DocumensoError(`${operation}: Invalid API key`, 401, false);
      case 403:
        throw new DocumensoError(
          `${operation}: Insufficient permissions — use team API key`,
          403,
          false
        );
      case 404:
        throw new DocumensoError(`${operation}: Resource not found`, 404, false);
      case 429:
        throw new DocumensoError(`${operation}: Rate limited`, 429, true);
      case 500:
      case 502:
      case 503:
        throw new DocumensoError(
          `${operation}: Documenso server error`,
          status,
          true
        );
      default:
        throw new DocumensoError(
          `${operation}: ${err.message ?? "Unknown error"}`,
          status,
          false
        );
    }
  }
}
```

### Pattern 4: Retry with Exponential Backoff

```typescript
// src/documenso/retry.ts
import { DocumensoError } from "./errors";

interface RetryConfig {
  maxRetries: number;
  baseDelayMs: number;
  maxDelayMs: number;
}

const DEFAULT_RETRY: RetryConfig = {
  maxRetries: 3,
  baseDelayMs: 1000,
  maxDelayMs: 30000,
};

export async function withRetry<T>(
  fn: () => Promise<T>,
  config: Partial<RetryConfig> = {}
): Promise<T> {
  const { maxRetries, baseDelayMs, maxDelayMs } = { ...DEFAULT_RETRY, ...config };
  let lastError: Error | undefined;

  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    try {
      return await fn();
    } catch (err) {
      lastError = err as Error;
      if (err instanceof DocumensoError && !err.retryable) throw err;
      if (attempt === maxRetries) break;

      const delay = Math.min(baseDelayMs * 2 ** attempt, maxDelayMs);
      const jitter = delay * (0.5 + Math.random() * 0.5);
      await new Promise((r) => setTimeout(r, jitter));
    }
  }
  throw lastError;
}
```

### Pattern 5: Python Service Pattern

```python
# src/documenso/service.py
from documenso_sdk_python import Documenso
from dataclasses import dataclass
from typing import Optional
import os

@dataclass
class SignerInput:
    email: str
    name: str
    field_type: str = "SIGNATURE"
    page: int = 1
    x: float = 50.0
    y: float = 80.0

class DocumensoService:
    def __init__(self, api_key: Optional[str] = None, base_url: Optional[str] = None):
        self.client = Documenso(
            api_key=api_key or os.environ["DOCUMENSO_API_KEY"],
            **({"server_url": base_url} if base_url else {}),
        )

    def create_and_send(
        self, title: str, pdf_path: str, signers: list[SignerInput]
    ) -> dict:
        doc = self.client.documents.create_v0(title=title)

        with open(pdf_path, "rb") as f:
            self.client.documents.set_file_v0(doc.document_id, file=f.read())

        recipient_ids = []
        for signer in signers:
            recip = self.client.documents_recipients.create_v0(
                doc.document_id, email=signer.email, name=signer.name, role="SIGNER"
            )
            recipient_ids.append(recip.recipient_id)

            self.client.documents_fields.create_v0(
                doc.document_id,
                recipient_id=recip.recipient_id,
                type=signer.field_type,
                page_number=signer.page,
                page_x=signer.x,
                page_y=signer.y,
            )

        self.client.documents.send_v0(doc.document_id)
        return {"document_id": doc.document_id, "recipient_ids": recipient_ids}
```

### Pattern 6: Testing with Mocks

```typescript
// tests/mocks/documenso.ts
import { vi } from "vitest";

export function createMockClient() {
  return {
    documents: {
      createV0: vi.fn().mockResolvedValue({ documentId: 1 }),
      setFileV0: vi.fn().mockResolvedValue(undefined),
      findV0: vi.fn().mockResolvedValue({ documents: [] }),
      sendV0: vi.fn().mockResolvedValue(undefined),
      deleteV0: vi.fn().mockResolvedValue(undefined),
    },
    documentsRecipients: {
      createV0: vi.fn().mockResolvedValue({ recipientId: 100 }),
    },
    documentsFields: {
      createV0: vi.fn().mockResolvedValue({ fieldId: 200 }),
    },
  };
}
```

## Error Handling

| Pattern Issue | Cause | Solution |
|--------------|-------|----------|
| Client not initialized | Missing env var | Check `DOCUMENSO_API_KEY` is set |
| Singleton stale after key rotation | Cached client | Call `resetClient()` |
| Retry loop on 401 | Non-retryable treated as retryable | Check `retryable` flag |
| Type mismatch on field type | Wrong enum string | Use union type from SDK |

## Resources

- [TypeScript SDK Source](https://github.com/documenso/sdk-typescript)
- [Python SDK Source](https://github.com/documenso/sdk-python)
- [SDK Documents API](https://github.com/documenso/sdk-typescript/blob/main/docs/sdks/documents/README.md)
- [Zod for Validation](https://zod.dev/)

## Next Steps

Apply patterns in `documenso-core-workflow-a` for document creation workflows.

Related Skills

exa-sdk-patterns

25
from ComeOnOliver/skillshub

Apply production-ready exa-js SDK patterns with type safety, singletons, and wrappers. Use when implementing Exa integrations, refactoring SDK usage, or establishing team coding standards for Exa. Trigger with phrases like "exa SDK patterns", "exa best practices", "exa code patterns", "idiomatic exa", "exa wrapper".

exa-reliability-patterns

25
from ComeOnOliver/skillshub

Implement Exa reliability patterns: query fallback chains, circuit breakers, and graceful degradation. Use when building fault-tolerant Exa integrations, implementing fallback strategies, or adding resilience to production search services. Trigger with phrases like "exa reliability", "exa circuit breaker", "exa fallback", "exa resilience", "exa graceful degradation".

evernote-sdk-patterns

25
from ComeOnOliver/skillshub

Advanced Evernote SDK patterns and best practices. Use when implementing complex note operations, batch processing, search queries, or optimizing SDK usage. Trigger with phrases like "evernote sdk patterns", "evernote best practices", "evernote advanced", "evernote batch operations".

elevenlabs-sdk-patterns

25
from ComeOnOliver/skillshub

Apply production-ready ElevenLabs SDK patterns for TypeScript and Python. Use when implementing ElevenLabs integrations, refactoring SDK usage, or establishing team coding standards for audio AI applications. Trigger: "elevenlabs SDK patterns", "elevenlabs best practices", "elevenlabs code patterns", "idiomatic elevenlabs", "elevenlabs typescript".

documenso-webhooks-events

25
from ComeOnOliver/skillshub

Implement Documenso webhook configuration and event handling. Use when setting up webhook endpoints, handling document events, or implementing real-time notifications for document signing. Trigger with phrases like "documenso webhook", "documenso events", "document completed webhook", "signing notification".

documenso-upgrade-migration

25
from ComeOnOliver/skillshub

Manage Documenso API version upgrades and SDK migrations. Use when upgrading from v1 to v2 API, updating SDK versions, or migrating between Documenso versions. Trigger with phrases like "documenso upgrade", "documenso v2 migration", "update documenso SDK", "documenso API version".

documenso-security-basics

25
from ComeOnOliver/skillshub

Implement security best practices for Documenso document signing integrations. Use when securing API keys, configuring webhooks securely, or implementing document security measures. Trigger with phrases like "documenso security", "secure documenso", "documenso API key security", "documenso webhook security".

documenso-reference-architecture

25
from ComeOnOliver/skillshub

Implement Documenso reference architecture with best-practice project layout. Use when designing new Documenso integrations, reviewing project structure, or establishing architecture standards for document signing applications. Trigger with phrases like "documenso architecture", "documenso best practices", "documenso project structure", "how to organize documenso".

documenso-rate-limits

25
from ComeOnOliver/skillshub

Implement Documenso rate limiting, backoff, and request throttling patterns. Use when handling rate limit errors, implementing retry logic, or optimizing API request throughput for Documenso. Trigger with phrases like "documenso rate limit", "documenso throttling", "documenso 429", "documenso retry", "documenso backoff".

documenso-prod-checklist

25
from ComeOnOliver/skillshub

Execute Documenso production deployment checklist and rollback procedures. Use when deploying Documenso integrations to production, preparing for launch, or implementing go-live procedures. Trigger with phrases like "documenso production", "deploy documenso", "documenso go-live", "documenso launch checklist".

documenso-performance-tuning

25
from ComeOnOliver/skillshub

Optimize Documenso integration performance with caching, batching, and efficient patterns. Use when improving response times, reducing API calls, or optimizing bulk document operations. Trigger with phrases like "documenso performance", "optimize documenso", "documenso caching", "documenso batch operations".

documenso-observability

25
from ComeOnOliver/skillshub

Implement monitoring, logging, and tracing for Documenso integrations. Use when setting up observability, implementing metrics collection, or debugging production issues. Trigger with phrases like "documenso monitoring", "documenso metrics", "documenso logging", "documenso tracing", "documenso observability".