Package Exports
- @ecodrix/erix-api
Readme
@ecodrix/erix-api
The official, isomorphic SDK for the ECODrIx platform.
Manage WhatsApp conversations, CRM leads, file storage, and Google Meet appointments — all from a single, type-safe library.
Table of Contents
- Installation
- Quick Start
- Configuration
- Resources
- Enterprise Capabilities
- Real-time Events
- Error Handling
- Browser / CDN Usage
Installation
# pnpm (recommended)
pnpm add @ecodrix/erix-api
# npm
npm install @ecodrix/erix-api
# yarn
yarn add @ecodrix/erix-apiRequires: Node.js >= 18
Quick Start
import { Ecodrix } from "@ecodrix/erix-api";
const ecod = new Ecodrix({
apiKey: "your_api_key",
clientCode: "YOUR_CLIENT_CODE", // Your tenant ID
});
// Send a WhatsApp message
await ecod.whatsapp.messages.send({
to: "+919876543210",
text: "Hello from ECODrIx!",
});
// Create a CRM lead
const lead = await ecod.crm.leads.create({
firstName: "Jhon",
phone: "+919876543210",
source: "website",
});
console.log(lead.data.id);Configuration
Pass an options object to new Ecodrix(options):
| Option | Type | Required | Default | Description |
|---|---|---|---|---|
apiKey |
string |
✅ Yes | — | Your ECOD Platform API key |
clientCode |
string |
Recommended | — | Your tenant ID (scopes all requests) |
baseUrl |
string |
No | https://api.ecodrix.com |
Override the API base URL (e.g. for local dev) |
socketUrl |
string |
No | Same as baseUrl |
Override the Socket.io server URL |
const ecod = new Ecodrix({
apiKey: process.env.ECOD_API_KEY!,
clientCode: process.env.ECOD_CLIENT_CODE,
baseUrl: "http://localhost:4000", // For local development
});Resources
Every resource follows the same predictable CRUD interface:
| Method | Description |
|---|---|
.create(params) |
Create a new record |
.list(params?) |
List records with optional filters |
.retrieve(id) |
Get a single record by ID |
.update(id, params) |
Update a record |
.delete(id) |
Delete or cancel a record |
Access via ecod.whatsapp.
ecod.whatsapp.messages
Send a text message
await ecod.whatsapp.messages.send({
to: "+919876543210",
text: "Your appointment is confirmed!",
});Send a media message (image, video, document, audio)
await ecod.whatsapp.messages.send({
to: "+919876543210",
mediaUrl: "https://cdn.ecodrix.com/invoice.pdf",
mediaType: "document",
filename: "invoice.pdf",
});Send a pre-approved template message
await ecod.whatsapp.messages.sendTemplate({
to: "+919876543210",
templateName: "appointment_reminder",
language: "en_US",
variables: ["Dhanesh", "Tomorrow 10AM"],
});Send a Meta-approved direct template (Bypass queues)
Use this specifically to dispatch high-priority utility templates containing dynamic variable maps.
const { messageId } = await ecod.whatsapp.sendTemplate({
phone: "+919876543210",
templateName: "payment_confirmation",
variables: {
name: "Dhanesh",
amount: "₹1,500",
},
});Mark a conversation as read
await ecod.whatsapp.messages.markRead("conversation_id");ecod.whatsapp.conversations
// List conversations (cursor-based pagination)
const { data } = await ecod.whatsapp.conversations.list({ limit: 20 });
// Get a specific conversation
const conv = await ecod.whatsapp.conversations.retrieve("conversation_id");
// Archive a conversation
await ecod.whatsapp.conversations.delete("conversation_id");CRM — Leads
Access via ecod.crm.leads.
Create a Lead
const { data: lead } = await ecod.crm.leads.create({
firstName: "Dhanesh",
lastName: "Kumar",
phone: "+919876543210",
email: "dhanesh@example.com",
source: "website", // 'website' | 'whatsapp' | 'direct' | ...
metadata: {
utmSource: "google",
},
});List Leads (with filters)
const { data: leads } = await ecod.crm.leads.list({
status: "new", // filter by status
source: "whatsapp",
page: 1,
limit: 25,
});(See Enterprise Capabilities for efficient auto-pagination or bulk-creation tricks like listAutoPaging and createMany).
Retrieve a Lead by ID
const { data: lead } = await ecod.crm.leads.retrieve("lead_id");Update a Lead
await ecod.crm.leads.update("lead_id", {
email: "new@email.com",
metadata: { score: 95 },
});Delete / Archive a Lead
await ecod.crm.leads.delete("lead_id");Meetings
Access via ecod.meet. Backed by Google Meet.
Schedule a Meeting
const { data: meeting } = await ecod.meet.create({
leadId: "lead_id",
participantName: "Dhanesh Kumar",
participantPhone: "+919876543210",
startTime: "2026-04-10T10:00:00.000Z",
endTime: "2026-04-10T10:30:00.000Z",
});
console.log(meeting.meetLink); // → https://meet.google.com/abc-defg-hijList Meetings
const { data: meetings } = await ecod.meet.list({ status: "scheduled" });Retrieve a Meeting
const { data } = await ecod.meet.retrieve("meeting_id");Reschedule a Meeting
await ecod.meet.update("meeting_id", {
startTime: "2026-04-11T11:00:00.000Z",
endTime: "2026-04-11T11:30:00.000Z",
});Cancel a Meeting
await ecod.meet.delete("meeting_id");Storage
Access via ecod.storage. Powered by Cloudflare R2.
Upload a File (Elite Helper)
This single call handles the entire R2 presigned-URL orchestration for you:
- Requests a presigned PUT URL from the backend.
- Uploads the file directly to R2 (no proxy overhead).
- Confirms the upload with the backend.
// Node.js: from a Buffer
import { readFileSync } from "fs";
const fileBuffer = readFileSync("./contract.pdf");
const { data } = await ecod.storage.upload(fileBuffer, {
folder: "customer_documents",
filename: "contract.pdf",
contentType: "application/pdf",
});
console.log(data.url); // → https://cdn.ecodrix.com/customer_documents/contract.pdf
// Browser: from an <input> file
const file = document.getElementById("file-input").files[0];
const { data } = await ecod.storage.upload(file, {
folder: "avatars",
filename: file.name,
contentType: file.type,
});
filename: "dhanesh.png",
contentType: "image/png"
});
console.log(data.url);
// -> https://cdn.ecodrix.com/avatars/dhanesh.pngGet a Presigned URL for Private Assets
const { data } = await ecod.media.getDownloadUrl("confidential/contract.pdf");Monitor Quota & Usage
const { data: usage } = await ecod.media.getUsage();
console.log(`${usage.usedMB} MB used of ${usage.limitMB} MB`);Access via ecod.email.
Send an Email Campaign
Dispatch an HTML email campaign to a given array of recipients. Powered by Ecodrix or AWS SES depending on tenant configuration.
const { success } = await ecod.email.sendEmailCampaign({
subject: "Summer Subscription Discount!",
recipients: ["user@example.com", "lead@example.com"],
html: "<h1>Get 20% off all plans today!</h1>",
});Send a Test Email
Send a system verification email to validate SMTP configuration for your tenant.
const { success } = await ecod.email.sendTestEmail("admin@example.com");Events & Workflows
Access via ecod.events. Programmatically integrate the CRM's automation engine with your external apps.
Retrieve Global Triggers
Fetch all active automation triggers belonging to the current tenant.
const { data: triggers } = await ecod.events.list();Register a Custom Event Definition
Register a new entry point that you want to show up in the CRM Automation Builder.
await ecod.events.assign({
name: "cart_abandoned",
displayName: "Shopping Cart Abandoned",
pipelineId: "pipeline_123" /* Auto map leads to this pipeline */,
});Emit a Payload / Trigger Workflow
Inject generic data into the EventBus to fire customized automation rules.
await ecod.events.trigger({
trigger: "cart_abandoned",
phone: "+919876543210", // Primary matching key
variables: { items: "T-Shirt, Mug", total: "₹850" },
createLeadIfMissing: true, // Upsert lead if it's a new customer
});Notifications & Logs
Access via ecod.notifications. View automation and webhook audit logs.
List Automation Execution Logs
const { data: logs } = await ecod.notifications.listLogs({
trigger: "lead_created",
status: "failed", // filter to only failed automations
startDate: "2026-04-01",
endDate: "2026-04-30",
limit: 50,
});Retrieve a Specific Log
const { data: log } = await ecod.notifications.retrieveLog("log_id");Get Automation Stats Summary
const { data: stats } = await ecod.notifications.getStats({
startDate: "2026-04-01",
endDate: "2026-04-30",
});List Provider Callback Logs (Webhooks)
const { data: callbacks } = await ecod.notifications.listCallbacks({
limit: 20,
});Enterprise Capabilities
The SDK is equipped with state-of-the-art native patterns for robust execution, zero-downtime performance, and unparalleled developer experience. All network requests automatically utilize an exponential-backoff retry engine to gracefully handle temporary network errors.
Auto-Paginating Iterators
To rapidly ingest records without manually iterating pages, use standard Node.js for await loops. The SDK controls memory buffers and page fetching dynamically.
// Look how beautiful this developer experience is:
for await (const lead of ecod.crm.leads.listAutoPaging({ status: "won" })) {
await syncToMyDatabase(lead);
}Bulk Data Chunking
Need to insert 5,000 leads at once but worried about network congestion or rate limits? createMany automatically chunks arrays into concurrent streams.
// The users array chunked into safe parallel batched requests
const results = await ecod.crm.leads.createMany(massiveArrayOfLeads, 100);
console.log(`Successfully ingested ${results.length} leads.`);Idempotency Keys
Because the SDK provides an automatic network retry engine (axios-retry), temporary blips could duplicate events. Passing an idempotencyKey strictly tells the backend: "Only execute this once, even if I accidentally retry the same payload."
await ecod.email.sendEmailCampaign(
{ subject: "Promo", recipients: ["user@example.com"] },
{ idempotencyKey: "promo_campaign_uuid_123_abc" },
);Webhook Signature Verification
Verify cryptographic webhook payloads issued by the ECODrIx platform reliably in Node environments, mitigating spoofing attacks seamlessly.
app.post(
"/api/webhooks",
express.raw({ type: "application/json" }),
async (req, res) => {
try {
const event = await ecod.webhooks.constructEvent(
req.body.toString(),
req.headers["x-ecodrix-signature"],
"whsec_your_secret_key",
);
console.log("Verified event received:", event);
} catch (err) {
return res.status(400).send(`Invalid signature: ${err.message}`);
}
},
);Raw Execution Engine
Need to execute an experimental, undocumented, or beta endpoint but still want full authentication mapping, global headers, and intelligent retries?
// Bypass strictly typed resources with full network resiliency
const customData = await ecod.request("POST", "/api/saas/beta-feature-route", {
experimentalFlag: true,
});Real-time Events
The SDK maintains a persistent Socket.io connection. Subscribe to live platform events using ecod.on(event, handler).
const ecod = new Ecodrix({ apiKey: "...", clientCode: "..." });
// New incoming WhatsApp message
ecod.on("whatsapp.message_received", (data) => {
console.log(`New message from ${data.from}: ${data.body}`);
});
// Lead stage changed in CRM
ecod.on("crm.lead_updated", (data) => {
console.log(`Lead ${data.leadId} moved to stage: ${data.stageName}`);
});
// Automation or event failed — for alert pipelines
ecod.on("automation.failed", (data) => {
console.error(`Automation failed: ${data.trigger} — ${data.reason}`);
});
// Storage upload completed
ecod.on("storage.upload_confirmed", (data) => {
console.log(`File available at: ${data.url}`);
});
// Disconnect when done (e.g. server shutdown)
ecod.disconnect();Standard Event Names
| Event | Payload | Description |
|---|---|---|
whatsapp.message_received |
{ from, body, conversationId } |
Inbound WhatsApp message |
whatsapp.message_sent |
{ to, messageId } |
Outbound message delivered |
crm.lead_created |
{ leadId, phone } |
New CRM lead created |
crm.lead_updated |
{ leadId, stageName } |
Lead stage or field changed |
meet.scheduled |
{ meetingId, meetLink } |
New Google Meet booked |
storage.upload_confirmed |
{ key, url, sizeBytes } |
File upload confirmed |
automation.failed |
{ trigger, reason, leadId } |
Automation execution failed |
Error Handling
All methods throw typed errors you can catch and inspect:
import {
Ecodrix,
APIError,
AuthenticationError,
RateLimitError,
} from "@ecodrix/erix-api";
try {
const { data } = await ecod.crm.leads.retrieve("non_existent_id");
} catch (err) {
if (err instanceof AuthenticationError) {
// 401 — invalid API key or client code
console.error("Check your credentials.");
} else if (err instanceof RateLimitError) {
// 429 — slow down requests
console.warn("Rate limit hit. Retrying after delay...");
} else if (err instanceof APIError) {
// Other HTTP errors from the API
console.error(`API Error [${err.status}]: ${err.message}`);
} else {
throw err; // re-throw unknown errors
}
}Error Classes
| Class | Status | Code | Description |
|---|---|---|---|
EcodrixError |
— | — | Base error class |
APIError |
varies | varies | Generic API error with status and code |
AuthenticationError |
401 | AUTH_FAILED |
Invalid API key or client code |
RateLimitError |
429 | RATE_LIMIT_EXCEEDED |
Too many requests |
Browser / CDN Usage
For usage without a bundler (plain HTML, marketing pages):
<!-- Via CDN (jsDelivr) -->
<script src="https://cdn.jsdelivr.net/npm/@ecodrix/erix-api/dist/ts/browser/index.global.js"></script>
<script>
const ecod = new Ecodrix.Ecodrix({
apiKey: "your_api_key",
clientCode: "YOUR_CLIENT_CODE",
});
ecod.whatsapp.messages.send({
to: "+919876543210",
text: "Hello from the browser!",
});
</script>Contributing
- Fork the repository.
- Create a feature branch:
git checkout -b feat/my-feature - Make changes, then run
pnpm checkto validate. - Submit a Pull Request.
License
MIT © 2026 ECODrIx Team