@crvouga/mockingbird-service-customerio

中文文档
3.11.0发布于 2026/11/11MITTypeScriptES Module构建来源已验证近 30 天下载 1.6万

Customer.io的状态仿真器:可兼容分块的 CDP(识别/跟踪/批发,SDK 滴入),App API 交易电子邮件/SMS/inbox 发送带有发箱,消息目录,点击链接跟踪,并签名报告webhooks.

中文使用文档
文档目录8 节
  1. 安装
  2. 使用量
  3. 路线
  4. 汇报网点
  5. 管理员(超过标准合同)
  6. 命名空间
  7. 故意不模拟
  8. API 密码

@crvouga/ 嘲笑鸟 - 服务 - 客户

本地模拟器。 真正的API合同. 部分 嘲笑鸟。 。 。 .

状态模拟器 顾客.io 测试套房,服务所有三个主机 我们的代码谈话从 一个进程: 与段相兼容 发展政策委员会 (单位:千美元)identify, (中文(简体) ), track, (中文(简体) ), batch,与 @customerio/cdp-analytics-node 员额) 应用 API 交易发送(电子邮件、短信、, 、收件箱信息、信息目录、配置属性读取、发送者选择退出调节、交付状态读取、以及 链接跟踪 点击结束点。 在一个发包箱中发送一个套件(并读取链接) (一) 报告活动(unsubscribed, (中文(简体) ), subscribed, (中文(简体) ), spammed,订阅偏好, clicked并签署客户签名的方式.

  • 行动范围: 支助
  • 合同openapi.yaml)由Customer.io的CDP(分块谱)和App API手写 参考书目,与我们的消费者寄送的东西相对应.

安装

npm install -D @crvouga/mockingbird-service-customerio

仅限无害环境管理。 节点 22或 Bun 1.2. 无土生属地. 给它服务 npx mockingbird-customerio serve, (中文(简体) ), createServer 从 ./server (节点),或 createRuntime 与任何获取服务器.

使用量

应用程序硬码为Customer.io的每个区域主机(customer-io.config.ts,接合G-Y1):一次 它们被env驱动,指向 CDP 主机(SDK's host, App API 主机和链接 跟踪模拟器中的域。 顾客.io只运行当 CUSTOMERIO_RUNTIME_ENABLED 开始和 舞台已经进入 CUSTOMERIO_ALLOWED_STAGES。 。 。 .

npx mockingbird-customerio serve --port 8810 \
  --webhook-url http://127.0.0.1:3000/v1/customer-io/reporting-webhook \
  --webhook-secret "$CUSTOMERIO_REPORTING_WEBHOOK_SIGNING_KEY"
import { Analytics } from "@customerio/cdp-analytics-node"
import { createServer } from "@crvouga/mockingbird-service-customerio/server"

const cio = await createServer({
  webhooks: { url: "http://127.0.0.1:3000/v1/customer-io/reporting-webhook", secret: "k".repeat(32) },
})

// The application's CDP client. Only its host changes.
const analytics = new Analytics({ writeKey: "wk", host: cio.url, maxEventsInBatch: 1 })
analytics.identify({ userId: "42", traits: { email: "[email protected]" } })
await analytics.closeAndFlush()

// Test control. The member unsubscribes in Customer.io: the signed reporting event reaches the backend.
await fetch(`${cio.url}/__admin/reporting-events`, {
  method: "POST",
  headers: { "content-type": "application/json" },
  body: JSON.stringify({ metric: "unsubscribed", userId: "42", objectType: "customer" }),
})
await cio.close()

交易发送通过 App API 客户端(customerio-node),指出这一点 模拟器。 测试内容是:

import { Analytics } from "@customerio/cdp-analytics-node"
import { APIClient, SendEmailRequest } from "customerio-node"
import { createServer } from "@crvouga/mockingbird-service-customerio/server"

const cio = await createServer()

// The application's clients. Only the CDP host and the App API url change.
const analytics = new Analytics({ writeKey: "wk", host: cio.url, maxEventsInBatch: 1 })
const api = new APIClient("app-key", { url: `${cio.url}/v1` })
analytics.identify({ userId: "42", traits: { email: "[email protected]" } })
await analytics.closeAndFlush()
await api.sendEmail(
  new SendEmailRequest({ transactional_message_id: 1, identifiers: { id: "42" }, to: "[email protected]" }),
)

// Test assertions read the emulator's state.
const profiles = await (await fetch(`${cio.url}/__admin/profiles`)).json()
const deliveries = await (await fetch(`${cio.url}/__admin/outbox?userId=42`)).json()
await cio.close()

路线

路线行为
POST /v1/identify, (中文(简体) ), /v1/track, (中文(简体) ), /v1/batch发展政策委员会, Authorization: Basic base64(<write key>:) (原为401) {error}) (中文(简体) ). 部分活动(batch 联 合 国 identify 编号 : track(b) 每个需要 userId 或者说 anonymousId (减:400人) {error},SDK不重试). 在适用任何条目之前,对批次进行验证。 → {success: true}查明浅层的特质; cio_subscription_preferences.channels 编号 : .topics 合并一个关卡, 因此省略密钥和清晰 false 留下来。 在一个剖面图上同时进行识别被序列化. 重复 messageId 被记录为复制而不适用.
POST /v1/send/email, (中文(简体) ), /v1/send/sms, (中文(简体) ), /v1/send/inbox_message应用API, Authorization: Bearer <app key> (原为401) {meta: {error}}) (中文(简体) ). {transactional_message_id (id or trigger name, case-insensitive), identifiers: exactly one of id | email | cio_id, to?, from?, subject?, message_data?, send_to_unsubscribed?, tracked?, disable_message_retention?, headers?, attachments?} → {delivery_id, queued_at}校验错误为 400 {meta: {error}}. 简讯 to,当存在时,必须是E.164. 与 strictMessages,一个未知的id是400 {meta: {error: "transactional_message_id not found"}}。一个 identifiers.id (a) 没有配置图可创建最小配置; to 保留字面上的收件人。 接受发送开始 pending (未交付). 未订阅的配置文件, 或其电子邮件/ SMS 频道 false获取 suppressed 除非 send_to_unsubscribed (框只跟随未订阅的旗帜). disable_message_retention 滴数 message_data 从发件箱中取出,除非 retainMessageDataForTests。 。 。 . tracked: true 重写每个 URL 为 <trackingBase>/click/<linkId>。没有发送能力:重复生成另一个发送.
GET /v1/transactional{messages: [{id, name, trigger_name, description, send_to_unsubscribed, link_tracking, …}]},不发作(整个目录,包括上百行). 种子与 acme_<key> 对于每个遗留的电子邮件密钥 消费者应用程序,还有 acme_inbox_message 财务报告和审定财务报表 acme_playground_notification (编号1-21). transactionalListKey: "transactional" 重命名数组密钥.
GET /v1/transactional/{id}{message: {...}} 由 id 或触发名称(大小写不敏感),或 404 .
GET /v1/customers/{customer_id}/attributes?id_type=id|email|cio_id{customer: {identifiers: {id, email?, cio_id}, attributes, devices}}未知号码 id_type 400; 不明客户为404。 属性传播存储的特性,然后 id, (中文(简体) ), cio_id, (中文(简体) ), email,以及 unsubscribed 赢了.
GET /v1/optouts?limit=&start=&from=工作空间发送器选择退出 {optouts: [{customer_id, cio_id, optouts: [{channel, from}]}], next?}。 。 。 . limit 默认为 100 (1-1000); 以下 next 使用 start 直到它缺席. from 过滤发件人/频道条目,省略没有匹配的人. 发件人值被修剪并小写;E.164数字保留其形式.
GET /v1/customers/{customer_id}/optouts?id_type=id|email|cio_id{optouts: [{channel, from}]} 对于一个已有的配置文件,如果没有,则为空,对于未知的人则为404。 使用与 CDP 识别和配置更新相同的身份状态. App API 认证适用于两种读取.
GET /v1/messages/{delivery_id}{message: {id, type, recipient, customer_id, created, state, status, metrics}}。 。 。 . type 实值 in_app 用于收件箱。 没有 message_data. 404 当id丢失或仍在里面 statusVisibleAfterMs。失败状态后添加 failure_message, (中文(简体) ), rejection_reason,以及 error。 。 。 .
POST /click/{linkId}我们的后端点击报告(未经认证) ^ 200,计算点击数并张贴a clicked 报告活动。 未知链接:平正文字 404.
GET /click/{linkId}浏览器沿着有轨链接 ~ 302 到原URL.

汇报网点

POST <webhook-url> 与 x-cio-timestamp: <unix seconds> 财务报告和审定财务报表 x-cio-signature: <hex HMAC-SHA256(secret, "v0:<timestamp>:<body>")> (墙-钟时间戳. 车身 : {event_id, object_type, metric, timestamp, data: {identifiers: {id, email, cio_id}, customer_id, email_address, delivery_id?, transactional_message_id?, href?, link_id?, content?}}· ; content 是订阅首选项的 JSON 字符串. timestamp 永远不要赶在时分前跑 (我们的接收器拒绝事件 > 5分钟). 报复, GET /__admin/webhooks, (中文(简体) ), …/events, (中文(简体) ), …/replay, (中文(简体) ), …/flush 财务报告和审定财务报表 PUT /__admin/webhook-endpoints 工作如常.

管理员(超过标准合同)

路线效果
GET /__admin/outbox?to=&recipient=&since=&channel=&transactional_message_id=&userId=&deliveryId=交易性交货,最先交货GET /__admin/outbox/:id 一个: channel, (中文(简体) ), to, (中文(简体) ), identifiers, (中文(简体) ), subject, (中文(简体) ), messageData, (中文(简体) ), links, (中文(简体) ), originalLinks, (中文(简体) ), tracked, (中文(简体) ), state (单位:千美元)pending 直至过渡,或 suppressed, (中文(简体) ), reason, (中文(简体) ), metrics, (中文(简体) ), clicks, (中文(简体) ), attachments (档案名). recipient 匹配 to。日记记录方法、路径和状态,绝不是正文、API密钥或消息内容.
POST /__admin/reporting-events{metric, userId? | email? | deliveryId?, objectType?, preferences?: {topics?, channels?}}: 将其应用到配置文件上 (unsubscribed, (中文(简体) ), subscribed, (中文(简体) ), spammed, (中文(简体) ), cio_subscription_preferences_changed)并张贴已签名的事件。 任何其他衡量标准(delivered, (中文(简体) ), opened, (中文(简体) ), bounced,.)作为-s发布.
GET /__admin/cdp/events?userId=&type=&event=收到的CDP电话(与 duplicate) (中文(简体) ).
GET /__admin/profiles, (中文(简体) ), GET /__admin/profiles/:id, (中文(简体) ), PUT /__admin/profiles/:id概况(海峡, cioId, (中文(简体) ), unsubscribed, (中文(简体) ), channelsOff, (中文(简体) ), preferences. PUT 合并 {traits?, email?, unsubscribed?, preferences?}。 。 。 .
POST /__admin/optouts{customerId, from, optout: boolean, channel?: "sms"|"whatsapp"} 脚本停止( E)true)或裁武条约(false(b) 现有人员;身份不明者为404人。 只有发送/频道更改 。 营销偏好和报告网友保持独立. 国家参与命名空间、快照、时光线、钟表和重置.
POST /__admin/deliveries/:id{"state": "pending"|"sent"|"delivered"|"bounced"|"dropped"|"failed"|"spammed"|"undeliverable"|"suppressed"}。邮票 metrics[state] 在命名空间时钟上有 unix 秒. delivered 失败状态是终极状态.
POST /__admin/namespace-clock{"advance": <ms>} 仅添加此命名空间的时钟偏移 .
GET|PUT /__admin/transactional读取或替换工作空间的交易信件( E)[{id?, name?, trigger_name, link_tracking?, send_to_unsubscribed?}]) (中文(简体) ).
GET|PUT /__admin/settings{strictMessages?, trackingBase?, keys?, statusVisibleAfterMs?, clockOffsetMs?, retainMessageDataForTests?, transactionalListKey?} (单位:千美元)keys 限制已接受的写入 / App API 密钥 .

错误预设( E)POST /__admin/faults {"preset": "<name>", "count"?: n}· ; GET /__admin/faults/presets: transactional_message_missing (400元误差: trigger_name_missing然后退后,不交付, transactional_404, (中文(简体) ), request_timeout_408 (408) 排队前,不交货,含糊不清, server_error (500后再排队,不交付,含糊不清), accepted_but_500 (排好,然后500), rate_limited (429 有数字) Retry-After当然,没有交付, invalid_app_key, (中文(简体) ), send_drop 财务报告和审定财务报表 send_drop_before_accept (口袋在排队前关闭:模棱两可,不交货), send_drop_after_accept (交货记录,然后插座关闭:模棱两可,一次交货), cdp_unavailable (503; SDK 重试),, cdp_bad_request (400;没有重试), cdp_slow (15 s,过去) 10s的交货暂停, transactional_list_unavailable, (中文(简体) ), omit_trigger_names (单位:百万 trigger_name,或仅 params.ids, (中文(简体) ), webhook_duplicate, (中文(简体) ), webhook_drop, (中文(简体) ), webhook_reorder。 。 。 . 人工断层可以注射403或503或429个 Retry-After 是一个 HTTP 日期。 终止 (肯定失败)是被停止的仿真器,而不是预设. 401号 {error} 政策发展协调委员会 {meta: {error}} 在应用API。 映射到相同名称空间的密钥共享配置和交付; 两个命名空间不包含断层和时钟相冲。 重置一个命名空间 留下另一个.

命名空间

x-mockingbird-namespace页:1 /__admin/ns/<name> 在主机或按键上设置前缀: CDP 写入密钥( Basic 用户名)或 App API 密钥 (Bearer) 通过 PUT /__admin/credentials {"credentials": {"<key>": "<namespace>"}}。点击端点不带证书:使用页眉或前缀.

故意不模拟

  • Opt-out通过公共PUT API,电话标识工作空间配置,Twilio发件人身份外壳恢复,以及自动载体停止回调. 使用管理员控制来脚本调和器状态;它不模拟承运人的交付执行.
  • 渲染: 未提供模板; 发件箱持有 message_data,而不是HTML. 翻译:.
  • 运动、片段、出行、广播和轨道 APItrack.customer.io) (中文(简体) ).
  • 发展政策委员会 page, (中文(简体) ), screen, (中文(简体) ), group 财务报告和审定财务报表 alias 电话(我们的消费者不发送).
  • 附件仅用文件名记录 。 客户.io文件a {filename: base64} 地图; 我们的后端发送 [{filename, content, content_type}]二者均被接受;是否真实 API接受阵列形式未经验证(没有沙盒证书).
  • 持发委东道机构{success: true})和准确的 App API 错误字符串 transactional_message_id not found 未经证实.

API 密码

导出仁爱说明
CustomerIoAPI类进程模拟器 : fetch(request), (中文(简体) ), reset(), (中文(简体) ), report(input), (中文(简体) ), profiles(), (中文(简体) ), mergeProfile(id, patch), (中文(简体) ), transitionDelivery(id, state), (中文(简体) ), advanceClock(ms), (中文(简体) ), state选项: sqlite, (中文(简体) ), now, (中文(简体) ), wallClock, (中文(简体) ), namespace, (中文(简体) ), messages, (中文(简体) ), settings, (中文(简体) ), onReport。 。 。 .
createRuntime函数全面服务合同的仿真器(健康、管理、命名空间、证书、预设、发包、报告网络呼号)。 选项 : webhooks: {url, secret, retryDelaysMs?, fetch?}, (中文(简体) ), messages, (中文(简体) ), settings, (中文(简体) ), clock, (中文(简体) ), wallClock, (中文(简体) ), seed, (中文(简体) ), adminKey, (中文(简体) ), onLog, (中文(简体) ), sqlite。 。 。 .
CUSTOMERIO_PRESETS对象每个命名的断层预设.
CUSTOMERIO_NAMESPACE字符串服务名称, "customerio"。 。 。 .
REPORTING_WEBHOOK_PATH字符串接收器的路径, /v1/customer-io/reporting-webhook。 。 。 .
signReporting函数(secret, timestampSeconds, body) - 六分卫 x-cio-signature。 。 。 .
customerIoCredential函数请求所携带的写键或 App API 键 .
DEFAULT_TRANSACTIONAL_MESSAGES, (中文(简体) ), DEFAULT_SETTINGS, (中文(简体) ), TRANSACTIONAL_EMAIL_KEYS数值种子目录,设置, 以及我们的后端遗留的电子邮件密钥.
DELIVERY_STATES数值交付生命周期状态。 接受的发送起始于 pending。 。 。 .
FAILURE_STATES数值终端失败状态 : bounced, (中文(简体) ), dropped, (中文(简体) ), failed, (中文(简体) ), spammed, (中文(简体) ), undeliverable, (中文(简体) ), suppressed。 。 。 . delivered 是成功的; sent 保持开放.
document, (中文(简体) ), operationIds, (中文(简体) ), supportedOperationIds数值销售商为OpenAPI合同及其业务代号.
createServer, (中文(简体) ), serveTarget, (中文(简体) ), DEFAULT_PORT (单位:千美元)./server(中文(简体) )节点服务过来 node:http; 数据 serve CLI目标;出港8810.

部分 嘲笑鸟。 。 。 .

版本与发布记录

@crvouga/mockingbird-service-customerio 共发布 42 个版本,首次发布于 2026/09/23;过去 12 个月发布了 42 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
3.11.0latest2026/11/11今天
3.10.92026/11/038 天前
3.10.82026/11/038 天前
3.10.72026/11/038 天前
3.10.62026/11/038 天前
3.10.52026/11/038 天前

关于 @crvouga/mockingbird-service-customerio 的常见问题

@crvouga/mockingbird-service-customerio 是什么?

Customer.io的状态仿真器:可兼容分块的 CDP(识别/跟踪/批发,SDK 滴入),App API 交易电子邮件/SMS/inbox 发送带有发箱,消息目录,点击链接跟踪,并签名报告webhooks.

如何安装 @crvouga/mockingbird-service-customerio?

在项目目录运行 npm install @crvouga/mockingbird-service-customerio,或使用 pnpm add / yarn add / bun add。它还提供命令行工具 mockingbird-customerio,可以用 npx mockingbird-customerio 直接运行。

@crvouga/mockingbird-service-customerio 支持 TypeScript 吗?

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

@crvouga/mockingbird-service-customerio 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@crvouga/mockingbird-service-customerio 可以商用吗?

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

@crvouga/mockingbird-service-customerio 的下载量有多少?

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

@crvouga/mockingbird-service-customerio 还在维护吗?

最新版本 3.11.0 发布于 2026/11/11(今天);至今共发布 42 个版本,其中过去 12 个月发布了 42 个;首次发布于 2026/09/23。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。