@chatlychat/sdk-节点
Chatly API 的服务器端客户端. 用 API 密钥认证, 所以它是 用于您的后端, 而不是浏览器, 其中键可以读取 .
pnpm add @chatlychat/sdk-node
快开始
import { ChatlyClient } from '@chatlychat/sdk-node';
const chatly = new ChatlyClient({
apiKey: process.env.CHATLY_API_KEY!, // ck_live_…
apiUrl: 'https://api.chatlychat.com', // optional
});
const contacts = await chatly.contacts.list({ limit: 20 });
在下方创建密钥 工作空间 — 开发者 — API 密钥符号显示 一次并仅作为散列储存——如果你失去它,撤销并再铸成一分.
制作 whoami() 你的第一个电话。 它返回密钥所属的工作空间
和它实际持有的瞄准镜, 所以一个误用瞄准镜的密钥 响亮的失败在
集成时间,而不是像一个不相干的人一样迷惑403
生产终点:
const { workspaceId, scopes } = await chatly.whoami();
7个Api-keys的路线接受一个钥匙,从那时起在其中铸造
2026-10-26 (英语) create 拒绝任何范围 调用密钥没有自控,
所以泄露的只读密钥不能升级. 仅
PUT /v1/api-keys/:id/machine-user 继续关闭密钥。 没有的
这里的键入方法可以通过 request(),这需要 headers —— 说
这就是你发送 x-secret-recipient 将新密钥密封
改为公用密钥,而不是以简写形式返回.
客户所能做的
下面的每一种方法都映射到一个接受密钥认证的终点. 范围 仅满足您整合需要的关键; 关键永远不能比 创建时瞄准镜已选中 .
| 打电话 | 所需范围 |
|---|---|
chatly.whoami() | workspace:read |
chatly.contacts.list({ cursor?, limit? }) | contacts:read |
chatly.contacts.upsert({ email, name, … }) | contacts:write |
chatly.conversations.list({ cursor?, limit? }) | conversations:read |
chatly.conversations.messages(conversationId) | conversations:read |
chatly.conversations.send({ conversationId, body }) | messages:write |
chatly.search.query('refund', { … }) | search:read |
chatly.search.kb('refund') | search:read |
chatly.events.track({ contactId, name, properties }) | contacts:write |
您随密钥发送的信件被记录为集成发送,而非由 钥匙的创造者, 钥匙的产生者 当他们离开的时候.
未包括,为何
反应和频道/部件配置是故意缺失的. 反应 记录 谁 反应和钥匙不是一个人,所以这些终点需要 注册用户。 频道配置需要一个无法按键的瞄准镜 。 都用过 他们都把403还给每个打电话的人.
目 录
写入接受一等能键, 所以网络失败后重试不进行 重复工作 :
await chatly.withIdempotencyKey('order-4471-refund').contacts.upsert({ … });
正在验证任何东西
verifyChatlySignature 是用来用的。 你告诉它 表面 你们
即将结束,将生体和请求头交给它,然后检查
表面实际使用的构造:
import { verifyChatlySignature } from '@chatlychat/sdk-node';
const result = verifyChatlySignature({
surface: 'event_webhook',
body: rawBody, // the EXACT bytes, before JSON.parse
headers: req.headers,
secret: process.env.CHATLY_WEBHOOK_SECRET!,
method: req.method, // see "the unified v2 signature" below
path: req.url,
});
if (!result.ok) {
console.warn('rejected', result.reason, result.message);
return res.status(400).end();
}
传递生体——重排解析 JSON 重排密钥并更改
白空间,所以文摘将不匹配. 在拒绝时, reason 是一个稳定
树枝上的字符串( t)signature_mismatch, (中文(简体) ), timestamp_outside_tolerance, (中文(简体) ),
missing_signature_header,(......)和 message 是写成的句子
已打印过。 从来投出.
8个表面
surface | 页眉 | 已签名字符串 | t 单位 |
|---|---|---|---|
unified_v2 | x-chatly-signature-v2: t=…,v1=… | <t>.<METHOD>.<path>.<rawBody> | 秒数 |
agent_delivery | x-chatly-signature: t=…,v1=… | <t>.<rawBody> | 秒数 |
event_webhook | x-livechat-signature: t=…,v1=… | <t>.<rawBody> | 秒数 |
ai_tool_call | x-chatly-signature: t=…,v1=… | <t>.<METHOD>.<path>.<rawBody> | 秒数 |
canvas_step | x-chatly-canvas-signature: sha256=… 财务报告和审定财务报表 x-chatly-canvas-ts | <ts>.<rawBody> | 毫秒 |
customer_card | x-chatly-signature: sha256=… 财务报告和审定财务报表 x-chatly-timestamp | <ts>.<rawBody> | 毫秒 |
workflow_webhook | x-chatly-signature-v2: t=…,v1=… | <t>.<rawBody> | 秒数 |
workflow_webhook_legacy | x-chatly-signature: sha256=… | <rawBody> - 没有时间戳 | 无 |
三个人派来了 x-chatly-signature 并签署三条不同的线条,
这就是为什么 surface 需要而不是从标题中推断:a
验证页眉名称上的密钥可以指向错误
建筑设计,同时看起来完全正确.
ai_tool_call 额外需求 method 财务报告和审定财务报表 path (单位:千美元)pathname + search, (中文(简体) ),
永远不要主机),因为两者都在已签名的字符串内. toleranceSeconds
默认为 300 并且总是在 秒数无论表面的单位
timerstamp使用——转换是此函数的工作,并把它弄错了
用手来检查新鲜度 大约54,000年 并拒绝
一切众生.
偏爱 workflow_webhook 结束 workflow_webhook_legacy。 。 。 . 每个工作流程
webhook 呼叫发送两个信头。 留下的遗物在身体上标出没有
时间戳,所以一个被捕获的请求 永远验证,没有什么可以约束一个
重新播放; verifyChatlySignature 拒绝,除非你通过
allowUnprotectedReplay: true,如果你这样做, 使端点一能.
统一 v2 签名
每个地表都在移动 一个 建筑业:
x-chatly-signature-v2: t=<unix seconds>,v1=<hex>
v1 = HMAC-SHA256(secret, `${t}.${METHOD}.${path}.${rawBody}`)
已经发送 并行 每个表层都有头,所以没有断裂
当发送者迁移时. path 实值 pathname + search 请求全文
来到了... 从来没有计划,也没有东道主。 方法与路径在内
文摘是因为 GET 没有身体标志 "<t>..",这是
与每次会议相同 GET {\fn华文楷体\fs20\bord1\shad1\1che0e0e0\2ch000000}而地表能使出并可以回放出相對相對出相
路径.
过 method 财务报告和审定财务报表 path 打开 每个 呼叫时不需要更改代码
发件人移动 : v2 默认为 'prefer',所以 v2 头被校验
并核查遗留的建筑.
const result = verifyChatlySignature({
surface: 'customer_card',
body: rawBody,
headers: req.headers,
secret: process.env.CHATLY_CARD_SECRET!,
method: req.method,
path: req.url,
v2: 'prefer', // the default: 'require' once you know the sender has moved
});
// result.surface is 'unified_v2' when the v2 header was the one that verified.
'prefer' 永不退后:如果v2头存在而不验证,
这是拒绝而不是尝试遗产标题的理由。 两个头
同一个秘密,所以一个好的遗产摘要 除了一个坏v2是
篡改或发送错误, 并接受它会隐藏两者。 使用
v2: 'ignore' 将旧行为归结.
一个皱纹,这是我们的: workflow_webhook 已经发送
x-chatly-signature-v2结束 <t>.<rawBody> - 那个标题比
统一基地。 所以在那个地上 两者 无论何时,都接受基地
供应 method 财务报告和审定财务报表 path,以及 result.base (单位:千美元)'body' 或者说 'target'告诉
发件人用的那个.
该值带有 基准标记数字 : t=…,v1=…,b=t 为统一基地,
b=b 页:1 <t>.<rawBody>。缺失标记意味着 <t>.<rawBody>,因为
在标记存在之前发送的每个 v2 值就是这个. 校对员看了
缩小其企图,并在拒绝时点出原因——a b=t
工作流程请求无 method编号 :path 实值 missing_request_target,而不是一个
不匹配——但绝不接受比表面允许的更多,因为任何人在
电线可以写出标记.
哪个表面发送 x-chatly-signature-v2 现时: 代理人交付
事件 webhook、客户卡获取和画布/步骤回调,全部 b=t· ;
工作流程动作, b=b. AI工具呼叫尚未发出——他们的遗产
x-chatly-signature 已签名统一字符串, 因此 'prefer' 坠落
通过一个相同的支票,你不会失去任何东西通过 method 财务报告和审定财务报表
path 现在.
如果您终止了多个表面, 请全部验证为 unified_v2。 。 。 . 那个
是一个 v2 标题的已记录路径; 平面名称用于
遗产头。 单一例外,直到发送者移动到 b=t,为
工作流程动作——核实为 workflow_webhook。 。 。 .
旋转一个秘密
旋转的两端都得到支持:
const result = verifyChatlySignature({
surface: 'agent_delivery',
body: rawBody,
headers: req.headers,
secret: [process.env.CHATLY_SECRET_NEW!, process.env.CHATLY_SECRET_OLD!],
});
if (result.ok) {
console.log('verified with secret', result.secretIndex); // 0 = the new one
}
secret需要一个阵列. 接受这个新旧秘密 重叠持续;result.secretIndex你是如何学会的旧的 停止使用.- 标题可以包含摘要列表 —— 说
t=…,v1=…,v1=…- 对于发送者 签了两个秘密 任何匹配的验证 它们必须形成良好的结构.
verifyWebhookSignature (仍在支持)
原作"单相"校正. 它处理 event_webhook 仅取
头值而不是头包。 出版、使用、不
离开:
import { verifyWebhookSignature } from '@chatlychat/sdk-node';
const ok = verifyWebhookSignature({
body: rawBody, // the EXACT bytes, before JSON.parse
signatureHeader: req.headers['x-livechat-signature'] as string,
secret: process.env.CHATLY_WEBHOOK_SECRET!,
});
计划是 t=<unix seconds>,v1=<hex>时 v1 hMAC -SHA256 已过
`${t}.${body}`。时间戳在签名的字符串内,所以一个俘虏
一旦外出就停止核查 toleranceSeconds。 。 。 .
这个例子在2026-10-12之前是错的,在三个方面 上面说
payload(现场是:body, (中文(简体) ),signature(这是signatureHeader和x-chatly-signature(网络用户)x-livechat-signature) (中文(简体) ). 单位 TypeScript 旧片段是一个编译错误; 在平版 JavaScript 中是 比回去还糟false,因为核查者分裂input.signatureHeader首先,一个缺席的投出一个TypeError调出 你的网络操作员.标题是值得知道的陷阱:
x-chatly-signature这是真实的, 但属于另外四个地表 ——外方代理交货,定制 AI工具呼叫、客户卡和工作流程fire_webhook行动——和 每一个都以不同的方式构建其基础字符串。 境外事件 webhoks 是一个使用x-livechat-signature不共享一个 核查员在检查时不检查施工情况.
关于此寄存器
这是一个 镜像。 。 。 . @chatlychat/sdk-node 由私人独身建筑 其余的
月台的迁移和合同检查现场直播
无法直接合并, 但补丁仍然是获得东西最快的方法
固定了,我们会把它 与归属.
您可以在这里做什么: 读取源代码, 运行测试, 打开一个问题, 或打开一个 PR 并且我们将把diff当作提案.
未镜像 : src/ signition-vectors- public. spec.ts —— 仍然在此重述的类别 与单列波的原作相匹配,这仅仅是其中的一个有意义的主张. 他们 继续跑.
问题: https://github.com/chatlychat/chatly-sdk-node/issues (中文(中国大陆) ) * 文件: https://chatlychat.com/docs (中文(简体) )