@ecodrix/erix-api 1.0.4 → 1.0.6
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 +540 -241
- package/dist/cli.js +1 -1
- package/dist/index.d.ts +10 -0
- package/dist/ts/browser/index.global.js +1 -1
- package/dist/ts/browser/index.global.js.map +1 -1
- package/dist/ts/cjs/index.cjs +1 -1
- package/dist/ts/cjs/index.cjs.map +1 -1
- package/dist/ts/cjs/index.d.cts +10 -0
- package/dist/ts/esm/index.d.ts +10 -0
- package/dist/ts/esm/index.js +1 -1
- package/dist/ts/esm/index.js.map +1 -1
- package/package.json +1 -1
- package/src/core.ts +14 -0
package/README.md
CHANGED
|
@@ -6,10 +6,11 @@
|
|
|
6
6
|
[](https://opensource.org/licenses/MIT)
|
|
7
7
|
[](https://www.typescriptlang.org/)
|
|
8
8
|
[](./schema/openapi.yaml)
|
|
9
|
+
[](https://nodejs.org/)
|
|
9
10
|
|
|
10
11
|
**The official, isomorphic SDK for the [ECODrIx](https://ecodrix.com) platform.**
|
|
11
12
|
|
|
12
|
-
Manage WhatsApp conversations, CRM leads, file storage, and Google Meet
|
|
13
|
+
Manage WhatsApp conversations, CRM leads, pipelines, automations, marketing campaigns, file storage, and Google Meet — all from a single, type-safe library.
|
|
13
14
|
|
|
14
15
|
</div>
|
|
15
16
|
|
|
@@ -22,12 +23,30 @@ Manage WhatsApp conversations, CRM leads, file storage, and Google Meet appointm
|
|
|
22
23
|
- [Configuration](#configuration)
|
|
23
24
|
- [Resources](#resources)
|
|
24
25
|
- [WhatsApp](#whatsapp)
|
|
25
|
-
|
|
26
|
+
- [Messages](#ecod-whatsapp-messages)
|
|
27
|
+
- [Conversations](#ecod-whatsapp-conversations)
|
|
28
|
+
- [Templates](#ecod-whatsapp-templates)
|
|
29
|
+
- [Broadcasts](#ecod-whatsapp-broadcasts)
|
|
30
|
+
- [CRM](#crm)
|
|
31
|
+
- [Leads](#ecod-crm-leads)
|
|
32
|
+
- [Pipelines & Stages](#ecod-crm-pipelines)
|
|
33
|
+
- [Automations](#ecod-crm-automations)
|
|
34
|
+
- [Sequences](#ecod-crm-sequences)
|
|
35
|
+
- [Activities & Timeline](#ecod-crm-activities)
|
|
36
|
+
- [Analytics](#ecod-crm-analytics)
|
|
37
|
+
- [Scoring](#ecod-crm-scoring)
|
|
38
|
+
- [Payments](#ecod-crm-payments)
|
|
39
|
+
- [Automation Dashboard](#ecod-crm-automationdashboard)
|
|
40
|
+
- [Events & Workflows](#events--workflows)
|
|
41
|
+
- [Marketing](#marketing)
|
|
26
42
|
- [Meetings](#meetings)
|
|
27
|
-
- [
|
|
43
|
+
- [Storage](#storage)
|
|
44
|
+
- [Media](#media)
|
|
28
45
|
- [Email](#email)
|
|
29
|
-
- [Events & Workflows](#events--workflows)
|
|
30
46
|
- [Notifications & Logs](#notifications--logs)
|
|
47
|
+
- [Queue Management](#queue-management)
|
|
48
|
+
- [Health & Diagnostics](#health--diagnostics)
|
|
49
|
+
- [Webhooks](#webhooks)
|
|
31
50
|
- [Enterprise Capabilities](#enterprise-capabilities)
|
|
32
51
|
- [Auto-Paginating Iterators](#auto-paginating-iterators)
|
|
33
52
|
- [Bulk Data Chunking](#bulk-data-chunking)
|
|
@@ -48,9 +67,6 @@ pnpm add @ecodrix/erix-api
|
|
|
48
67
|
|
|
49
68
|
# npm
|
|
50
69
|
npm install @ecodrix/erix-api
|
|
51
|
-
|
|
52
|
-
# yarn
|
|
53
|
-
yarn add @ecodrix/erix-api
|
|
54
70
|
```
|
|
55
71
|
|
|
56
72
|
> **Requires**: Node.js >= 18
|
|
@@ -63,8 +79,8 @@ yarn add @ecodrix/erix-api
|
|
|
63
79
|
import { Ecodrix } from "@ecodrix/erix-api";
|
|
64
80
|
|
|
65
81
|
const ecod = new Ecodrix({
|
|
66
|
-
apiKey:
|
|
67
|
-
clientCode:
|
|
82
|
+
apiKey: process.env.ECOD_API_KEY!,
|
|
83
|
+
clientCode: process.env.ECOD_CLIENT_CODE,
|
|
68
84
|
});
|
|
69
85
|
|
|
70
86
|
// Send a WhatsApp message
|
|
@@ -75,12 +91,17 @@ await ecod.whatsapp.messages.send({
|
|
|
75
91
|
|
|
76
92
|
// Create a CRM lead
|
|
77
93
|
const lead = await ecod.crm.leads.create({
|
|
78
|
-
firstName: "
|
|
94
|
+
firstName: "Priya",
|
|
79
95
|
phone: "+919876543210",
|
|
80
96
|
source: "website",
|
|
81
97
|
});
|
|
82
98
|
|
|
83
|
-
|
|
99
|
+
// Fire an automation trigger
|
|
100
|
+
await ecod.events.trigger({
|
|
101
|
+
trigger: "trial_started",
|
|
102
|
+
phone: "+919876543210",
|
|
103
|
+
createLeadIfMissing: true,
|
|
104
|
+
});
|
|
84
105
|
```
|
|
85
106
|
|
|
86
107
|
---
|
|
@@ -92,7 +113,7 @@ Pass an options object to `new Ecodrix(options)`:
|
|
|
92
113
|
| Option | Type | Required | Default | Description |
|
|
93
114
|
| ------------ | -------- | ----------- | ------------------------- | ---------------------------------------------- |
|
|
94
115
|
| `apiKey` | `string` | ✅ Yes | — | Your ECOD Platform API key |
|
|
95
|
-
| `clientCode` | `string` | Recommended | — | Your tenant ID
|
|
116
|
+
| `clientCode` | `string` | Recommended | — | Your tenant ID — scopes all requests |
|
|
96
117
|
| `baseUrl` | `string` | No | `https://api.ecodrix.com` | Override the API base URL (e.g. for local dev) |
|
|
97
118
|
| `socketUrl` | `string` | No | Same as `baseUrl` | Override the Socket.io server URL |
|
|
98
119
|
|
|
@@ -108,22 +129,12 @@ const ecod = new Ecodrix({
|
|
|
108
129
|
|
|
109
130
|
## Resources
|
|
110
131
|
|
|
111
|
-
Every resource follows the same predictable CRUD interface:
|
|
112
|
-
|
|
113
|
-
| Method | Description |
|
|
114
|
-
| --------------------- | ---------------------------------- |
|
|
115
|
-
| `.create(params)` | Create a new record |
|
|
116
|
-
| `.list(params?)` | List records with optional filters |
|
|
117
|
-
| `.retrieve(id)` | Get a single record by ID |
|
|
118
|
-
| `.update(id, params)` | Update a record |
|
|
119
|
-
| `.delete(id)` | Delete or cancel a record |
|
|
120
|
-
|
|
121
|
-
---
|
|
122
|
-
|
|
123
132
|
### WhatsApp
|
|
124
133
|
|
|
125
134
|
Access via `ecod.whatsapp`.
|
|
126
135
|
|
|
136
|
+
---
|
|
137
|
+
|
|
127
138
|
#### `ecod.whatsapp.messages`
|
|
128
139
|
|
|
129
140
|
**Send a text message**
|
|
@@ -146,355 +157,651 @@ await ecod.whatsapp.messages.send({
|
|
|
146
157
|
});
|
|
147
158
|
```
|
|
148
159
|
|
|
149
|
-
**Send a
|
|
160
|
+
**Send a template message via queue**
|
|
150
161
|
|
|
151
162
|
```typescript
|
|
152
163
|
await ecod.whatsapp.messages.sendTemplate({
|
|
153
164
|
to: "+919876543210",
|
|
154
165
|
templateName: "appointment_reminder",
|
|
155
166
|
language: "en_US",
|
|
156
|
-
variables: ["
|
|
167
|
+
variables: ["Priya", "Tomorrow 10AM"],
|
|
157
168
|
});
|
|
158
169
|
```
|
|
159
170
|
|
|
160
|
-
**
|
|
161
|
-
|
|
162
|
-
Use this specifically to dispatch high-priority utility templates containing dynamic variable maps.
|
|
171
|
+
**Mark messages as read**
|
|
163
172
|
|
|
164
173
|
```typescript
|
|
165
|
-
|
|
166
|
-
phone: "+919876543210",
|
|
167
|
-
templateName: "payment_confirmation",
|
|
168
|
-
variables: {
|
|
169
|
-
name: "Dhanesh",
|
|
170
|
-
amount: "₹1,500",
|
|
171
|
-
},
|
|
172
|
-
});
|
|
174
|
+
await ecod.whatsapp.messages.markRead("message_id");
|
|
173
175
|
```
|
|
174
176
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
```typescript
|
|
178
|
-
await ecod.whatsapp.messages.markRead("conversation_id");
|
|
179
|
-
```
|
|
177
|
+
---
|
|
180
178
|
|
|
181
179
|
#### `ecod.whatsapp.conversations`
|
|
182
180
|
|
|
183
181
|
```typescript
|
|
184
182
|
// List conversations (cursor-based pagination)
|
|
185
|
-
const { data } = await ecod.whatsapp.conversations.list({
|
|
183
|
+
const { data } = await ecod.whatsapp.conversations.list({
|
|
184
|
+
limit: 20,
|
|
185
|
+
status: "open",
|
|
186
|
+
after: "cursor_token",
|
|
187
|
+
});
|
|
186
188
|
|
|
187
189
|
// Get a specific conversation
|
|
188
190
|
const conv = await ecod.whatsapp.conversations.retrieve("conversation_id");
|
|
189
191
|
|
|
190
|
-
//
|
|
192
|
+
// Get messages in a conversation
|
|
193
|
+
const { data: msgs } = await ecod.whatsapp.conversations.messages("conversation_id", {
|
|
194
|
+
limit: 50,
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
// Create a conversation explicitly
|
|
198
|
+
await ecod.whatsapp.conversations.create({ phone: "+919876543210", name: "Priya" });
|
|
199
|
+
|
|
200
|
+
// Link a conversation to a CRM lead
|
|
201
|
+
await ecod.whatsapp.conversations.linkLead("conversation_id", "lead_id");
|
|
202
|
+
|
|
203
|
+
// Mark a conversation as read (clears unread badge)
|
|
204
|
+
await ecod.whatsapp.conversations.markRead("conversation_id");
|
|
205
|
+
|
|
206
|
+
// Delete / archive a conversation
|
|
191
207
|
await ecod.whatsapp.conversations.delete("conversation_id");
|
|
208
|
+
|
|
209
|
+
// Bulk delete conversations
|
|
210
|
+
await ecod.whatsapp.conversations.bulkDelete(["conv_1", "conv_2"]);
|
|
192
211
|
```
|
|
193
212
|
|
|
194
213
|
---
|
|
195
214
|
|
|
196
|
-
|
|
215
|
+
#### `ecod.whatsapp.templates`
|
|
197
216
|
|
|
198
|
-
|
|
217
|
+
```typescript
|
|
218
|
+
// List pre-approved Meta templates
|
|
219
|
+
const { data } = await ecod.whatsapp.templates.list();
|
|
199
220
|
|
|
200
|
-
|
|
221
|
+
// Sync templates from the Meta Business Account
|
|
222
|
+
await ecod.whatsapp.templates.sync();
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
#### `ecod.whatsapp.broadcasts`
|
|
228
|
+
|
|
229
|
+
Send a personalised WhatsApp template message to multiple recipients at once.
|
|
201
230
|
|
|
202
231
|
```typescript
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
232
|
+
await ecod.whatsapp.broadcasts.create({
|
|
233
|
+
name: "April Promo",
|
|
234
|
+
templateName: "discount_offer",
|
|
235
|
+
templateLanguage: "en_US",
|
|
236
|
+
recipients: [
|
|
237
|
+
{ phone: "+919876543210", variables: ["Priya", "20%"] },
|
|
238
|
+
{ phone: "+919123456789", variables: ["Ravi", "30%"] },
|
|
239
|
+
],
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
// List past broadcasts
|
|
243
|
+
const { data } = await ecod.whatsapp.broadcasts.list({ status: "completed" });
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
|
|
248
|
+
#### `ecod.whatsapp.sendTemplate` — Direct Template (Bypass Queue)
|
|
249
|
+
|
|
250
|
+
Use this for high-priority utility templates that must deliver immediately outside the automation queue.
|
|
251
|
+
|
|
252
|
+
```typescript
|
|
253
|
+
const result = await ecod.whatsapp.sendTemplate({
|
|
206
254
|
phone: "+919876543210",
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
255
|
+
templateName: "payment_confirmation",
|
|
256
|
+
variables: {
|
|
257
|
+
name: "Priya",
|
|
258
|
+
amount: "₹1,500",
|
|
211
259
|
},
|
|
212
260
|
});
|
|
261
|
+
// result.messageId → WA message ID
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
---
|
|
265
|
+
|
|
266
|
+
### CRM
|
|
267
|
+
|
|
268
|
+
Access via `ecod.crm`.
|
|
269
|
+
|
|
270
|
+
---
|
|
271
|
+
|
|
272
|
+
#### `ecod.crm.leads`
|
|
273
|
+
|
|
274
|
+
**Create**
|
|
275
|
+
|
|
276
|
+
```typescript
|
|
277
|
+
const { data: lead } = await ecod.crm.leads.create({
|
|
278
|
+
firstName: "Priya",
|
|
279
|
+
lastName: "Sharma",
|
|
280
|
+
phone: "+919876543210",
|
|
281
|
+
email: "priya@example.com",
|
|
282
|
+
source: "website",
|
|
283
|
+
pipelineId: "pipeline_id",
|
|
284
|
+
stageId: "stage_id",
|
|
285
|
+
metadata: { utmSource: "google" },
|
|
286
|
+
});
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
**Upsert by phone** — Creates if absent, updates if exists
|
|
290
|
+
|
|
291
|
+
```typescript
|
|
292
|
+
await ecod.crm.leads.upsert({
|
|
293
|
+
leadData: { phone: "+919876543210", firstName: "Priya" },
|
|
294
|
+
trigger: "webinar_joined",
|
|
295
|
+
});
|
|
213
296
|
```
|
|
214
297
|
|
|
215
|
-
**List
|
|
298
|
+
**List with filters**
|
|
216
299
|
|
|
217
300
|
```typescript
|
|
218
|
-
const { data
|
|
219
|
-
status: "new",
|
|
301
|
+
const { data } = await ecod.crm.leads.list({
|
|
302
|
+
status: "new",
|
|
220
303
|
source: "whatsapp",
|
|
304
|
+
pipelineId: "pipeline_id",
|
|
221
305
|
page: 1,
|
|
222
306
|
limit: 25,
|
|
223
307
|
});
|
|
224
308
|
```
|
|
225
309
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
**Retrieve a Lead by ID**
|
|
310
|
+
**Retrieve**
|
|
229
311
|
|
|
230
312
|
```typescript
|
|
231
313
|
const { data: lead } = await ecod.crm.leads.retrieve("lead_id");
|
|
314
|
+
const { data } = await ecod.crm.leads.retrieveByPhone("+919876543210");
|
|
315
|
+
const { data } = await ecod.crm.leads.retrieveByRef("orderId", "ORD-123");
|
|
232
316
|
```
|
|
233
317
|
|
|
234
|
-
**Update
|
|
318
|
+
**Update**
|
|
235
319
|
|
|
236
320
|
```typescript
|
|
237
|
-
await ecod.crm.leads.update("lead_id", {
|
|
238
|
-
|
|
239
|
-
|
|
321
|
+
await ecod.crm.leads.update("lead_id", { email: "new@email.com" });
|
|
322
|
+
await ecod.crm.leads.updateMetadata("lead_id", {
|
|
323
|
+
refs: { orderId: "ORD-456" },
|
|
324
|
+
extra: { plan: "pro" },
|
|
240
325
|
});
|
|
241
326
|
```
|
|
242
327
|
|
|
243
|
-
**
|
|
328
|
+
**Move & Convert**
|
|
329
|
+
|
|
330
|
+
```typescript
|
|
331
|
+
await ecod.crm.leads.move("lead_id", "target_stage_id");
|
|
332
|
+
await ecod.crm.leads.convert("lead_id", "won", "Signed contract");
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
**Tags**
|
|
244
336
|
|
|
245
337
|
```typescript
|
|
338
|
+
await ecod.crm.leads.tags("lead_id", { add: ["vip", "hot"], remove: ["cold"] });
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
**Score**
|
|
342
|
+
|
|
343
|
+
```typescript
|
|
344
|
+
await ecod.crm.leads.recalculateScore("lead_id");
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
**Bulk**
|
|
348
|
+
|
|
349
|
+
```typescript
|
|
350
|
+
await ecod.crm.leads.import(leadArray); // Bulk import
|
|
246
351
|
await ecod.crm.leads.delete("lead_id");
|
|
352
|
+
await ecod.crm.leads.bulkDelete(["id_1", "id_2"]);
|
|
247
353
|
```
|
|
248
354
|
|
|
249
355
|
---
|
|
250
356
|
|
|
251
|
-
|
|
357
|
+
#### `ecod.crm.pipelines`
|
|
252
358
|
|
|
253
|
-
|
|
359
|
+
```typescript
|
|
360
|
+
// CRUD
|
|
361
|
+
const { data } = await ecod.crm.pipelines.list();
|
|
362
|
+
await ecod.crm.pipelines.create({ name: "Sales", isDefault: true });
|
|
363
|
+
await ecod.crm.pipelines.retrieve("pipeline_id");
|
|
364
|
+
await ecod.crm.pipelines.update("pipeline_id", { name: "Deals" });
|
|
365
|
+
await ecod.crm.pipelines.delete("pipeline_id");
|
|
366
|
+
|
|
367
|
+
// Advanced
|
|
368
|
+
await ecod.crm.pipelines.setDefault("pipeline_id");
|
|
369
|
+
await ecod.crm.pipelines.duplicate("pipeline_id", "Sales Copy");
|
|
370
|
+
await ecod.crm.pipelines.archive("pipeline_id");
|
|
371
|
+
const { data: board } = await ecod.crm.pipelines.board("pipeline_id");
|
|
372
|
+
const { data: forecast } = await ecod.crm.pipelines.forecast("pipeline_id");
|
|
373
|
+
|
|
374
|
+
// Stage management
|
|
375
|
+
await ecod.crm.pipelines.addStage("pipeline_id", { name: "Negotiation", color: "#f59e0b" });
|
|
376
|
+
await ecod.crm.pipelines.reorderStages("pipeline_id", ["stage_1", "stage_3", "stage_2"]);
|
|
377
|
+
await ecod.crm.pipelines.updateStage("stage_id", { probability: 80 });
|
|
378
|
+
await ecod.crm.pipelines.deleteStage("stage_id", "fallback_stage_id");
|
|
379
|
+
```
|
|
254
380
|
|
|
255
|
-
|
|
381
|
+
---
|
|
382
|
+
|
|
383
|
+
#### `ecod.crm.automations`
|
|
384
|
+
|
|
385
|
+
```typescript
|
|
386
|
+
// CRUD
|
|
387
|
+
const { data } = await ecod.crm.automations.list();
|
|
388
|
+
await ecod.crm.automations.create({ name: "Follow-up", trigger: "lead_created", nodes: [], edges: [] });
|
|
389
|
+
await ecod.crm.automations.update("rule_id", { isActive: false });
|
|
390
|
+
await ecod.crm.automations.toggle("rule_id");
|
|
391
|
+
await ecod.crm.automations.deleteRule("rule_id");
|
|
392
|
+
await ecod.crm.automations.bulkDelete(["rule_1", "rule_2"]);
|
|
393
|
+
|
|
394
|
+
// Testing & events
|
|
395
|
+
await ecod.crm.automations.test("rule_id", "lead_id");
|
|
396
|
+
const { data: events } = await ecod.crm.automations.getAvailableEvents();
|
|
397
|
+
|
|
398
|
+
// Enrollment management
|
|
399
|
+
const { data } = await ecod.crm.automations.enrollments("rule_id", { status: "active", page: 1 });
|
|
400
|
+
await ecod.crm.automations.getEnrollment("enrollment_id");
|
|
401
|
+
await ecod.crm.automations.pauseEnrollment("rule_id", "enrollment_id");
|
|
402
|
+
await ecod.crm.automations.resumeEnrollment("rule_id", "enrollment_id");
|
|
403
|
+
|
|
404
|
+
// Run inspection
|
|
405
|
+
const { data: runs } = await ecod.crm.automations.runs("rule_id");
|
|
406
|
+
await ecod.crm.automations.getRun("run_id");
|
|
407
|
+
await ecod.crm.automations.resumeRun("run_id");
|
|
408
|
+
await ecod.crm.automations.abortRun("run_id");
|
|
409
|
+
|
|
410
|
+
// Unlock a wait_event node from external tool (e.g. Zapier, payment gateway callback)
|
|
411
|
+
await ecod.crm.automations.webhookEvent("rule_id", "payment_received", {
|
|
412
|
+
amount: 1500,
|
|
413
|
+
currency: "INR",
|
|
414
|
+
});
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
---
|
|
418
|
+
|
|
419
|
+
#### `ecod.crm.sequences`
|
|
420
|
+
|
|
421
|
+
Manually enroll / unenroll leads in drip automation sequences.
|
|
256
422
|
|
|
257
423
|
```typescript
|
|
258
|
-
|
|
424
|
+
await ecod.crm.sequences.enroll({
|
|
259
425
|
leadId: "lead_id",
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
startTime: "2026-04-10T10:00:00.000Z",
|
|
263
|
-
endTime: "2026-04-10T10:30:00.000Z",
|
|
426
|
+
ruleId: "rule_id",
|
|
427
|
+
variables: { discount: "20%" },
|
|
264
428
|
});
|
|
265
|
-
|
|
266
|
-
|
|
429
|
+
await ecod.crm.sequences.unenroll("enrollment_id");
|
|
430
|
+
const { data } = await ecod.crm.sequences.listForLead("lead_id");
|
|
267
431
|
```
|
|
268
432
|
|
|
269
|
-
|
|
433
|
+
---
|
|
434
|
+
|
|
435
|
+
#### `ecod.crm.activities`
|
|
270
436
|
|
|
271
437
|
```typescript
|
|
272
|
-
|
|
438
|
+
// Lead timeline (all CRM events in order)
|
|
439
|
+
const { data } = await ecod.crm.activities.timeline("lead_id", { page: 1, limit: 50 });
|
|
440
|
+
|
|
441
|
+
// Filtered activity list
|
|
442
|
+
const { data } = await ecod.crm.activities.list("lead_id", { type: "call" });
|
|
443
|
+
|
|
444
|
+
// Log a call outcome
|
|
445
|
+
await ecod.crm.activities.logCall("lead_id", {
|
|
446
|
+
outcome: "answered",
|
|
447
|
+
duration: 120,
|
|
448
|
+
notes: "Interested in Pro plan",
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
// Log a generic activity
|
|
452
|
+
await ecod.crm.activities.log({
|
|
453
|
+
leadId: "lead_id",
|
|
454
|
+
type: "email_opened",
|
|
455
|
+
title: "Campaign Email Opened",
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
// --- Notes ---
|
|
459
|
+
const { data: notes } = await ecod.crm.activities.notes.list("lead_id");
|
|
460
|
+
await ecod.crm.activities.notes.create("lead_id", { content: "Call scheduled for Monday" });
|
|
461
|
+
await ecod.crm.activities.notes.update("note_id", "Updated note text");
|
|
462
|
+
await ecod.crm.activities.notes.pin("note_id"); // pin to top
|
|
463
|
+
await ecod.crm.activities.notes.pin("note_id", false); // unpin
|
|
273
464
|
```
|
|
274
465
|
|
|
275
|
-
|
|
466
|
+
---
|
|
467
|
+
|
|
468
|
+
#### `ecod.crm.analytics`
|
|
276
469
|
|
|
277
470
|
```typescript
|
|
278
|
-
const { data } = await ecod.
|
|
471
|
+
const { data: overview } = await ecod.crm.analytics.overview("pipeline_id");
|
|
472
|
+
const { data: conversion } = await ecod.crm.analytics.conversionRate("pipeline_id");
|
|
473
|
+
const { data: velocity } = await ecod.crm.analytics.dealVelocity("pipeline_id");
|
|
474
|
+
const { data: stageTime } = await ecod.crm.analytics.stageTime("pipeline_id");
|
|
279
475
|
```
|
|
280
476
|
|
|
281
|
-
|
|
477
|
+
---
|
|
478
|
+
|
|
479
|
+
#### `ecod.crm.scoring`
|
|
282
480
|
|
|
283
481
|
```typescript
|
|
284
|
-
await ecod.
|
|
285
|
-
|
|
286
|
-
endTime: "2026-04-11T11:30:00.000Z",
|
|
287
|
-
});
|
|
482
|
+
const { data } = await ecod.crm.scoring.getConfig();
|
|
483
|
+
await ecod.crm.scoring.updateConfig({ rules: [...] });
|
|
288
484
|
```
|
|
289
485
|
|
|
290
|
-
|
|
486
|
+
---
|
|
487
|
+
|
|
488
|
+
#### `ecod.crm.payments`
|
|
291
489
|
|
|
292
490
|
```typescript
|
|
293
|
-
await ecod.
|
|
491
|
+
const { data } = await ecod.crm.payments.list("lead_id");
|
|
294
492
|
```
|
|
295
493
|
|
|
296
494
|
---
|
|
297
495
|
|
|
298
|
-
|
|
496
|
+
#### `ecod.crm.automationDashboard`
|
|
299
497
|
|
|
300
|
-
|
|
498
|
+
```typescript
|
|
499
|
+
const { data: stats } = await ecod.crm.automationDashboard.stats();
|
|
500
|
+
const { data: logs } = await ecod.crm.automationDashboard.logs({ limit: 10, status: "failed" });
|
|
501
|
+
await ecod.crm.automationDashboard.retryFailedEvent("log_id");
|
|
502
|
+
```
|
|
301
503
|
|
|
302
|
-
|
|
504
|
+
---
|
|
303
505
|
|
|
304
|
-
|
|
506
|
+
### Events & Workflows
|
|
305
507
|
|
|
306
|
-
|
|
307
|
-
2. Uploads the file directly to R2 (no proxy overhead).
|
|
308
|
-
3. Confirms the upload with the backend.
|
|
508
|
+
Access via `ecod.events`. Connect your external applications to the CRM automation engine.
|
|
309
509
|
|
|
310
|
-
|
|
311
|
-
// Node.js: from a Buffer
|
|
312
|
-
import { readFileSync } from "fs";
|
|
510
|
+
**List all available triggers**
|
|
313
511
|
|
|
314
|
-
|
|
315
|
-
const { data } = await ecod.
|
|
316
|
-
|
|
317
|
-
filename: "contract.pdf",
|
|
318
|
-
contentType: "application/pdf",
|
|
319
|
-
});
|
|
512
|
+
```typescript
|
|
513
|
+
const { data: triggers } = await ecod.events.list();
|
|
514
|
+
```
|
|
320
515
|
|
|
321
|
-
|
|
516
|
+
**Register a custom event**
|
|
322
517
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
contentType: file.type,
|
|
329
|
-
});
|
|
330
|
-
filename: "dhanesh.png",
|
|
331
|
-
contentType: "image/png"
|
|
518
|
+
```typescript
|
|
519
|
+
await ecod.events.assign({
|
|
520
|
+
name: "cart_abandoned",
|
|
521
|
+
displayName: "Shopping Cart Abandoned",
|
|
522
|
+
pipelineId: "pipeline_123",
|
|
332
523
|
});
|
|
333
524
|
|
|
334
|
-
|
|
335
|
-
|
|
525
|
+
// Deactivate
|
|
526
|
+
await ecod.events.unassign("cart_abandoned");
|
|
527
|
+
await ecod.events.unassignBulk(["event_a", "event_b"]);
|
|
336
528
|
```
|
|
337
529
|
|
|
338
|
-
**
|
|
530
|
+
**Fire an event / trigger workflows**
|
|
339
531
|
|
|
340
|
-
```
|
|
341
|
-
|
|
532
|
+
```typescript
|
|
533
|
+
await ecod.events.trigger({
|
|
534
|
+
trigger: "cart_abandoned",
|
|
535
|
+
phone: "+919876543210",
|
|
536
|
+
variables: { items: "T-Shirt, Mug", total: "₹850" },
|
|
537
|
+
createLeadIfMissing: true,
|
|
538
|
+
delayMinutes: 30,
|
|
539
|
+
// Optional: auto-book a Google Meet during the workflow
|
|
540
|
+
requiresMeet: true,
|
|
541
|
+
meetConfig: {
|
|
542
|
+
summary: "Follow-up call",
|
|
543
|
+
duration: 30,
|
|
544
|
+
timezone: "Asia/Kolkata",
|
|
545
|
+
},
|
|
546
|
+
});
|
|
342
547
|
```
|
|
343
548
|
|
|
344
|
-
**
|
|
549
|
+
**Custom event definitions (CRM-managed)**
|
|
345
550
|
|
|
346
|
-
```
|
|
347
|
-
const { data
|
|
348
|
-
|
|
551
|
+
```typescript
|
|
552
|
+
const { data } = await ecod.events.listCustomEvents();
|
|
553
|
+
await ecod.events.createCustomEvent({ name: "webinar_attended", displayName: "Webinar Attended" });
|
|
554
|
+
await ecod.events.deleteCustomEvent("event_id");
|
|
555
|
+
await ecod.events.emit({ eventName: "webinar_attended", leadId: "lead_id" });
|
|
349
556
|
```
|
|
350
557
|
|
|
351
558
|
---
|
|
352
559
|
|
|
353
|
-
###
|
|
560
|
+
### Marketing
|
|
561
|
+
|
|
562
|
+
Access via `ecod.marketing`.
|
|
354
563
|
|
|
355
|
-
|
|
564
|
+
**Email campaigns**
|
|
356
565
|
|
|
357
|
-
|
|
566
|
+
```typescript
|
|
567
|
+
await ecod.marketing.emails.sendCampaign({
|
|
568
|
+
recipients: ["user@example.com"],
|
|
569
|
+
subject: "Summer Sale!",
|
|
570
|
+
html: "<h1>Get 20% off!</h1>",
|
|
571
|
+
});
|
|
572
|
+
await ecod.marketing.emails.sendTest("dev@example.com");
|
|
573
|
+
```
|
|
358
574
|
|
|
359
|
-
|
|
575
|
+
**Campaigns (Email + SMS)**
|
|
360
576
|
|
|
361
577
|
```typescript
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
578
|
+
await ecod.marketing.campaigns.create({ name: "Q2 Push", type: "email" });
|
|
579
|
+
await ecod.marketing.campaigns.list({ status: "active" });
|
|
580
|
+
await ecod.marketing.campaigns.retrieve("campaign_id");
|
|
581
|
+
await ecod.marketing.campaigns.update("campaign_id", { subject: "New subject" });
|
|
582
|
+
await ecod.marketing.campaigns.send("campaign_id", { scheduledAt: "2026-05-01T09:00:00Z" });
|
|
583
|
+
await ecod.marketing.campaigns.stats("campaign_id");
|
|
584
|
+
await ecod.marketing.campaigns.delete("campaign_id");
|
|
585
|
+
```
|
|
586
|
+
|
|
587
|
+
**WhatsApp marketing (CRM-integrated template dispatch)**
|
|
588
|
+
|
|
589
|
+
Unlike the direct `ecod.whatsapp.sendTemplate`, this endpoint resolves CRM field variables automatically.
|
|
590
|
+
|
|
591
|
+
```typescript
|
|
592
|
+
await ecod.marketing.whatsapp.sendTemplate({
|
|
593
|
+
phone: "+919876543210",
|
|
594
|
+
templateName: "seasonal_offer",
|
|
595
|
+
variables: { discount: "40%" },
|
|
366
596
|
});
|
|
367
597
|
```
|
|
368
598
|
|
|
369
|
-
|
|
599
|
+
---
|
|
370
600
|
|
|
371
|
-
|
|
601
|
+
### Meetings
|
|
602
|
+
|
|
603
|
+
Access via `ecod.meet`. Backed by **Google Meet**.
|
|
372
604
|
|
|
373
605
|
```typescript
|
|
374
|
-
const {
|
|
606
|
+
const { data: meeting } = await ecod.meet.create({
|
|
607
|
+
leadId: "lead_id",
|
|
608
|
+
participantName: "Priya Sharma",
|
|
609
|
+
participantPhone: "+919876543210",
|
|
610
|
+
startTime: "2026-04-10T10:00:00.000Z",
|
|
611
|
+
endTime: "2026-04-10T10:30:00.000Z",
|
|
612
|
+
});
|
|
613
|
+
console.log(meeting.meetLink); // → https://meet.google.com/abc-defg-hij
|
|
614
|
+
|
|
615
|
+
const { data: meetings } = await ecod.meet.list({ status: "scheduled" });
|
|
616
|
+
const { data } = await ecod.meet.retrieve("meeting_id");
|
|
617
|
+
await ecod.meet.update("meeting_id", { startTime: "2026-04-11T11:00:00.000Z" });
|
|
618
|
+
await ecod.meet.delete("meeting_id");
|
|
375
619
|
```
|
|
376
620
|
|
|
377
621
|
---
|
|
378
622
|
|
|
379
|
-
###
|
|
623
|
+
### Storage
|
|
380
624
|
|
|
381
|
-
Access via `ecod.
|
|
625
|
+
Access via `ecod.storage`. Powered by **Cloudflare R2**.
|
|
382
626
|
|
|
383
|
-
|
|
627
|
+
This handles the full presigned-URL orchestration transparently:
|
|
384
628
|
|
|
385
|
-
|
|
629
|
+
1. Requests a presigned PUT URL from the backend.
|
|
630
|
+
2. Uploads directly to R2 (no proxy overhead).
|
|
631
|
+
3. Confirms the upload.
|
|
386
632
|
|
|
387
633
|
```typescript
|
|
388
|
-
|
|
634
|
+
// Node.js: from a Buffer
|
|
635
|
+
import { readFileSync } from "fs";
|
|
636
|
+
|
|
637
|
+
const fileBuffer = readFileSync("./contract.pdf");
|
|
638
|
+
const { data } = await ecod.storage.upload(fileBuffer, {
|
|
639
|
+
folder: "customer_documents",
|
|
640
|
+
filename: "contract.pdf",
|
|
641
|
+
contentType: "application/pdf",
|
|
642
|
+
});
|
|
643
|
+
console.log(data.url); // → https://cdn.ecodrix.com/customer_documents/contract.pdf
|
|
644
|
+
|
|
645
|
+
// Browser: from an <input> element
|
|
646
|
+
const file = document.getElementById("file-input").files[0];
|
|
647
|
+
const { data } = await ecod.storage.upload(file, {
|
|
648
|
+
folder: "avatars",
|
|
649
|
+
filename: file.name,
|
|
650
|
+
contentType: file.type,
|
|
651
|
+
});
|
|
389
652
|
```
|
|
390
653
|
|
|
391
|
-
|
|
654
|
+
---
|
|
655
|
+
|
|
656
|
+
### Media
|
|
392
657
|
|
|
393
|
-
|
|
658
|
+
Access via `ecod.media`. Manage files stored in R2.
|
|
394
659
|
|
|
395
660
|
```typescript
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
});
|
|
661
|
+
// Get a presigned download URL for a private file
|
|
662
|
+
const { data } = await ecod.media.getDownloadUrl("confidential/contract.pdf");
|
|
663
|
+
|
|
664
|
+
// Monitor storage quota
|
|
665
|
+
const { data: usage } = await ecod.media.getUsage();
|
|
666
|
+
console.log(`${usage.usedMB} MB of ${usage.limitMB} MB used`);
|
|
667
|
+
|
|
668
|
+
// List files in a folder
|
|
669
|
+
await ecod.media.list({ folder: "invoices" });
|
|
670
|
+
|
|
671
|
+
// Delete a file
|
|
672
|
+
await ecod.media.delete("invoices/old_invoice.pdf");
|
|
401
673
|
```
|
|
402
674
|
|
|
403
|
-
|
|
675
|
+
---
|
|
676
|
+
|
|
677
|
+
### Email
|
|
404
678
|
|
|
405
|
-
|
|
679
|
+
Access via `ecod.email`. Backed by SMTP or AWS SES depending on tenant configuration.
|
|
406
680
|
|
|
407
681
|
```typescript
|
|
408
|
-
await ecod.
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
createLeadIfMissing: true, // Upsert lead if it's a new customer
|
|
682
|
+
await ecod.email.sendEmailCampaign({
|
|
683
|
+
subject: "Summer Discount!",
|
|
684
|
+
recipients: ["user@example.com"],
|
|
685
|
+
html: "<h1>Get 20% off all plans!</h1>",
|
|
413
686
|
});
|
|
687
|
+
|
|
688
|
+
// Verify SMTP configuration
|
|
689
|
+
await ecod.email.sendTestEmail("admin@example.com");
|
|
414
690
|
```
|
|
415
691
|
|
|
416
692
|
---
|
|
417
693
|
|
|
418
694
|
### Notifications & Logs
|
|
419
695
|
|
|
420
|
-
Access via `ecod.notifications`.
|
|
421
|
-
|
|
422
|
-
**List Automation Execution Logs**
|
|
696
|
+
Access via `ecod.notifications`.
|
|
423
697
|
|
|
424
698
|
```typescript
|
|
699
|
+
// Automation execution logs
|
|
425
700
|
const { data: logs } = await ecod.notifications.listLogs({
|
|
426
701
|
trigger: "lead_created",
|
|
427
|
-
status: "failed",
|
|
702
|
+
status: "failed",
|
|
428
703
|
startDate: "2026-04-01",
|
|
429
704
|
endDate: "2026-04-30",
|
|
430
|
-
limit: 50,
|
|
431
705
|
});
|
|
432
|
-
```
|
|
433
|
-
|
|
434
|
-
**Retrieve a Specific Log**
|
|
435
|
-
|
|
436
|
-
```typescript
|
|
437
|
-
const { data: log } = await ecod.notifications.retrieveLog("log_id");
|
|
438
|
-
```
|
|
439
706
|
|
|
440
|
-
|
|
707
|
+
await ecod.notifications.retrieveLog("log_id");
|
|
441
708
|
|
|
442
|
-
|
|
709
|
+
// Aggregate stats
|
|
443
710
|
const { data: stats } = await ecod.notifications.getStats({
|
|
444
711
|
startDate: "2026-04-01",
|
|
445
712
|
endDate: "2026-04-30",
|
|
446
713
|
});
|
|
714
|
+
|
|
715
|
+
// Provider webhook callback logs
|
|
716
|
+
const { data } = await ecod.notifications.listCallbacks({ limit: 20 });
|
|
717
|
+
```
|
|
718
|
+
|
|
719
|
+
---
|
|
720
|
+
|
|
721
|
+
### Queue Management
|
|
722
|
+
|
|
723
|
+
Access via `ecod.queue`. Inspect and manage background automation jobs.
|
|
724
|
+
|
|
725
|
+
```typescript
|
|
726
|
+
// View failed jobs
|
|
727
|
+
const { data: failed } = await ecod.queue.listFailed();
|
|
728
|
+
|
|
729
|
+
// Get queue health by status
|
|
730
|
+
const stats = await ecod.queue.getStats();
|
|
731
|
+
// stats → { waiting: 12, active: 3, completed: 482, failed: 7, delayed: 0 }
|
|
732
|
+
|
|
733
|
+
// Retry a failed job
|
|
734
|
+
await ecod.queue.retryJob("job_id");
|
|
735
|
+
|
|
736
|
+
// Remove a job permanently
|
|
737
|
+
await ecod.queue.deleteJob("job_id");
|
|
447
738
|
```
|
|
448
739
|
|
|
449
|
-
|
|
740
|
+
---
|
|
741
|
+
|
|
742
|
+
### Health & Diagnostics
|
|
743
|
+
|
|
744
|
+
Access via `ecod.health`.
|
|
450
745
|
|
|
451
746
|
```typescript
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
}
|
|
747
|
+
// Global platform status
|
|
748
|
+
const health = await ecod.health.system();
|
|
749
|
+
// { status: "ok", version: "...", env: "production", uptime: 3600, db: "connected", queueDepth: 5 }
|
|
750
|
+
|
|
751
|
+
// Tenant-scoped service readiness
|
|
752
|
+
const clientHealth = await ecod.health.clientHealth();
|
|
753
|
+
// { clientCode: "...", services: { whatsapp: "connected", email: "configured", googleMeet: "configured" }, ... }
|
|
754
|
+
|
|
755
|
+
// Background job status lookup
|
|
756
|
+
const job = await ecod.health.jobStatus("job_id");
|
|
455
757
|
```
|
|
456
758
|
|
|
457
759
|
---
|
|
458
760
|
|
|
459
|
-
|
|
761
|
+
### Webhooks
|
|
460
762
|
|
|
461
|
-
|
|
763
|
+
Access via `ecod.webhooks`.
|
|
764
|
+
|
|
765
|
+
> ⚠️ **Node.js only** — Requires `node:crypto`. Not available in browser bundles.
|
|
766
|
+
|
|
767
|
+
---
|
|
768
|
+
|
|
769
|
+
## Enterprise Capabilities
|
|
462
770
|
|
|
463
771
|
### Auto-Paginating Iterators
|
|
464
772
|
|
|
465
|
-
|
|
773
|
+
Stream all records without manual page management:
|
|
466
774
|
|
|
467
775
|
```typescript
|
|
468
|
-
//
|
|
469
|
-
for await (const lead of ecod.crm.leads.listAutoPaging({ status: "won" })) {
|
|
776
|
+
// With optional type parameter for full type safety
|
|
777
|
+
for await (const lead of ecod.crm.leads.listAutoPaging<Lead>({ status: "won" })) {
|
|
470
778
|
await syncToMyDatabase(lead);
|
|
471
779
|
}
|
|
472
780
|
```
|
|
473
781
|
|
|
474
782
|
### Bulk Data Chunking
|
|
475
783
|
|
|
476
|
-
|
|
784
|
+
Insert thousands of leads without hitting rate limits. `createMany` automatically chunks and concurrently streams batches:
|
|
477
785
|
|
|
478
786
|
```typescript
|
|
479
|
-
// The users array chunked into safe parallel batched requests
|
|
480
787
|
const results = await ecod.crm.leads.createMany(massiveArrayOfLeads, 100);
|
|
481
|
-
console.log(`
|
|
788
|
+
console.log(`Ingested ${results.length} leads.`);
|
|
482
789
|
```
|
|
483
790
|
|
|
484
791
|
### Idempotency Keys
|
|
485
792
|
|
|
486
|
-
|
|
793
|
+
Prevent duplicate requests caused by automatic retries:
|
|
487
794
|
|
|
488
795
|
```typescript
|
|
489
796
|
await ecod.email.sendEmailCampaign(
|
|
490
|
-
{ subject: "Promo", recipients: ["user@example.com"] },
|
|
491
|
-
{ idempotencyKey: "
|
|
797
|
+
{ subject: "Promo", recipients: ["user@example.com"], html: "..." },
|
|
798
|
+
{ idempotencyKey: "promo_campaign_uuid_2026_q2" },
|
|
492
799
|
);
|
|
493
800
|
```
|
|
494
801
|
|
|
495
802
|
### Webhook Signature Verification
|
|
496
803
|
|
|
497
|
-
|
|
804
|
+
Cryptographically verify that webhook payloads originated from ECODrIx:
|
|
498
805
|
|
|
499
806
|
```typescript
|
|
500
807
|
app.post(
|
|
@@ -505,9 +812,10 @@ app.post(
|
|
|
505
812
|
const event = await ecod.webhooks.constructEvent(
|
|
506
813
|
req.body.toString(),
|
|
507
814
|
req.headers["x-ecodrix-signature"],
|
|
508
|
-
"
|
|
815
|
+
"whsec_your_webhook_secret",
|
|
509
816
|
);
|
|
510
|
-
console.log("Verified event
|
|
817
|
+
console.log("Verified event:", event);
|
|
818
|
+
res.json({ received: true });
|
|
511
819
|
} catch (err) {
|
|
512
820
|
return res.status(400).send(`Invalid signature: ${err.message}`);
|
|
513
821
|
}
|
|
@@ -517,11 +825,10 @@ app.post(
|
|
|
517
825
|
|
|
518
826
|
### Raw Execution Engine
|
|
519
827
|
|
|
520
|
-
|
|
828
|
+
Access any API endpoint — including experimental or custom ones — with full authentication and retry benefits:
|
|
521
829
|
|
|
522
830
|
```typescript
|
|
523
|
-
|
|
524
|
-
const customData = await ecod.request("POST", "/api/saas/beta-feature-route", {
|
|
831
|
+
const { data } = await ecod.request("POST", "/api/saas/beta-feature", {
|
|
525
832
|
experimentalFlag: true,
|
|
526
833
|
});
|
|
527
834
|
```
|
|
@@ -530,46 +837,41 @@ const customData = await ecod.request("POST", "/api/saas/beta-feature-route", {
|
|
|
530
837
|
|
|
531
838
|
## Real-time Events
|
|
532
839
|
|
|
533
|
-
The SDK maintains a persistent
|
|
534
|
-
|
|
535
|
-
```typescript
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
});
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
})
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
});
|
|
552
|
-
|
|
553
|
-
// Storage upload completed
|
|
554
|
-
ecod.on("storage.upload_confirmed", (data) => {
|
|
555
|
-
console.log(`File available at: ${data.url}`);
|
|
556
|
-
});
|
|
840
|
+
The SDK maintains a persistent Socket.io connection, scoped to your `clientCode` tenant. Use `ecod.on()` to subscribe:
|
|
841
|
+
|
|
842
|
+
```typescript
|
|
843
|
+
ecod
|
|
844
|
+
.on("whatsapp.message_received", (msg) => {
|
|
845
|
+
console.log(`New message from ${msg.from}: ${msg.body}`);
|
|
846
|
+
})
|
|
847
|
+
.on("crm.lead_created", ({ leadId }) => {
|
|
848
|
+
console.log(`New lead: ${leadId}`);
|
|
849
|
+
})
|
|
850
|
+
.on("crm.lead_updated", ({ leadId, stageName }) => {
|
|
851
|
+
console.log(`${leadId} moved to ${stageName}`);
|
|
852
|
+
})
|
|
853
|
+
.on("meet.scheduled", ({ meetLink }) => {
|
|
854
|
+
console.log(`Meeting booked: ${meetLink}`);
|
|
855
|
+
})
|
|
856
|
+
.on("automation.failed", ({ trigger, reason }) => {
|
|
857
|
+
alertTeam(`Automation ${trigger} failed: ${reason}`);
|
|
858
|
+
});
|
|
557
859
|
|
|
558
|
-
//
|
|
559
|
-
ecod.disconnect();
|
|
860
|
+
// Graceful shutdown
|
|
861
|
+
process.on("SIGTERM", () => ecod.disconnect());
|
|
560
862
|
```
|
|
561
863
|
|
|
562
|
-
### Standard Event
|
|
864
|
+
### Standard Event Reference
|
|
563
865
|
|
|
564
|
-
| Event | Payload | Description
|
|
565
|
-
| --------------------------- | -------------------------------- |
|
|
566
|
-
| `whatsapp.message_received` | `{ from, body, conversationId }` | Inbound WhatsApp message
|
|
567
|
-
| `whatsapp.message_sent` | `{ to, messageId }` | Outbound message delivered
|
|
568
|
-
| `crm.lead_created` | `{ leadId, phone }` | New CRM lead created
|
|
569
|
-
| `crm.lead_updated` | `{ leadId, stageName }` | Lead stage or
|
|
570
|
-
| `meet.scheduled` | `{ meetingId, meetLink }` |
|
|
571
|
-
| `storage.upload_confirmed` | `{ key, url, sizeBytes }` | File upload confirmed
|
|
572
|
-
| `automation.failed` | `{ trigger, reason, leadId }` | Automation execution failed
|
|
866
|
+
| Event | Payload | Description |
|
|
867
|
+
| --------------------------- | -------------------------------- | ------------------------------ |
|
|
868
|
+
| `whatsapp.message_received` | `{ from, body, conversationId }` | Inbound WhatsApp message |
|
|
869
|
+
| `whatsapp.message_sent` | `{ to, messageId }` | Outbound message delivered |
|
|
870
|
+
| `crm.lead_created` | `{ leadId, phone }` | New CRM lead created |
|
|
871
|
+
| `crm.lead_updated` | `{ leadId, stageName }` | Lead stage or fields updated |
|
|
872
|
+
| `meet.scheduled` | `{ meetingId, meetLink }` | Google Meet appointment booked |
|
|
873
|
+
| `storage.upload_confirmed` | `{ key, url, sizeBytes }` | File upload confirmed |
|
|
874
|
+
| `automation.failed` | `{ trigger, reason, leadId }` | Automation execution failed |
|
|
573
875
|
|
|
574
876
|
---
|
|
575
877
|
|
|
@@ -578,12 +880,7 @@ ecod.disconnect();
|
|
|
578
880
|
All methods throw typed errors you can catch and inspect:
|
|
579
881
|
|
|
580
882
|
```typescript
|
|
581
|
-
import {
|
|
582
|
-
Ecodrix,
|
|
583
|
-
APIError,
|
|
584
|
-
AuthenticationError,
|
|
585
|
-
RateLimitError,
|
|
586
|
-
} from "@ecodrix/erix-api";
|
|
883
|
+
import { APIError, AuthenticationError, RateLimitError, Ecodrix } from "@ecodrix/erix-api";
|
|
587
884
|
|
|
588
885
|
try {
|
|
589
886
|
const { data } = await ecod.crm.leads.retrieve("non_existent_id");
|
|
@@ -592,31 +889,30 @@ try {
|
|
|
592
889
|
// 401 — invalid API key or client code
|
|
593
890
|
console.error("Check your credentials.");
|
|
594
891
|
} else if (err instanceof RateLimitError) {
|
|
595
|
-
// 429 —
|
|
596
|
-
console.warn("Rate limit hit.
|
|
892
|
+
// 429 — too many requests (SDK auto-retries up to 3×)
|
|
893
|
+
console.warn("Rate limit hit.");
|
|
597
894
|
} else if (err instanceof APIError) {
|
|
598
|
-
// Other HTTP errors from the API
|
|
599
895
|
console.error(`API Error [${err.status}]: ${err.message}`);
|
|
600
896
|
} else {
|
|
601
|
-
throw err;
|
|
897
|
+
throw err;
|
|
602
898
|
}
|
|
603
899
|
}
|
|
604
900
|
```
|
|
605
901
|
|
|
606
902
|
### Error Classes
|
|
607
903
|
|
|
608
|
-
| Class | Status |
|
|
609
|
-
| --------------------- |
|
|
610
|
-
| `EcodrixError` | —
|
|
611
|
-
| `APIError` | varies
|
|
612
|
-
| `AuthenticationError` | 401
|
|
613
|
-
| `RateLimitError` | 429
|
|
904
|
+
| Class | HTTP Status | Description |
|
|
905
|
+
| --------------------- | ----------- | ------------------------------------------ |
|
|
906
|
+
| `EcodrixError` | — | Base error class |
|
|
907
|
+
| `APIError` | varies | Generic API error with `.status` and `.code` |
|
|
908
|
+
| `AuthenticationError` | 401 | Invalid API key or client code |
|
|
909
|
+
| `RateLimitError` | 429 | Too many requests |
|
|
614
910
|
|
|
615
911
|
---
|
|
616
912
|
|
|
617
913
|
## Browser / CDN Usage
|
|
618
914
|
|
|
619
|
-
For usage without a bundler
|
|
915
|
+
For usage without a bundler:
|
|
620
916
|
|
|
621
917
|
```html
|
|
622
918
|
<!-- Via CDN (jsDelivr) -->
|
|
@@ -634,14 +930,17 @@ For usage without a bundler (plain HTML, marketing pages):
|
|
|
634
930
|
</script>
|
|
635
931
|
```
|
|
636
932
|
|
|
933
|
+
> ⚠️ **Note**: `ecod.webhooks.constructEvent` and `ecod.storage.upload` (from `Buffer`) are Node.js only and will not function in browser environments.
|
|
934
|
+
|
|
637
935
|
---
|
|
638
936
|
|
|
639
937
|
## Contributing
|
|
640
938
|
|
|
641
939
|
1. Fork the repository.
|
|
642
940
|
2. Create a feature branch: `git checkout -b feat/my-feature`
|
|
643
|
-
3. Make changes, then run `pnpm check` to validate.
|
|
644
|
-
4.
|
|
941
|
+
3. Make changes, then run `pnpm check` to validate formatting and lint.
|
|
942
|
+
4. Run `pnpm build` to verify the output compiles cleanly.
|
|
943
|
+
5. Submit a Pull Request.
|
|
645
944
|
|
|
646
945
|
---
|
|
647
946
|
|