@xenterprises/fastify-xsignwell
v1.3.0
Published
Fastify plugin for SignWell document signing API integration
Readme
@xenterprises/fastify-xsignwell
Fastify plugin for the SignWell e-signature API. It gives consuming
applications a single fastify.xSignwell namespace for document creation and sending, template
management, bulk sends, webhook registration/signature verification, and embedded signing — with
fail-fast option validation and structured API errors.
Install
npm install @xenterprises/fastify-xsignwell fastify@5Minimal example
import Fastify from "fastify";
import xSignwell from "@xenterprises/fastify-xsignwell";
const fastify = Fastify();
await fastify.register(xSignwell, {
apiKey: process.env.SIGNWELL_API_KEY, // the consumer owns env access
});
const doc = await fastify.xSignwell.documents.create({
name: "Employment Agreement",
recipients: [{ email: "[email protected]", name: "John Doe" }],
files: [{ name: "agreement.pdf", url: "https://example.com/agreement.pdf" }],
});The plugin never reads process.env itself — pass configuration in via the options object
(e.g. testMode: process.env.NODE_ENV !== "production" in your own app code).
Options
| Name | Type | Default | Required | Description |
|------|------|---------|----------|-------------|
| apiKey | string | — | Yes | SignWell API key (non-empty string) |
| baseUrl | string | https://www.signwell.com/api/v1 | No | API base URL override |
| testMode | boolean | false | No | Send test_mode: true on document/bulk-send creation (SignWell won't deliver signing emails) |
| active | boolean | true | No | Set false to disable the plugin entirely (no decorator is added) |
Registration throws immediately on a missing/invalid apiKey or a wrong-typed option — see
Error behavior.
Decorators
The plugin adds a single decorator namespace: fastify.xSignwell. It adds no routes and no
request decorators.
| Decorator | Description |
|-----------|-------------|
| fastify.xSignwell.config | Resolved plugin configuration (apiKey, baseUrl, testMode) |
| fastify.xSignwell.documents | Document management methods (below) |
| fastify.xSignwell.templates | Template management methods (below) |
| fastify.xSignwell.bulkSend | Bulk send methods (below) |
| fastify.xSignwell.webhooks | Webhook management + signature verification (below) |
| fastify.xSignwell.me() | Promise<Object> — get current SignWell account info |
documents
| Method | Description |
|--------|-------------|
| create(params) | Create a document for signing. params: name (required), recipients (required, each needs email), files, draft, subject, message, metadata, testMode |
| createFromTemplate(templateId, params) | Create a document from a template. params.recipients required |
| get(documentId) | Get document details by ID |
| list(params?) | List documents ({ page, limit }) |
| send(documentId, params?) | Send a draft document |
| remind(documentId) | Send a reminder to unsigned recipients |
| remove(documentId) / delete(documentId) | Delete a document |
| getCompletedPdf(documentId) | Get download URL for the completed PDF |
| getEmbeddedSigningUrl(documentId, recipientId) | Get the embedded signing URL for a recipient |
| getAuditTrail(documentId) | Get the document audit trail |
templates
| Method | Description |
|--------|-------------|
| get(templateId) | Get template by ID |
| create(params) | Create a template. params.name required; optional files, recipients, fields, subject, message |
| update(templateId, params) | Update an existing template |
| remove(templateId) / delete(templateId) | Delete a template |
| list(params?) | List templates ({ page, limit }) |
| getFields(templateId) | Get template field definitions ([] when none) |
| getRecipients(templateId) | Get template recipient placeholders ([] when none) |
bulkSend
| Method | Description |
|--------|-------------|
| get(bulkSendId) | Get bulk send by ID |
| list(params?) | List bulk sends ({ page, limit }) |
| create(params) | Create a bulk send. params.templateId and params.recipients (non-empty) required |
| getCsvTemplate(templateId) | Get the CSV template for bulk upload |
| validateCsv(templateId, csvContent) | Validate CSV content before sending |
| getDocuments(bulkSendId, params?) | Get documents produced by a bulk send |
webhooks
| Method | Description |
|--------|-------------|
| list() | List registered webhooks |
| create(params) | Register a webhook. params.callbackUrl required; optional event |
| remove(webhookId) / delete(webhookId) | Delete a webhook |
| events | Event type constants (below) |
| verifySignature(payload, signature, secret) | Verify a webhook HMAC-SHA256 signature (boolean) |
| parseEvent(payload) | Parse a webhook payload into { event, documentId, document, recipient, timestamp, raw } |
Webhook event constants
fastify.xSignwell.webhooks.events.DOCUMENT_COMPLETED // "document.completed"
fastify.xSignwell.webhooks.events.DOCUMENT_SENT // "document.sent"
fastify.xSignwell.webhooks.events.DOCUMENT_VIEWED // "document.viewed"
fastify.xSignwell.webhooks.events.DOCUMENT_SIGNED // "document.signed"
fastify.xSignwell.webhooks.events.DOCUMENT_DECLINED // "document.declined"
fastify.xSignwell.webhooks.events.DOCUMENT_EXPIRED // "document.expired"
fastify.xSignwell.webhooks.events.DOCUMENT_VOIDED // "document.voided"
fastify.xSignwell.webhooks.events.RECIPIENT_COMPLETED // "recipient.completed"
fastify.xSignwell.webhooks.events.RECIPIENT_VIEWED // "recipient.viewed"
fastify.xSignwell.webhooks.events.RECIPIENT_SIGNED // "recipient.signed"
fastify.xSignwell.webhooks.events.RECIPIENT_DECLINED // "recipient.declined"Routes
None. The plugin only decorates the Fastify instance; handling inbound SignWell webhooks is the
consumer's responsibility (use webhooks.verifySignature + webhooks.parseEvent in your own
route).
Error behavior
Registration fails fast with a descriptive Error:
| Error | When |
|-------|------|
| xsignwell: missing required option \apiKey` (string), e.g. `app.register(xSignwell, { apiKey: 'sw_...' })`| NoapiKeypassed |
|xsignwell: option `apiKey` must be a non-empty string, e.g. ...|apiKeynot a non-empty string |
|xsignwell: option `baseUrl` must be a string, e.g. ...|baseUrlwrong type |
|xsignwell: option `testMode` must be a boolean, e.g. ...|testModewrong type |
|xsignwell: option `active` must be a boolean, e.g. ...|active` wrong type |
Method calls throw [xSignwell] <service>.<method>: <param> is required style errors on
missing/invalid arguments, before any network call.
API errors: a non-2xx SignWell response throws an Error with the API's message plus two
extra properties for programmatic handling:
try {
await fastify.xSignwell.documents.get("bad_id");
} catch (err) {
err.statusCode; // 404
err.signwellError; // { message: "Document not found", ... }
}Network failures throw [xSignwell] Network error calling <endpoint>: <message>.
Requirements
- Node.js >= 20
- Fastify >= 5 (peer dependency)
Testing
npm test # node --test, fully offline (SignWell API mocked via fetch stub)
npm run lint # biome check src/ test/License
Proprietary — All Rights Reserved, X Enterprises. See LICENSE.
