@xenterprises/fastify-xsignwell 1.0.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/.gitlab-ci.yml +45 -0
- package/README.md +340 -0
- package/package.json +35 -0
- package/src/services/bulkSend.js +179 -0
- package/src/services/documents.js +251 -0
- package/src/services/templates.js +196 -0
- package/src/services/webhooks.js +172 -0
- package/src/xSignwell.js +82 -0
- package/test/xSignwell.test.js +539 -0
package/.gitlab-ci.yml
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# ============================================================================
|
|
2
|
+
# GitLab CI/CD Pipeline - xSignwell
|
|
3
|
+
# ============================================================================
|
|
4
|
+
# Runs tests on merge requests and commits to main/master
|
|
5
|
+
|
|
6
|
+
stages:
|
|
7
|
+
- test
|
|
8
|
+
|
|
9
|
+
variables:
|
|
10
|
+
NODE_ENV: test
|
|
11
|
+
|
|
12
|
+
# ============================================================================
|
|
13
|
+
# Shared Configuration
|
|
14
|
+
# ============================================================================
|
|
15
|
+
.shared_rules: &shared_rules
|
|
16
|
+
rules:
|
|
17
|
+
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
|
|
18
|
+
- if: '$CI_COMMIT_BRANCH == "main"'
|
|
19
|
+
- if: '$CI_COMMIT_BRANCH == "master"'
|
|
20
|
+
- if: '$CI_COMMIT_TAG'
|
|
21
|
+
|
|
22
|
+
# ============================================================================
|
|
23
|
+
# STAGE: TEST
|
|
24
|
+
# ============================================================================
|
|
25
|
+
test:
|
|
26
|
+
stage: test
|
|
27
|
+
image: node:20-alpine
|
|
28
|
+
<<: *shared_rules
|
|
29
|
+
|
|
30
|
+
cache:
|
|
31
|
+
key: ${CI_COMMIT_REF_SLUG}
|
|
32
|
+
paths:
|
|
33
|
+
- node_modules/
|
|
34
|
+
|
|
35
|
+
before_script:
|
|
36
|
+
- npm ci
|
|
37
|
+
|
|
38
|
+
script:
|
|
39
|
+
- echo "Running xSignwell tests..."
|
|
40
|
+
- npm test
|
|
41
|
+
- npm audit --audit-level=high || true
|
|
42
|
+
|
|
43
|
+
retry:
|
|
44
|
+
max: 2
|
|
45
|
+
when: runner_system_failure
|
package/README.md
ADDED
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
# xSignwell
|
|
2
|
+
|
|
3
|
+
A Fastify plugin for integrating with SignWell's e-signature API. Provides document creation, template management, bulk sending, and webhook handling.
|
|
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
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install xsignwell
|
|
18
|
+
```
|
|
19
|
+
|
|
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
|
|
30
|
+
|
|
31
|
+
```javascript
|
|
32
|
+
import Fastify from 'fastify';
|
|
33
|
+
import xSignwell from 'xsignwell';
|
|
34
|
+
|
|
35
|
+
const fastify = Fastify();
|
|
36
|
+
|
|
37
|
+
await fastify.register(xSignwell, {
|
|
38
|
+
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
|
|
249
|
+
});
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
#### Delete Webhook
|
|
253
|
+
|
|
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 };
|
|
281
|
+
});
|
|
282
|
+
```
|
|
283
|
+
|
|
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
|
|
304
|
+
|
|
305
|
+
```javascript
|
|
306
|
+
const account = await fastify.xsignwell.me();
|
|
307
|
+
console.log(account.email);
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
## API Reference
|
|
311
|
+
|
|
312
|
+
### Decorators
|
|
313
|
+
|
|
314
|
+
After registration, the following decorators are available on the Fastify instance:
|
|
315
|
+
|
|
316
|
+
| Decorator | Description |
|
|
317
|
+
|-----------|-------------|
|
|
318
|
+
| `fastify.xsignwell.documents` | Document management methods |
|
|
319
|
+
| `fastify.xsignwell.templates` | Template management methods |
|
|
320
|
+
| `fastify.xsignwell.bulkSend` | Bulk send methods |
|
|
321
|
+
| `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
|
|
331
|
+
|
|
332
|
+
## Testing
|
|
333
|
+
|
|
334
|
+
```bash
|
|
335
|
+
npm test
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
## License
|
|
339
|
+
|
|
340
|
+
MIT
|
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@xenterprises/fastify-xsignwell",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Fastify plugin for SignWell document signing API integration",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "src/xSignwell.js",
|
|
7
|
+
"engines": {
|
|
8
|
+
"node": ">=20.0.0",
|
|
9
|
+
"npm": ">=10.0.0"
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"test": "node --test test/xSignwell.test.js",
|
|
13
|
+
"lint": "eslint src/ test/"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"fastify",
|
|
17
|
+
"signwell",
|
|
18
|
+
"esignature",
|
|
19
|
+
"document-signing",
|
|
20
|
+
"pdf",
|
|
21
|
+
"api"
|
|
22
|
+
],
|
|
23
|
+
"author": "X Enterprises",
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"fastify-plugin": "^5.0.1"
|
|
27
|
+
},
|
|
28
|
+
"peerDependencies": {
|
|
29
|
+
"fastify": "^5.0.0"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"eslint": "^9.0.0",
|
|
33
|
+
"fastify": "^5.0.0"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SignWell Bulk Send Service
|
|
3
|
+
*
|
|
4
|
+
* Handles bulk document sending operations.
|
|
5
|
+
*
|
|
6
|
+
* @see https://developers.signwell.com/reference/get_api-v1-bulk-sends-id
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Setup bulk send service
|
|
11
|
+
*
|
|
12
|
+
* @param {import('fastify').FastifyInstance} fastify - Fastify instance
|
|
13
|
+
* @param {Object} config - Plugin configuration
|
|
14
|
+
*/
|
|
15
|
+
export async function setupBulkSend(fastify, config) {
|
|
16
|
+
const { apiKey, baseUrl, testMode } = config;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Make an API request to SignWell
|
|
20
|
+
* @param {string} endpoint - API endpoint
|
|
21
|
+
* @param {Object} options - Fetch options
|
|
22
|
+
* @returns {Promise<Object>} API response
|
|
23
|
+
*/
|
|
24
|
+
async function apiRequest(endpoint, options = {}) {
|
|
25
|
+
const url = `${baseUrl}${endpoint}`;
|
|
26
|
+
const headers = {
|
|
27
|
+
"X-Api-Key": apiKey,
|
|
28
|
+
"Content-Type": "application/json",
|
|
29
|
+
...options.headers,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const response = await fetch(url, {
|
|
33
|
+
...options,
|
|
34
|
+
headers,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
if (!response.ok) {
|
|
38
|
+
const errorText = await response.text();
|
|
39
|
+
let errorData;
|
|
40
|
+
try {
|
|
41
|
+
errorData = JSON.parse(errorText);
|
|
42
|
+
} catch {
|
|
43
|
+
errorData = { message: errorText };
|
|
44
|
+
}
|
|
45
|
+
fastify.log.error({ endpoint, status: response.status, error: errorData }, "SignWell API error");
|
|
46
|
+
throw new Error(errorData.message || `SignWell API error: ${response.status}`);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const text = await response.text();
|
|
50
|
+
if (!text) return { success: true };
|
|
51
|
+
|
|
52
|
+
return JSON.parse(text);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Get a bulk send by ID
|
|
57
|
+
* @param {string} bulkSendId - Bulk send ID
|
|
58
|
+
* @returns {Promise<Object>} Bulk send details
|
|
59
|
+
*/
|
|
60
|
+
async function get(bulkSendId) {
|
|
61
|
+
return apiRequest(`/bulk_sends/${bulkSendId}`, {
|
|
62
|
+
method: "GET",
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* List all bulk sends
|
|
68
|
+
* @param {Object} [params] - Query parameters
|
|
69
|
+
* @param {number} [params.page] - Page number
|
|
70
|
+
* @param {number} [params.limit] - Items per page
|
|
71
|
+
* @returns {Promise<Object>} List of bulk sends
|
|
72
|
+
*/
|
|
73
|
+
async function list(params = {}) {
|
|
74
|
+
const queryParams = new URLSearchParams();
|
|
75
|
+
if (params.page) queryParams.set("page", params.page);
|
|
76
|
+
if (params.limit) queryParams.set("limit", params.limit);
|
|
77
|
+
|
|
78
|
+
const queryString = queryParams.toString();
|
|
79
|
+
const endpoint = `/bulk_sends${queryString ? `?${queryString}` : ""}`;
|
|
80
|
+
|
|
81
|
+
return apiRequest(endpoint, {
|
|
82
|
+
method: "GET",
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Create a bulk send
|
|
88
|
+
* @param {Object} params - Bulk send parameters
|
|
89
|
+
* @param {string} params.templateId - Template ID to use
|
|
90
|
+
* @param {Array<Object>} params.recipients - List of recipient data
|
|
91
|
+
* @param {string} [params.subject] - Email subject
|
|
92
|
+
* @param {string} [params.message] - Email message
|
|
93
|
+
* @returns {Promise<Object>} Created bulk send
|
|
94
|
+
*/
|
|
95
|
+
async function create(params) {
|
|
96
|
+
const {
|
|
97
|
+
templateId,
|
|
98
|
+
recipients,
|
|
99
|
+
subject,
|
|
100
|
+
message,
|
|
101
|
+
...rest
|
|
102
|
+
} = params;
|
|
103
|
+
|
|
104
|
+
const body = {
|
|
105
|
+
document_template_id: templateId,
|
|
106
|
+
bulk_send_rows: recipients,
|
|
107
|
+
test_mode: testMode || params.testMode,
|
|
108
|
+
...rest,
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
if (subject) body.subject = subject;
|
|
112
|
+
if (message) body.message = message;
|
|
113
|
+
|
|
114
|
+
return apiRequest("/bulk_sends", {
|
|
115
|
+
method: "POST",
|
|
116
|
+
body: JSON.stringify(body),
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Get CSV template for bulk send
|
|
122
|
+
* @param {string} templateId - Template ID
|
|
123
|
+
* @returns {Promise<Object>} CSV template info
|
|
124
|
+
*/
|
|
125
|
+
async function getCsvTemplate(templateId) {
|
|
126
|
+
return apiRequest(`/bulk_sends/csv_template?document_template_id=${templateId}`, {
|
|
127
|
+
method: "GET",
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Validate CSV for bulk send
|
|
133
|
+
* @param {string} templateId - Template ID
|
|
134
|
+
* @param {string} csvContent - CSV content (base64 or raw)
|
|
135
|
+
* @returns {Promise<Object>} Validation result
|
|
136
|
+
*/
|
|
137
|
+
async function validateCsv(templateId, csvContent) {
|
|
138
|
+
return apiRequest("/bulk_sends/validate_csv", {
|
|
139
|
+
method: "POST",
|
|
140
|
+
body: JSON.stringify({
|
|
141
|
+
document_template_id: templateId,
|
|
142
|
+
csv: csvContent,
|
|
143
|
+
}),
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Get documents from a bulk send
|
|
149
|
+
* @param {string} bulkSendId - Bulk send ID
|
|
150
|
+
* @param {Object} [params] - Query parameters
|
|
151
|
+
* @param {number} [params.page] - Page number
|
|
152
|
+
* @param {number} [params.limit] - Items per page
|
|
153
|
+
* @returns {Promise<Object>} List of documents
|
|
154
|
+
*/
|
|
155
|
+
async function getDocuments(bulkSendId, params = {}) {
|
|
156
|
+
const queryParams = new URLSearchParams();
|
|
157
|
+
if (params.page) queryParams.set("page", params.page);
|
|
158
|
+
if (params.limit) queryParams.set("limit", params.limit);
|
|
159
|
+
|
|
160
|
+
const queryString = queryParams.toString();
|
|
161
|
+
const endpoint = `/bulk_sends/${bulkSendId}/documents${queryString ? `?${queryString}` : ""}`;
|
|
162
|
+
|
|
163
|
+
return apiRequest(endpoint, {
|
|
164
|
+
method: "GET",
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Add bulk send service to xsignwell namespace
|
|
169
|
+
fastify.xsignwell.bulkSend = {
|
|
170
|
+
get,
|
|
171
|
+
list,
|
|
172
|
+
create,
|
|
173
|
+
getCsvTemplate,
|
|
174
|
+
validateCsv,
|
|
175
|
+
getDocuments,
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
console.info(" • Bulk Send Service initialized");
|
|
179
|
+
}
|