@xenterprises/fastify-xsignwell 1.1.1 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,60 @@
1
+ PROPRIETARY SOFTWARE LICENSE
2
+
3
+ Copyright (c) 2024-2026 X Enterprises LLC. All Rights Reserved.
4
+
5
+ This software and associated documentation files (the "Software") are the
6
+ exclusive property of X Enterprises LLC, a Washington limited liability
7
+ company.
8
+
9
+ TERMS AND CONDITIONS
10
+
11
+ 1. OWNERSHIP
12
+ All rights, title, and interest in and to the Software, including all
13
+ intellectual property rights, are and shall remain the exclusive property
14
+ of X Enterprises LLC.
15
+
16
+ 2. RESTRICTIONS
17
+ Without the prior written consent of X Enterprises LLC, you may not:
18
+ - Copy, modify, or distribute the Software
19
+ - Reverse engineer, decompile, or disassemble the Software
20
+ - Sublicense, sell, lease, or otherwise transfer the Software
21
+ - Remove or alter any proprietary notices or labels
22
+
23
+ 3. AUTHORIZED USE
24
+ Use of this Software is limited to authorized employees, contractors, and
25
+ agents of X Enterprises LLC, solely for purposes approved by X Enterprises
26
+ LLC.
27
+
28
+ 4. NO WARRANTY
29
+ THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
31
+ FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT. IN NO EVENT SHALL
32
+ X ENTERPRISES LLC BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY,
33
+ WHETHER IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT OF,
34
+ OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
35
+ SOFTWARE.
36
+
37
+ 5. LIMITATION OF LIABILITY
38
+ IN NO EVENT SHALL X ENTERPRISES LLC BE LIABLE FOR ANY INDIRECT, INCIDENTAL,
39
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
40
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
41
+ OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
42
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
43
+ OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
44
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
45
+
46
+ 6. GOVERNING LAW
47
+ This license shall be governed by and construed in accordance with the laws
48
+ of the State of Washington, United States, without regard to its conflict
49
+ of law provisions.
50
+
51
+ 7. TERMINATION
52
+ This license is effective until terminated. X Enterprises LLC may terminate
53
+ this license at any time without notice. Upon termination, you must destroy
54
+ all copies of the Software in your possession.
55
+
56
+ For licensing inquiries, contact: legal@x.enterprises
57
+
58
+ ---
59
+ X Enterprises LLC
60
+ Bothell, Washington, United States
package/README.md CHANGED
@@ -1,333 +1,166 @@
1
- # xSignwell
1
+ # @xenterprises/fastify-xsignwell
2
2
 
3
- A Fastify plugin for integrating with SignWell's e-signature API. Provides document creation, template management, bulk sending, and webhook handling.
3
+ Fastify plugin for [SignWell](https://www.signwell.com/) e-signature API integration document creation, templates, bulk sending, webhooks, and embedded signing.
4
4
 
5
- ## Features
6
-
7
- - **Document Management**: Create, send, and track documents for signing
8
- - **Template Support**: Create and manage reusable document templates
9
- - **Embedded Signing**: Get URLs for embedded signing experiences
10
- - **Bulk Send**: Send documents to multiple recipients at once
11
- - **Webhooks**: Register and manage webhook callbacks for document events
12
- - **Test Mode**: Built-in support for SignWell's test mode
13
-
14
- ## Installation
5
+ ## Install
15
6
 
16
7
  ```bash
17
- npm install xsignwell
8
+ npm install @xenterprises/fastify-xsignwell
18
9
  ```
19
10
 
20
- ## Configuration
21
-
22
- ### Environment Variables
23
-
24
- | Variable | Description | Required |
25
- |----------|-------------|----------|
26
- | `SIGNWELL_API_KEY` | SignWell API key | Yes |
27
- | `SIGNWELL_TEST_MODE` | Enable test mode | No |
28
-
29
- ### Plugin Registration
11
+ ## Quick Start
30
12
 
31
13
  ```javascript
32
- import Fastify from 'fastify';
33
- import xSignwell from 'xsignwell';
14
+ import Fastify from "fastify";
15
+ import xSignwell from "@xenterprises/fastify-xsignwell";
34
16
 
35
17
  const fastify = Fastify();
36
18
 
37
19
  await fastify.register(xSignwell, {
38
20
  apiKey: process.env.SIGNWELL_API_KEY,
39
- testMode: process.env.NODE_ENV !== 'production',
40
- });
41
- ```
42
-
43
- ## Usage
44
-
45
- ### Documents
46
-
47
- #### Create a Document
48
-
49
- ```javascript
50
- const document = await fastify.xsignwell.documents.create({
51
- name: 'Employment Agreement',
52
- recipients: [
53
- {
54
- id: 'signer_1',
55
- name: 'John Doe',
56
- email: 'john@example.com',
57
- },
58
- ],
59
- files: [
60
- {
61
- name: 'agreement.pdf',
62
- url: 'https://example.com/agreement.pdf',
63
- // OR use base64:
64
- // base64: 'JVBERi0xLjQK...',
65
- },
66
- ],
67
- subject: 'Please sign your employment agreement',
68
- message: 'Hi John, please review and sign the attached agreement.',
69
- });
70
- ```
71
-
72
- #### Create from Template
73
-
74
- ```javascript
75
- const document = await fastify.xsignwell.documents.createFromTemplate(
76
- 'template_id_here',
77
- {
78
- recipients: [
79
- {
80
- id: 'signer_1', // Must match template recipient ID
81
- name: 'John Doe',
82
- email: 'john@example.com',
83
- },
84
- ],
85
- fields: {
86
- employee_name: 'John Doe',
87
- start_date: '2025-02-01',
88
- salary: '$75,000',
89
- },
90
- }
91
- );
92
- ```
93
-
94
- #### Get Document Status
95
-
96
- ```javascript
97
- const document = await fastify.xsignwell.documents.get('document_id');
98
- console.log(document.status); // 'pending', 'completed', etc.
99
- ```
100
-
101
- #### Send a Document
102
-
103
- ```javascript
104
- await fastify.xsignwell.documents.send('document_id');
105
- ```
106
-
107
- #### Send Reminder
108
-
109
- ```javascript
110
- await fastify.xsignwell.documents.remind('document_id');
111
- ```
112
-
113
- #### Get Completed PDF
114
-
115
- ```javascript
116
- const pdf = await fastify.xsignwell.documents.getCompletedPdf('document_id');
117
- // pdf.file_url contains the download URL
118
- ```
119
-
120
- #### Get Embedded Signing URL
121
-
122
- ```javascript
123
- const { url, recipient } = await fastify.xsignwell.documents.getEmbeddedSigningUrl(
124
- 'document_id',
125
- 'recipient_id'
126
- );
127
- // Redirect user to `url` for signing
128
- ```
129
-
130
- #### Delete Document
131
-
132
- ```javascript
133
- await fastify.xsignwell.documents.remove('document_id');
134
- ```
135
-
136
- ### Templates
137
-
138
- #### Get Template
139
-
140
- ```javascript
141
- const template = await fastify.xsignwell.templates.get('template_id');
142
- ```
143
-
144
- #### List Templates
145
-
146
- ```javascript
147
- const templates = await fastify.xsignwell.templates.list({
148
- page: 1,
149
- limit: 20,
150
- });
151
- ```
152
-
153
- #### Create Template
154
-
155
- ```javascript
156
- const template = await fastify.xsignwell.templates.create({
157
- name: 'NDA Template',
158
- files: [
159
- {
160
- name: 'nda.pdf',
161
- url: 'https://example.com/nda.pdf',
162
- },
163
- ],
164
- recipients: [
165
- { id: 'signer_1', name: 'Signer' },
166
- { id: 'signer_2', name: 'Counter-Signer' },
167
- ],
168
- });
169
- ```
170
-
171
- #### Update Template
172
-
173
- ```javascript
174
- await fastify.xsignwell.templates.update('template_id', {
175
- name: 'Updated NDA Template',
176
- subject: 'New subject line',
177
- });
178
- ```
179
-
180
- #### Delete Template
181
-
182
- ```javascript
183
- await fastify.xsignwell.templates.remove('template_id');
184
- ```
185
-
186
- #### Get Template Fields
187
-
188
- ```javascript
189
- const fields = await fastify.xsignwell.templates.getFields('template_id');
190
- ```
191
-
192
- ### Bulk Send
193
-
194
- #### Create Bulk Send
195
-
196
- ```javascript
197
- const bulkSend = await fastify.xsignwell.bulkSend.create({
198
- templateId: 'template_id',
199
- recipients: [
200
- {
201
- email: 'john@example.com',
202
- name: 'John Doe',
203
- // Field values for this recipient
204
- employee_name: 'John Doe',
205
- start_date: '2025-02-01',
206
- },
207
- {
208
- email: 'jane@example.com',
209
- name: 'Jane Smith',
210
- employee_name: 'Jane Smith',
211
- start_date: '2025-02-15',
212
- },
213
- ],
214
- });
215
- ```
216
-
217
- #### List Bulk Sends
218
-
219
- ```javascript
220
- const bulkSends = await fastify.xsignwell.bulkSend.list();
221
- ```
222
-
223
- #### Get Bulk Send Documents
224
-
225
- ```javascript
226
- const documents = await fastify.xsignwell.bulkSend.getDocuments('bulk_send_id');
227
- ```
228
-
229
- #### Get CSV Template
230
-
231
- ```javascript
232
- const csvTemplate = await fastify.xsignwell.bulkSend.getCsvTemplate('template_id');
233
- ```
234
-
235
- ### Webhooks
236
-
237
- #### List Webhooks
238
-
239
- ```javascript
240
- const webhooks = await fastify.xsignwell.webhooks.list();
241
- ```
242
-
243
- #### Create Webhook
244
-
245
- ```javascript
246
- const webhook = await fastify.xsignwell.webhooks.create({
247
- callbackUrl: 'https://your-api.com/webhooks/signwell',
248
- event: 'document.completed', // Optional: subscribe to specific event
21
+ testMode: process.env.NODE_ENV !== "production",
249
22
  });
250
- ```
251
-
252
- #### Delete Webhook
253
23
 
254
- ```javascript
255
- await fastify.xsignwell.webhooks.remove('webhook_id');
256
- ```
257
-
258
- #### Handle Webhook Events
259
-
260
- ```javascript
261
- fastify.post('/webhooks/signwell', async (request, reply) => {
262
- const event = fastify.xsignwell.webhooks.parseEvent(request.body);
263
-
264
- switch (event.event) {
265
- case 'document.completed':
266
- console.log(`Document ${event.documentId} completed`);
267
- // Download the completed PDF
268
- const pdf = await fastify.xsignwell.documents.getCompletedPdf(event.documentId);
269
- break;
270
-
271
- case 'document.signed':
272
- console.log(`Document ${event.documentId} signed by ${event.recipient?.email}`);
273
- break;
274
-
275
- case 'document.declined':
276
- console.log(`Document ${event.documentId} was declined`);
277
- break;
278
- }
279
-
280
- return { received: true };
24
+ // Create and send a document
25
+ const doc = await fastify.xsignwell.documents.create({
26
+ name: "Employment Agreement",
27
+ recipients: [{ email: "john@example.com", name: "John Doe" }],
28
+ files: [{ name: "agreement.pdf", url: "https://example.com/agreement.pdf" }],
281
29
  });
282
30
  ```
283
31
 
284
- #### Webhook Event Types
285
-
286
- ```javascript
287
- const events = fastify.xsignwell.webhooks.events;
288
- // {
289
- // DOCUMENT_COMPLETED: 'document.completed',
290
- // DOCUMENT_SENT: 'document.sent',
291
- // DOCUMENT_VIEWED: 'document.viewed',
292
- // DOCUMENT_SIGNED: 'document.signed',
293
- // DOCUMENT_DECLINED: 'document.declined',
294
- // DOCUMENT_EXPIRED: 'document.expired',
295
- // DOCUMENT_VOIDED: 'document.voided',
296
- // RECIPIENT_COMPLETED: 'recipient.completed',
297
- // RECIPIENT_VIEWED: 'recipient.viewed',
298
- // RECIPIENT_SIGNED: 'recipient.signed',
299
- // RECIPIENT_DECLINED: 'recipient.declined',
300
- // }
301
- ```
302
-
303
- ### Account Info
32
+ ## Options
304
33
 
305
- ```javascript
306
- const account = await fastify.xsignwell.me();
307
- console.log(account.email);
308
- ```
34
+ | Name | Type | Default | Required | Description |
35
+ |------|------|---------|----------|-------------|
36
+ | `apiKey` | `string` | — | Yes | SignWell API key |
37
+ | `baseUrl` | `string` | `https://www.signwell.com/api/v1` | No | API base URL |
38
+ | `testMode` | `boolean` | `false` | No | Enable test mode (documents won't actually send) |
39
+ | `active` | `boolean` | `true` | No | Set `false` to disable the plugin entirely |
309
40
 
310
- ## API Reference
41
+ ## Environment Variables
311
42
 
312
- ### Decorators
43
+ | Name | Required | Description |
44
+ |------|----------|-------------|
45
+ | `SIGNWELL_API_KEY` | Yes | SignWell API key |
46
+ | `SIGNWELL_TEST_MODE` | No | Set `"true"` to enable test mode |
313
47
 
314
- After registration, the following decorators are available on the Fastify instance:
48
+ ## Decorated Properties
315
49
 
316
50
  | Decorator | Description |
317
51
  |-----------|-------------|
52
+ | `fastify.xsignwell.config` | Plugin configuration object |
318
53
  | `fastify.xsignwell.documents` | Document management methods |
319
54
  | `fastify.xsignwell.templates` | Template management methods |
320
55
  | `fastify.xsignwell.bulkSend` | Bulk send methods |
321
56
  | `fastify.xsignwell.webhooks` | Webhook management methods |
322
- | `fastify.xsignwell.me` | Get account info |
323
- | `fastify.xsignwell.config` | Plugin configuration |
324
-
325
- ### Rate Limits
326
-
327
- SignWell API has the following rate limits:
328
- - Standard requests: 100 requests per 60 seconds
329
- - Document creation: 30 requests per minute
330
- - Test mode: 20 requests per minute
57
+ | `fastify.xsignwell.me()` | Get current account info |
58
+
59
+ ### `documents`
60
+
61
+ | Method | Description |
62
+ |--------|-------------|
63
+ | `create(params)` | Create a new document for signing |
64
+ | `createFromTemplate(templateId, params)` | Create a document from a template |
65
+ | `get(documentId)` | Get document details by ID |
66
+ | `list(params?)` | List documents (page, limit) |
67
+ | `send(documentId, params?)` | Send a draft document |
68
+ | `remind(documentId)` | Send reminder to unsigned recipients |
69
+ | `remove(documentId)` | Delete a document |
70
+ | `getCompletedPdf(documentId)` | Get download URL for completed PDF |
71
+ | `getEmbeddedSigningUrl(documentId, recipientId)` | Get embedded signing URL |
72
+ | `getAuditTrail(documentId)` | Get document audit trail |
73
+
74
+ ### `templates`
75
+
76
+ | Method | Description |
77
+ |--------|-------------|
78
+ | `get(templateId)` | Get template by ID |
79
+ | `create(params)` | Create a new template |
80
+ | `update(templateId, params)` | Update an existing template |
81
+ | `remove(templateId)` | Delete a template |
82
+ | `list(params?)` | List all templates (page, limit) |
83
+ | `getFields(templateId)` | Get template field definitions |
84
+ | `getRecipients(templateId)` | Get template recipient placeholders |
85
+
86
+ ### `bulkSend`
87
+
88
+ | Method | Description |
89
+ |--------|-------------|
90
+ | `get(bulkSendId)` | Get bulk send by ID |
91
+ | `list(params?)` | List all bulk sends (page, limit) |
92
+ | `create(params)` | Create a bulk send from a template |
93
+ | `getCsvTemplate(templateId)` | Get CSV template for bulk upload |
94
+ | `validateCsv(templateId, csvContent)` | Validate CSV before sending |
95
+ | `getDocuments(bulkSendId, params?)` | Get documents from a bulk send |
96
+
97
+ ### `webhooks`
98
+
99
+ | Method | Description |
100
+ |--------|-------------|
101
+ | `list()` | List all webhooks |
102
+ | `create(params)` | Create a new webhook |
103
+ | `remove(webhookId)` | Delete a webhook |
104
+ | `events` | Event type constants (see below) |
105
+ | `verifySignature(payload, signature, secret)` | Verify webhook HMAC-SHA256 signature |
106
+ | `parseEvent(payload)` | Parse webhook payload into structured event |
107
+
108
+ #### Webhook Event Constants
109
+
110
+ ```javascript
111
+ fastify.xsignwell.webhooks.events.DOCUMENT_COMPLETED // "document.completed"
112
+ fastify.xsignwell.webhooks.events.DOCUMENT_SENT // "document.sent"
113
+ fastify.xsignwell.webhooks.events.DOCUMENT_VIEWED // "document.viewed"
114
+ fastify.xsignwell.webhooks.events.DOCUMENT_SIGNED // "document.signed"
115
+ fastify.xsignwell.webhooks.events.DOCUMENT_DECLINED // "document.declined"
116
+ fastify.xsignwell.webhooks.events.DOCUMENT_EXPIRED // "document.expired"
117
+ fastify.xsignwell.webhooks.events.DOCUMENT_VOIDED // "document.voided"
118
+ fastify.xsignwell.webhooks.events.RECIPIENT_COMPLETED // "recipient.completed"
119
+ fastify.xsignwell.webhooks.events.RECIPIENT_VIEWED // "recipient.viewed"
120
+ fastify.xsignwell.webhooks.events.RECIPIENT_SIGNED // "recipient.signed"
121
+ fastify.xsignwell.webhooks.events.RECIPIENT_DECLINED // "recipient.declined"
122
+ ```
123
+
124
+ ## Error Reference
125
+
126
+ All errors thrown by the plugin are prefixed with `[xSignwell]`.
127
+
128
+ | Error | When |
129
+ |-------|------|
130
+ | `[xSignwell] apiKey is required` | Plugin registered without `apiKey` option |
131
+ | `[xSignwell] apiKey must be a string` | `apiKey` is not a string |
132
+ | `[xSignwell] baseUrl must be a string` | `baseUrl` is not a string |
133
+ | `[xSignwell] testMode must be a boolean` | `testMode` is not a boolean |
134
+ | `[xSignwell] documents.create: name (string) is required` | `create()` called without `name` |
135
+ | `[xSignwell] documents.create: recipients (non-empty array) is required` | `create()` missing recipients |
136
+ | `[xSignwell] documents.create: each recipient must have an email` | Recipient without email field |
137
+ | `[xSignwell] <service>.<method>: <param> is required` | Any method called with missing required param |
138
+ | `[xSignwell] Recipient <id> not found in document <id>` | `getEmbeddedSigningUrl` can't find recipient |
139
+ | `[xSignwell] API error: <status>` | SignWell API returned a non-2xx response |
140
+ | `[xSignwell] Network error calling <endpoint>: <message>` | Network/connection failure |
141
+
142
+ API errors include `statusCode` and `signwellError` properties on the Error object for programmatic handling:
143
+
144
+ ```javascript
145
+ try {
146
+ await fastify.xsignwell.documents.get("bad_id");
147
+ } catch (err) {
148
+ console.log(err.statusCode); // 404
149
+ console.log(err.signwellError); // { message: "Document not found" }
150
+ }
151
+ ```
152
+
153
+ ## How It Works
154
+
155
+ The plugin registers a single `xsignwell` decorator on the Fastify instance. On startup it validates options (apiKey type, baseUrl type, testMode type) and builds a config object. Four service modules (documents, templates, webhooks, bulkSend) attach their methods to sub-objects on the decorator.
156
+
157
+ All API calls go through a shared `apiRequest` helper that:
158
+ 1. Adds the `X-Api-Key` header from config
159
+ 2. Parses JSON responses (handles empty bodies for DELETE)
160
+ 3. On non-2xx responses, attaches `statusCode` and `signwellError` to the thrown Error
161
+ 4. On network failures, wraps with `[xSignwell] Network error` message
162
+
163
+ The plugin uses `fastify-plugin` with `fastify >=5.0.0` constraint so the decorator is visible across all scopes. The `testMode` config flag is passed as `test_mode` in document/bulk-send creation payloads so SignWell won't actually deliver signing emails.
331
164
 
332
165
  ## Testing
333
166
 
@@ -335,6 +168,8 @@ SignWell API has the following rate limits:
335
168
  npm test
336
169
  ```
337
170
 
171
+ 82 tests covering plugin registration, startup validation, all document/template/webhook/bulk-send methods (happy path + input validation + error propagation), webhook signature verification, and network error handling.
172
+
338
173
  ## License
339
174
 
340
- MIT
175
+ UNLICENSED
package/index.d.ts ADDED
@@ -0,0 +1,164 @@
1
+ import { FastifyPluginAsync } from "fastify";
2
+
3
+ interface XSignwellOptions {
4
+ /** SignWell API key (required) */
5
+ apiKey: string;
6
+ /** API base URL (default: "https://www.signwell.com/api/v1") */
7
+ baseUrl?: string;
8
+ /** Enable test mode (default: false) */
9
+ testMode?: boolean;
10
+ /** Enable/disable the plugin (default: true) */
11
+ active?: boolean;
12
+ }
13
+
14
+ interface Recipient {
15
+ id?: string;
16
+ email: string;
17
+ name?: string;
18
+ sendEmail?: boolean;
19
+ [key: string]: unknown;
20
+ }
21
+
22
+ interface FileAttachment {
23
+ name: string;
24
+ base64?: string;
25
+ file_base64?: string;
26
+ url?: string;
27
+ file_url?: string;
28
+ }
29
+
30
+ interface CreateDocumentParams {
31
+ name: string;
32
+ recipients: Recipient[];
33
+ files?: FileAttachment[];
34
+ draft?: boolean;
35
+ testMode?: boolean;
36
+ subject?: string;
37
+ message?: string;
38
+ metadata?: Record<string, unknown>;
39
+ [key: string]: unknown;
40
+ }
41
+
42
+ interface CreateFromTemplateParams {
43
+ recipients: Recipient[];
44
+ fields?: Record<string, unknown>;
45
+ draft?: boolean;
46
+ testMode?: boolean;
47
+ subject?: string;
48
+ message?: string;
49
+ metadata?: Record<string, unknown>;
50
+ [key: string]: unknown;
51
+ }
52
+
53
+ interface PaginationParams {
54
+ page?: number;
55
+ limit?: number;
56
+ }
57
+
58
+ interface DocumentsService {
59
+ create(params: CreateDocumentParams): Promise<Record<string, unknown>>;
60
+ createFromTemplate(templateId: string, params: CreateFromTemplateParams): Promise<Record<string, unknown>>;
61
+ get(documentId: string): Promise<Record<string, unknown>>;
62
+ list(params?: PaginationParams): Promise<Record<string, unknown>>;
63
+ send(documentId: string, params?: Record<string, unknown>): Promise<Record<string, unknown>>;
64
+ remind(documentId: string): Promise<Record<string, unknown>>;
65
+ remove(documentId: string): Promise<Record<string, unknown>>;
66
+ delete(documentId: string): Promise<Record<string, unknown>>;
67
+ getCompletedPdf(documentId: string): Promise<Record<string, unknown>>;
68
+ getEmbeddedSigningUrl(documentId: string, recipientId: string): Promise<{ url: string; recipient: Record<string, unknown> }>;
69
+ getAuditTrail(documentId: string): Promise<Record<string, unknown>>;
70
+ }
71
+
72
+ interface CreateTemplateParams {
73
+ name: string;
74
+ files?: FileAttachment[];
75
+ recipients?: Array<{ id?: string; name?: string; placeholder_name?: string; [key: string]: unknown }>;
76
+ fields?: unknown[];
77
+ subject?: string;
78
+ message?: string;
79
+ [key: string]: unknown;
80
+ }
81
+
82
+ interface TemplatesService {
83
+ get(templateId: string): Promise<Record<string, unknown>>;
84
+ create(params: CreateTemplateParams): Promise<Record<string, unknown>>;
85
+ update(templateId: string, params: Record<string, unknown>): Promise<Record<string, unknown>>;
86
+ remove(templateId: string): Promise<Record<string, unknown>>;
87
+ delete(templateId: string): Promise<Record<string, unknown>>;
88
+ list(params?: PaginationParams): Promise<Record<string, unknown>>;
89
+ getFields(templateId: string): Promise<unknown[]>;
90
+ getRecipients(templateId: string): Promise<unknown[]>;
91
+ }
92
+
93
+ interface WebhookEvents {
94
+ DOCUMENT_COMPLETED: "document.completed";
95
+ DOCUMENT_SENT: "document.sent";
96
+ DOCUMENT_VIEWED: "document.viewed";
97
+ DOCUMENT_SIGNED: "document.signed";
98
+ DOCUMENT_DECLINED: "document.declined";
99
+ DOCUMENT_EXPIRED: "document.expired";
100
+ DOCUMENT_VOIDED: "document.voided";
101
+ RECIPIENT_COMPLETED: "recipient.completed";
102
+ RECIPIENT_VIEWED: "recipient.viewed";
103
+ RECIPIENT_SIGNED: "recipient.signed";
104
+ RECIPIENT_DECLINED: "recipient.declined";
105
+ }
106
+
107
+ interface ParsedEvent {
108
+ event: string;
109
+ documentId: string;
110
+ document: Record<string, unknown>;
111
+ recipient: Record<string, unknown> | undefined;
112
+ timestamp: string;
113
+ raw: Record<string, unknown>;
114
+ }
115
+
116
+ interface WebhooksService {
117
+ list(): Promise<Record<string, unknown>>;
118
+ create(params: { callbackUrl: string; event?: string; [key: string]: unknown }): Promise<Record<string, unknown>>;
119
+ remove(webhookId: string): Promise<Record<string, unknown>>;
120
+ delete(webhookId: string): Promise<Record<string, unknown>>;
121
+ events: WebhookEvents;
122
+ verifySignature(payload: string, signature: string, secret: string): boolean;
123
+ parseEvent(payload: Record<string, unknown>): ParsedEvent;
124
+ }
125
+
126
+ interface CreateBulkSendParams {
127
+ templateId: string;
128
+ recipients: Record<string, unknown>[];
129
+ testMode?: boolean;
130
+ subject?: string;
131
+ message?: string;
132
+ [key: string]: unknown;
133
+ }
134
+
135
+ interface BulkSendService {
136
+ get(bulkSendId: string): Promise<Record<string, unknown>>;
137
+ list(params?: PaginationParams): Promise<Record<string, unknown>>;
138
+ create(params: CreateBulkSendParams): Promise<Record<string, unknown>>;
139
+ getCsvTemplate(templateId: string): Promise<Record<string, unknown>>;
140
+ validateCsv(templateId: string, csvContent: string): Promise<Record<string, unknown>>;
141
+ getDocuments(bulkSendId: string, params?: PaginationParams): Promise<Record<string, unknown>>;
142
+ }
143
+
144
+ interface XSignwellDecorator {
145
+ config: {
146
+ apiKey: string;
147
+ baseUrl: string;
148
+ testMode: boolean;
149
+ };
150
+ documents: DocumentsService;
151
+ templates: TemplatesService;
152
+ webhooks: WebhooksService;
153
+ bulkSend: BulkSendService;
154
+ me(): Promise<Record<string, unknown>>;
155
+ }
156
+
157
+ declare module "fastify" {
158
+ interface FastifyInstance {
159
+ xsignwell: XSignwellDecorator;
160
+ }
161
+ }
162
+
163
+ declare const xSignwell: FastifyPluginAsync<XSignwellOptions>;
164
+ export default xSignwell;