@zyphr-dev/node-sdk 0.1.1 → 0.1.3
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 +436 -47
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
# @zyphr-dev/node-sdk
|
|
2
2
|
|
|
3
|
-
Official Zyphr SDK for Node.js, React, and React Native.
|
|
3
|
+
Official Zyphr SDK for Node.js, React, and React Native. Type-safe access to multi-channel notifications, subscriber management, webhooks, and authentication.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@zyphr-dev/node-sdk)
|
|
6
|
+
[](./LICENSE)
|
|
4
7
|
|
|
5
8
|
## Installation
|
|
6
9
|
|
|
@@ -10,7 +13,7 @@ npm install @zyphr-dev/node-sdk
|
|
|
10
13
|
yarn add @zyphr-dev/node-sdk
|
|
11
14
|
```
|
|
12
15
|
|
|
13
|
-
|
|
16
|
+
**Requirements:** Node.js 18+. Zero runtime dependencies.
|
|
14
17
|
|
|
15
18
|
## Quick Start
|
|
16
19
|
|
|
@@ -22,48 +25,425 @@ const zyphr = new Zyphr({
|
|
|
22
25
|
});
|
|
23
26
|
|
|
24
27
|
// Send an email
|
|
25
|
-
|
|
26
|
-
to: 'user@example.com',
|
|
28
|
+
await zyphr.emails.sendEmail({
|
|
29
|
+
to: [{ email: 'user@example.com', name: 'Jane' }],
|
|
27
30
|
subject: 'Welcome!',
|
|
28
|
-
html: '<h1>Hello!</h1>',
|
|
31
|
+
html: '<h1>Hello, {{name}}!</h1>',
|
|
32
|
+
templateData: { name: 'Jane' },
|
|
29
33
|
});
|
|
30
34
|
|
|
31
35
|
// Send a push notification
|
|
32
|
-
await zyphr.push.
|
|
33
|
-
|
|
34
|
-
title: 'New message',
|
|
35
|
-
body: 'You have a new notification',
|
|
36
|
+
await zyphr.push.sendPush({
|
|
37
|
+
subscriberId: 'sub_123',
|
|
38
|
+
payload: { title: 'New message', body: 'You have a new notification' },
|
|
36
39
|
});
|
|
37
40
|
|
|
38
41
|
// Send an SMS
|
|
39
|
-
await zyphr.sms.
|
|
42
|
+
await zyphr.sms.sendSms({
|
|
40
43
|
to: '+15551234567',
|
|
41
|
-
|
|
44
|
+
message: 'Your verification code is 123456',
|
|
42
45
|
});
|
|
43
46
|
|
|
44
47
|
// Send an in-app notification
|
|
45
|
-
await zyphr.inbox.
|
|
46
|
-
|
|
48
|
+
await zyphr.inbox.sendInApp({
|
|
49
|
+
subscriberId: 'sub_123',
|
|
47
50
|
title: 'Welcome aboard',
|
|
48
51
|
body: 'Thanks for signing up!',
|
|
49
52
|
});
|
|
50
53
|
```
|
|
51
54
|
|
|
52
|
-
##
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
|
62
|
-
|
|
63
|
-
| `
|
|
64
|
-
| `zyphr.
|
|
65
|
-
|
|
66
|
-
|
|
55
|
+
## Configuration
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
const zyphr = new Zyphr({
|
|
59
|
+
apiKey: 'zy_live_xxxx', // Required — your API key
|
|
60
|
+
baseUrl: 'https://custom.api.url', // Optional — defaults to https://api.zyphr.dev/v1
|
|
61
|
+
});
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
| Option | Type | Default | Description |
|
|
65
|
+
|--------|------|---------|-------------|
|
|
66
|
+
| `apiKey` | `string` | — | **Required.** API key (`zy_live_*` or `zy_test_*`) |
|
|
67
|
+
| `baseUrl` | `string` | `https://api.zyphr.dev/v1` | API base URL override |
|
|
68
|
+
|
|
69
|
+
## API Reference
|
|
70
|
+
|
|
71
|
+
### Emails — `zyphr.emails`
|
|
72
|
+
|
|
73
|
+
Send transactional emails with template support, tracking, and scheduling.
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
// Send a single email
|
|
77
|
+
await zyphr.emails.sendEmail({
|
|
78
|
+
to: [{ email: 'user@example.com', name: 'Jane' }],
|
|
79
|
+
from: { email: 'noreply@company.com', name: 'My App' },
|
|
80
|
+
subject: 'Order Confirmed',
|
|
81
|
+
html: '<h1>Order #{{orderId}} confirmed</h1>',
|
|
82
|
+
templateData: { orderId: '12345' },
|
|
83
|
+
tag: 'order-confirmation',
|
|
84
|
+
trackingEnabled: true,
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// Send batch emails (up to 100)
|
|
88
|
+
await zyphr.emails.sendBatchEmail({
|
|
89
|
+
messages: [
|
|
90
|
+
{ to: [{ email: 'a@example.com' }], subject: 'Hello A', html: '...' },
|
|
91
|
+
{ to: [{ email: 'b@example.com' }], subject: 'Hello B', html: '...' },
|
|
92
|
+
],
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// Get email details and tracking
|
|
96
|
+
const email = await zyphr.emails.getEmail('email_id');
|
|
97
|
+
const events = await zyphr.emails.getEmailEvents('email_id');
|
|
98
|
+
const tracking = await zyphr.emails.getEmailTracking('email_id');
|
|
99
|
+
|
|
100
|
+
// List emails with filtering
|
|
101
|
+
const { data } = await zyphr.emails.listEmails('delivered', 'welcome', 20, 0);
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
**Send options:** `to`, `from`, `replyTo`, `cc`, `bcc`, `subject`, `html`, `text`, `templateId`, `templateData`, `tag`, `metadata`, `headers`, `trackingEnabled`, `sendAt`, `delay`.
|
|
105
|
+
|
|
106
|
+
### SMS — `zyphr.sms`
|
|
107
|
+
|
|
108
|
+
Send SMS messages with scheduling and provider configuration.
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
// Send SMS
|
|
112
|
+
await zyphr.sms.sendSms({
|
|
113
|
+
to: '+15551234567',
|
|
114
|
+
message: 'Your code is 123456',
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// Batch send (up to 100)
|
|
118
|
+
await zyphr.sms.sendBatchSms({
|
|
119
|
+
messages: [
|
|
120
|
+
{ to: '+15551234567', message: 'Hello from Zyphr' },
|
|
121
|
+
{ to: '+15559876543', message: 'Hello from Zyphr' },
|
|
122
|
+
],
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// Manage SMS provider configuration
|
|
126
|
+
const config = await zyphr.sms.getSmsConfig();
|
|
127
|
+
await zyphr.sms.upsertSmsConfig({
|
|
128
|
+
provider: 'twilio',
|
|
129
|
+
accountSid: 'AC...',
|
|
130
|
+
authToken: '...',
|
|
131
|
+
fromNumber: '+15550001234',
|
|
132
|
+
});
|
|
133
|
+
await zyphr.sms.verifySmsConfig();
|
|
134
|
+
|
|
135
|
+
// List and inspect
|
|
136
|
+
const list = await zyphr.sms.listSms(1, 20, 'delivered');
|
|
137
|
+
const detail = await zyphr.sms.getSms('sms_id');
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Push Notifications — `zyphr.push`
|
|
141
|
+
|
|
142
|
+
Send push notifications to individual devices, subscribers, or topic subscribers.
|
|
143
|
+
|
|
144
|
+
```ts
|
|
145
|
+
// Send to a subscriber (all their devices)
|
|
146
|
+
await zyphr.push.sendPush({
|
|
147
|
+
subscriberId: 'sub_123',
|
|
148
|
+
payload: {
|
|
149
|
+
title: 'New Order',
|
|
150
|
+
body: 'Order #12345 has been placed',
|
|
151
|
+
icon: 'https://cdn.example.com/icon.png',
|
|
152
|
+
clickAction: 'https://app.example.com/orders/12345',
|
|
153
|
+
customData: { orderId: '12345' },
|
|
154
|
+
},
|
|
155
|
+
priority: 'high',
|
|
156
|
+
ttl: 3600,
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
// Send to a topic
|
|
160
|
+
await zyphr.push.sendPushToTopic('product-updates', {
|
|
161
|
+
payload: { title: 'New Feature', body: 'Check out our latest update' },
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
// Topic management
|
|
165
|
+
await zyphr.push.subscribePushTopic('alerts', { deviceIds: ['device_1'] });
|
|
166
|
+
await zyphr.push.unsubscribePushTopic('alerts', { deviceIds: ['device_1'] });
|
|
167
|
+
|
|
168
|
+
// Stats and listing
|
|
169
|
+
const stats = await zyphr.push.getPushStats();
|
|
170
|
+
const pushes = await zyphr.push.listPush('sub_123');
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### In-App Inbox — `zyphr.inbox`
|
|
174
|
+
|
|
175
|
+
Manage in-app notifications for the `@zyphr-dev/inbox-react` component library.
|
|
176
|
+
|
|
177
|
+
```ts
|
|
178
|
+
// Send in-app notification
|
|
179
|
+
await zyphr.inbox.sendInApp({
|
|
180
|
+
subscriberId: 'sub_123',
|
|
181
|
+
title: 'New comment',
|
|
182
|
+
body: 'Someone replied to your post',
|
|
183
|
+
category: 'comments',
|
|
184
|
+
cta: { label: 'View Comment', action: '/posts/456#comments' },
|
|
185
|
+
icon: 'https://cdn.example.com/comment.svg',
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
// Batch send (up to 100)
|
|
189
|
+
await zyphr.inbox.sendBatchInApp({
|
|
190
|
+
notifications: [
|
|
191
|
+
{ subscriberId: 'sub_123', title: 'Hello', body: '...' },
|
|
192
|
+
{ subscriberId: 'sub_456', title: 'Hello', body: '...' },
|
|
193
|
+
],
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
// Read operations
|
|
197
|
+
const unread = await zyphr.inbox.getUnreadCount('sub_123');
|
|
198
|
+
const notifications = await zyphr.inbox.listInbox('sub_123');
|
|
199
|
+
|
|
200
|
+
// Actions
|
|
201
|
+
await zyphr.inbox.markInboxRead('notification_id');
|
|
202
|
+
await zyphr.inbox.markAllInboxRead({ subscriberId: 'sub_123' });
|
|
203
|
+
await zyphr.inbox.archiveInboxNotification('notification_id');
|
|
204
|
+
await zyphr.inbox.deleteInboxNotification('notification_id');
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Subscribers — `zyphr.subscribers`
|
|
208
|
+
|
|
209
|
+
Manage subscribers, their preferences, and consent records.
|
|
210
|
+
|
|
211
|
+
```ts
|
|
212
|
+
// Create/upsert subscriber
|
|
213
|
+
const subscriber = await zyphr.subscribers.createSubscriber({
|
|
214
|
+
externalId: 'user_123',
|
|
215
|
+
email: 'jane@example.com',
|
|
216
|
+
name: 'Jane Doe',
|
|
217
|
+
timezone: 'America/New_York',
|
|
218
|
+
metadata: { plan: 'pro', company: 'Acme' },
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
// Get by ID or external ID
|
|
222
|
+
const sub = await zyphr.subscribers.getSubscriber('sub_id');
|
|
223
|
+
const subByExt = await zyphr.subscribers.getSubscriberByExternalId('user_123');
|
|
224
|
+
|
|
225
|
+
// Update
|
|
226
|
+
await zyphr.subscribers.updateSubscriber('sub_id', {
|
|
227
|
+
name: 'Jane Smith',
|
|
228
|
+
metadata: { plan: 'enterprise' },
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
// List with filtering
|
|
232
|
+
const subs = await zyphr.subscribers.listSubscribers('subscribed', undefined, 50, 0);
|
|
233
|
+
|
|
234
|
+
// Preferences
|
|
235
|
+
const prefs = await zyphr.subscribers.getSubscriberPreferences('sub_id');
|
|
236
|
+
await zyphr.subscribers.setSubscriberPreferences('sub_id', {
|
|
237
|
+
categoryId: 'marketing',
|
|
238
|
+
subscribed: false,
|
|
239
|
+
channel: 'email',
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
// Unsubscribe/resubscribe
|
|
243
|
+
await zyphr.subscribers.unsubscribeSubscriber('sub_id');
|
|
244
|
+
await zyphr.subscribers.resubscribeSubscriber('sub_id');
|
|
245
|
+
|
|
246
|
+
// Consent management
|
|
247
|
+
await zyphr.subscribers.recordSubscriberConsent('sub_id', {
|
|
248
|
+
type: 'opt_in', source: 'signup_form',
|
|
249
|
+
});
|
|
250
|
+
const consent = await zyphr.subscribers.getSubscriberConsent('sub_id');
|
|
251
|
+
const history = await zyphr.subscribers.getSubscriberConsentHistory('sub_id');
|
|
252
|
+
|
|
253
|
+
// Categories
|
|
254
|
+
const category = await zyphr.subscribers.createCategory({
|
|
255
|
+
name: 'Product Updates', slug: 'product-updates',
|
|
256
|
+
});
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
### Templates — `zyphr.templates`
|
|
260
|
+
|
|
261
|
+
Create and manage reusable email templates with variable substitution.
|
|
262
|
+
|
|
263
|
+
```ts
|
|
264
|
+
// Create template
|
|
265
|
+
const template = await zyphr.templates.createTemplate({
|
|
266
|
+
name: 'welcome-email',
|
|
267
|
+
subject: 'Welcome, {{name}}!',
|
|
268
|
+
html: '<h1>Hello {{name}}</h1><p>Welcome to {{company}}.</p>',
|
|
269
|
+
variables: ['name', 'company'],
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
// Render template (preview without sending)
|
|
273
|
+
const rendered = await zyphr.templates.renderTemplate('template_id', {
|
|
274
|
+
data: { name: 'Jane', company: 'Acme' },
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
// CRUD operations
|
|
278
|
+
const t = await zyphr.templates.getTemplate('template_id');
|
|
279
|
+
await zyphr.templates.updateTemplate('template_id', { subject: 'New subject' });
|
|
280
|
+
await zyphr.templates.deleteTemplate('template_id');
|
|
281
|
+
const all = await zyphr.templates.listTemplates(20, 0);
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
### Webhooks — `zyphr.webhooks`
|
|
285
|
+
|
|
286
|
+
Configure webhook endpoints, monitor deliveries, and manage circuit breakers.
|
|
287
|
+
|
|
288
|
+
```ts
|
|
289
|
+
// Create webhook
|
|
290
|
+
const webhook = await zyphr.webhooks.createWebhook({
|
|
291
|
+
url: 'https://api.example.com/webhooks',
|
|
292
|
+
events: ['email.delivered', 'email.bounced', 'subscriber.created'],
|
|
293
|
+
active: true,
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
// Delivery management
|
|
297
|
+
const deliveries = await zyphr.webhooks.listWebhookDeliveries(
|
|
298
|
+
'webhook_id', 'failed', undefined, undefined, undefined, undefined, 20, 0
|
|
299
|
+
);
|
|
300
|
+
await zyphr.webhooks.retryWebhookDelivery('webhook_id', 'delivery_id');
|
|
301
|
+
await zyphr.webhooks.bulkRetryWebhookDeliveries('webhook_id', {
|
|
302
|
+
status: 'failed', startDate: new Date('2026-01-01'),
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
// Replay events
|
|
306
|
+
await zyphr.webhooks.replayWebhookEvents('webhook_id', {
|
|
307
|
+
startDate: new Date('2026-01-01'), endDate: new Date('2026-01-02'),
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
// Testing
|
|
311
|
+
await zyphr.webhooks.sendWebhookTestEvent('webhook_id', {
|
|
312
|
+
eventType: 'email.delivered',
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
// Metrics and health
|
|
316
|
+
const metrics = await zyphr.webhooks.getWebhookMetrics('webhook_id');
|
|
317
|
+
const circuit = await zyphr.webhooks.getWebhookCircuitState('webhook_id');
|
|
318
|
+
await zyphr.webhooks.closeWebhookCircuit('webhook_id');
|
|
319
|
+
|
|
320
|
+
// Secret rotation
|
|
321
|
+
await zyphr.webhooks.rotateWebhookSecret('webhook_id');
|
|
322
|
+
|
|
323
|
+
// Metadata
|
|
324
|
+
const eventTypes = await zyphr.webhooks.listWebhookEventTypes();
|
|
325
|
+
const versions = await zyphr.webhooks.listWebhookVersions();
|
|
326
|
+
const ips = await zyphr.webhooks.getWebhookIps();
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
### Topics — `zyphr.topics`
|
|
330
|
+
|
|
331
|
+
Group subscribers by interest for targeted notifications.
|
|
332
|
+
|
|
333
|
+
```ts
|
|
334
|
+
// Create topic
|
|
335
|
+
await zyphr.topics.createTopic({
|
|
336
|
+
key: 'product-updates',
|
|
337
|
+
name: 'Product Updates',
|
|
338
|
+
description: 'New features and releases',
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
// Manage subscribers
|
|
342
|
+
await zyphr.topics.addTopicSubscribers('product-updates', {
|
|
343
|
+
subscriberIds: ['sub_123', 'sub_456'],
|
|
344
|
+
});
|
|
345
|
+
await zyphr.topics.removeTopicSubscribers('product-updates', ['sub_789']);
|
|
346
|
+
|
|
347
|
+
// CRUD
|
|
348
|
+
const topic = await zyphr.topics.getTopic('product-updates');
|
|
349
|
+
await zyphr.topics.updateTopic('product-updates', { name: 'Product News' });
|
|
350
|
+
await zyphr.topics.deleteTopic('old-topic');
|
|
351
|
+
const topics = await zyphr.topics.listTopics(50, 0);
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
### Devices — `zyphr.devices`
|
|
355
|
+
|
|
356
|
+
Register and manage push notification devices.
|
|
357
|
+
|
|
358
|
+
```ts
|
|
359
|
+
// Register device
|
|
360
|
+
const device = await zyphr.devices.registerDevice({
|
|
361
|
+
userId: 'user_123',
|
|
362
|
+
platform: 'ios',
|
|
363
|
+
pushToken: 'apns_token_xxx',
|
|
364
|
+
deviceName: 'iPhone 16 Pro',
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
// List devices
|
|
368
|
+
const devices = await zyphr.devices.listDevices('user_123', 'ios', 20, 0);
|
|
369
|
+
|
|
370
|
+
// Stats
|
|
371
|
+
const stats = await zyphr.devices.getDeviceStats();
|
|
372
|
+
|
|
373
|
+
// Cleanup
|
|
374
|
+
await zyphr.devices.deleteDevice('device_id');
|
|
375
|
+
await zyphr.devices.deleteUserDevices('user_123');
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
### Authentication — `zyphr.auth.*`
|
|
379
|
+
|
|
380
|
+
Full authentication API with login, registration, MFA, magic links, OAuth, and more.
|
|
381
|
+
|
|
382
|
+
```ts
|
|
383
|
+
// Login
|
|
384
|
+
const session = await zyphr.auth.login.loginEndUser({
|
|
385
|
+
email: 'user@example.com',
|
|
386
|
+
password: 'secure_password',
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
// Registration
|
|
390
|
+
await zyphr.auth.registration.registerUser({
|
|
391
|
+
email: 'new@example.com',
|
|
392
|
+
password: 'secure_password',
|
|
393
|
+
name: 'New User',
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
// Email verification
|
|
397
|
+
await zyphr.auth.emailVerification.sendVerification('user@example.com');
|
|
398
|
+
|
|
399
|
+
// Password reset
|
|
400
|
+
await zyphr.auth.passwordReset.requestReset('user@example.com');
|
|
401
|
+
|
|
402
|
+
// Magic links
|
|
403
|
+
await zyphr.auth.magicLinks.sendMagicLink('user@example.com');
|
|
404
|
+
|
|
405
|
+
// MFA
|
|
406
|
+
const mfaStatus = await zyphr.auth.mfa.getMfaStatus();
|
|
407
|
+
await zyphr.auth.mfa.enrollMfa({ method: 'totp' });
|
|
408
|
+
|
|
409
|
+
// User profile
|
|
410
|
+
const profile = await zyphr.auth.profile.getProfile();
|
|
411
|
+
await zyphr.auth.profile.updateProfile({ name: 'Updated Name' });
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
**Available auth modules:** `login`, `registration`, `sessions`, `emailVerification`, `passwordReset`, `magicLinks`, `mfa`, `oauth`, `phone`, `webauthn`, `profile`.
|
|
415
|
+
|
|
416
|
+
### WaaS — `zyphr.waas.*`
|
|
417
|
+
|
|
418
|
+
Webhooks-as-a-Service: multi-tenant webhook delivery infrastructure for your customers.
|
|
419
|
+
|
|
420
|
+
```ts
|
|
421
|
+
// Create a WaaS application
|
|
422
|
+
const app = await zyphr.waas.applications.createWaaSApplication({
|
|
423
|
+
name: 'My SaaS',
|
|
424
|
+
description: 'Webhook delivery for My SaaS customers',
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
// Define event types
|
|
428
|
+
await zyphr.waas.eventTypes.createEventType(app.data.id, {
|
|
429
|
+
eventType: 'order.created',
|
|
430
|
+
name: 'Order Created',
|
|
431
|
+
description: 'Fired when a new order is placed',
|
|
432
|
+
examplePayload: { order_id: '123', total: 99.99 },
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
// Send events to all subscribed endpoints
|
|
436
|
+
await zyphr.waas.events.sendEvent(app.data.id, {
|
|
437
|
+
eventType: 'order.created',
|
|
438
|
+
payload: { order_id: '456', total: 149.99 },
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
// Generate portal token for embedded UI
|
|
442
|
+
const portalToken = await zyphr.waas.portal.getPortalToken(app.data.id);
|
|
443
|
+
// Pass this token to @zyphr-dev/webhook-portal
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
**Available WaaS modules:** `applications`, `eventTypes`, `endpoints`, `events`, `deliveries`, `portal`.
|
|
67
447
|
|
|
68
448
|
## Error Handling
|
|
69
449
|
|
|
@@ -80,41 +460,50 @@ import {
|
|
|
80
460
|
} from '@zyphr-dev/node-sdk';
|
|
81
461
|
|
|
82
462
|
try {
|
|
83
|
-
await zyphr.subscribers.
|
|
463
|
+
await zyphr.subscribers.getSubscriber('non_existent_id');
|
|
84
464
|
} catch (error) {
|
|
85
465
|
if (error instanceof ZyphrNotFoundError) {
|
|
86
|
-
console.log('Not found:', error.message);
|
|
466
|
+
console.log('Not found:', error.message); // 404
|
|
87
467
|
} else if (error instanceof ZyphrValidationError) {
|
|
88
|
-
console.log('Invalid input:', error.details);
|
|
468
|
+
console.log('Invalid input:', error.details); // 400/422
|
|
89
469
|
} else if (error instanceof ZyphrAuthenticationError) {
|
|
90
|
-
console.log('Check your API key');
|
|
470
|
+
console.log('Check your API key'); // 401/403
|
|
91
471
|
} else if (error instanceof ZyphrRateLimitError) {
|
|
92
|
-
console.log('Retry after:', error.retryAfter);
|
|
472
|
+
console.log('Retry after:', error.retryAfter); // 429
|
|
93
473
|
} else if (error instanceof ZyphrError) {
|
|
94
474
|
console.log('API error:', error.status, error.code);
|
|
95
475
|
}
|
|
96
476
|
}
|
|
97
477
|
```
|
|
98
478
|
|
|
99
|
-
|
|
479
|
+
### Error Properties
|
|
100
480
|
|
|
101
|
-
|
|
102
|
-
- `code` — Machine-readable error code
|
|
103
|
-
- `requestId` — Request ID for support
|
|
104
|
-
- `details` — Additional error context (validation errors)
|
|
481
|
+
All error classes extend `ZyphrError`, which extends `Error`:
|
|
105
482
|
|
|
106
|
-
|
|
483
|
+
| Property | Type | Description |
|
|
484
|
+
|----------|------|-------------|
|
|
485
|
+
| `status` | `number` | HTTP status code |
|
|
486
|
+
| `code` | `string \| undefined` | Machine-readable error code |
|
|
487
|
+
| `requestId` | `string \| undefined` | Request ID for support tickets |
|
|
488
|
+
| `details` | `Record<string, unknown> \| undefined` | Validation errors and context |
|
|
489
|
+
| `retryAfter` | `number \| undefined` | Seconds to wait (`ZyphrRateLimitError` only) |
|
|
107
490
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
491
|
+
## Bundle
|
|
492
|
+
|
|
493
|
+
Dual-format build — works with both ESM and CommonJS:
|
|
494
|
+
|
|
495
|
+
- **ESM:** `dist/index.js`
|
|
496
|
+
- **CommonJS:** `dist/index.cjs`
|
|
497
|
+
- **Types:** `dist/index.d.ts`
|
|
498
|
+
|
|
499
|
+
Zero runtime dependencies.
|
|
114
500
|
|
|
115
|
-
##
|
|
501
|
+
## Related Packages
|
|
116
502
|
|
|
117
|
-
|
|
503
|
+
| Package | Description |
|
|
504
|
+
|---------|-------------|
|
|
505
|
+
| [`@zyphr-dev/inbox-react`](https://www.npmjs.com/package/@zyphr-dev/inbox-react) | Drop-in React notification inbox components |
|
|
506
|
+
| [`@zyphr-dev/webhook-portal`](https://www.npmjs.com/package/@zyphr-dev/webhook-portal) | Embeddable webhook management portal |
|
|
118
507
|
|
|
119
508
|
## License
|
|
120
509
|
|