ERIX API

REST API v1 · server 1.0.0 Checking status

API documentation

One REST API for your workspace: CRM, the unified inbox, Flow automations, WhatsApp, email and Telegram sends, Google Meet, storage and invoices. Call it from your server with the @ecodrix/erix-api SDK or plain HTTP. This page covers the calls most integrations need; every endpoint is in the API reference.

On this page

CRM

Leads, pipelines, notes, scoring and analytics.

Unified inbox

One inbox for every channel’s conversations.

Flow automations

Fire your own events; matching flows run.

Channel sends

WhatsApp, email and Telegram from one endpoint.

Google Meet

Book, reschedule and cancel meetings.

Invoices

GST invoices, payment links, send on WhatsApp.

LAIE is invite-only. The lead-generation engine isn’t covered on this page.

Getting started

Authentication

Every request belongs to one workspace. Create keys in the dashboard under Settings → Developer. There are two kinds:

  • Workspace key. Send x-api-key and x-client-code. Full access to the workspace: it acts as the owner.
  • Scoped key. erix_<scope>_… sent as Authorization: Bearer. Limited to one module (crm, flow, connect, storage) or a sub-scope such as erix_connect_whatsapp_…. Revocable, and the right choice for integrations. Scoped keys can’t perform admin-only actions.
Keep keys on your server. Never put a key in browser code or in a NEXT_PUBLIC_* variable. In a browser, use the SDK’s proxy mode: requests go to your own route, which checks your user and adds the key server-side.

Base URL: https://api.ecodrix.com/v1/api. Paths are grouped by domain: /product/erix/* (CRM, events, invoices), /product/flow/* (automations), /platform/inbox/* (inbox), /infra/connect/* (channels, Meet) and /infra/storage/* (files). The SDK sets the base URL for you.

Headers
# Workspace key
x-api-key: YOUR_API_KEY
x-client-code: ERIX_CLNT_XXXXXX

# Scoped key
Authorization: Bearer erix_crm_YOUR_SECRET
Browser (proxy mode)
// No key in the page
const ecod = new ECODrIxAPI({
  proxy: {
    url: "/api/erix", // your server route adds x-api-key / x-client-code
    ticket: () => fetch("/api/erix/ticket").then((r) => r.text()), // optional, for realtime
  },
});

Getting started

Quick start

Install the SDK (Node.js 18 or later), then create a lead and fire your own event. Every active flow that listens for that event starts a run.

Prefer plain HTTP? Every sample on this page has a cURL tab; your choice is remembered.

Terminal
pnpm add @ecodrix/erix-api   # or: npm install @ecodrix/erix-api
import { ECODrIxAPI } from "@ecodrix/erix-api";

const ecod = new ECODrIxAPI({
  apiKey: process.env.ECOD_API_KEY,         // server-side only
  clientCode: process.env.ECOD_CLIENT_CODE, // e.g. ERIX_CLNT_XXXXXX
});

// 1. Save an enquiry as a lead
const { data: lead } = await ecod.product.erix.leads.create({
  firstName: "Asha",
  phone: "+91XXXXXXXXXX",
  source: "website",
});

// 2. Fire your own event
await ecod.product.erix.events.trigger({
  trigger: "enquiry_received",
  phone: "+91XXXXXXXXXX",
  variables: { product: "Annual plan" },
});

Getting started

Errors and limits

Responses are JSON. Success is { "success": true, "data": … }. Failures carry success: false, a readable message and a machine code in error or code. Validation failures add fieldErrors.

StatusMeaning
400Invalid input. See fieldErrors.
401Missing, invalid or revoked key.
403The key lacks the scope or role, or the feature isn’t on your plan.
404Not found in this workspace.
429Rate limit or monthly quota reached. Back off and retry.
  • Rate limits are per workspace. Current usage comes back in the standard RateLimit and RateLimit-Policy headers.
  • Retries. Send an Idempotency-Key header on channel sends, invoice and storage writes; a retry with the same key isn’t applied twice. /events/trigger takes idempotencyKey in the body.
  • SDK errors. Failed calls throw APIError (with status and code), with AuthenticationError and RateLimitError subclasses. The SDK retries 429s and network errors up to 3 times with backoff.
Error response
{
  "success": false,
  "error": "INVALID_KEY",
  "message": "Invalid, expired, or revoked API key."
}
import { APIError, RateLimitError } from "@ecodrix/erix-api";

try {
  await ecod.product.erix.leads.create({ firstName: "Asha", phone: "+91XXXXXXXXXX" });
} catch (err) {
  if (err instanceof RateLimitError) {
    // back off, then retry
  } else if (err instanceof APIError) {
    console.error(err.status, err.code, err.message);
  }
}

CRM

Leads

Contacts in your pipelines. Creating a lead logs a “Lead created” activity and starts any flow listening for new leads.

POST/v1/api/product/erix/crm/leads

Create a lead in a pipeline.

Parameters
NameTypeRequiredDescription
firstNamestringRequiredContact’s first name.
phonestringRequiredMobile number with country code, e.g. +91XXXXXXXXXX.
lastNamestringOptionalContact’s last name.
emailstringOptionalEmail address.
sourcestringOptionalWhere the lead came from, e.g. website.
pipelineIdstringOptionalDefaults to your default pipeline.
stageIdstringOptionalDefaults to the pipeline’s first stage.
valuenumberOptionalDeal value.
metadataobjectOptionalYour own key/value data.

POST/v1/api/product/erix/crm/leads/upsert

Find a lead by phone, then update it or create it. Best for forms and webhooks.

Parameters
NameTypeRequiredDescription
leadDataobjectRequiredLead fields; must include phone.
refsobjectOptionalYour own ids, e.g. { "orderId": "…" }. Saved on the lead for lookups.
pipelineIdstringOptionalPipeline for a new lead.
stageIdstringOptionalStage to create in, or move an existing lead to.
triggerstringOptionalA label for what caused the upsert, saved on the lead.

GET/v1/api/product/erix/crm/leads

Paginated, filterable list of leads.

Parameters
NameTypeRequiredDescription
searchstringOptionalMatches name, phone or email.
statusstringOptionalLead status.
pipelineId / stageIdstringOptionalLimit to a pipeline or stage.
source / tagsstringOptionalFilter by source or tag.
startDate / endDateISO dateOptionalCreated within this range.
page / limitnumberOptionalPagination.
sortBy / sortDirstringOptionalSort field and asc or desc.

GET/v1/api/product/erix/crm/leads/:leadId

Get one lead.

GET/v1/api/product/erix/crm/leads/phone/:phone

Look up a lead by phone number.

PATCH/v1/api/product/erix/crm/leads/:leadId

Update a lead’s fields.

PATCH/v1/api/product/erix/crm/leads/:leadId/move

Move a lead to another stage. Won and lost stages update its status.

Parameters
NameTypeRequiredDescription
stageIdstringRequiredTarget stage.

PATCH/v1/api/product/erix/crm/leads/:leadId/tags

Add or remove tags.

Parameters
NameTypeRequiredDescription
addstring[]OptionalTags to add.
removestring[]OptionalTags to remove.

DELETE/v1/api/product/erix/crm/leads/:leadId

Archive a lead (soft delete).

const { data: lead } = await ecod.product.erix.leads.upsert({
  leadData: { firstName: "Asha", phone: "+91XXXXXXXXXX" },
  refs: { orderId: "ORD-1001" },
});

const { data: page } = await ecod.product.erix.leads.list({
  search: "Asha",
  limit: 20,
});

await ecod.product.erix.leads.move(lead.id, "STAGE_ID");
await ecod.product.erix.leads.tags(lead.id, { add: ["vip"] });

CRM

Pipelines and stages

A workspace can run several pipelines (sales, support, onboarding), each with ordered stages.

GET/v1/api/product/erix/crm/pipelines

List all pipelines with their stages.

POST/v1/api/product/erix/crm/pipelines

Create a pipeline.

Parameters
NameTypeRequiredDescription
namestringRequiredPipeline name.
stagesstring[]RequiredStage names in order, e.g. ["New", "Won"].

GET/v1/api/product/erix/crm/pipelines/:pipelineId/board

Kanban view: stages with their leads.

POST/v1/api/product/erix/crm/pipelines/:pipelineId/stages

Add a stage to a pipeline.

const { data: pipelines } = await ecod.product.erix.pipelines.list();

await ecod.product.erix.pipelines.create({
  name: "Sales",
  stages: ["New", "Quoted", "Won"],
});

CRM

Notes and activity

Every lead has a timeline. Log calls, emails and meetings against it, or add notes for your team.

GET/v1/api/product/erix/crm/leads/:leadId/timeline

Everything that happened to a lead, newest first.

POST/v1/api/product/erix/crm/leads/:leadId/activities

Log an activity (call, email, meeting) on the timeline.

POST/v1/api/product/erix/crm/leads/:leadId/notes

Add a note to a lead.

Parameters
NameTypeRequiredDescription
contentstringRequiredThe note text.
await ecod.product.erix.activities.notes.create(leadId, {
  content: "Asked for a quote",
});

const { data: timeline } = await ecod.product.erix.activities.timeline(leadId);

CRM

Lead scoring

Scores update from activity and deal progress. You can tune the weights and force a recalculation.

GET/v1/api/product/erix/crm/scoring

Get the current scoring weights.

PATCH/v1/api/product/erix/crm/scoring

Update the scoring weights.

POST/v1/api/product/erix/crm/scoring/:leadId/recalculate

Recalculate one lead’s score now.

const { data: config } = await ecod.product.erix.scoring.getConfig();
await ecod.product.erix.scoring.recalculate(leadId);

CRM

Analytics

The numbers behind the dashboard, for your own reports.

GET/v1/api/product/erix/crm/analytics/overview

Headline numbers: leads, conversion, pipeline value.

GET/v1/api/product/erix/crm/analytics/funnel

Stage-by-stage conversion for a pipeline.

Parameters
NameTypeRequiredDescription
pipelineIdstringRequiredQuery parameter: the pipeline to analyse.

GET/v1/api/product/erix/crm/analytics/sources

Leads and wins by source.

GET/v1/api/product/erix/crm/analytics/team

Performance per team member.

const { data: overview } = await ecod.product.erix.analytics.overview();
const { data: funnel } = await ecod.product.erix.analytics.funnel(pipelineId);

Automation (Flow)

Fire an event

Flow is the automation engine. Your system tells it something happened (“order placed”, “form submitted”) and every active flow whose trigger matches starts a run. This is the only way to fire an event from outside.

Built-in events (payment captured, stage changed, …) are fired by ECODrIx itself and are rejected here with RESERVED_TRIGGER. Define your own under custom events. A scoped key needs the flow:events or flow scope. Each run counts toward your plan’s monthly runs.

POST/v1/api/product/erix/events/trigger

Fire an event. Returns trigger, idempotencyKey and, when a contact was found or created, leadId.

* Needs Flow v1 on your plan. Without it these fields are ignored and listed in data.ignored.

Parameters
NameTypeRequiredDescription
triggerstringRequiredYour event name. No spaces, max 100 characters.
phone / emailstringRequiredThe contact. One is required unless your plan includes Flow v1.
variablesobjectOptionalFlat key/value pairs available to the flow’s steps.
dataobjectOptionalAny extra payload.
leadDataobjectOptionalfirstName, lastName, source for a new contact.
createLeadIfMissingbooleanOptionalFind or create the CRM contact and attach it to the run.*
delaySeconds / delayMinutes / runAtnumber / ISO dateOptionalRun later, up to 30 days ahead. Use only one.*
idempotencyKeystringOptionalSame key, same event: safe to retry.
await ecod.product.erix.events.trigger({
  trigger: "order_placed",
  phone: "+91XXXXXXXXXX",
  variables: { orderId: "ORD-1001", amount: "4999" },
  idempotencyKey: "ORD-1001",
});

Automation (Flow)

Custom events

Define the event names your system will fire, so they show up as triggers in the Flow builder. Creating and deleting needs a workspace key or an admin session.

GET/v1/api/product/flow/config/triggers

Every trigger a flow can start on: built-ins plus your custom events.

POST/v1/api/product/flow/config/triggers

Create a custom event.

Parameters
NameTypeRequiredDescription
namestringRequiredLowercase letters, digits and _ . -, e.g. appointment_confirm.
displayNamestringRequiredName shown in the Flow builder.
descriptionstringOptionalWhat the event means.

DELETE/v1/api/product/flow/config/triggers/:id

Delete a custom event.

await ecod.product.erix.events.createCustomEvent({
  name: "order_placed",
  displayName: "Order placed",
});

const { data } = await ecod.product.erix.events.listCustomEvents();

Automation (Flow)

Flows and runs

Build flows in the dashboard. Over the API you can list them, start a run by hand and follow runs. Scoped keys need the flow scope. The SDK has no typed Flow methods yet; use the raw ecod.request(), which keeps auth and retries.

GET/v1/api/product/flow/workflows

List your flows.

POST/v1/api/product/flow/workflows/:id/run

Start a run now. Drafts can be test-run; archived flows return 409.

GET/v1/api/product/flow/runs

List recent runs.

GET/v1/api/product/flow/runs/:runId

One run with its step status.

GET/v1/api/product/flow/runs/:runId/logs

Step-by-step log for debugging.

const { data: flows } = await ecod.request("GET", "/product/flow/workflows");
const { data: run } = await ecod.request("GET", `/product/flow/runs/${runId}`);

Messaging

Unified inbox

One inbox holds every channel’s conversations: WhatsApp, Instagram, Facebook, Telegram, email, web chat and the client portal. A reply goes out on the conversation’s own channel.

GET/v1/api/platform/inbox/conversations

List conversations (cursor pagination, filter by status).

GET/v1/api/platform/inbox/conversations/:id/messages

Messages in a thread.

POST/v1/api/platform/inbox/conversations/:id/messages

Reply in a thread.

Parameters
NameTypeRequiredDescription
textstringOptionalMessage text. Send text, media or both.
mediaobjectOptionalA file you uploaded: { key, mimeType, fileName }.

PATCH/v1/api/platform/inbox/conversations/:id/lead

Link the thread to an existing lead.

Parameters
NameTypeRequiredDescription
leadIdstringRequiredThe lead to link.

POST/v1/api/platform/inbox/conversations/:id/read

Mark a thread as read.

GET/v1/api/platform/inbox/unread

Unread counts.

const { data: threads } = await ecod.product.erix.chat.conversations.list({
  status: "open",
  limit: 20,
});

await ecod.product.erix.chat.messages.send({
  conversationId: threads[0].id,
  text: "Thanks! Your quote is on the way.",
});

await ecod.product.erix.chat.conversations.linkLead(conversationId, leadId);

Messaging

Direct send

Send one message on a channel without an existing conversation: an OTP, an order update, a reminder. One endpoint per channel, plus a multi-channel fallback. Scoped keys need connect or the channel sub-scope (erix_connect_whatsapp_…). Bulk sends are Flow campaigns, not this endpoint.

POST/v1/api/infra/connect/send/whatsapp

Send one WhatsApp message.

Parameters
NameTypeRequiredDescription
phonestringRequiredRecipient with country code.
templateNamestringOptionalAn approved template. Send this or text.
languagestringOptionalTemplate language, e.g. en.
variablesstring[]OptionalTemplate variables, in order.
textstringOptionalFree text. Needs an open 24-hour window.

POST/v1/api/infra/connect/send/email

Send one email.

Parameters
NameTypeRequiredDescription
tostringRequiredRecipient address.
subjectstringOptionalRequired unless you send templateId.
htmlstringOptionalEmail body.
templateIdstringOptionalA saved email template.
variablesobjectOptionalTemplate variables.

POST/v1/api/infra/connect/send/telegram

Send one Telegram message.

Parameters
NameTypeRequiredDescription
chatIdstringRequiredTelegram chat id.
textstringRequiredMessage text.

POST/v1/api/infra/connect/send

Try channels in order until one succeeds.

Parameters
NameTypeRequiredDescription
tostringRequiredRecipient: phone or email.
messagestringOptionalText. Send this or template.
templatestringOptionalTemplate name.
channelPreferencestring[]OptionalOrder to try. Default ["whatsapp", "email"].
// WhatsApp template
await ecod.product.erix.chat.messages.sendTemplate({
  to: "+91XXXXXXXXXX",
  templateName: "order_update",
  language: "en",
  variables: ["Asha", "ORD-1001"],
});

// Email: no typed method yet, so use the raw request
await ecod.request("POST", "/infra/connect/send/email", {
  to: "customer@example.com",
  subject: "Your invoice",
  html: "<p>Thanks for your order.</p>",
});

Messaging

WhatsApp templates

Templates approved on your WhatsApp Business account. Business-initiated messages outside the 24-hour window must use one.

GET/v1/api/infra/connect/whatsapp/templates

List templates and their approval status.

POST/v1/api/infra/connect/whatsapp/templates/sync

Pull the latest templates from Meta.

const { data: templates } = await ecod.infra.connect.whatsapp.templates.list();
await ecod.infra.connect.whatsapp.templates.sync();

Platform

Google Meet

Book meetings against a lead; online meetings get a Meet link from your connected Google account. Flows can react to the meeting-created and meeting-rescheduled events, for reminders for example.

POST/v1/api/infra/connect/meet

Book a meeting.

Parameters
NameTypeRequiredDescription
leadIdstringRequiredThe lead the meeting is for.
participantNamestringRequiredWho you’re meeting.
participantPhonestringRequiredTheir phone number.
startTime / endTimeISO dateRequiredWhen it starts and ends.
participantEmailsstring[]OptionalCalendar invitees.
meetingModestringOptionalonline (Meet link) or offline.
type / amountstring / numberOptionalfree or paid, and the fee.

GET/v1/api/infra/connect/meet

List meetings (filter by leadId, status).

GET/v1/api/infra/connect/meet/:id

Get one meeting.

PATCH/v1/api/infra/connect/meet/:id

Reschedule or cancel a meeting.

Parameters
NameTypeRequiredDescription
startTime / endTimeISO dateOptionalNew time.
statusstringOptionalcancelled to cancel.
const meeting = await ecod.infra.connect.meet.create({
  leadId,
  participantName: "Asha",
  participantPhone: "+91XXXXXXXXXX",
  startTime: "2026-11-02T10:00:00+05:30",
  endTime: "2026-11-02T10:30:00+05:30",
  meetingMode: "online",
});

await ecod.infra.connect.meet.reschedule(meetingId, { startTime, endTime });
await ecod.infra.connect.meet.delete(meetingId); // sets status "cancelled"

Platform

Storage and media

Files live in your workspace’s own storage, organised by folder. Post small files to /media. For large files, get a presigned URL, upload straight to storage, then confirm.

POST/v1/api/infra/storage/media

Upload files (multipart). Large images are compressed.

Parameters
NameTypeRequiredDescription
filefileRequiredUp to 50 files, 100 MB each.
folderstringOptionalDestination folder.

GET/v1/api/infra/storage/media

List media in a folder (?folder=).

DELETE/v1/api/infra/storage/media

Delete a file by ?key=.

POST/v1/api/infra/storage/files/upload-url

Get a presigned upload URL (plan feature).

Parameters
NameTypeRequiredDescription
folderstringRequiredDestination folder.
filenamestringRequiredFile name with extension.
contentTypestringRequiredMIME type, e.g. application/pdf.

POST/v1/api/infra/storage/files/confirm-upload

Confirm a presigned upload; returns the file’s URL and type.

Parameters
NameTypeRequiredDescription
keystringRequiredThe key returned with the upload URL.

POST/v1/api/infra/storage/files/download-url

Short-lived download URL for a file.

Parameters
NameTypeRequiredDescription
keystringRequiredThe file’s key.

GET/v1/api/infra/storage/files/usage

Bytes used against your quota.

// Presign, upload straight to storage, and confirm in one call
const { data: file } = await ecod.infra.storage.media.upload(buffer, {
  folder: "invoices",
  filename: "INV-1001.pdf",
  contentType: "application/pdf",
});

Platform

Invoices and payments

GST-ready invoices tied to a lead. Create one, attach a payment link from your connected payment gateway, and send it on WhatsApp or email. When the customer pays, the invoice is marked paid and flows can react.

POST/v1/api/product/erix/commerce/invoices

Create an invoice.

Parameters
NameTypeRequiredDescription
clientNamestringRequiredWho the invoice is for.
itemsobject[]RequiredLine items: description, quantity, rate.
leadIdstringOptionalLink to a lead.
currencystringOptional3-letter code, e.g. INR.
taxRate / discountnumberOptionalGST rate in percent, and discount.
dueDateISO dateOptionalPayment due date.
clientGstin / placeOfSupplystringOptional15-character GSTIN and 2-digit state code.

GET/v1/api/product/erix/commerce/invoices

List invoices (page, limit, status).

POST/v1/api/product/erix/commerce/invoices/:id/payment-link

Create a payment link; the invoice moves to “sent”.

POST/v1/api/product/erix/commerce/invoices/:id/send-whatsapp

Send the invoice on WhatsApp.

POST/v1/api/product/erix/commerce/invoices/:id/send-email

Send the invoice by email.

const { data: invoice } = await ecod.product.erix.invoices.create({
  clientName: "Asha",
  leadId,
  currency: "INR",
  taxRate: 18,
  items: [{ description: "Annual plan", quantity: 1, rate: 4999 }],
});

await ecod.request("POST", `/product/erix/commerce/invoices/${invoice.id}/payment-link`);
await ecod.product.erix.invoices.sendViaWhatsApp(invoice.id);

Platform

Realtime

The SDK keeps a socket open to your workspace, so you get changes as they happen instead of polling. After a reconnect, missed events are replayed; a resync event means “refetch”. Keep handlers idempotent.

In a browser, get a 5-minute socket ticket from your server via POST /v1/api/platform/realtime/ticket (see proxy mode under Authentication).

TypeScript SDK
ecod.on("inbox.message", (event) => {
  // a message arrived or was sent in the unified inbox
});

process.on("SIGTERM", () => ecod.disconnect());

Platform

Health

Check the API before a batch job, or watch it from your monitoring.

GET/v1/api/health

Machine-readable API status. No key needed.

GET/health

The public status page. Send Accept: application/json for JSON.

const status = await ecod.platform.health.system();

Tools

Try it

Make a live call against your own workspace from this page. Your key goes only to this API and isn’t stored.

Use a test workspace or a scoped key. POST calls create real data and send real messages.
Sent for POST and PATCH only.
Response No request yet
// The response will appear here

Need an endpoint that isn’t here? Every route, with request and response shapes, is in the API reference. Release notes are in the changelog.