Skip to content

Latest commit

 

History

History
266 lines (235 loc) · 12 KB

File metadata and controls

266 lines (235 loc) · 12 KB

Documenso Zapier Integration - Implementation Plan

Overview

Build a code-based Zapier integration for Documenso using @documenso/sdk-typescript, mirroring the same resources, operations, and patterns as the existing n8n integration (/Users/lucas/dev/documenso/n8n).

Project Structure

zapier/
├── biome.json
├── package.json
├── tsconfig.json
├── src/
│   ├── index.ts                          # App entry (defineApp)
│   ├── authentication.ts                 # Custom auth (API key + base URL)
│   ├── lib/
│   │   └── client.ts                     # SDK client factory + error handling
│   ├── triggers/
│   │   └── documentEvent.ts              # Webhook trigger (REST hook)
│   ├── creates/
│   │   ├── document/
│   │   │   ├── createDocument.ts
│   │   │   ├── createAndSendDocument.ts
│   │   │   ├── updateDocument.ts
│   │   │   ├── deleteDocument.ts
│   │   │   ├── duplicateDocument.ts
│   │   │   ├── sendDocument.ts
│   │   │   └── resendDocument.ts
│   │   ├── template/
│   │   │   ├── createTemplate.ts
│   │   │   ├── updateTemplate.ts
│   │   │   ├── deleteTemplate.ts
│   │   │   ├── duplicateTemplate.ts
│   │   │   └── useTemplate.ts
│   │   ├── recipient/
│   │   │   ├── createRecipient.ts
│   │   │   ├── updateRecipient.ts
│   │   │   └── deleteRecipient.ts
│   │   ├── field/
│   │   │   ├── createField.ts
│   │   │   ├── updateField.ts
│   │   │   └── deleteField.ts
│   │   ├── folder/
│   │   │   ├── createFolder.ts
│   │   │   ├── updateFolder.ts
│   │   │   └── deleteFolder.ts
│   │   └── attachment/
│   │       ├── createAttachment.ts
│   │       ├── updateAttachment.ts
│   │       └── deleteAttachment.ts
│   └── searches/
│       ├── document/
│       │   ├── findDocument.ts
│       │   └── getDocument.ts
│       ├── template/
│       │   ├── findTemplate.ts
│       │   └── getTemplate.ts
│       ├── recipient/
│       │   └── getRecipient.ts
│       ├── field/
│       │   └── getField.ts
│       ├── folder/
│       │   └── findFolder.ts
│       └── attachment/
│           └── findAttachment.ts
│   └── test/
│       └── authentication.test.ts

Zapier Concepts Mapping

In Zapier, there are three action types:

  • Triggers - watch for new data (polling or webhook-based)
  • Creates - create/modify/delete data in the app
  • Searches - find existing data in the app

Mapping n8n operations → Zapier action types:

n8n Resource n8n Operation Zapier Type Zapier Key
Document find Search document_find
Document get Search document_get
Document create Create document_create
Document createAndSend Create document_create_and_send
Document update Create document_update
Document delete Create document_delete
Document duplicate Create document_duplicate
Document send Create document_send
Document resend Create document_resend
Document download -- Skip for now (binary)
Template find Search template_find
Template get Search template_get
Template create Create template_create
Template update Create template_update
Template delete Create template_delete
Template duplicate Create template_duplicate
Template use Create template_use
Recipient create Create recipient_create
Recipient get Search recipient_get
Recipient update Create recipient_update
Recipient delete Create recipient_delete
Field create Create field_create
Field get Search field_get
Field update Create field_update
Field delete Create field_delete
Folder find Search folder_find
Folder create Create folder_create
Folder update Create folder_update
Folder delete Create folder_delete
Attachment find Search attachment_find
Attachment create Create attachment_create
Attachment update Create attachment_update
Attachment delete Create attachment_delete
Trigger webhook Trigger document_event

Note: File upload/download operations are skipped initially since Zapier handles binary data differently (via z.dehydrateFile / z.stashFile). These can be added later.

Implementation Details

1. Authentication (src/authentication.ts)

  • Type: custom
  • Fields:
    • apiKey (string, required) - Documenso API key
    • baseUrl (string, optional, default: https://app.documenso.com/api/v2) - for self-hosted
  • Test: Use client.envelope.envelopeFind({ page: 1, perPage: 1, type: "DOCUMENT" }) to verify credentials
  • Connection label: Show the base URL to distinguish accounts

2. SDK Client Factory (src/lib/client.ts)

Mirror the n8n GenericFunctions.ts pattern:

import { Documenso } from "@documenso/sdk-typescript";

export function getDocumensoClient(apiKey: string, baseUrl?: string): Documenso {
  return new Documenso({
    apiKey,
    serverURL: baseUrl || "https://app.documenso.com/api/v2",
  });
}

Error handling helper that converts SDK errors into Zapier-friendly errors.

3. Trigger (src/triggers/documentEvent.ts)

  • Type: REST Hook (webhook-based)
  • Events: DOCUMENT_CREATED, DOCUMENT_SENT, DOCUMENT_OPENED, DOCUMENT_SIGNED, DOCUMENT_COMPLETED, DOCUMENT_REJECTED, DOCUMENT_CANCELLED
  • Zapier REST hooks use subscribeHook / unsubscribeHook for auto-registration (unlike the n8n manual approach)
  • Since Documenso doesn't have a webhook management API, this will be a polling trigger or a static webhook (user provides webhook URL manually)
  • Decision: Use static webhook (type: "hook" with performSubscribe/performUnsubscribe as no-ops, and instructions for users to set up the webhook URL in Documenso)

4. Creates

Each create follows this pattern:

import { defineCreate } from "zapier-platform-core";

export default defineCreate({
  key: "document_create",
  noun: "Document",
  display: {
    label: "Create Document",
    description: "Creates a new document in Documenso.",
  },
  operation: {
    inputFields: [...],
    perform: async (z, bundle) => {
      const client = getDocumensoClient(bundle.authData.apiKey, bundle.authData.baseUrl);
      // SDK call
    },
    sample: { ... },
  },
});

5. Searches

Each search follows this pattern:

import { defineSearch } from "zapier-platform-core";

export default defineSearch({
  key: "document_find",
  noun: "Document",
  display: {
    label: "Find Document",
    description: "Finds a document in Documenso.",
  },
  operation: {
    inputFields: [...],
    perform: async (z, bundle) => {
      const client = getDocumensoClient(bundle.authData.apiKey, bundle.authData.baseUrl);
      // SDK call
    },
    sample: { ... },
  },
});

6. SDK Method Reference (from n8n integration)

Operation SDK Method
Envelope Find client.envelope.envelopeFind({ type, page, perPage })
Envelope Get client.envelopes.get({ envelopeId })
Envelope Create client.envelopes.create({ payload, files })
Envelope Update client.envelopes.update({ envelopeId, data })
Envelope Delete client.envelopes.delete({ envelopeId })
Envelope Duplicate client.envelopes.duplicate({ envelopeId })
Envelope Distribute client.envelopes.distribute({ envelopeId, ...meta })
Envelope Redistribute client.envelopes.redistribute({ envelopeId, recipients })
Envelope Use client.envelopes.use({ payload })
Recipients Create client.envelopes.recipients.createMany({ envelopeId, data })
Recipients Get client.envelopes.recipients.get({ recipientId })
Recipients Update client.envelopes.recipients.updateMany({ envelopeId, data })
Recipients Delete client.envelopes.recipients.delete({ recipientId })
Fields Create client.envelopes.fields.createMany({ envelopeId, data })
Fields Get client.envelopes.fields.get({ fieldId })
Fields Update client.envelopes.fields.updateMany({ envelopeId, data })
Fields Delete client.envelopes.fields.delete({ fieldId })
Folders Find client.folders.find({ page, perPage, query })
Folders Create client.folders.create({ name, parentId })
Folders Update client.folders.update({ folderId, data })
Folders Delete client.folders.delete({ folderId })
Attachments Find client.envelopes.attachments.find({ envelopeId })
Attachments Create client.envelopes.attachments.create({ envelopeId, data })
Attachments Update client.envelopes.attachments.update({ id, data })
Attachments Delete client.envelopes.attachments.delete({ id })

7. Biome Configuration

Copy the same biome config as the n8n integration:

  • Biome schema 2.3.14
  • 2-space indent, double quotes
  • Recommended rules + noExplicitAny: off, useBlockStatements: error
  • Auto import organization
  • Exclude dist/

Implementation Order

  1. Setup: biome.json, update package.json (name, scripts), update tsconfig.json
  2. Core: src/lib/client.ts (SDK factory + error handling)
  3. Auth: src/authentication.ts (API key + base URL + test)
  4. Trigger: src/triggers/documentEvent.ts (webhook trigger)
  5. Document creates: create, createAndSend, update, delete, duplicate, send, resend
  6. Document searches: find, get
  7. Template creates: create, update, delete, duplicate, use
  8. Template searches: find, get
  9. Recipient: create, update, delete (creates) + get (search)
  10. Field: create, update, delete (creates) + get (search)
  11. Folder: create, update, delete (creates) + find (search)
  12. Attachment: create, update, delete (creates) + find (search)
  13. Index: Wire everything into src/index.ts
  14. Lint/format: Run biome check
  15. Build: Verify tsc compiles cleanly