SaaS 和产品团队
你的产品知道一些营销工具永远观察不到的事
谁完成了新手引导,谁卡在第三步。谁邀请了同事。谁这周两次撞到上限。谁两周没打开过那个东西。每一个都是比邮件打开率更好的触发条件,而它们离成为触发条件只差两行代码。
事件就是全部集成
用你自己的令牌请求 POST /v1/events:一个你起的名字、一个联系人、一份负载、一个幂等键。这就是全部的对接。没有需要持续维护的 SDK,没有映射界面,也没有一套需要你把产品翻译过去的我们的术语。
每个事件都会落到联系人的只追加日志上,从那里起它同时是三样东西。一个触发器,事件到达时启动一个漏斗。一个谓词,让细分人群可以说“最近十四天内做过这件事”,或者更有用的是“没做过”。还有一个目标,让一个序列在某人完成它所推动的那件事的那一刻结束。
第三点是让生命周期消息变得可以接受的关键。催你完成账户设置的提醒,应该在账户设置完成的那一刻消失,而在大多数工具里它不会,因为序列和产品之间互不相通。
- ⚡触发器
api_event—signup.completed,套餐free。 - 2发送邮件先做这一件事。不是十一项功能的导览。
- 3等待 2 天运行记录上的
wake_at。没有排队的任务,就算你明天重写这里,也没有什么需要拆解。 - ?条件
project.created到了吗?没有 → 走帮助分支。到了 → 走下面的目标。 - 4帮助分支一条消息,针对他们没完成的那件具体的事。然后再一次等待。
- 5目标收到
project.created。运行退出。此后这个人再也不会收到任何引导邮件。
你的事件名称你对“已激活”的定义
五个漏斗
生命周期,按实际发生的顺序
1 · 激活
触发条件:注册。两到三封邮件,每封只讲一个动作,每封都有一个目标,当该动作发生时结束整个序列。这是你能构建的最有价值的漏斗,也是最值得重写三遍的漏斗。
2 · 停滞
触发条件:segment_enter —— 已注册,但七天内没有任何有意义的事件。一封以询问而非告知为主的邮件,再加一封提供具体东西的邮件。然后就停止。给一个已经无视了三封邮件的人发第四封,等于发给无人。
3 · 扩展时刻
触发条件:一个表明他们正在获得价值的事件 —— 达到上限、邀请了第三位同事、第二次导出。这是唯一适合发送升级邮件的时刻,而且你的产品可以精确地命名这个时刻。
4 · 续费与催缴
触发条件:续费前的 date_field,或某个支付事件。通知、提醒,以及 —— 如果支付失败 —— 一个在成功那一刻立即停止的短序列。在催缴中,目标节点不是可选项;它是提醒与骚扰之间的分界线。
5 · 唤回
触发条件:segment_enter —— 已取消或休眠六十天。两封邮件,要坦诚,然后打上标签,归于沉默。“他们离开之后发生了什么变化”是一封比打折更好的邮件。
还有内部那个
notify_team 会在一个值得人工关注的账户越过某条线时通知一个人。漏斗不必以发给客户的邮件结束;有时正确的动作是让你这边的人拿起电话。

没有人是故意流失的。他们只是不再打开它了。
为什么开发者可能真的会喜欢这个
当你就是那个做集成的人时,真正重要的部分
没有私有端点
每个界面都可以用公开 API 搭建,因为除此之外没有别的 API。如果你想把营销活动报告嵌入你自己的管理后台,没有任何东西挡你的路,也不需要逆向工程任何东西。
处处都有幂等键
在每个会修改数据的路由上。你的重试逻辑、你的至少一次投递队列和你不稳定的网络,全都变成别人的问题 —— 具体地说,是一个唯一索引的问题。
上线之前先模拟
POST /v1/simulate 会让一个联系人试跑整个漏斗,并返回路径以及它将发送的每一封邮件。愿意的话可以放进 CI:漏斗是一张图,而图是可以测试的。
一个 MCP 服务器
把一个智能体指向 /mcp,让它编写和检查漏斗。具备发送能力的工具需要显式确认,并受配额限制,所以一次误读的提示不会变成五万封邮件。
Webhook 输出
带签名、按退避策略重试、至少送达一次。使用与报表相同的事件词汇,这样你的数据仓库和你的仪表盘对“已送达”的含义就不会有分歧。
真正能触达的删除
一个删除请求会在这里移除该联系人及其消息历史,并扩散到每一个持有副本的兄弟服务。一个请求,一个结果,而且当被问起时,你有东西可以指。
边界在哪里
ClickSomo 持有一个邮件列表以及这个列表做过什么。它不是你的用户数据库,也不打算成为:联系人永远不携带凭据、永远不登录、永远不会变成一个账户。你的用户住在你的产品里;联系人住在这里,两者通过一个电子邮箱地址和你选择发送的事件连接起来。
这种分离是刻意的,也正是同意模型能够成立的原因。你是你的用户的数据控制者;我们代表你进行处理。一种让营销工具悄悄变成身份存储的设计,是日后无法解开的,而这正是本设计要避免的失败。
实操版本:发送事件,发送你想用来分群的属性,其余的一切留在原处。如果你发现自己在把整个数据库模式往这里推,那你试图构建的那个分群,很可能其实是你自己数据库里的一个查询,它应该作为一个布尔属性传过来。