用 Trigger 接收第三方事件
Trigger 订阅关注某个终端用户的连接账号,把新的第三方事件作为 trigger.message 发送到你的项目 Webhook。例如用户的 Google Sheets 新增了一行、Gmail 收到新邮件,或 Stripe 付款状态变了,你的后端会收到一条对应的事件。
订阅由 Connector 运行:轮询 provider、注册和接收 provider 的 webhook 都在 Connector 侧完成。你的后端负责创建订阅和处理收到的事件。
事件如何到达
| 方式 | Connector 如何获取事件 | 示例 |
|---|---|---|
| 轮询(Polling) | 按固定间隔读取账号,发送自上次读取以来新增的行、邮件或记录。 | Gmail、Google Sheets、Google Calendar、Notion |
| 推送(Push) | provider 把事件发到 Connector 的回调地址,Connector 校验后转发匹配的事件。 | GitHub、Stripe、Shopify、Slack |
推送类 Trigger 涉及两个地址:项目 Webhook 接收 Connector 发来的事件,第三方入站回调地址(push.callbackUrl)接收 provider 发来的事件。大部分回调地址由 Connector 自动注册;Slack、Microsoft Teams、飞书和 Intercom 需要管理员把它填到 provider 应用中。
准备工作
- 按 Connector for SaaS 使用指南完成接入,让后端持有 Project API key,并保存每个用户的
connectedAccountId。 - 创建项目 Webhook,
eventTypes包含trigger.message,authTypes包含要订阅账号的授权类型。Google 账号为oauth2。一个 Webhook 可以接收项目内所有订阅的事件。 - 让终端用户连接 Trigger 要读取的账号。
如果账号已路由到专用 Webhook,事件只会发往该 Webhook,上述条件改为对它检查。
创建或恢复订阅时,Connector 会检查 Webhook。没有匹配的 active Webhook 时,请求返回 trigger_delivery_unavailable。
第 1 步:选择 Trigger
列出已发布的 Trigger,并查看所需 Trigger 的配置 schema:
curl --silent --show-error \
'https://connector.oomol.com/v1/saas/trigger-types/googlesheets.on_row_added' \
-H "Authorization: Bearer $PROJECT_API_KEY"
GET /v1/saas/trigger-types 列出所有已发布的 Trigger,加 ?service=googlesheets 可按 provider 筛选。所有项目看到的目录相同。
| 字段 | 含义 |
|---|---|
id | 创建订阅时使用的 Trigger ID。 |
type | poll 或 push。 |
configSchema | 订阅 config 的 JSON Schema,包含默认值和必填字段。 |
eventSchema | 投递事件中 data.payload 的 JSON Schema。 |
definitionVersion | 新订阅记录的 Trigger 定义版本。 |
defaultIntervalSeconds / minIntervalSeconds | 默认和最短轮询间隔。推送类 Trigger 为 null。 |
第 2 步:创建订阅
下面的示例监听 Orders 工作表的新增行:
curl --silent --show-error \
'https://connector.oomol.com/v1/saas/trigger-subscriptions' \
-H "Authorization: Bearer $PROJECT_API_KEY" \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: orders-sheet-customer-1' \
--data @- <<JSON
{
"userId": "customer-1",
"connectedAccountId": "$CONNECTED_ACCOUNT_ID",
"triggerId": "googlesheets.on_row_added",
"config": {
"spreadsheetId": "<spreadsheet-id>",
"sheet": "Orders"
},
"intervalSeconds": 300
}
JSON
| 字段 | 说明 |
|---|---|
userId | 必填:连接账号所属的终端用户在你产品中的 ID。 |
connectedAccountId | 必填:订阅读取的账号,创建后不能修改。 |
triggerId | 必填:Trigger 目录中的 id。 |
config | 必填:符合 configSchema 的对象,创建后不能修改;需要监听其他对象时新建订阅。 |
intervalSeconds | 可选,仅轮询类:读取间隔,不小于 minIntervalSeconds。推送类订阅不接受此字段。 |
请求时带上 Idempotency-Key,避免重试请求创建出第二个订阅。首次请求返回 201;用同一个 key 重放相同请求返回 200 和原订阅;同一个 key 用于不同请求返回 409。
把返回的 id 与用户、账号一起保存到数据库。也可以在 Console 中创建和管理订阅:打开项目后进入事件订阅。
接收事件
每个事件都以签名的 trigger.message 投递到项目 Webhook。先校验签名,再读取 envelope:
{
"id": "evt_0199d2a8-4c1b-7e2f-8a3d-6b5c4d3e2f10",
"type": "trigger.message",
"version": 1,
"createdAt": 1800000300000,
"data": {
"subscriptionId": "0199d290-1a2b-7c3d-8e4f-5a6b7c8d9e0f",
"triggerId": "googlesheets.on_row_added",
"definitionVersion": 2,
"externalUserId": "customer-1",
"connectedAccountId": "0199d1f4-2e5f-7b61-8c72-9d0e1f2a3b4c",
"providerConfigId": "0199d1a0-5f6e-7d8c-9b0a-1c2d3e4f5a6b",
"service": "googlesheets",
"payload": {
"spreadsheetId": "<spreadsheet-id>",
"sheetId": 0,
"sheetTitle": "Orders",
"rowNumber": 12,
"row": { "Order ID": "A-1001", "Amount": 42 },
"values": ["A-1001", 42]
}
}
}
data.payload 符合该 Trigger 的 eventSchema。用 subscriptionId 或 externalUserId 把事件路由给对应用户,并按 envelope 的 id 去重:同一事件在重试和不同 Webhook 之间保持相同的 id。
轮询类订阅的首次读取只记录当前位置,不会发送已有的行、邮件或记录。读取完成后,订阅的 initialized 变为 true,之后产生的事件会在后续读取中发送。
投递沿用项目 Webhook 的重试策略。同一事件可能多次到达;重试用尽或遇到不可重试的 4xx 时,投递以 failed 结束,可以在 Console 的投递记录或投递记录 API 中查看。每个 Webhook 同时最多有 5 个请求在发送;端点响应慢只会延后它自己的队列,不影响其他 Webhook。投递到达终态的事件保留 7 天。
管理订阅
| 操作 | API |
|---|---|
| 列出订阅 | GET /v1/saas/trigger-subscriptions,可按 userId、connectedAccountId、status 筛选,支持 limit(最大 100)和 offset。 |
| 查看单个订阅 | GET /v1/saas/trigger-subscriptions/{subscriptionId} |
| 暂停或恢复 | PATCH /v1/saas/trigger-subscriptions/{subscriptionId},传 {"status": "paused"} 或 {"status": "active"} |
| 调整轮询间隔 | PATCH /v1/saas/trigger-subscriptions/{subscriptionId},传 {"intervalSeconds": 600} |
| 删除 | DELETE /v1/saas/trigger-subscriptions/{subscriptionId} |
订阅会返回 status、pauseReason、initialized、nextPollAt、lastSuccessAt、lastError 和 consecutiveFailures。推送类订阅还会返回 push.callbackUrl、push.setup(automatic 或 application)和 push.ready。删除订阅后不再读取新数据,删除前已记录的事件仍会投递。
订阅暂停时
Connector 无法安全继续时会暂停订阅,pauseReason 说明原因和处理方式:
pauseReason | 原因 | 处理方式 |
|---|---|---|
manual | 通过 API 或 Console 手动暂停。 | 需要时恢复。 |
connection_unavailable | 账号、凭据、权限或服务配置不可用。 | 让用户重新连接账号,然后恢复。 |
config_invalid | provider 判定配置无效,或该 Trigger 已下线。 | 在 provider 侧修复后恢复,或用新配置创建订阅。 |
delivery_unavailable | 记录事件时没有与该账号匹配的 active Webhook。已路由的账号只看它的路由 Webhook。 | 修复 Webhook 后恢复。 |
checkpoint_reset_required | 无法从已保存的位置继续读取,例如工作表被替换、行被删除,或 provider 的同步令牌已过期。pauseDetail 给出具体原因。 | 创建新订阅。原订阅不能恢复,期间的变更不会补发。 |
provider 的临时错误不会导致暂停。Connector 会从 30 秒起退避重试,最长间隔 30 分钟,并在 lastError 和 consecutiveFailures 中记录最近状态。
用户重新连接同一个 provider 账号时,订阅照常运行。如果用户在同一 alias 下换成另一个 provider 账号,相关订阅会以 checkpoint_reset_required 暂停。
计费与团队余额
每个事件在首次成功投递到项目内任一 Webhook 时计费一次。读取、空读、重试、额外的 Webhook,以及最终投递失败的事件都不计费。
Trigger 需要团队余额足以覆盖 Connector 用量:
- 余额小于零时,创建或恢复订阅返回
402 insufficient_credit,读取和投递暂停。查看、调整间隔、暂停和删除仍然可用。 - 暂时无法核实余额时,上述请求返回
503 balance_unavailable,并带Retry-After: 30。 - 投递受阻期间,每个项目最多缓冲 10,000 条待处理的推送事件。超出部分 Connector 仍会向 provider 正常应答,但不会保存,provider 也不会重发。确认欠费满 7 天后,待处理事件会过期,新的推送事件也会这样被丢弃,直到余额恢复。
billing视图会统计这两种情况。 - 团队充值后,读取和投递自动恢复。因其他原因暂停的订阅保持暂停。
订阅响应包含项目级 billing 摘要,其中有 state(allowed、insufficient_credit、balance_unavailable 或 unverified)、缓冲数量,以及被拒收和已过期事件的计数。列表响应在 meta.billing 中返回。unverified 表示团队余额还没有核实过,通常是因为项目还没有订阅;它不阻塞请求,创建订阅时会核实余额。
错误
HTTP 状态与 errorCode | 含义 |
|---|---|
404 trigger_not_found | 该 Trigger ID 未发布。 |
409 trigger_delivery_unavailable | 没有可接收该账号授权类型 trigger.message 的 active Webhook。data.reason 为 no_active_webhook、event_type_not_subscribed、auth_type_not_subscribed 或 routed_webhook_unavailable(账号的路由 Webhook 已停用或不匹配);data.webhookIds 列出可更新的 Webhook。 |
409 trigger_subscription_reset_required | 订阅不能恢复,请新建订阅。 |
409 app_not_ready | 连接账号不可用,例如已断开连接。让用户重新连接。 |
402 insufficient_credit | 团队余额小于零。 |
503 balance_unavailable | 暂时无法核实余额,按 Retry-After 延迟后重试。 |
可用的 Trigger
以 GET /v1/saas/trigger-types 返回的目录为准。
| 轮询类 Trigger ID | 监听内容 | 默认 / 最短间隔 |
|---|---|---|
airtable.on_record_changed | 表记录新增或更新 | 300 / 120 秒 |
gmail.on_message_received | 新邮件 | 120 / 120 秒 |
googlecalendar.on_event_changed | 日历事件变更 | 120 / 120 秒 |
googledrive.on_file_change | 文件新增或更新 | 120 / 120 秒 |
googlesheets.on_row_added | 新增行 | 120 / 120 秒 |
notion.on_database_page_event | 数据库页面新增或编辑 | 120 / 120 秒 |
one_drive.on_item_changed | 文件或文件夹变更 | 120 / 120 秒 |
outlook.on_message_received | 新邮件,可按文件夹和邮件条件筛选 | 120 / 120 秒 |
| 推送类 Trigger ID | 监听内容 | 接入方式 |
|---|---|---|
calendly.on_booking_event | 预约创建、取消 | 自动注册;使用 Personal Access Token |
clickup.on_task_event | 任务创建、状态变更和新评论 | 自动注册;需 Workspace ID 或 List ID |
feishu_app_bot.on_event | 已启用的应用事件 | 应用回调;凭据需包含 Verification Token 和 Encrypt Key |
github.on_repo_event | 仓库事件 | 自动注册;需要管理目标仓库 webhook 的权限 |
gitlab.on_project_event | 项目 push、issue、MR、pipeline 等所选 Hook | 自动注册项目 Hook;使用 Secret Token 验签 |
intercom.on_conversation_event | 客户会话、客户回复和新工单 | 应用回调;使用连接的 OAuth Client ID 和 Client Secret |
jira.on_issue_event | Issue 创建、更新和评论 | 自动注册并续期;需要 Jira Cloud OAuth 及 webhook scope |
linear.on_issue_event | Issue 创建、更新和删除 | 自动注册;需要管理员 API key 或 OAuth admin scope |
microsoft_teams_bot.on_activity | 机器人消息和活动 | Azure Bot Messaging endpoint |
pandadoc.on_document_event | 文档状态变化 | 自动注册并校验签名 |
pipedrive.on_crm_event | 联系人、交易创建或交易字段变化 | 自动注册 |
resend.on_email_event | 入站邮件、退信和投诉 | 自动注册并校验签名 |
shopify.on_shop_event | 店铺事件 | 自动注册;OAuth 或应用 client credentials 连接 |
slackbot.on_event | 提及、私信和交互 | Slack 应用的 Events 与 Interactivity URL;需要该应用的 Signing Secret |
stripe.on_event | Stripe 事件 | 自动注册 |
tally.on_form_response | 完整的表单回复 | 自动注册并校验签名 |
telegram.on_update | Bot 消息和所选更新类型 | 自动注册 setWebhook;使用 Bot Token |
typeform.on_form_response | 完整的表单回复 | 自动注册 |
vercel.on_deployment_event | 部署成功或失败 | 自动注册 |
woocommerce.on_store_event | 订单、商品、优惠券和客户事件 | 自动注册;需要 Read/Write consumer key |
zendesk.on_event | 所选的 Zendesk 事件 | 自动注册 |
Provider 注意事项
轮询发送的是每次读取时可见的状态,两次读取之间的中间编辑不会逐条发送。同一 provider 账号、Base 或工作区下的多个订阅共享该 provider 的调用额度。
| Provider | 注意事项 |
|---|---|
| Airtable | triggerField 必须是时间字段:监听新增用 Created time,监听更新用跟踪目标字段的 Last modified time。空读也消耗 API 额度,单个订阅按默认 5 分钟间隔每 30 天约读取 8,640 次;额度紧张时调大 intervalSeconds。 |
| Notion | 把目标数据库共享给该连接并启用 Read content。数据库有多个 data source 时需指定 dataSourceId。首次读取按分钟向上取整,此前的变更不会发送。 |
| OneDrive | parentFolderId 只匹配直接父目录。 |
| Slack、Microsoft Teams、飞书、Intercom | 由应用管理员把 push.callbackUrl 填到 provider 应用中,同一应用的订阅共用这个地址。轮换应用的签名密钥后要更新连接凭据;Slack 和飞书还要用新密钥重新验证回调地址。 |
| Slack、飞书 | 同一应用的订阅共用一个接收器,每新建一个订阅,都会用它的连接凭据替换接收器的签名密钥。如果这份凭据里的密钥和应用不一致,该应用下所有订阅的事件都会验签失败。创建订阅和轮换密钥时,都要让该应用所有连接凭据里的签名密钥与应用保持一致。 |
| Intercom | 需在 Intercom Developer Hub 的 Webhooks 页面订阅覆盖 Trigger eventTypes 的主题(conversation.user.created、conversation.user.replied、ticket.created),Intercom 只推送已订阅的主题。保存回调地址时 Intercom 会发出无签名的 HEAD 校验,Connector 返回 200;push.ready 在收到签名 ping 后变为 true,未就绪不影响事件入库。 |
| Microsoft Teams | 连接凭据里的 tenantId 是获取 token 的 authority;Trigger 配置里可选的 tenantId 用来按租户筛选活动。 |
| Linear | 在服务配置的 scope 中加入 admin 后重新连接。只授予 read 的连接无法创建 webhook。 |
| Shopify | Connector 用当前的 client secret 校验事件。轮换 secret 时按 Shopify 官方轮换步骤操作。 |
故障排查
| 现象 | 检查项 |
|---|---|
创建订阅返回 trigger_delivery_unavailable | 按 data.reason 处理:创建 Webhook、为其事件类型加入 trigger.message,或加入该账号的授权类型。routed_webhook_unavailable 时,更新该路由 Webhook,或取消账号的路由。 |
| 创建轮询订阅后没有事件 | 等 initialized 变为 true 后再新增数据。已有数据不会发送。 |
推送订阅的 push.ready 一直为 false | 查看 lastError。Slack、Teams、飞书和 Intercom 需确认 provider 应用使用的是 push.callbackUrl;Intercom 还需确认应用已订阅该 Trigger 的事件主题。 |
事件停止且 pauseReason 有值 | 按订阅暂停时中的处理方式操作。 |
事件停止且 billing.state 不是 allowed | 为团队充值,或等待余额核实恢复。 |