@crvouga/mockingbird-service-intercom (中文(简体) )
本地模拟器。 真正的API合同. 部分 嘲笑鸟。 。 。 .
国家模拟器 Intercom REST API (第 2. 11 版) 测试套房。 服务于电话 我们的后端:
- 联系人 : a. 搜索、创建(复制409个,Intercom的方式)、更新和获取;
- 对话 : 创建( 可选)
Idempotency-Key,更新,作为成员或作为 管理员(JSON或多部分附件),关闭/打开/snooze/指派,与?display_as=plaintext,并用光标涂上搜索; - 身份 :
/admins财务报告和审定财务报表/me。 。 。 .
行政答复和关闭/开放(对于订阅这些答复的接收者,还包括成员信息和
答复)发送Intercom的 notification_event 与 webhoks 签约
X-Hub-Signature: sha1=<hex HMAC-SHA1>,给两个接收器:后端的
POST /messaging/webhook 以及欧洲公路运输公司 POST /v1/webhooks/intercom。 。 。 .
- 行动范围: 支助
- 合同
openapi.yaml由Intercom发表的2.11 引用 消费者使用.
安装
npm install -D @crvouga/mockingbird-service-intercom
仅限无害环境管理。 节点 22或 Bun 1.2. 无土生属地. 给它服务
npx mockingbird-intercom serve, (中文(简体) ), createServer 从 ./server (节点),或 createRuntime 与
任何获取服务器.
使用量
npx mockingbird-intercom serve --port 8807 \
--webhook-url http://127.0.0.1:3000/messaging/webhook \
--emr-webhook-url http://127.0.0.1:4000/v1/webhooks/intercom \
--webhook-secret "$INTERCOM_WEBHOOK_SECRET"
添加 --webhook-events conversation.user.created,conversation.user.replied,conversation.admin.replied,conversation.admin.closed,conversation.admin.opened
订阅 --webhook-url 成员专题; --emr-webhook-url 只保留管理员
默认.
| 消费者 | 设置 |
|---|---|
成员信息适配器(intercom-messaging.adapter.ts(中文(简体) ) | INTERCOM_API_BASE_URL=http://127.0.0.1:8807 (已读出), INTERCOM_ACCESS_TOKEN=<any> |
Intercom同步适配器(intercom-api.adapter.ts(中文(简体) ) | 缝合 G-I1级: 此适配器硬码 https://api.intercom.io 今天,它需要一个嵌入基址。 它的笔迹也由 FEATURE_INTERCOM_SYNC_ENABLED。 。 。 . |
| 两个网路接收器 | INTERCOM_WEBHOOK_SECRET =: --webhook-secret |
import { IntercomClient } from "intercom-client"
import { createServer } from "@crvouga/mockingbird-service-intercom/server"
const emulator = await createServer({
webhooks: {
urls: ["http://127.0.0.1:3000/messaging/webhook", "http://127.0.0.1:4000/v1/webhooks/intercom"],
secret: "whsec-test",
},
})
// The application's Intercom client. Only baseUrl changes.
const intercom = new IntercomClient({ token: "any-token", baseUrl: emulator.url })
const contact = await intercom.contacts.create({ role: "user", external_id: "1652", email: "[email protected]" })
// The member opens a conversation through the app.
const message = await intercom.conversations.create({
from: { type: "user", id: contact.id ?? "" },
body: "Are my results in?",
})
// Test control. Support answers: appends an admin comment and fires the signed conversation.admin.replied.
await fetch(`${emulator.url}/__admin/conversations/${message.conversation_id}/admin-reply`, {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ adminId: "1000001", body: "Your results are in" }),
})
await emulator.close()
路线
每条路线都需要 Authorization: Bearer <token>除非
tokens 已经设定. Intercom-Version 默认值为2.11,一个错误的值回答400
intercom_version_invalid。每次错误都使用 Intercom 的信封 :
{type: "error.list", request_id, errors: [{code, message}]}。 。 。 .
| 路线 | 行为 |
|---|---|
GET /contacts | 联系人收集; per_page (违约10,最多150起), starting_after 光标和 page。当前状态来自现有联系人 API. |
GET /conversations | 对话收集; per_page (违约20起,最多150起)和 starting_after 光标。 列表省略对话框部分; 获取单个对话框部分 . |
POST /contacts/search | {query, pagination?} → {type: "list", data, total_count, pages}。见下文"搜索". |
POST /contacts | {role, external_id?, email?, name?, phone?, signed_up_at?, custom_attributes?} 联系人,其 id 是24个十六进制字符。 A 类 user 需要电子邮件或外部 id。 一秒钟 user 同样的 external_id,或者同一个电子邮件(对大小写不敏感),答案 409个 conflict:"一个与这些细节相匹配的联系已经存在id=...". 同步适配器然后搜索和PUT. 永远不导致冲突. |
PUT /contacts/{id} | 部分更新. custom_attributes 合并。 404 (韩语) User Not Found; 409 如果新的识别器相撞. |
GET /contacts/{id} | 联系人(name, (中文(简体) ), email, (中文(简体) ), external_id,.),或404个. |
POST /conversations | {from: {type: "user", id}, body} → {type: "user_message", id, created_at, body, message_type: "inapp", conversation_id}。联系人必须存在(404人除外)。 一个 Idempotency-Key 头重放存储的对应同体. 409号钥匙是不同的身体. |
PUT /conversations/{id} | {read?, title?, custom_attributes?} (例如 {custom_attributes: {chatbot_escalation: true}} 或者说 {read: true}谈话. |
POST /conversations/{id}/reply | 贾森 {message_type: "comment", type: "user", intercom_user_id | user_id | email, body, attachment_files?: [{content_type, name, data (base64)}], attachment_urls?},或 {type: "admin", admin_id, message_type: "comment" | "note" | "quick_reply", body}。 。 。 . 或多块外加 attachment_files[] 文件部分。 返回对话. |
POST /conversations/{id}/parts | {message_type: "close" | "open" | "snoozed" | "assignment", type: "admin", admin_id, snoozed_until?, assignee_id?} 谈话. |
GET /conversations/{id}?display_as=plaintext | id, state, open, read, created_at, source{id, body, author{type, id, name, email}, attachments, delivered_as}, contacts.contacts[0].external_id, conversation_parts.conversation_parts[] (每一部分类型,包括关闭/打开/注;适配器保留) comment),队友,自定义属性. |
POST /conversations/search | {query, pagination: {per_page ≤ 150, starting_after}, sort_field, sort_order} → {type: "conversation.list", conversations, total_count, pages: {page, per_page, total_pages, next?: {page, starting_after}}}。与真实的API一样,结果带有 没有 conversation_parts。 。 。 . |
GET /admins | {type: "admin.list", admins: [{id, name, email, …}]}种子管理员是 1000001 (单位:千美元)[email protected]和 1000002 (单位:千美元)[email protected]) (中文(简体) ). |
GET /me | 信使的管理员和应用程序. |
对话状态如下Intercom :
- 管理评论集
read: false,意思是未读成员. - 成员答复
read: true设置waiting_since,然后重新打开一个已关闭或已打呼的 谈话. PUT {read: true}标记谈话内容.- 笔记改变不了成员所看到的任何东西.
- 尸体作为 HTML 存储. 纯文本被包入
<p>,每行一段,以及display_as=plaintext变回正文.
附件仅保留其元数据:名称、内容类型、大小和a
downloads.intercomcdn.com 未服务的 URL 。 上传的字节从未被存储 .
搜索
查询是过滤器 {field, operator, value} 或化合物
{operator: "AND" | "OR", value: [query, …]},巢至两层.
- 运算符 :
=, (中文(简体) ),!=, (中文(简体) ),IN, (中文(简体) ),NIN(这两个取一阵子),<, (中文(简体) ),>, (中文(简体) ),~(夹子),!~, (中文(简体) ),^(从开始)和$(结束). 字符串比较对大小写不敏感. - 联系字段 :
id, (中文(简体) ),external_id, (中文(简体) ),email, (中文(简体) ),name, (中文(简体) ),phone, (中文(简体) ),role时间戳, 财务报告和审定财务报表custom_attributes.<name>。 。 。 . - 对话字段 :
id, (中文(简体) ),contact_ids, (中文(简体) ),teammate_ids, (中文(简体) ),admin_assignee_id, (中文(简体) ),team_assignee_id, (中文(简体) ),state, (中文(简体) ),open, (中文(简体) ),read, (中文(简体) ),priority, (中文(简体) ),title,时间戳,和source.{id,type,delivered_as,subject,body,author.id,author.type,author.name,author.email}。 。 。 . - 未知字段或运算符 答复 400
parameter_invalid。 。 。 . - 排序 :
updated_at默认下降, id作为断线器. - 光标 : 不透明基数64,默认每页有20个.
网络呼号
模拟器为这些事件发送了网络呼号:
| 活动 | 专题 |
|---|---|
行政评论或快速回复(API或 POST /__admin/conversations/:id/admin-reply(中文(简体) ) | conversation.admin.replied |
关闭( E)/parts 或者说 POST /__admin/conversations/:id/close(中文(简体) ) | conversation.admin.closed |
打开( O)/parts 或者说 POST /__admin/conversations/:id/open(中文(简体) ) | conversation.admin.opened |
行政发起的谈话POST /__admin/conversations(中文(简体) ) | conversation.admin.single.created |
成员开始交谈(POST /conversations(中文(简体) ) | conversation.user.created (选入) |
成员答复/reply 与 type: "user"(中文(简体) ) | conversation.user.replied (选入) |
端点接收上面四个管理主题, 除非它列出自己的主题 events成员
议题, conversation.admin.snoozed 财务报告和审定财务报表 .assigned 已发布,但选择进入:用
--webhook-events, (中文(简体) ), webhooks.urls: [{url, events}] 或者说 PUT /__admin/webhook-endpoints。 EMR
处理每个 notification_event 它作为管理事件收到,所以它的订阅不能
包括成员专题。 笔记什么也没有发出.
每一次送货都有一个JSON机体 X-Hub-Signature: sha1=<hex HMAC-SHA1(secret, rawBody)>数字 :
{ "type": "notification_event", "app_id": "mockapp", "topic": "conversation.admin.replied",
"id": "notif_…", "created_at": 1760000000, "delivery_status": "pending", "delivery_attempts": 1,
"data": { "type": "notification_event_data", "item": { "type": "conversation", "id": "…",
"source": { "delivered_as": "customer_initiated", "author": { "email": "…" }, "body": "…" },
"contacts": { "contacts": [{ "id": "…", "external_id": "1652" }] },
"conversation_parts": { "conversation_parts": [ { "id": "…", "part_type": "comment", "body": "<p>…</p>", "created_at": 1760000000 } ] } } } }
- 只有新的部分.
item.conversation_parts仅保留导致事件的部分, 就像Intercom自己的有效载荷一样. - 长相相出相出相. 该部分的时间戳和信封
created_at使用真实 时间,绝不是模拟时钟,因为EMR将超过5分钟的部件拒绝用于其 拥有时钟. - 稳定编号. 通知
id复试和复试时保持不变webhook_duplicate这样 后门的delivery_id ?? iddedupe和EMR的处理-标记器 dedupe都持有. - 复问. 非-2xx的回答在5 s, 5 min, 30 min和 2 h 之后重审.
- 行政飞机.
GET /__admin/webhooks, (中文(简体) ),…/events, (中文(简体) ),…/flush, (中文(简体) ),…/:id/replay财务报告和审定财务报表PUT /__admin/webhook-endpoints是标准的 webhook 管理员路径.
管理员(超过标准合同)
| 路线 | 效果 |
|---|---|
POST /__admin/conversations/:id/admin-reply | {adminId? | admin_id? (default: first admin), body, messageType?: "comment" | "note"} 附加一个管理员部分("护理团队回复")并放出"webhook". |
GET /__admin/outbox?since=&to=&limit=, (中文(简体) ), GET /__admin/outbox/:id | 客户送来的东西 POST /conversations 财务报告和审定财务报表 /reply,最古老的第一个: {id, operation, conversationId, contactId, partId, partType ("source" for the opening message), authorType, authorId, hasBody, bodyLength, attachmentCount, at, createdAt}。 。 。 . 只有元数据:尸体从未被储存. to= 匹配对话或联系人身份; since= 在模拟器时钟上取去时代 ms 或 ISO-8601。 管理员飞机本身的答复没有列出. |
POST /__admin/conversations/:id/close, (中文(简体) ), …/open | {adminId?} 关闭或重新开放作为管理员,并点燃了webhook. |
POST /__admin/conversations | {contactId | externalId, adminId?, body} 创建管理员启动的对话。 然后,EMR检查成员 contacts[0].external_id。 。 。 . |
GET /__admin/conversations, (中文(简体) ), GET /__admin/contacts | 名字空间的记录. |
PUT /__admin/admins | 替换管理员 : [{id, name, email}]。 。 。 . |
GET/PUT /__admin/settings | {tokens?: string[], customAttributes?: string[] | null}与 customAttributes 设置,写入未定义的属性是400,如同在真实的工作空间. |
错误预设( E)POST /__admin/faults {"preset": "<name>", "count"?: n}:
| 预设 | 效果 |
|---|---|
rate_limited | 每一次电话回答429 rate_limit_exceeded。适配器将其映射到429. |
unauthorized | 每个呼叫都答401. |
server_error | 每呼应答五百. 适者掷出. |
service_unavailable | 每通来电答503. 适者掷出. |
contact_stale_404 | 接下来的对话搜索回答404. 适配器将缓存的联系人ID放下,重新解开并重试一次. |
search_unavailable | 搜索答案 conversations: null。管理员的收件箱回答 503. |
repeated_cursor | 搜索始终如一 next.starting_after。管理员收件箱检测回路并回答503. |
webhook_duplicate | 送出下个网游两次. |
webhook_reorder | 换下两个网友. |
webhook_drop | 永远不要送下个网页. |
命名空间
- 页:1
x-mockingbird-namespace页眉; - (单位:千美元)
/__admin/ns/<name>前缀在INTERCOM_API_BASE_URL· ; - 访问符号 :
PUT /__admin/credentials {"credentials": {"<INTERCOM_ACCESS_TOKEN>": "<namespace>"}}。 。 。 .
请求日记记录了操作的ID,状态和联系,谈话和部分ID. 这个 从不记录信件机构或联系方式.
故意不模拟
- 成员- 应用程序 信使 SDK 和 Web 部件 (
@intercom/intercom-react-native, (中文(简体) ),@intercom/messenger-js-sdk) (中文(简体) ). 他们通过自己的协议与Intercom自己的主机交谈. 这个 web 部件没有测试阶段的门, 因此 QA 应该屏蔽它 . - 附件下载: URL已录入但未服务.
- 标记、笔记、公司、片段、门票、文章、数据属性管理、团队和 解放军. 这些只是有效载荷所在的空清单.
- 正常响应的速率限制头. 仅
rate_limited派他们来. - Intercom对同位素冲突的确切措辞,未经验证:仿真器答案
409个
conflict。 。 。 .
API 密码
| 导出 | 仁爱 | 说明 |
|---|---|---|
IntercomAPI | 类 | 进程模拟器 : fetch(request), (中文(简体) ), reset(), (中文(简体) ), appendPart(…), (中文(简体) ), manage(…), (中文(简体) ), startAdminConversation(…), (中文(简体) ), conversations(), (中文(简体) ), contacts(), (中文(简体) ), conversationBody(…), (中文(简体) ), contactBody(…), (中文(简体) ), error(…), (中文(简体) ), state选项: sqlite, (中文(简体) ), now, (中文(简体) ), wallClock, (中文(简体) ), namespace, (中文(简体) ), admins, (中文(简体) ), settings, (中文(简体) ), onWebhook。 。 。 . |
IntercomError | 类 | 管理员制法引起的供应商出错(状态,代码,消息). |
createRuntime | 函数 | 全面服务合同的仿真器(健康、管理、命名空间、证书、预设、网络呼号)。 选项 : webhooks: {urls, secret?, events?, retryDelaysMs?, fetch?} 联合国 urls 条目可能是 {url, events} 要覆盖 events 对于那个URL, admins, (中文(简体) ), settings, (中文(简体) ), clock, (中文(简体) ), wallClock, (中文(简体) ), seed, (中文(简体) ), adminKey, (中文(简体) ), onLog, (中文(简体) ), sqlite。 。 。 . |
INTERCOM_PRESETS | 对象 | 每个命名的断层预设. |
INTERCOM_NAMESPACE | 字符串 | 服务名称, "intercom"。 。 。 . |
INTERCOM_TOPICS | 数组 | 模拟者可以发送的每个webhook主题,包括选入成员主题. |
HUB_SIGNATURE_HEADER, (中文(简体) ), signHub | 数值 | X-Hub-Signature 编辑 sha1=<hex> 签名人,给自己的接收者. |
DEFAULT_ADMINS, (中文(简体) ), DEFAULT_SETTINGS | 数值 | 种子管理员和默认设置 . |
toHtml, (中文(简体) ), toPlaintext, (中文(简体) ), encodeCursor, (中文(简体) ), decodeCursor | 函数 | 身体渲染和搜索光标格式. |
document, (中文(简体) ), operationIds, (中文(简体) ), supportedOperationIds | 数值 | 销售商为OpenAPI合同及其业务代号. |
createServer, (中文(简体) ), serveTarget, (中文(简体) ), DEFAULT_PORT (单位:千美元)./server(中文(简体) ) | 节点 | 服务过来 node:http; 数据 serve CLI目标(--webhook-url, (中文(简体) ), --webhook-events, (中文(简体) ), --emr-webhook-url, (中文(简体) ), --webhook-secret, (中文(简体) ), --access-token; 第8807号口. |
部分 嘲笑鸟。 。 。 .