@rynko/sdk 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/README.md ADDED
@@ -0,0 +1,735 @@
1
+ # @rynko/sdk
2
+
3
+ Official Node.js SDK for [Rynko](https://rynko.dev) - the document generation platform with unified template design for PDF and Excel documents.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/@rynko/sdk.svg)](https://www.npmjs.com/package/@rynko/sdk)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+
8
+ ## Table of Contents
9
+
10
+ - [Installation](#installation)
11
+ - [Quick Start](#quick-start)
12
+ - [Features](#features)
13
+ - [Authentication](#authentication)
14
+ - [Document Generation](#document-generation)
15
+ - [Generate PDF](#generate-pdf)
16
+ - [Generate Excel](#generate-excel)
17
+ - [Generate with Options](#generate-with-options)
18
+ - [Batch Generation](#batch-generation)
19
+ - [Wait for Completion](#wait-for-completion)
20
+ - [Document Jobs](#document-jobs)
21
+ - [Get Job Status](#get-job-status)
22
+ - [List Jobs](#list-jobs)
23
+ - [Templates](#templates)
24
+ - [List Templates](#list-templates)
25
+ - [Get Template Details](#get-template-details)
26
+ - [Webhooks](#webhooks)
27
+ - [List Webhooks](#list-webhooks)
28
+ - [Verify Webhook Signatures](#verify-webhook-signatures)
29
+ - [Configuration](#configuration)
30
+ - [Error Handling](#error-handling)
31
+ - [TypeScript Support](#typescript-support)
32
+ - [API Reference](#api-reference)
33
+ - [Requirements](#requirements)
34
+ - [Support](#support)
35
+
36
+ ## Installation
37
+
38
+ ```bash
39
+ npm install @rynko/sdk
40
+ # or
41
+ yarn add @rynko/sdk
42
+ # or
43
+ pnpm add @rynko/sdk
44
+ ```
45
+
46
+ ## Quick Start
47
+
48
+ ```typescript
49
+ import { Rynko } from '@rynko/sdk';
50
+
51
+ const rynko = new Rynko({
52
+ apiKey: process.env.RYNKO_API_KEY!,
53
+ });
54
+
55
+ // Generate a PDF document (async - returns job info immediately)
56
+ const job = await rynko.documents.generatePdf({
57
+ templateId: 'tmpl_invoice',
58
+ variables: {
59
+ customerName: 'John Doe',
60
+ invoiceNumber: 'INV-001',
61
+ total: 150.00,
62
+ },
63
+ });
64
+
65
+ console.log('Job ID:', job.jobId);
66
+ console.log('Status:', job.status); // 'queued'
67
+
68
+ // Wait for completion to get the download URL
69
+ const completed = await rynko.documents.waitForCompletion(job.jobId);
70
+ console.log('Download URL:', completed.downloadUrl);
71
+ ```
72
+
73
+ ## Features
74
+
75
+ - **Full TypeScript support** with comprehensive type definitions
76
+ - **Promise-based API** for modern async/await usage
77
+ - **PDF generation** - Generate PDF documents from templates
78
+ - **Excel generation** - Generate Excel spreadsheets from templates
79
+ - **Batch generation** - Generate multiple documents in a single request
80
+ - **Workspace support** - Generate documents in specific workspaces
81
+ - **Webhook verification** - Secure HMAC signature verification for incoming webhooks
82
+ - **Polling utility** - Built-in `waitForCompletion()` method with configurable timeout
83
+ - **Automatic retries** - Configurable retry logic for transient failures
84
+
85
+ ## Authentication
86
+
87
+ ### Get an API Key
88
+
89
+ 1. Log in to your [Rynko Dashboard](https://app.rynko.dev)
90
+ 2. Navigate to **Settings** → **API Keys**
91
+ 3. Click **Create API Key**
92
+ 4. Copy the key and store it securely (it won't be shown again)
93
+
94
+ ### Initialize the Client
95
+
96
+ ```typescript
97
+ import { Rynko } from '@rynko/sdk';
98
+
99
+ // Using environment variable (recommended)
100
+ const rynko = new Rynko({
101
+ apiKey: process.env.RYNKO_API_KEY!,
102
+ });
103
+
104
+ // Verify authentication
105
+ const user = await rynko.me();
106
+ console.log('Authenticated as:', user.email);
107
+ console.log('Team:', user.teamName);
108
+ ```
109
+
110
+ ### Verify API Key
111
+
112
+ ```typescript
113
+ // Check if API key is valid
114
+ const isValid = await rynko.verifyApiKey();
115
+ console.log('API Key valid:', isValid);
116
+ ```
117
+
118
+ ## Document Generation
119
+
120
+ Document generation in Rynko is **asynchronous**. When you call a generate method, the job is queued for processing and you receive a job ID immediately. Use `waitForCompletion()` to poll until the document is ready.
121
+
122
+ ### Generate PDF
123
+
124
+ ```typescript
125
+ // Queue PDF generation
126
+ const job = await rynko.documents.generatePdf({
127
+ templateId: 'tmpl_invoice',
128
+ variables: {
129
+ invoiceNumber: 'INV-001',
130
+ customerName: 'John Doe',
131
+ customerEmail: 'john@example.com',
132
+ items: [
133
+ { description: 'Product A', quantity: 2, price: 50.00 },
134
+ { description: 'Product B', quantity: 1, price: 50.00 },
135
+ ],
136
+ subtotal: 150.00,
137
+ tax: 15.00,
138
+ total: 165.00,
139
+ },
140
+ });
141
+
142
+ console.log('Job queued:', job.jobId);
143
+ console.log('Status:', job.status); // 'queued'
144
+
145
+ // Wait for completion
146
+ const completed = await rynko.documents.waitForCompletion(job.jobId);
147
+ console.log('Download URL:', completed.downloadUrl);
148
+ ```
149
+
150
+ ### Generate Excel
151
+
152
+ ```typescript
153
+ const job = await rynko.documents.generateExcel({
154
+ templateId: 'tmpl_sales_report',
155
+ variables: {
156
+ reportTitle: 'Q1 2026 Sales Report',
157
+ reportDate: '2026-03-31',
158
+ salesData: [
159
+ { region: 'North', q1: 125000, q2: 0, q3: 0, q4: 0 },
160
+ { region: 'South', q1: 98000, q2: 0, q3: 0, q4: 0 },
161
+ { region: 'East', q1: 145000, q2: 0, q3: 0, q4: 0 },
162
+ { region: 'West', q1: 112000, q2: 0, q3: 0, q4: 0 },
163
+ ],
164
+ totalSales: 480000,
165
+ },
166
+ });
167
+
168
+ const completed = await rynko.documents.waitForCompletion(job.jobId);
169
+ console.log('Excel file ready:', completed.downloadUrl);
170
+ ```
171
+
172
+ ### Generate with Options
173
+
174
+ The `generate()` method supports all document formats and advanced options:
175
+
176
+ ```typescript
177
+ const job = await rynko.documents.generate({
178
+ // Required
179
+ templateId: 'tmpl_contract',
180
+ format: 'pdf', // 'pdf' | 'excel' | 'csv'
181
+
182
+ // Template variables
183
+ variables: {
184
+ contractNumber: 'CTR-2026-001',
185
+ clientName: 'Acme Corporation',
186
+ startDate: '2026-02-01',
187
+ endDate: '2027-01-31',
188
+ },
189
+
190
+ // Optional settings
191
+ filename: 'contract-acme-2026', // Custom filename (without extension)
192
+ workspaceId: 'ws_abc123', // Generate in specific workspace
193
+ webhookUrl: 'https://your-app.com/webhooks/document-ready', // Webhook notification
194
+ metadata: { // Custom metadata (passed to webhook)
195
+ orderId: 'ORD-12345',
196
+ userId: 'user_abc',
197
+ },
198
+ useDraft: false, // Use draft template version (for testing)
199
+ useCredit: false, // Force use of purchased credits
200
+ });
201
+ ```
202
+
203
+ ### Batch Generation
204
+
205
+ Generate multiple documents from a single template:
206
+
207
+ ```typescript
208
+ // Each object in the documents array contains variables for one document
209
+ const batch = await rynko.documents.generateBatch({
210
+ templateId: 'tmpl_invoice',
211
+ format: 'pdf',
212
+ documents: [
213
+ {
214
+ invoiceNumber: 'INV-001',
215
+ customerName: 'John Doe',
216
+ total: 150.00,
217
+ },
218
+ {
219
+ invoiceNumber: 'INV-002',
220
+ customerName: 'Jane Smith',
221
+ total: 275.50,
222
+ },
223
+ {
224
+ invoiceNumber: 'INV-003',
225
+ customerName: 'Bob Wilson',
226
+ total: 89.99,
227
+ },
228
+ ],
229
+ webhookUrl: 'https://your-app.com/webhooks/batch-complete',
230
+ });
231
+
232
+ console.log('Batch ID:', batch.batchId);
233
+ console.log('Total jobs:', batch.totalJobs); // 3
234
+ console.log('Status:', batch.status); // 'queued'
235
+ console.log('Estimated wait:', batch.estimatedWaitSeconds, 'seconds');
236
+ ```
237
+
238
+ ### Wait for Completion
239
+
240
+ The `waitForCompletion()` method polls the job status until it completes or fails:
241
+
242
+ ```typescript
243
+ // Default settings (1 second interval, 30 second timeout)
244
+ const completed = await rynko.documents.waitForCompletion(job.jobId);
245
+
246
+ // Custom polling settings
247
+ const completed = await rynko.documents.waitForCompletion(job.jobId, {
248
+ pollInterval: 2000, // Check every 2 seconds
249
+ timeout: 60000, // Wait up to 60 seconds
250
+ });
251
+
252
+ // Check result
253
+ if (completed.status === 'completed') {
254
+ console.log('Download URL:', completed.downloadUrl);
255
+ console.log('File size:', completed.fileSize, 'bytes');
256
+ console.log('Expires at:', completed.downloadUrlExpiresAt);
257
+ } else if (completed.status === 'failed') {
258
+ console.error('Generation failed:', completed.errorMessage);
259
+ console.error('Error code:', completed.errorCode);
260
+ }
261
+ ```
262
+
263
+ ## Document Jobs
264
+
265
+ ### Get Job Status
266
+
267
+ ```typescript
268
+ const job = await rynko.documents.getJob('job_abc123');
269
+
270
+ console.log('Status:', job.status);
271
+ // Possible values: 'queued' | 'processing' | 'completed' | 'failed'
272
+
273
+ console.log('Template:', job.templateName);
274
+ console.log('Format:', job.format);
275
+ console.log('Created:', job.createdAt);
276
+
277
+ if (job.status === 'completed') {
278
+ console.log('Download URL:', job.downloadUrl);
279
+ console.log('File size:', job.fileSize);
280
+ console.log('URL expires:', job.downloadUrlExpiresAt);
281
+ }
282
+
283
+ if (job.status === 'failed') {
284
+ console.log('Error:', job.errorMessage);
285
+ console.log('Error code:', job.errorCode);
286
+ }
287
+ ```
288
+
289
+ ### List Jobs
290
+
291
+ ```typescript
292
+ // List recent jobs with pagination
293
+ const { data: jobs, meta } = await rynko.documents.listJobs({
294
+ limit: 20,
295
+ page: 1,
296
+ });
297
+
298
+ console.log('Total jobs:', meta.total);
299
+ console.log('Pages:', meta.totalPages);
300
+
301
+ for (const job of jobs) {
302
+ console.log(`${job.jobId}: ${job.status} - ${job.templateName}`);
303
+ }
304
+
305
+ // Filter by status
306
+ const { data: completedJobs } = await rynko.documents.listJobs({
307
+ status: 'completed',
308
+ });
309
+
310
+ // Filter by format
311
+ const { data: pdfJobs } = await rynko.documents.listJobs({
312
+ format: 'pdf',
313
+ });
314
+
315
+ // Filter by template
316
+ const { data: invoiceJobs } = await rynko.documents.listJobs({
317
+ templateId: 'tmpl_invoice',
318
+ });
319
+
320
+ // Filter by workspace
321
+ const { data: workspaceJobs } = await rynko.documents.listJobs({
322
+ workspaceId: 'ws_abc123',
323
+ });
324
+
325
+ // Filter by date range
326
+ const { data: recentJobs } = await rynko.documents.listJobs({
327
+ dateFrom: new Date('2026-01-01'),
328
+ dateTo: new Date('2026-01-31'),
329
+ });
330
+
331
+ // Combine filters
332
+ const { data: filteredJobs } = await rynko.documents.listJobs({
333
+ status: 'completed',
334
+ format: 'pdf',
335
+ templateId: 'tmpl_invoice',
336
+ limit: 50,
337
+ });
338
+ ```
339
+
340
+ ## Templates
341
+
342
+ ### List Templates
343
+
344
+ ```typescript
345
+ // List all templates
346
+ const { data: templates, meta } = await rynko.templates.list();
347
+
348
+ console.log('Total templates:', meta.total);
349
+
350
+ for (const template of templates) {
351
+ console.log(`${template.id}: ${template.name} (${template.type})`);
352
+ }
353
+
354
+ // Paginated list
355
+ const { data: page2 } = await rynko.templates.list({
356
+ page: 2,
357
+ limit: 10,
358
+ });
359
+
360
+ // Search by name
361
+ const { data: invoiceTemplates } = await rynko.templates.list({
362
+ search: 'invoice',
363
+ });
364
+
365
+ // List PDF templates only
366
+ const { data: pdfTemplates } = await rynko.templates.listPdf();
367
+
368
+ // List Excel templates only
369
+ const { data: excelTemplates } = await rynko.templates.listExcel();
370
+ ```
371
+
372
+ ### Get Template Details
373
+
374
+ ```typescript
375
+ // Get template by ID (supports UUID, shortId, or slug)
376
+ const template = await rynko.templates.get('tmpl_invoice');
377
+
378
+ console.log('Template:', template.name);
379
+ console.log('Type:', template.type); // 'pdf' | 'excel'
380
+ console.log('Description:', template.description);
381
+ console.log('Created:', template.createdAt);
382
+ console.log('Updated:', template.updatedAt);
383
+
384
+ // View template variables
385
+ if (template.variables) {
386
+ console.log('\nVariables:');
387
+ for (const variable of template.variables) {
388
+ console.log(` ${variable.name} (${variable.type})`);
389
+ console.log(` Required: ${variable.required ?? false}`);
390
+ if (variable.defaultValue !== undefined) {
391
+ console.log(` Default: ${JSON.stringify(variable.defaultValue)}`);
392
+ }
393
+ }
394
+ }
395
+ ```
396
+
397
+ ## Webhooks
398
+
399
+ Webhook subscriptions are managed through the [Rynko Dashboard](https://app.rynko.dev). The SDK provides read-only access to view webhooks and utilities for signature verification.
400
+
401
+ ### List Webhooks
402
+
403
+ ```typescript
404
+ const { data: webhooks, meta } = await rynko.webhooks.list();
405
+
406
+ for (const webhook of webhooks) {
407
+ console.log(`${webhook.id}: ${webhook.url}`);
408
+ console.log(` Events: ${webhook.events.join(', ')}`);
409
+ console.log(` Active: ${webhook.isActive}`);
410
+ console.log(` Created: ${webhook.createdAt}`);
411
+ }
412
+ ```
413
+
414
+ ### Get Webhook Details
415
+
416
+ ```typescript
417
+ const webhook = await rynko.webhooks.get('wh_abc123');
418
+
419
+ console.log('URL:', webhook.url);
420
+ console.log('Events:', webhook.events);
421
+ console.log('Active:', webhook.isActive);
422
+ console.log('Description:', webhook.description);
423
+ ```
424
+
425
+ ### Verify Webhook Signatures
426
+
427
+ When receiving webhooks, always verify the signature to ensure the request came from Rynko:
428
+
429
+ ```typescript
430
+ import { verifyWebhookSignature, WebhookSignatureError } from '@rynko/sdk';
431
+
432
+ // Express.js example
433
+ app.post('/webhooks/rynko', express.raw({ type: 'application/json' }), (req, res) => {
434
+ const signature = req.headers['x-rynko-signature'] as string;
435
+ const timestamp = req.headers['x-rynko-timestamp'] as string;
436
+
437
+ try {
438
+ const event = verifyWebhookSignature({
439
+ payload: req.body.toString(),
440
+ signature,
441
+ timestamp, // Optional but recommended for replay protection
442
+ secret: process.env.WEBHOOK_SECRET!,
443
+ });
444
+
445
+ // Process the verified event
446
+ console.log('Event type:', event.type);
447
+ console.log('Event ID:', event.id);
448
+ console.log('Timestamp:', event.timestamp);
449
+
450
+ switch (event.type) {
451
+ case 'document.generated':
452
+ const { jobId, downloadUrl, templateId } = event.data;
453
+ console.log(`Document ${jobId} ready: ${downloadUrl}`);
454
+ // Download or process the document
455
+ break;
456
+
457
+ case 'document.failed':
458
+ const { jobId: failedJobId, error, errorCode } = event.data;
459
+ console.error(`Document ${failedJobId} failed: ${error}`);
460
+ // Handle failure (retry, notify user, etc.)
461
+ break;
462
+
463
+ case 'document.downloaded':
464
+ const { jobId: downloadedJobId } = event.data;
465
+ console.log(`Document ${downloadedJobId} was downloaded`);
466
+ break;
467
+
468
+ default:
469
+ console.log('Unhandled event type:', event.type);
470
+ }
471
+
472
+ res.status(200).send('OK');
473
+ } catch (error) {
474
+ if (error instanceof WebhookSignatureError) {
475
+ console.error('Invalid webhook signature:', error.message);
476
+ res.status(401).send('Invalid signature');
477
+ } else {
478
+ console.error('Webhook processing error:', error);
479
+ res.status(500).send('Internal error');
480
+ }
481
+ }
482
+ });
483
+ ```
484
+
485
+ #### Webhook Event Types
486
+
487
+ | Event | Description | Payload |
488
+ |-------|-------------|---------|
489
+ | `document.generated` | Document successfully generated | `jobId`, `templateId`, `format`, `downloadUrl`, `fileSize` |
490
+ | `document.failed` | Document generation failed | `jobId`, `templateId`, `error`, `errorCode` |
491
+ | `document.downloaded` | Document was downloaded | `jobId`, `downloadedAt` |
492
+
493
+ #### Webhook Headers
494
+
495
+ Rynko sends these headers with each webhook request:
496
+
497
+ | Header | Description |
498
+ |--------|-------------|
499
+ | `X-Rynko-Signature` | HMAC-SHA256 signature (format: `v1=<hex>`) |
500
+ | `X-Rynko-Timestamp` | Unix timestamp when the webhook was sent |
501
+ | `X-Rynko-Event-Id` | Unique event identifier |
502
+ | `X-Rynko-Event-Type` | Event type (e.g., `document.generated`) |
503
+
504
+ #### Low-Level Signature Utilities
505
+
506
+ For advanced use cases, you can use the low-level signature utilities:
507
+
508
+ ```typescript
509
+ import { parseSignatureHeader, computeSignature } from '@rynko/sdk';
510
+
511
+ // Parse the signature header
512
+ const { timestamp, signatures } = parseSignatureHeader(signatureHeader);
513
+
514
+ // Compute expected signature
515
+ const expectedSignature = computeSignature(timestamp, payload, secret);
516
+
517
+ // Compare signatures
518
+ const isValid = signatures.some(sig => sig === expectedSignature);
519
+ ```
520
+
521
+ ## Configuration
522
+
523
+ ```typescript
524
+ const rynko = new Rynko({
525
+ // Required: Your API key
526
+ apiKey: process.env.RYNKO_API_KEY!,
527
+
528
+ // Optional: Custom base URL (default: https://api.rynko.dev)
529
+ baseUrl: 'https://api.rynko.dev',
530
+
531
+ // Optional: Request timeout in milliseconds (default: 30000)
532
+ timeout: 30000,
533
+
534
+ // Optional: Custom headers for all requests
535
+ headers: {
536
+ 'X-Custom-Header': 'value',
537
+ },
538
+ });
539
+ ```
540
+
541
+ ### Environment Variables
542
+
543
+ We recommend using environment variables for configuration:
544
+
545
+ ```bash
546
+ # .env
547
+ RYNKO_API_KEY=your_api_key_here
548
+ WEBHOOK_SECRET=your_webhook_secret_here
549
+ ```
550
+
551
+ ```typescript
552
+ import 'dotenv/config';
553
+ import { Rynko } from '@rynko/sdk';
554
+
555
+ const rynko = new Rynko({
556
+ apiKey: process.env.RYNKO_API_KEY!,
557
+ });
558
+ ```
559
+
560
+ ## Error Handling
561
+
562
+ ```typescript
563
+ import { Rynko, RynkoError } from '@rynko/sdk';
564
+
565
+ const rynko = new Rynko({ apiKey: 'your_api_key' });
566
+
567
+ try {
568
+ const job = await rynko.documents.generatePdf({
569
+ templateId: 'invalid_template',
570
+ variables: {},
571
+ });
572
+ } catch (error) {
573
+ if (error instanceof RynkoError) {
574
+ console.error('API Error:', error.message);
575
+ console.error('Error Code:', error.code);
576
+ console.error('Status Code:', error.statusCode);
577
+
578
+ // Handle specific error codes
579
+ switch (error.code) {
580
+ case 'ERR_TMPL_001':
581
+ console.error('Template not found');
582
+ break;
583
+ case 'ERR_TMPL_003':
584
+ console.error('Template validation failed');
585
+ break;
586
+ case 'ERR_QUOTA_001':
587
+ console.error('Document quota exceeded - upgrade your plan');
588
+ break;
589
+ case 'ERR_AUTH_001':
590
+ console.error('Invalid API key');
591
+ break;
592
+ case 'ERR_AUTH_004':
593
+ console.error('API key expired or revoked');
594
+ break;
595
+ default:
596
+ console.error('Unknown error');
597
+ }
598
+ } else {
599
+ // Network error or other non-API error
600
+ throw error;
601
+ }
602
+ }
603
+ ```
604
+
605
+ ### Common Error Codes
606
+
607
+ | Code | Description |
608
+ |------|-------------|
609
+ | `ERR_AUTH_001` | Invalid credentials / API key |
610
+ | `ERR_AUTH_004` | Token expired or revoked |
611
+ | `ERR_TMPL_001` | Template not found |
612
+ | `ERR_TMPL_003` | Template validation failed |
613
+ | `ERR_DOC_001` | Document job not found |
614
+ | `ERR_DOC_004` | Document generation failed |
615
+ | `ERR_QUOTA_001` | Document quota exceeded |
616
+ | `ERR_QUOTA_002` | Rate limit exceeded |
617
+
618
+ ## TypeScript Support
619
+
620
+ This SDK is written in TypeScript and includes comprehensive type definitions:
621
+
622
+ ```typescript
623
+ import {
624
+ Rynko,
625
+ RynkoError,
626
+ verifyWebhookSignature,
627
+ WebhookSignatureError,
628
+ } from '@rynko/sdk';
629
+
630
+ import type {
631
+ // Configuration
632
+ RynkoConfig,
633
+
634
+ // Document types
635
+ GenerateDocumentOptions,
636
+ GenerateBatchOptions,
637
+ GenerateDocumentResponse,
638
+ GenerateBatchResponse,
639
+ DocumentJob,
640
+ DocumentJobStatus,
641
+ ListDocumentJobsOptions,
642
+
643
+ // Template types
644
+ Template,
645
+ TemplateVariable,
646
+ ListTemplatesOptions,
647
+
648
+ // Webhook types
649
+ WebhookSubscription,
650
+ WebhookEventType,
651
+ WebhookEvent,
652
+
653
+ // Response types
654
+ ApiResponse,
655
+ PaginationMeta,
656
+ ApiError,
657
+
658
+ // User types
659
+ User,
660
+ } from '@rynko/sdk';
661
+
662
+ // Type-safe document generation
663
+ const options: GenerateDocumentOptions = {
664
+ templateId: 'tmpl_invoice',
665
+ format: 'pdf',
666
+ variables: {
667
+ invoiceNumber: 'INV-001',
668
+ items: [{ name: 'Widget', price: 29.99 }],
669
+ },
670
+ workspaceId: 'ws_abc123', // Optional
671
+ };
672
+
673
+ const result: GenerateDocumentResponse = await rynko.documents.generate(options);
674
+ ```
675
+
676
+ ## API Reference
677
+
678
+ ### Client Methods
679
+
680
+ | Method | Returns | Description |
681
+ |--------|---------|-------------|
682
+ | `me()` | `Promise<User>` | Get current authenticated user |
683
+ | `verifyApiKey()` | `Promise<boolean>` | Verify API key is valid |
684
+
685
+ ### Documents Resource
686
+
687
+ | Method | Returns | Description |
688
+ |--------|---------|-------------|
689
+ | `generate(options)` | `Promise<GenerateDocumentResponse>` | Generate a document (PDF, Excel, or CSV) |
690
+ | `generatePdf(options)` | `Promise<GenerateDocumentResponse>` | Generate a PDF document |
691
+ | `generateExcel(options)` | `Promise<GenerateDocumentResponse>` | Generate an Excel document |
692
+ | `generateBatch(options)` | `Promise<GenerateBatchResponse>` | Generate multiple documents |
693
+ | `getJob(jobId)` | `Promise<DocumentJob>` | Get document job by ID |
694
+ | `listJobs(options?)` | `Promise<{ data: DocumentJob[]; meta: PaginationMeta }>` | List/search document jobs |
695
+ | `waitForCompletion(jobId, options?)` | `Promise<DocumentJob>` | Poll until job completes or fails |
696
+
697
+ ### Templates Resource
698
+
699
+ | Method | Returns | Description |
700
+ |--------|---------|-------------|
701
+ | `get(templateId)` | `Promise<Template>` | Get template by ID (UUID, shortId, or slug) |
702
+ | `list(options?)` | `Promise<{ data: Template[]; meta: PaginationMeta }>` | List all templates |
703
+ | `listPdf(options?)` | `Promise<{ data: Template[]; meta: PaginationMeta }>` | List PDF templates only |
704
+ | `listExcel(options?)` | `Promise<{ data: Template[]; meta: PaginationMeta }>` | List Excel templates only |
705
+
706
+ ### Webhooks Resource
707
+
708
+ | Method | Returns | Description |
709
+ |--------|---------|-------------|
710
+ | `get(webhookId)` | `Promise<WebhookSubscription>` | Get webhook subscription by ID |
711
+ | `list()` | `Promise<{ data: WebhookSubscription[]; meta: PaginationMeta }>` | List all webhook subscriptions |
712
+
713
+ ### Utilities
714
+
715
+ | Function | Returns | Description |
716
+ |----------|---------|-------------|
717
+ | `verifyWebhookSignature(options)` | `WebhookEvent` | Verify signature and parse webhook event |
718
+ | `parseSignatureHeader(header)` | `{ timestamp: string; signatures: string[] }` | Parse signature header |
719
+ | `computeSignature(timestamp, payload, secret)` | `string` | Compute expected signature |
720
+
721
+ ## Requirements
722
+
723
+ - Node.js 18.0.0 or higher
724
+ - npm, yarn, or pnpm
725
+
726
+ ## License
727
+
728
+ MIT
729
+
730
+ ## Support
731
+
732
+ - **Documentation**: https://docs.rynko.dev/sdk/node
733
+ - **API Reference**: https://docs.rynko.dev/api
734
+ - **GitHub Issues**: https://github.com/rynko/sdk-node/issues
735
+ - **Email**: support@rynko.dev