---
author: OOMOL
author_url: https://oomol.com/zh-cn/about/
title: 用 Trigger 接收第三方事件
description: 为终端用户订阅新增行、新邮件、CRM 变更等第三方事件，并通过签名的项目 Webhook 接收。
lang: zh-CN
canonical_url: https://oomol.com/zh-cn/docs/saas-triggers/
markdown_url: https://oomol.com/zh-cn/docs/saas-triggers.md
---

# 用 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 应用中。

## 准备工作

1. 按 [Connector for SaaS 使用指南](/zh-cn/docs/connector-saas/)完成接入，让后端持有 Project API key，并保存每个用户的 `connectedAccountId`。
2. [创建项目 Webhook](/zh-cn/docs/saas-webhooks/#创建-webhook)，`eventTypes` 包含 `trigger.message`，`authTypes` 包含要订阅账号的授权类型。Google 账号为 `oauth2`。一个 Webhook 可以接收项目内所有订阅的事件。
3. 让终端用户连接 Trigger 要读取的账号。

如果账号已[路由到专用 Webhook](/zh-cn/docs/saas-webhooks/#把单个账号的事件路由到专用-webhook)，事件只会发往该 Webhook，上述条件改为对它检查。

创建或恢复订阅时，Connector 会检查 Webhook。没有匹配的 active Webhook 时，请求返回 `trigger_delivery_unavailable`。

## 第 1 步：选择 Trigger

列出已发布的 Trigger，并查看所需 Trigger 的配置 schema：

```bash
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` 工作表的新增行：

```bash
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。先[校验签名](/zh-cn/docs/saas-webhooks/#校验每次投递)，再读取 envelope：

```json
{
  "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 的重试策略](/zh-cn/docs/saas-webhooks/#响应与重试)。同一事件可能多次到达；重试用尽或遇到不可重试的 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 官方轮换步骤](https://shopify.dev/docs/apps/build/authentication-authorization/manage-credentials)操作。 |

## 故障排查

| 现象 | 检查项 |
| --- | --- |
| 创建订阅返回 `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` | 为团队充值，或等待余额核实恢复。 |
