# @ecodrix/erix-api 中文文档

规范地址：https://npmcn.com/package/%40ecodrix/erix-api/

版本：4\.3\.2
npm 元数据更新时间：2026-11-13T10:25:01.738Z
中文译文更新时间：2026-11-13T05:52:32.390Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40ecodrix/erix-api
原文对照：https://npmcn.com/package/%40ecodrix/erix-api/?lang=original
项目主页：https://ecodrix.com/
源码仓库：https://github.com/dhanesh1232/erix-api

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：675 kB，12 个文件
- 模块格式：ESM + CJS
- TypeScript 类型：包内自带
- 运行依赖：6 个
- 首次发布：2026-04-03T08:30:54.740Z
- 最新版本发布：2026-11-13T10:25:01.537Z
- 近 30 天下载量：2194（2026-10-13 至 2026-11-11，npm 官方下载统计）
- 已发布版本数：67（近 12 个月 67 个）

## 中文简介

ECODrIx为ERIX API提供的官方TypeScript SDK:CRM,流程自动化,一个横跨WhatsApp的收件箱,Instagram和电子邮件,GST发票和支付. 节点和浏览器(代理模式).

## 安装

```sh
npm install @ecodrix/erix-api
```

也可以使用：`pnpm add @ecodrix/erix-api`、`yarn add @ecodrix/erix-api`、`bun add @ecodrix/erix-api`

## README

# @ ecodrix/ erix- api

[![npm](https://img.shields.io/npm/v/@ecodrix/erix-api.svg)](https://www.npmjs.com/package/@ecodrix/erix-api) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://npmcn.com/package/%40ecodrix/erix-api/LICENSE)

官方类型SDK [ECODRIx 函数](https://ecodrix.com/) 平台. 使用您自己的后端来工作空间: CRM 引导和 管道、流程自动化、统一收件箱(WhatsApp、Instagram、Facebook、, 电报、电子邮件、网络聊天、发票和付款链接、文件存储和实况 事件。 每一次通话都被监视到你的钥匙所属的工作空间.

-   开发者指南 : [https://api.ecodrix.com/docs (中文(简体) )](https://api.ecodrix.com/docs)
-   API 文档 : [https://api.ecodrix.com/docs (中文(简体) )](https://api.ecodrix.com/docs)

## 安装

```bash
pnpm add @ecodrix/erix-api
# or: npm install @ecodrix/erix-api
```

-   **节点.js 18+** (使用全球 `fetch` 财务报告和审定财务报表 `Blob`) (中文(简体) ). 船舶无害环境管理和共同JS 以捆绑的类型定义构建 .
-   **浏览器**: 通过捆绑器( Vite, Next.js, webpack) 支持 [代理模式](https://npmcn.com/package/%40ecodrix/erix-api/#readme-browser-use-proxy-mode) 只加无键 [网站聊天访问客户端](https://npmcn.com/package/%40ecodrix/erix-api/#readme-website-chat-visitor-client)没有 CDN建设.

## 快开始

在您的服务器上运行 。 将密钥保存在只使用服务器的环境变量中 .

```ts
import { ECODrIxAPI } from "@ecodrix/erix-api";

const ecod = new ECODrIxAPI({
  apiKey: process.env.ECOD_API_KEY!,
  clientCode: "ERIX_CLNT_XXXXXX", // Settings → Developer in the dashboard
});

const { data: lead } = await ecod.product.erix.leads.create({
  firstName: "Test",
  lastName: "Customer",
  phone: "+91XXXXXXXXXX",
  source: "website",
});

await ecod.product.erix.events.trigger({
  trigger: "enquiry_received",
  phone: "+91XXXXXXXXXX",
});

// The client keeps a realtime socket open. Close it when your process stops.
process.on("SIGTERM", () => ecod.disconnect());
```

| 选项 | 类型 | 默认 | 页:1 |
| --- | --- | --- | --- |
| `apiKey` | `string` | 无 | 工作空间密钥或 a [范围密钥](https://npmcn.com/package/%40ecodrix/erix-api/#readme-scoped-keys)仅限服务器. |
| `clientCode` | `string` | 无 | 你的工作空间代码,例如. `ERIX_CLNT_XXXXXX`。 。 。 . |
| `version` | `"v1"` | `"v1"` | API路由版本. |
| `timeout` | `number` (单位:百万美元) | `30000` | 每一个请求. `0` 禁用 . |
| `proxy` | `{ url, ticket? }` | 无 | 浏览器模式 。 替换 `apiKey`。 。 。 . |

## 如何安排客户

客户端遵循API的路由树:

| 命名空间 | 它包含什么 |
| --- | --- |
| `ecod.product.erix.*` | 客户关系管理`leads`, (中文(简体) ), `pipelines`, (中文(简体) ), `activities`, (中文(简体) ), `analytics`, (中文(简体) ), `events` ( Flow 触发器), `chat` (输入), `invoices`, (中文(简体) ), `payments`, (中文(简体) ), `ai` |
| `ecod.infra.connect.*` | 频道 : `whatsapp.templates`, (中文(简体) ), `email`, (中文(简体) ), `meet`, (中文(简体) ), `connections` |
| `ecod.infra.storage.*` | 文件 : `media`, (中文(简体) ), `files`, (中文(简体) ), `folders` |
| `ecod.platform.*` | 工作空间 : `knowledge` (大赦国际知识库), `users.notifications` |
| `ecod.webhooks` | Webhook 签名验证 |
| `ecod.on()` 编号 : `ecod.off()` | 实时活动 |
| `ecod.request()` | 还没有输入方法就授权调用任何端点 |

## 浏览器使用( 代理模式)

从不将工作空间密钥放入浏览器中. 这包括: `NEXT_PUBLIC_*`, (中文(简体) ), `VITE_*` 或任何其它的变量 最终在客户端捆绑。 谁 打开dev工具可以读取它,一个工作空间密钥可以完全访问.

在浏览器中,以代理模式运行 SDK :

1.  您的服务器曝光 `/api/erix/*`它检查您的登录用户, 并添加 键,并将请求转发到 ECODrIx.
2.  实时来说,你的服务器薄荷 5分钟的套接字票。 浏览器得到 罚单,没有钥匙.

代理路由(Next.js App路由器, `app/api/erix/[...path]/route.ts`:

```ts
const API = "https://api.ecodrix.com";
const PASS_HEADERS = ["content-type", "accept", "idempotency-key"];
const DROP_HEADERS = ["content-encoding", "content-length", "transfer-encoding", "connection"];

async function proxy(req: Request, ctx: { params: Promise<{ path: string[] }> }) {
  const user = await requireUser(req); // your own session check
  if (!user) {
    return Response.json({ success: false, error: "Unauthorized" }, { status: 401 });
  }

  const { path } = await ctx.params;
  const rel = `/${path.map(encodeURIComponent).join("/")}`;
  if (!/^\/v\d+\/api\//.test(rel)) {
    return Response.json({ success: false, error: "Not found" }, { status: 404 });
  }

  const headers = new Headers({
    "x-api-key": process.env.ECOD_API_KEY!,
    "x-client-code": "ERIX_CLNT_XXXXXX",
  });
  for (const name of PASS_HEADERS) {
    const value = req.headers.get(name);
    if (value) headers.set(name, value);
  }

  const hasBody = req.method !== "GET" && req.method !== "HEAD";
  const upstream = await fetch(`${API}${rel}${new URL(req.url).search}`, {
    method: req.method,
    headers,
    body: hasBody ? await req.arrayBuffer() : undefined,
    redirect: "manual",
  });

  const out = new Headers(upstream.headers);
  for (const name of DROP_HEADERS) out.delete(name);
  return new Response(upstream.body, { status: upstream.status, headers: out });
}

export { proxy as GET, proxy as POST, proxy as PUT, proxy as PATCH, proxy as DELETE };
```

车票路线(`app/api/erix/ticket/route.ts`:

```ts
export async function POST(req: Request) {
  const user = await requireUser(req); // your own session check
  if (!user) return new Response("Unauthorized", { status: 401 });

  const res = await fetch("https://api.ecodrix.com/v1/api/platform/realtime/ticket", {
    method: "POST",
    headers: {
      "x-api-key": process.env.ECOD_API_KEY!,
      "x-client-code": "ERIX_CLNT_XXXXXX",
    },
    cache: "no-store",
  });
  const body = (await res.json().catch(() => null)) as { data?: { ticket?: string } } | null;
  const ticket = body?.data?.ticket;
  if (!res.ok || !ticket) return new Response("Ticket unavailable", { status: 502 });

  return new Response(ticket, {
    headers: { "content-type": "text/plain", "cache-control": "no-store" },
  });
}
```

浏览器客户端 :

```ts
import { ECODrIxAPI } from "@ecodrix/erix-api";

export const ecod = new ECODrIxAPI({
  proxy: {
    url: "/api/erix",
    ticket: () =>
      fetch("/api/erix/ticket", { method: "POST" }).then((r) =>
        r.ok ? r.text() : Promise.reject(new Error("No realtime ticket")),
      ),
  },
});
```

SDK每一次重联都会得到一张新票. 无 `ticket`后退时 调用工作而不打开套接字.

任何人签到您的应用程序 现在可以做 任何工作空间密钥所能做的. 如果你的用户不应该拥有所有这些,允许列出他们所需要的路径 代理路线.

## 网站聊天访问客户端

`@ecodrix/erix-api/visitor` 是一个匿名网站的单独条目 访问者与工作空间聊天。 它不需要钥匙,只达到 游客自己的线条。 用这个 `fetch` 和负载 `socket.io-client` 仅在 所以聊天部件不会把SDK装满 ERIX 聊天部件 运行在它.

```ts
import { WebchatVisitor, WebchatVisitorError } from "@ecodrix/erix-api/visitor";

const chat = new WebchatVisitor({
  clientCode: "ERIX_CLNT_XXXXXX",
  // The visitor's only secret: random, 20–80 characters of A-Z a-z 0-9 _ -.
  // Keep it (e.g. in localStorage) to continue the same thread next visit.
  sessionId,
  // The site the chat runs on. It must be on the workspace's allowed domains.
  parent: "https://www.example.in",
});

const { data: messages, widget, consentNotice } = await chat.messages();

try {
  await chat.send("Do you open on Sunday?", {
    messageId: crypto.randomUUID(), // resend with the same id: stored once
    page: { path: location.pathname, title: document.title },
  });
} catch (err) {
  if (err instanceof WebchatVisitorError) {
    console.warn(err.code, err.status, err.field, err.message);
  }
}

await chat.contact({ name: "Ravi", phone: "98765 43210" });
```

现场答复和打字`/visitor` 套接字 :

```ts
chat.connect({
  onMessage: (message) => upsert(message), // `from`: visitor | ai | team | system
  onTyping: ({ on, waiting }) => showTyping(on, waiting), // waiting: the team will reply
  onStatus: ({ ids, status }) => markTicks(ids, status), // "read": the team opened the chat
  onError: () => startPolling(), // live is down: poll messages()
  onReconnect: () => {
    stopPolling();
    chat.messages().then(redraw); // nothing missed is replayed
  },
});

chat.disconnect();
```

滴答,跟WhatsApp一样 每个消息都有 `status` (单位:千美元)`sent` ✓, `delivered` ✓✓, `read` 参观者自己是 `delivered` 曾经存储和 `read` 一次 团队打开了聊天。 报告企业的答复,最多50 ids a 调用; 勾选只向前移动 :

```ts
await chat.receipts(replyIds, "delivered"); // the chat got them
await chat.receipts(replyIds, "read"); // open and on screen
```

| `err.code` | 含义 |
| --- | --- |
| `VALIDATION_ERROR` | 坏输入. `err.field` 说吧, `err.message` 是访客副本 |
| `ORIGIN_NOT_ALLOWED` | 网站不在工作空间允许的域上 |
| `NOT_FOUND` | 未知客户端代码 |
| `RATE_LIMITED` | 太多的信息或连接 。 单 |
| `MALICIOUS_INPUT` | 文本被拒绝作为脚本或注射 |
| `INTERNAL_ERROR` | 服务器错误 。 再试一次 |
| `NETWORK_ERROR` | 无答(离线,30 s超时). 再试一次 |

活套接字只接受 ERIX 部件框架的出处 。 您的聊天用户界面 当HTTP网站是工作空间的网站(浏览器)时,自有的页面在HTTP上工作 和民意测验 `messages()` 用于答复.

## 范围化密钥

对于一个能完成一项工作的整合(一个启动"流"事件的预订形式, ),在下方创建范围化的密钥 **设置 → 开发者 → 范围化 API 密钥**。 。 。 . 范围化的密钥可以被撤销,可以过期并有使用跟踪. 每一个 一次性补助金:

| 目的 | 赠款 | 工程为 |
| --- | --- | --- |
| 触发事件 | `flow:events` | `product.erix.events.trigger()` |
| 发送WhatsApp | `connect:whatsapp` | `chat.messages.send({ to })`, (中文(简体) ), `sendTemplate()` |
| 发送电子邮件 | `connect:email` | `POST /infra/connect/send/email` |
| 发送电报 | `connect:telegram` | `POST /infra/connect/send/telegram` |

钥匙看起来像 `erix_<scope>_<secret>`。通过一个 `apiKey`服务器 强制执行其赠款,因此赠款以外的任何电话都无法 `AuthenticationError` (HTTP 403) (韩语). 超普通的 HTTP 您也可以以 `Authorization: Bearer erix_<scope>_…`。 。 。 .

```ts
import { ECODrIxAPI } from "@ecodrix/erix-api";

const events = new ECODrIxAPI({
  apiKey: process.env.ECOD_EVENTS_KEY!, // erix_flow_… with flow:events
  clientCode: "ERIX_CLNT_XXXXXX",
});

await events.product.erix.events.trigger({ trigger: "booking_created", phone: "+91XXXXXXXXXX" });
```

## 客户关系管理:领导和管道

```ts
// Create or update by phone. `refs` are your own IDs, kept on the lead.
await ecod.product.erix.leads.upsert({
  leadData: { phone: "+91XXXXXXXXXX", firstName: "Test", source: "website" },
  refs: { orderId: "ORD-1042" },
});

const { data: leads, pagination } = await ecod.product.erix.leads.list({
  status: "open", // open | won | lost | archived
  search: "test",
  limit: 25,
});

await ecod.product.erix.leads.move("LEAD_ID", "STAGE_ID"); // pipeline column
await ecod.product.erix.leads.setFollowUp("LEAD_ID", "2026-10-20T15:00:00+05:30", "Share the quote");
await ecod.product.erix.leads.tags("LEAD_ID", { add: ["hot"], remove: ["cold"] });
await ecod.product.erix.leads.convert("LEAD_ID", "won", "Advance received");
await ecod.product.erix.leads.delete("LEAD_ID"); // archives; history stays
```

其他检查 : `retrieve(id)`, (中文(简体) ), `retrieveByPhone(phone)`, (中文(简体) ), `retrieveByRef(key, value)`, (中文(简体) ), `update(id, patch)`, (中文(简体) ), `notes(id)`, (中文(简体) ), `createNote(id, { content })`, (中文(简体) ), `activities(id)`, (中文(简体) ), `profile(id)`, (中文(简体) ), `import(leads)` 财务报告和审定财务报表 `merge(primaryId, secondaryId)`。 。 。 .

数据保护(DPDP). 只有业主和管理人员才能做到这一点:

```ts
const { data: everything } = await ecod.product.erix.leads.export("LEAD_ID"); // (3.2.0)

// Irreversible. Wipes personal data across CRM, inbox and automations.
// Invoices are kept for GST records.
const { data: result } = await ecod.product.erix.leads.erase("LEAD_ID"); // (3.2.0)
console.log(result.invoicesKept);
```

管道:

```ts
const { data: pipeline } = await ecod.product.erix.pipelines.create({
  name: "Admissions",
  stages: ["Enquiry", "Visit booked", "Fee paid", "Admitted"],
});

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

await ecod.product.erix.pipelines.addStage("PIPELINE_ID", { name: "Follow-up", color: "#f59e0b" });
// Moves the stage's leads to another stage of the same pipeline, then deletes it.
await ecod.product.erix.pipelines.deleteStage("STAGE_ID", "TARGET_STAGE_ID");
```

## 流程:事件和自定义触发器

`events.trigger()` 启动一个事件。 每个有匹配触发的活性流动 启动联系人运行 。 惠璶 `phone` 或者说 `email`。 。 。 .

```ts
const res = await ecod.product.erix.events.trigger({
  trigger: "appointment_booked",
  phone: "+91XXXXXXXXXX",
  variables: { slot: "Mon 11:00", branch: "Indore" },
  createLeadIfMissing: true,
  leadData: { firstName: "Test", source: "website" },
  delayMinutes: 30, // or delaySeconds, or runAt (ISO with offset). Use one.
  idempotencyKey: "booking-8812", // a retry with the same key won't start flows twice
});
console.log(res.data?.idempotencyKey, res.data?.leadId);
```

`createLeadIfMissing`,延迟和 `runAt` 每个工作空间都会释放. 没有发布,服务器会忽略他们,在回应中会这样说.

定义自己的触发器, 以便启动它们 :

```ts
await ecod.product.erix.events.createCustomEvent({
  name: "appointment_confirm", // lowercase letters, digits, _ . -
  displayName: "Appointment confirmed",
});

const { data } = await ecod.product.erix.events.listCustomEvents(); // data.triggers
await ecod.product.erix.events.deleteCustomEvent("TRIGGER_ID");
```

一些人在批准阶段停下来等待一个人。 你可以列出这些 并决定:

```ts
const { data } = await ecod.product.erix.ai.approvals(); // { drafts, runs }
for (const run of data.runs) {
  // Pass run.nodeId (3.2.0) so a stale view can't decide a different step.
  await ecod.product.erix.ai.decideRun(run.id, "approve", run.nodeId);
}
```

## 频道:收件箱和直接发送

所有频道共用一个收件箱. 任何线索都可以用 `chat.messages.send({ conversationId })`。 。 。 .

```ts
const { data: threads } = await ecod.product.erix.chat.conversations.list({
  channel: "whatsapp",
  limit: 20,
});

const { data: messages, hasMore } = await ecod.product.erix.chat.conversations.messages(
  "CONVERSATION_ID",
  { limit: 50 }, // page back with { before: oldestMessage.createdAt }
);

await ecod.product.erix.chat.messages.send({
  conversationId: "CONVERSATION_ID",
  text: "Your order is packed and ships today.",
});
await ecod.product.erix.chat.conversations.markRead("CONVERSATION_ID");

// Open (or find) a thread for a number and link it to a lead.
const { data: thread } = await ecod.product.erix.chat.conversations.create({
  phone: "+91XXXXXXXXXX",
  channel: "whatsapp",
});
await ecod.product.erix.chat.conversations.linkLead(thread.id, "LEAD_ID");
```

发送一个文件。 上传到您的存储器中, 然后附加 :

```ts
const input = document.querySelector<HTMLInputElement>("#attachment")!;
const media = await ecod.product.erix.chat.messages.upload(input.files![0]);

await ecod.product.erix.chat.messages.send({
  conversationId: "CONVERSATION_ID",
  media,
  text: "Invoice attached",
});
```

直接WhatsApp发送, 没有收件串编号 :

```ts
// An approved template. Use this to start a conversation.
await ecod.product.erix.chat.messages.sendTemplate({
  to: "+91XXXXXXXXXX",
  templateName: "order_update",
  language: "en",
  variables: ["ORD-1042", "₹1,499"],
});

// Free text. Only works inside WhatsApp's 24-hour customer service window.
await ecod.product.erix.chat.messages.send({ to: "+91XXXXXXXXXX", text: "Thanks, we got your enquiry." });
```

管理模板为 `ecod.infra.connect.whatsapp.templates`数字 : `list()`, (中文(简体) ), `sync()` 财务报告和审定财务报表 `retrieve(name)`。 。 。 .

## 发票和付款链接

金额以卢比计。 这张发票是25,000美元+18%的GST=-29,500美元:

```ts
const { data: invoice } = await ecod.product.erix.invoices.create({
  clientName: "Test Customer",
  clientPhone: "+91XXXXXXXXXX",
  leadId: "LEAD_ID",
  items: [{ description: "Website design", quantity: 1, rate: 25000, hsnSac: "998314" }],
  taxRate: 18,
  dueDate: "2026-11-15",
});

// A link on your connected gateway (Razorpay or Stripe). Calling again returns the same link.
const { data: link } = await ecod.product.erix.invoices.paymentLink(invoice.id); // (3.2.0)
console.log(link.paymentLinkUrl);

await ecod.product.erix.invoices.sendWhatsApp(invoice.id); // (3.2.0) with the payment link
await ecod.product.erix.invoices.sendEmail(invoice.id); // (3.2.0) PDF + payment link
```

发票不能删除,只能作废(`invoices.void(id)`因此,GST记录 保持原样 其他电话: `list({ status })`, (中文(简体) ), `getInvoice(id)` 财务报告和审定财务报表 `update(id, patch)`. 会计出口 `product.erix.invoiceExport`数字 : `csv()`, (中文(简体) ), `tally()` 财务报告和审定财务报表 `zoho()`。 。 。 .

一个一次性的付款链接 与发票无关 或者你拿的付款 离线 :

```ts
await ecod.infra.connect.connections.createPaymentLink({
  amount: 1499, // ₹1,499
  description: "Consultation fee",
  customer: { phone: "+91XXXXXXXXXX" },
});

// Cash, UPI or bank transfer. With orderId, a retry is counted once.
await ecod.product.erix.payments.capture({ leadId: "LEAD_ID", amount: 5000, orderId: "UPI-2026-0042" });
```

## 存储上传

`media.upload()` 获得一个预先签名的 URL, 直接上传到存储, 然后 确认上传,全部在一个呼叫中。 文件字节从不经过 API,你的密钥从不去存储主机.

```ts
import { readFile } from "node:fs/promises";

const buffer = await readFile("./brochure.pdf");
const { data: file } = await ecod.infra.storage.media.upload(buffer, {
  folder: "documents",
  filename: "brochure.pdf",
  contentType: "application/pdf",
});

const { data: download } = await ecod.infra.storage.files.getDownloadUrl<{
  data: { downloadUrl: string };
}>(file.key);
console.log(download.downloadUrl); // short-lived URL
```

同一个电话需要浏览器 `File`其他电话: `files.list(folder)` 财务报告和审定财务报表 `files.delete(key)`。 。 。 .

## 实时活动

事件流过一个套接字 被放大到工作空间 你只收到一个 工作空间的事.

```ts
import type { Message } from "@ecodrix/erix-api";

const onMessage = ({ conversationId, message }: { conversationId: string; message: Message }) => {
  console.log(conversationId, message.direction, message.text);
};

ecod
  .on("inbox.message", onMessage)
  .on("message_status_update", ({ messageId, status }) => console.log(messageId, status))
  .on("resync", () => {
    // Reconnected after a gap too large to replay. Refetch your data.
  });

// Later, e.g. in a React effect cleanup:
ecod.off("inbox.message", onMessage);
```

| 活动 | 有效载荷/ 含义 |
| --- | --- |
| `inbox.message` | `{ conversationId, message }`。每个已存储消息:任何通道、进出 |
| `message_status_update` | `{ messageId, conversationId, status }`。发送、交付、读取或失败 |
| `ai_suggestion` 编号 : `ai_handoff` | AI的草稿正在等待中 |
| `workflow-run-update` | 流量运行进度 |
| `platform:notification` | 新的申请通知 |
| `knowledge.source_updated` | 知识库来源改变状态 |
| `resync` | 错过的事件无法重播. 追溯 |

每个事件的最后论点是 `{ seq }`。在重新连接后, SDK 将返回 最后一个 `seq` 它看到了,服务器重放 错过的东西。 重播游戏 重复一个事件, 所以写一个可以安全运行两次的处理器( 通过 ID 更新) .

## Webhook 签名验证

Flow的 Webhook 步骤将 JSON 发送给您的 URL 。 如果你把一个秘密 Webhook 连接, 请求与它一起签名于 `x-ecodrix-signature: sha256=<hex>`。对照 **原始内容** 身体,在你分析它之前。 只有节点.

```ts
import { APIError } from "@ecodrix/erix-api";
import { ecod } from "./ecodrix"; // your server-side client from Quick start

export async function POST(req: Request) {
  const raw = await req.text();
  try {
    const event = await ecod.webhooks.constructEvent(
      raw,
      req.headers.get("x-ecodrix-signature") ?? undefined,
      process.env.ECOD_WEBHOOK_SECRET!,
    );
    console.log("verified", event);
    return Response.json({ received: true });
  } catch (err) {
    // WebhookSignatureError: APIError with code "invalid_signature"
    const message = err instanceof APIError ? err.message : "Bad request";
    return new Response(message, { status: 400 });
  }
}
```

## 原始请求

使用 `ecod.request()` 对于还没有输入方法的终点。 还是你 获取认证,重复和超时。 路径相对 `/v1/api`数字 :

```ts
await ecod.request("POST", "/infra/connect/send/email", {
  to: "customer@example.com",
  subject: "Your booking is confirmed",
  html: "<p>See you on Monday at 11:00.</p>",
});
```

## 错误

呼叫失败 。 API用一个信封回答像 `{ success: false, error, message, code? }`而SDK把它变成其中之一 这些课程:

| 类 | 何时 |
| --- | --- |
| `EcodrixError` | 下面所有东西的基级 |
| `APIError` | 任何其它失败。 有过 `.status`, (中文(简体) ), `.code` (发送时)和 `.message` |
| `AuthenticationError` | HTTP 401或403:坏键或客户端代码,缺失范围,或不允许的角色 |
| `RateLimitError` | HTTP 429,在SDK自己的回放耗尽之后 |

```ts
import { APIError, AuthenticationError, RateLimitError } from "@ecodrix/erix-api";

try {
  await ecod.product.erix.leads.retrieve("LEAD_ID");
} catch (err) {
  if (err instanceof AuthenticationError) {
    console.error("Check the key, client code, scope or role:", err.message);
  } else if (err instanceof RateLimitError) {
    console.warn("Rate limited, back off and retry later");
  } else if (err instanceof APIError) {
    console.error(`API error ${err.status ?? "network"}: ${err.message}`, err.code);
  } else {
    throw err;
  }
}
```

`ecod.request()` 抛出平原 `APIError` 每个状态.

**复次及时出.** SDK以指数重试了三次 备份。 它重复网络错误( 任何方法) , 5xx 对同位素的答复 方法(GET、PUT、DELETE)和429个响应。 每一次请求都会在 30 s; 修改 `timeout` 选项。 超时请求没有重审. 网络出错也可以击中 POST 的响应已丢失, 而重试 然后再次发送它。 将您自己的参考信息传递给一个方法 (单位:千美元)`refs`, (中文(简体) ), `orderId`所以,一个复制是安全的.

## 类型脚本

方法返回响应正体,所以通过一个类型参数使其得到打字. SDK导出主要实体和参数类型(`Lead`, (中文(简体) ), `CreateLeadParams`, (中文(简体) ), `ListLeadsParams`, (中文(简体) ), `Pipeline`, (中文(简体) ), `PipelineStage`, (中文(简体) ), `Conversation`, (中文(简体) ), `Message`, (中文(简体) ), `SendMessageParams`, (中文(简体) ), `PausedRun`, (中文(简体) ), `AiSuggestion`, (中文(简体) ), `KnowledgeSource`, (中文(简体) ), `PaginatedResponse` (见a/cn.9/wg.iii/wp.iii/wp.48,第2段).

```ts
import type { Lead, PaginatedResponse } from "@ecodrix/erix-api";

const page = await ecod.product.erix.leads.list<PaginatedResponse<Lead>>({ limit: 50 });
console.log(page.pagination.total, page.data[0]?.firstName);

// Page through every lead without handling pages yourself.
for await (const lead of ecod.product.erix.leads.listAutoPaging<Lead>({ status: "open" })) {
  console.log(lead.phone);
}
```

## 版本

-   SDK跟着 [铸造](https://semver.org/) 在自己的线路(3.x)上. 断开 仅改变主要释放区的土地。 见 [变动情况](https://npmcn.com/package/%40ecodrix/erix-api/CHANGELOG.md)。 。 。 .
-   API服务器有自己的版本号:平台v1.0是服务器1.0. SDK称 `/v1` 路线,以及 `version` 选项选择路径 版本.
-   标记的方法 **(3.2.0) (中文(简体) )** 需要SDK 3.2.0或以后.

指南和每个终点: [https://api.ecodrix.com/docs (中文(简体) )](https://api.ecodrix.com/docs)。 。 。 .

## 许可证

[麻省理工学院](https://npmcn.com/package/%40ecodrix/erix-api/LICENSE)

## 常见问题

### @ecodrix/erix-api 是什么？

ECODrIx为ERIX API提供的官方TypeScript SDK:CRM,流程自动化,一个横跨WhatsApp的收件箱,Instagram和电子邮件,GST发票和支付\. 节点和浏览器\(代理模式\)\.

### 如何安装 @ecodrix/erix-api？

在项目目录运行 npm install @ecodrix/erix-api，或使用 pnpm add / yarn add / bun add。它还提供命令行工具 erix，可以用 npx erix 直接运行。

### @ecodrix/erix-api 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @ecodrix/erix-api 支持 ESM 还是 CommonJS？

同时提供 ES Module 与 CommonJS 入口，import 和 require\(\) 都可以使用，打包工具会自动选择合适的版本。

### @ecodrix/erix-api 可以商用吗？

@ecodrix/erix-api 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @ecodrix/erix-api 的下载量有多少？

根据 npm 官方下载统计，@ecodrix/erix-api 在 2026/10/13 – 2026/11/11 这 30 天内被下载 2,194 次，日均约 73 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @ecodrix/erix-api 还在维护吗？

最新版本 4\.3\.2 发布于 2026/11/13（今天）；至今共发布 67 个版本，其中过去 12 个月发布了 67 个；首次发布于 2026/04/03。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

