@zindua/sdk 1.2.2 → 1.2.4
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 +254 -135
- package/dist/client.d.ts +30 -0
- package/dist/client.js +20 -3
- package/dist/index.d.ts +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,217 +1,350 @@
|
|
|
1
1
|
# @zindua/sdk
|
|
2
2
|
|
|
3
|
-
Official **server-side** SDK for [Zindua](https://zindua.run):
|
|
3
|
+
Official **server-side** SDK for [Zindua](https://zindua.run): send transactional **email** and **WhatsApp** messages with one API.
|
|
4
4
|
|
|
5
|
-
|
|
|
6
|
-
|
|
7
|
-
|
|
|
8
|
-
|
|
|
9
|
-
| Pricing
|
|
10
|
-
| Dashboard | [zindua.run/login](https://zindua.run/login) |
|
|
5
|
+
| | |
|
|
6
|
+
|---|---|
|
|
7
|
+
| Full API reference | [zindua.run/developers](https://zindua.run/developers) |
|
|
8
|
+
| Dashboard (keys, templates, services) | [zindua.run/login](https://zindua.run/login) |
|
|
9
|
+
| Pricing | [zindua.run/pricing](https://zindua.run/pricing) |
|
|
11
10
|
|
|
12
|
-
|
|
11
|
+
```bash
|
|
12
|
+
npm install @zindua/sdk
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
**Requirements:** Node.js 18+, run only on your **backend** (not in the browser).
|
|
13
16
|
|
|
14
17
|
---
|
|
15
18
|
|
|
16
|
-
##
|
|
19
|
+
## Quick start
|
|
20
|
+
|
|
21
|
+
### 1. Create a Zindua project
|
|
22
|
+
|
|
23
|
+
1. Sign in at [zindua.run/login](https://zindua.run/login).
|
|
24
|
+
2. Open **Projects** → create a project (or use an existing one).
|
|
25
|
+
3. Copy the API key (`znd_live_…` for production, `znd_test_…` for sandbox).
|
|
26
|
+
4. In the project: connect **Service** (Gmail, SMTP, …) for email, and/or link **WhatsApp** for OTP.
|
|
27
|
+
5. Create at least one **template** (e.g. slug `otp`, `welcome`).
|
|
17
28
|
|
|
18
|
-
|
|
29
|
+
### 2. Install and configure
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npm install @zindua/sdk
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
# .env — never commit real keys; never expose in frontend code
|
|
37
|
+
ZINDUA_API_KEY=znd_live_xxxxxxxxxxxxxxxxxxxxxxxx
|
|
38
|
+
```
|
|
19
39
|
|
|
20
|
-
|
|
40
|
+
```typescript
|
|
41
|
+
import { Zindua } from "@zindua/sdk";
|
|
21
42
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
| **Team** | 1000 | 100 |
|
|
43
|
+
export const zindua = new Zindua({
|
|
44
|
+
apiKey: process.env.ZINDUA_API_KEY!,
|
|
45
|
+
});
|
|
46
|
+
```
|
|
27
47
|
|
|
28
|
-
|
|
48
|
+
### 3. Send a message
|
|
29
49
|
|
|
30
50
|
```typescript
|
|
31
|
-
//
|
|
51
|
+
// Email (default channel)
|
|
32
52
|
await zindua.send({
|
|
33
53
|
to: "user@example.com",
|
|
34
54
|
template: "welcome",
|
|
35
|
-
lang: "fr",
|
|
36
55
|
variables: { name: "Alex" },
|
|
37
56
|
});
|
|
38
57
|
|
|
39
|
-
// WhatsApp
|
|
58
|
+
// WhatsApp — phone in E.164 with +
|
|
40
59
|
await zindua.send({
|
|
41
60
|
to: "+243812345678",
|
|
42
61
|
channel: "whatsapp",
|
|
43
|
-
template: "otp
|
|
44
|
-
|
|
45
|
-
variables: { code: "4592", app: "MonApp" },
|
|
62
|
+
template: "otp",
|
|
63
|
+
variables: { code: "482910" },
|
|
46
64
|
});
|
|
47
65
|
```
|
|
48
66
|
|
|
49
67
|
---
|
|
50
68
|
|
|
51
|
-
##
|
|
69
|
+
## Plans and channels
|
|
52
70
|
|
|
53
|
-
|
|
71
|
+
| Plan | Email API | WhatsApp | Email / month | WhatsApp OTP / month |
|
|
72
|
+
|------|-----------|----------|---------------|----------------------|
|
|
73
|
+
| **Free** | Yes, if a **Service** is connected on the project | Yes | 25,000 | 200 |
|
|
74
|
+
| **Pro** | Yes | Yes | 160,000 | 20,000 |
|
|
75
|
+
| **Team** | Yes | Yes | High volume | Unlimited |
|
|
54
76
|
|
|
55
|
-
|
|
56
|
-
|-------------|--------------|--------|
|
|
57
|
-
| Zindua account | All | [Sign up / login](https://zindua.run/login) |
|
|
58
|
-
| Project + API key (`znd_live_…` or `znd_test_…`) | All | Dashboard → **Projects** → your project |
|
|
59
|
-
| Email **Service** connected (Gmail, Outlook, SendGrid, SMTP, …) | `channel: "email"` | Dashboard → **Service** |
|
|
60
|
-
| WhatsApp connected (QR) | `channel: "whatsapp"` | Dashboard → **WhatsApp** |
|
|
61
|
-
| Template slug (e.g. `welcome`, `otp-verification`) | All | Dashboard → **Templates** |
|
|
62
|
-
| **Pro** or **Team** plan | Email API on production sends (Free = WhatsApp OTP API) | Dashboard → **Billing** |
|
|
77
|
+
On **Free**, email works through **your** connected provider (Gmail, SMTP, etc.). **Pro** and **Team** raise template counts and monthly limits. Details: [pricing](https://zindua.run/pricing).
|
|
63
78
|
|
|
64
|
-
|
|
79
|
+
| | Free | Pro / Team |
|
|
80
|
+
|---|------|------------|
|
|
81
|
+
| Templates per project | 5 | 50+ |
|
|
82
|
+
| Languages per template | 3 | 10+ |
|
|
65
83
|
|
|
66
|
-
|
|
67
|
-
- **Server only** — do not bundle this package for the browser (see [Mobile & SPA](#mobile--spa))
|
|
84
|
+
Use `znd_test_…` keys to try the API without consuming live quota (sandbox behaviour).
|
|
68
85
|
|
|
69
86
|
---
|
|
70
87
|
|
|
71
|
-
##
|
|
88
|
+
## One project or several?
|
|
72
89
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
90
|
+
| Setup | When it fits |
|
|
91
|
+
|-------|----------------|
|
|
92
|
+
| **One Zindua project, one API key** | One product, one sender, shared templates and quota. |
|
|
93
|
+
| **Several Zindua projects, one key each** | Several clients or brands: separate templates, Gmail accounts, logs, and quotas. |
|
|
76
94
|
|
|
77
|
-
|
|
78
|
-
yarn add @zindua/sdk
|
|
79
|
-
```
|
|
95
|
+
### Several keys in one backend
|
|
80
96
|
|
|
81
97
|
```bash
|
|
82
|
-
|
|
98
|
+
ZINDUA_KEY_CLIENT_A=znd_live_aaaaaaaaaaaaaaaaaaaaaaaa
|
|
99
|
+
ZINDUA_KEY_CLIENT_B=znd_live_bbbbbbbbbbbbbbbbbbbbbbbb
|
|
83
100
|
```
|
|
84
101
|
|
|
85
|
-
|
|
102
|
+
```typescript
|
|
103
|
+
import { Zindua } from "@zindua/sdk";
|
|
104
|
+
|
|
105
|
+
const clients = {
|
|
106
|
+
clientA: new Zindua({ apiKey: process.env.ZINDUA_KEY_CLIENT_A! }),
|
|
107
|
+
clientB: new Zindua({ apiKey: process.env.ZINDUA_KEY_CLIENT_B! }),
|
|
108
|
+
};
|
|
86
109
|
|
|
87
|
-
|
|
110
|
+
await clients.clientA.send({
|
|
111
|
+
to: "user@example.com",
|
|
112
|
+
template: "otp",
|
|
113
|
+
variables: { code: "123456" },
|
|
114
|
+
});
|
|
115
|
+
```
|
|
88
116
|
|
|
89
|
-
|
|
117
|
+
Each key only accesses **its** Zindua project (templates, service, usage).
|
|
90
118
|
|
|
91
|
-
|
|
119
|
+
---
|
|
92
120
|
|
|
93
|
-
|
|
94
|
-
# .env (example — load with dotenv or your framework)
|
|
95
|
-
ZINDUA_API_KEY=znd_live_xxxxxxxxxxxxxxxxxxxxxxxx
|
|
96
|
-
```
|
|
121
|
+
## Framework examples
|
|
97
122
|
|
|
98
|
-
|
|
123
|
+
Use the same pattern everywhere: **your server** holds the API key; the client app calls **your** API.
|
|
99
124
|
|
|
100
|
-
###
|
|
125
|
+
### Next.js (App Router)
|
|
101
126
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
| Constructor `baseUrl` | env or default | Overrides env; must be **HTTPS** in production (`http://localhost` allowed for local dev) |
|
|
127
|
+
```typescript
|
|
128
|
+
// lib/zindua.ts
|
|
129
|
+
import { Zindua } from "@zindua/sdk";
|
|
106
130
|
|
|
107
|
-
|
|
131
|
+
export const zindua = new Zindua({ apiKey: process.env.ZINDUA_API_KEY! });
|
|
132
|
+
```
|
|
108
133
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
134
|
+
```typescript
|
|
135
|
+
// app/api/notify/route.ts
|
|
136
|
+
import { zindua } from "@/lib/zindua";
|
|
137
|
+
import { NextResponse } from "next/server";
|
|
138
|
+
|
|
139
|
+
export async function POST(req: Request) {
|
|
140
|
+
const { email, code } = await req.json();
|
|
141
|
+
const result = await zindua.send({
|
|
142
|
+
to: email,
|
|
143
|
+
template: "otp",
|
|
144
|
+
variables: { code },
|
|
145
|
+
});
|
|
146
|
+
return NextResponse.json(result, { status: 202 });
|
|
147
|
+
}
|
|
148
|
+
```
|
|
112
149
|
|
|
113
|
-
###
|
|
150
|
+
### Express
|
|
114
151
|
|
|
115
152
|
```typescript
|
|
153
|
+
import express from "express";
|
|
116
154
|
import { Zindua } from "@zindua/sdk";
|
|
117
155
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
156
|
+
const app = express();
|
|
157
|
+
app.use(express.json());
|
|
158
|
+
|
|
159
|
+
const zindua = new Zindua({ apiKey: process.env.ZINDUA_API_KEY! });
|
|
160
|
+
|
|
161
|
+
app.post("/api/notify", async (req, res) => {
|
|
162
|
+
try {
|
|
163
|
+
const result = await zindua.send({
|
|
164
|
+
to: req.body.email,
|
|
165
|
+
template: req.body.template ?? "otp",
|
|
166
|
+
variables: req.body.variables ?? {},
|
|
167
|
+
});
|
|
168
|
+
res.status(202).json(result);
|
|
169
|
+
} catch (err) {
|
|
170
|
+
res.status(500).json({ error: "Send failed" });
|
|
171
|
+
}
|
|
122
172
|
});
|
|
123
173
|
```
|
|
124
174
|
|
|
125
|
-
|
|
175
|
+
### Fastify
|
|
126
176
|
|
|
127
|
-
|
|
177
|
+
```typescript
|
|
178
|
+
import Fastify from "fastify";
|
|
179
|
+
import { Zindua } from "@zindua/sdk";
|
|
128
180
|
|
|
129
|
-
|
|
181
|
+
const zindua = new Zindua({ apiKey: process.env.ZINDUA_API_KEY! });
|
|
182
|
+
const app = Fastify();
|
|
130
183
|
|
|
131
|
-
|
|
132
|
-
await zindua.send({
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
184
|
+
app.post<{ Body: { email: string; code: string } }>("/notify", async (req, reply) => {
|
|
185
|
+
const result = await zindua.send({
|
|
186
|
+
to: req.body.email,
|
|
187
|
+
template: "otp",
|
|
188
|
+
variables: { code: req.body.code },
|
|
189
|
+
});
|
|
190
|
+
return reply.status(202).send(result);
|
|
136
191
|
});
|
|
137
192
|
```
|
|
138
193
|
|
|
139
|
-
###
|
|
140
|
-
|
|
141
|
-
Phone numbers must be **E.164** with a leading `+` (e.g. `+243812345678`).
|
|
194
|
+
### Hono
|
|
142
195
|
|
|
143
196
|
```typescript
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
197
|
+
import { Hono } from "hono";
|
|
198
|
+
import { Zindua } from "@zindua/sdk";
|
|
199
|
+
|
|
200
|
+
const zindua = new Zindua({ apiKey: process.env.ZINDUA_API_KEY! });
|
|
201
|
+
const app = new Hono();
|
|
202
|
+
|
|
203
|
+
app.post("/notify", async (c) => {
|
|
204
|
+
const { email, code } = await c.req.json();
|
|
205
|
+
const result = await zindua.send({
|
|
206
|
+
to: email,
|
|
207
|
+
template: "otp",
|
|
208
|
+
variables: { code },
|
|
209
|
+
});
|
|
210
|
+
return c.json(result, 202);
|
|
149
211
|
});
|
|
150
212
|
```
|
|
151
213
|
|
|
152
|
-
###
|
|
214
|
+
### Mobile apps (React Native, Flutter)
|
|
215
|
+
|
|
216
|
+
Do **not** embed `@zindua/sdk` or `znd_live_…` in the app. Call your backend route above from the device.
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## Configuration options
|
|
221
|
+
|
|
222
|
+
| Option | Default | Description |
|
|
223
|
+
|--------|---------|-------------|
|
|
224
|
+
| `apiKey` | — | **Required.** `znd_live_…` or `znd_test_…` from the dashboard. |
|
|
225
|
+
| `baseUrl` | `https://zindua.run/api/v1` | Override only for local testing (`http://localhost:3000/api/v1`). |
|
|
226
|
+
| `timeoutMs` | `30000` | Request timeout (max `120000`). |
|
|
153
227
|
|
|
154
228
|
```typescript
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
cc: "billing@example.com",
|
|
160
|
-
replyTo: "support@example.com",
|
|
161
|
-
variables: { amount: "99" },
|
|
229
|
+
const zindua = new Zindua({
|
|
230
|
+
apiKey: process.env.ZINDUA_API_KEY!,
|
|
231
|
+
baseUrl: process.env.ZINDUA_API_BASE_URL, // optional
|
|
232
|
+
timeoutMs: 45_000,
|
|
162
233
|
});
|
|
163
234
|
```
|
|
164
235
|
|
|
165
|
-
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
## Send options
|
|
239
|
+
|
|
240
|
+
| Field | Required | Description |
|
|
241
|
+
|-------|----------|-------------|
|
|
242
|
+
| `to` | Yes | Email address, or E.164 phone (`+243…`) for WhatsApp. |
|
|
243
|
+
| `template` | Yes | Template slug from your dashboard. |
|
|
244
|
+
| `channel` | No | `"email"` (default) or `"whatsapp"`. |
|
|
245
|
+
| `lang` | No | `fr`, `en`, … — falls back to project default. |
|
|
246
|
+
| `variables` | No | `{{placeholders}}` in the template. |
|
|
247
|
+
| `cc`, `bcc`, `replyTo` | No | Email only. |
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
251
|
+
## Successful response
|
|
166
252
|
|
|
167
253
|
```typescript
|
|
168
254
|
const result = await zindua.send({ /* … */ });
|
|
169
|
-
// { success: true, status: "queued", logId: "…", channel: "email" | "whatsapp", … }
|
|
170
255
|
```
|
|
171
256
|
|
|
257
|
+
| Field | Meaning |
|
|
258
|
+
|-------|---------|
|
|
259
|
+
| `success` | `true` |
|
|
260
|
+
| `status` | `queued`, `processing`, or `sent` (test keys often return `sent` immediately). |
|
|
261
|
+
| `logId` | Id for support / logs in the dashboard. |
|
|
262
|
+
| `channel` | `email` or `whatsapp` |
|
|
263
|
+
| `context` | Workspace snapshot (see below). |
|
|
264
|
+
|
|
265
|
+
### `context` object
|
|
266
|
+
|
|
267
|
+
The API returns metadata so you can log or debug without exposing secrets:
|
|
268
|
+
|
|
269
|
+
```json
|
|
270
|
+
{
|
|
271
|
+
"context": {
|
|
272
|
+
"project": { "name": "My App", "slug": "my-app" },
|
|
273
|
+
"apiKey": { "mode": "live", "suffix": "ejho" },
|
|
274
|
+
"plan": { "slug": "free", "name": "Free", "emailQuota": 25000, "emailsUsed": 12 },
|
|
275
|
+
"channels": { "email": true, "whatsapp": false }
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
- **`context.apiKey.suffix`** — last 4 characters of the key (match in the dashboard).
|
|
281
|
+
- **`context.plan`** — current plan and usage for the workspace linked to this key.
|
|
282
|
+
- **`context.channels`** — whether email / WhatsApp is ready for this project.
|
|
283
|
+
|
|
284
|
+
The full API key is **never** returned in responses.
|
|
285
|
+
|
|
172
286
|
---
|
|
173
287
|
|
|
174
288
|
## Errors
|
|
175
289
|
|
|
290
|
+
Wrap sends in `try/catch` and handle `ZinduaError`:
|
|
291
|
+
|
|
176
292
|
```typescript
|
|
177
293
|
import { Zindua, ZinduaError } from "@zindua/sdk";
|
|
178
294
|
|
|
179
295
|
try {
|
|
180
|
-
await zindua.send({ to: "
|
|
296
|
+
await zindua.send({ to: "user@example.com", template: "otp", variables: { code: "1" } });
|
|
181
297
|
} catch (e) {
|
|
182
298
|
if (e instanceof ZinduaError) {
|
|
183
|
-
console.
|
|
184
|
-
//
|
|
299
|
+
console.log(e.status); // HTTP status
|
|
300
|
+
console.log(e.code); // machine-readable code
|
|
301
|
+
console.log(e.message); // human-readable
|
|
302
|
+
console.log(e.details); // optional: hint, context, retryAfterSec, …
|
|
185
303
|
}
|
|
186
|
-
throw e;
|
|
187
304
|
}
|
|
188
305
|
```
|
|
189
306
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
307
|
+
### Error codes
|
|
308
|
+
|
|
309
|
+
| Code | HTTP | What it means | What to do |
|
|
310
|
+
|------|------|---------------|------------|
|
|
311
|
+
| `INVALID_API_KEY` | 401 | Missing or malformed key. | Use `Authorization: Bearer znd_live_…` (24 chars after prefix). |
|
|
312
|
+
| `API_KEY_NOT_FOUND` | 401 | Key not linked to a project. | Copy the key from Dashboard → your project. |
|
|
313
|
+
| `ORIGIN_NOT_ALLOWED` | 403 | Browser origin blocked. | Prefer server-side SDK; or add origin in Dashboard → Settings → Integrations. |
|
|
314
|
+
| `MISSING_FIELDS` | 400 | `to` or `template` missing. | Send both in the request body. |
|
|
315
|
+
| `INVALID_EMAIL` | 400 | Bad email format. | Use `user@domain.com`. |
|
|
316
|
+
| `INVALID_PHONE` | 400 | Bad WhatsApp number. | Use E.164 with `+`, e.g. `+243812345678`. |
|
|
317
|
+
| `NO_SUBSCRIPTION` | 403 | Workspace has no active plan. | Open Dashboard → Billing or contact support. |
|
|
318
|
+
| `EMAIL_NOT_AVAILABLE` | 403 | Email not allowed on current plan setup. | Connect a Service on the project (Free), or upgrade plan. |
|
|
319
|
+
| `EMAIL_SERVICE_NOT_CONFIGURED` | 422 | No Gmail/SMTP connected. | Dashboard → project → **Service**. |
|
|
320
|
+
| `QUOTA_EXCEEDED` | 429 | Monthly email limit reached. | Upgrade plan or wait for reset. |
|
|
321
|
+
| `WHATSAPP_NOT_AVAILABLE` | 403 | WhatsApp not on plan. | Check [pricing](https://zindua.run/pricing). |
|
|
322
|
+
| `WHATSAPP_NOT_CONNECTED` | 422 | WhatsApp not linked. | Dashboard → project → **WhatsApp** → scan QR. |
|
|
323
|
+
| `WHATSAPP_PAUSED` | 422 | WhatsApp session paused. | Resume in the dashboard. |
|
|
324
|
+
| `WHATSAPP_QUOTA_EXCEEDED` | 429 | Monthly WhatsApp limit reached. | Upgrade or wait. |
|
|
325
|
+
| `RATE_LIMIT_EXCEEDED` | 429 | Sending too fast (WhatsApp). | Wait `retryAfterSec` from `e.details`, then retry. |
|
|
326
|
+
| `TEMPLATE_NOT_FOUND` | 404 | Unknown template slug. | Create template or fix slug; check `availableTemplateSlugs` in details. |
|
|
327
|
+
| `TEMPLATE_NO_CONTENT` | 404 | Template has no language version. | Add content in Dashboard → Templates. |
|
|
328
|
+
| `TEMPLATE_NO_WHATSAPP_BODY` | 422 | No plain text for WhatsApp. | Add a text body for that language. |
|
|
329
|
+
| `QUEUE_UNAVAILABLE` | 503 | Temporary delivery queue issue. | Retry shortly; contact support if it persists. |
|
|
330
|
+
| `BROWSER_FORBIDDEN` | — | SDK used in browser. | Move the call to your backend. |
|
|
331
|
+
| `REQUEST_TIMEOUT` | — | Request exceeded `timeoutMs`. | Increase timeout or retry. |
|
|
332
|
+
|
|
333
|
+
Many errors include a **`context`** field (same shape as success) with `plan` and `project` to help you debug.
|
|
201
334
|
|
|
202
335
|
---
|
|
203
336
|
|
|
204
|
-
##
|
|
337
|
+
## Best practices
|
|
205
338
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
339
|
+
1. Store the API key in environment variables or a secrets manager.
|
|
340
|
+
2. Call Zindua from your **API routes** only, not from React/Vue/mobile bundles.
|
|
341
|
+
3. Use **`znd_test_…`** in staging; **`znd_live_…`** in production.
|
|
342
|
+
4. Pin the SDK version in `package.json`, e.g. `"@zindua/sdk": "1.2.4"`.
|
|
343
|
+
5. One Zindua project per client when quotas, senders, or templates must stay isolated.
|
|
209
344
|
|
|
210
345
|
---
|
|
211
346
|
|
|
212
|
-
##
|
|
213
|
-
|
|
214
|
-
Any language can call the same endpoint:
|
|
347
|
+
## Without the SDK (HTTP)
|
|
215
348
|
|
|
216
349
|
```bash
|
|
217
350
|
curl -X POST https://zindua.run/api/v1/send \
|
|
@@ -220,34 +353,20 @@ curl -X POST https://zindua.run/api/v1/send \
|
|
|
220
353
|
-d '{"to":"user@example.com","template":"welcome","variables":{"name":"Alex"}}'
|
|
221
354
|
```
|
|
222
355
|
|
|
223
|
-
|
|
356
|
+
See [HTTP / cURL](https://zindua.run/developers#http).
|
|
224
357
|
|
|
225
358
|
---
|
|
226
359
|
|
|
227
|
-
## API
|
|
360
|
+
## API reference
|
|
228
361
|
|
|
229
362
|
| Export | Description |
|
|
230
363
|
|--------|-------------|
|
|
231
364
|
| `Zindua` | Client class |
|
|
232
|
-
| `ZinduaError` |
|
|
365
|
+
| `ZinduaError` | Error type (`status`, `code`, `message`, `details`) |
|
|
366
|
+
| `ZinduaSendResult` | Success payload type |
|
|
367
|
+
| `ZinduaSendContext` | Type of `result.context` |
|
|
233
368
|
| `DEFAULT_API_BASE` | `https://zindua.run/api/v1` |
|
|
234
|
-
| `LIMITS` |
|
|
235
|
-
|
|
236
|
-
---
|
|
237
|
-
|
|
238
|
-
## Local development (monorepo)
|
|
239
|
-
|
|
240
|
-
```bash
|
|
241
|
-
cd packages/zindua-js
|
|
242
|
-
npm run build
|
|
243
|
-
npm test
|
|
244
|
-
```
|
|
245
|
-
|
|
246
|
-
From the app repo root:
|
|
247
|
-
|
|
248
|
-
```bash
|
|
249
|
-
npm install file:./packages/zindua-js
|
|
250
|
-
```
|
|
369
|
+
| `LIMITS` | Client-side validation limits |
|
|
251
370
|
|
|
252
371
|
---
|
|
253
372
|
|
package/dist/client.d.ts
CHANGED
|
@@ -17,6 +17,34 @@ export type ZinduaClientOptions = {
|
|
|
17
17
|
/** Request timeout (default 30s, max 120s). */
|
|
18
18
|
timeoutMs?: number;
|
|
19
19
|
};
|
|
20
|
+
export type ZinduaSendContext = {
|
|
21
|
+
project: {
|
|
22
|
+
id: string;
|
|
23
|
+
name: string;
|
|
24
|
+
slug: string;
|
|
25
|
+
teamId: string;
|
|
26
|
+
};
|
|
27
|
+
apiKey: {
|
|
28
|
+
mode: "live" | "test";
|
|
29
|
+
prefix: string;
|
|
30
|
+
suffix: string;
|
|
31
|
+
};
|
|
32
|
+
plan: {
|
|
33
|
+
slug: string;
|
|
34
|
+
name: string;
|
|
35
|
+
status: string;
|
|
36
|
+
emailApiEnabled: boolean;
|
|
37
|
+
whatsappEnabled: boolean;
|
|
38
|
+
emailQuota: number;
|
|
39
|
+
emailsUsed: number;
|
|
40
|
+
whatsappOtpQuota: number | null;
|
|
41
|
+
whatsappUsed: number;
|
|
42
|
+
} | null;
|
|
43
|
+
channels: {
|
|
44
|
+
email: boolean;
|
|
45
|
+
whatsapp: boolean;
|
|
46
|
+
};
|
|
47
|
+
};
|
|
20
48
|
export type ZinduaSendResult = {
|
|
21
49
|
success: true;
|
|
22
50
|
channel: SendChannel;
|
|
@@ -25,6 +53,8 @@ export type ZinduaSendResult = {
|
|
|
25
53
|
langUsed?: string;
|
|
26
54
|
langFallback?: boolean;
|
|
27
55
|
testMode?: boolean;
|
|
56
|
+
project?: string;
|
|
57
|
+
context?: ZinduaSendContext;
|
|
28
58
|
};
|
|
29
59
|
export declare class Zindua {
|
|
30
60
|
private readonly apiKey;
|
package/dist/client.js
CHANGED
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.Zindua = void 0;
|
|
4
4
|
const errors_1 = require("./errors");
|
|
5
5
|
const validate_1 = require("./validate");
|
|
6
|
-
const SDK_VERSION = "1.2.
|
|
6
|
+
const SDK_VERSION = "1.2.4";
|
|
7
7
|
const USER_AGENT = `Zindua-JS/${SDK_VERSION}`;
|
|
8
8
|
function buildPayload(options, channel) {
|
|
9
9
|
const to = (0, validate_1.validateRecipient)(options.to, channel);
|
|
@@ -46,12 +46,25 @@ function parseApiError(status, body) {
|
|
|
46
46
|
const details = {};
|
|
47
47
|
if (typeof body.code === "string")
|
|
48
48
|
details.code = body.code;
|
|
49
|
+
if (typeof body.hint === "string")
|
|
50
|
+
details.hint = body.hint;
|
|
49
51
|
if (typeof body.retryAfterSec === "number")
|
|
50
52
|
details.retryAfterSec = body.retryAfterSec;
|
|
51
|
-
|
|
53
|
+
if (Array.isArray(body.availableTemplateSlugs)) {
|
|
54
|
+
details.availableTemplateSlugs = body.availableTemplateSlugs;
|
|
55
|
+
}
|
|
56
|
+
if (body.context && typeof body.context === "object") {
|
|
57
|
+
details.context = body.context;
|
|
58
|
+
}
|
|
59
|
+
const fullMessage = typeof body.hint === "string" && body.hint.length > 0 ? `${message} ${body.hint}` : message;
|
|
60
|
+
return new errors_1.ZinduaError(fullMessage, {
|
|
52
61
|
status,
|
|
53
62
|
code: typeof body.code === "string" ? body.code : "API_ERROR",
|
|
54
|
-
details: Object.keys(details).length > 0
|
|
63
|
+
details: Object.keys(details).length > 0
|
|
64
|
+
? details
|
|
65
|
+
: typeof body.hint === "string"
|
|
66
|
+
? { hint: body.hint }
|
|
67
|
+
: undefined,
|
|
55
68
|
});
|
|
56
69
|
}
|
|
57
70
|
class Zindua {
|
|
@@ -115,6 +128,10 @@ class Zindua {
|
|
|
115
128
|
langUsed: typeof data.langUsed === "string" ? data.langUsed : undefined,
|
|
116
129
|
langFallback: typeof data.langFallback === "boolean" ? data.langFallback : undefined,
|
|
117
130
|
testMode: typeof data.testMode === "boolean" ? data.testMode : undefined,
|
|
131
|
+
project: typeof data.project === "string" ? data.project : undefined,
|
|
132
|
+
context: data.context && typeof data.context === "object"
|
|
133
|
+
? data.context
|
|
134
|
+
: undefined,
|
|
118
135
|
};
|
|
119
136
|
}
|
|
120
137
|
catch (err) {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { Zindua } from "./client";
|
|
2
|
-
export type { ZinduaClientOptions, ZinduaSendOptions, ZinduaSendResult, SendChannel, } from "./client";
|
|
2
|
+
export type { ZinduaClientOptions, ZinduaSendContext, ZinduaSendOptions, ZinduaSendResult, SendChannel, } from "./client";
|
|
3
3
|
export { ZinduaError } from "./errors";
|
|
4
4
|
export type { ZinduaErrorCode } from "./errors";
|
|
5
5
|
export { DEFAULT_API_BASE, LIMITS } from "./validate";
|