Webhook
最后更新:2026年7月3日
设想您经营一家服装网店。每次上架新商品时,都有一些必须亲手处理的后续工作。比如把商品说明翻译成其他国家的语言,或是把上架这件事通知到公司内部的即时通讯工具里。这些后续工作不必每次都靠人手去做,您可以让系统在商品上架的那一刻,自动通知外部的某个程序来代为处理。这种"某件事发生时就自动通知到预先指定的地方"的装置,就是 Webhook。
可以把它比作装在店门上的门铃。客人推门进来时(商品被上架时),门铃会自动响起,里面的店员(外部程序)一听到"有客人来了"就立刻开始行动。不需要有人一直守在门口盯着。Webhook 就像那只门铃,在预定的事件发生的那一刻,向预定的地方发送请求。
本页先来看 Webhook 是什么、在什么情况下使用,然后在服装店 Space 里亲手创建一个 Webhook。同时还会介绍如何把外部程序返回的结果再填回到商品里的 WriteBack。
Webhook 做的事
Webhook 由预先设定的三件事构成。
- 何时发送:设定在什么事件发生时发送请求。例如可以设为"商品(Content)被新建时"。
- 发送到哪里:设定接收请求的外部程序的地址。填入一个互联网地址(URL)即可。
- 开启还是关闭:设定现在要开启这个 Webhook(ACTIVE),还是暂时关闭它(INACTIVE)。关闭后,即使预定的事件发生,也不会发送请求。
当预定的事件实际发生时,Webhook 会向填入的地址发送请求,告知这件事。请求中会带上诸如发生了什么事、是在哪个商品上发生的之类的信息。收到请求的外部程序会根据这些信息去做自己的工作。
哪些变化会触发请求
触发请求的"事件",是 Space 内的资源所发生的变化。您可以选择诸如商品这样的 Content、上传的文件 Media、作为表单模板的 Content Type 上发生某事时的情况。
每种资源可选的变化如下。
| 变化 | 何时发生 | 服装店示例 |
|---|---|---|
| Create | 被新建时 | 上架新商品 |
| Save | 修改内容并保存时 | 修改并保存商品说明 |
| Delete | 被删除时 | 删除已停产的商品 |
| Publish | 发布并对外公开时 | 把商品公开到网站 |
| Unpublish | 取消发布时 | 把缺货商品从网站撤下 |
| Archive | 进行归档时 | 把过季商品归档 |
| Unarchive | 解除归档时 | 把归档的商品恢复 |
例如"每当有新商品上架时就发送请求",就是选择"商品(Content)的 Create"。
一个 Webhook 也可以同时选择多种变化。如果同时选择"商品被新建时"和"商品被修改时",那么这两者中任何一个发生,请求都会发出。
加条件来收窄范围
有时即使选中的变化发生了,您也不希望每次都发送请求。例如您可能只想在"不是所有 Content,而是用'商品'表单创建的 Content 被新建时"才接收。这时就用筛选来收窄发送请求的情形。
一条筛选由"以什么为基准、如何比较"这样一行构成。以什么为基准来过滤,要从四项中选择。
- 是用哪个表单创建的项目:例如只向用"商品" Content Type 创建的 Content 发送请求。这是最常用的条件。
- 是否为某个特定项目:只对在某个指定项目上发生的变化发送请求。
- 是谁创建的项目:只对特定的人创建的项目发送请求。
- 是谁最后修改的项目:只对特定的人最后修改过的项目发送请求。
同时也要选择比较的方式。可以收窄为:仅当与设定值相等时、仅当不相等时、仅当属于设定的多个值之一时、仅当不属于其中任何一个时,或仅当符合或不符合设定格式(模式)时。
在内容工作室的触发器设置中,用 + 添加筛选逐行添加条件。设置多条筛选时,只有全部满足这些条件的情况才会发送请求;一条都不设时,则每当选中的变化发生时就发送请求。
按外部程序想要的格式发送
如果不另行设定,请求中会原样带上发生变化的那个项目的全部信息。例如保温杯商品被新建时,请求中带去的内容大致是这样的形状。
{
"sys": { "id": "3trmXRM3RqbgSnifyg7OGhwhlqvAvq", "type": "Content" },
"fields": {
"productName": { "ko-KR": "스테인리스 텀블러 500ml" }
}
}(实际上会带上更多信息,上面只是摘取的一部分。)外部程序从中挑选自己需要的值来用即可。但也有一些程序规定了"只接收这种格式"。这种情况下,就在内容工作室的 Payload 中选择自定义 Webhook payload,自己写下要发送的格式。
写下要发送的格式时,在需要从上面的数据中取值填入的地方使用占位符。占位符的形状为 { /payload/… }。这里的 payload 指的就是上面展示的那个项目整体,其后的路径用来精确定位想要的值。
{ /payload/sys/id }→ 上面数据中sys内的id(商品的唯一编号){ /payload/fields/productName/ko-KR }→fields内productName的ko-KR(韩语商品名)。fields/之后依次接 Field 的 ID(商品名即productName)和语言代码(韩语即ko-KR)。
例如翻译程序要求"按这种格式给出待翻译的文本和商品编号",那么就这样写 payload。
{
"id": "{ /payload/sys/id }",
"text": "{ /payload/fields/productName/ko-KR }"
}这样一来,保温杯商品被新建的那一刻,占位符会被替换为实际的值,按如下形式发送。
{
"id": "3trmXRM3RqbgSnifyg7OGhwhlqvAvq",
"text": "스테인리스 텀블러 500ml"
}同样的占位符也可以放进发送地址(URL)或请求头的值里,发送的方式(method)和格式(JSON 或表单格式)也可以一并选择。如果指向的路径上没有值,那个位置就会变成空值。
像外部 API 密钥这种不能让别人看到的值,在添加请求头时把它的类型设为 Secret。这样该值就会被遮蔽后保存,不会暴露给最终用户。
用收到的响应回填:WriteBack
如果说上一节是设定要发送的请求的格式,那么 WriteBack 处理的是返回的响应。Webhook 调用外部程序并收到正常(2xx)响应时,可以对该响应进行加工,从而在 Space 内创建、修改 Content 或 Media,或对其进行发布、删除。人工复制结果再粘贴的过程就此消失。
我们把服装店的翻译示例一路跟到底。前面已经把新商品的韩语商品名发给了翻译程序。假设翻译程序这样响应。
{ "translated": "Stainless Tumbler 500ml" }接下来配置一个 WriteBack,把这段译文填入同一商品的英文商品名栏。在内容工作室的 WriteBack 中,用 + 添加操作添加一个 Content 的 Update(修改)动作,并这样设定。
- 目标:如果不另行指定,发生变化的那个商品(保温杯)就是目标。
- 要填的栏和语言:因为是英文商品名,所以栏为商品名(
productName),语言为英语(en-US)。 - 要填的值:指向响应中译文的
{ /response/translated }。
这样一来,保温杯商品的英文商品名栏就会被填入 Stainless Tumbler 500ml。
这样的 WriteBack 在与外部 LLM 对接时尤其有用。例如可以用一个 Webhook 构成这样的流程:把商品说明发出去生成宣传图片并保存为 Media,或用生成的简介文案创建新的 Content。
执行顺序
- 发生变化时,Webhook 按设定的格式向外部程序发送请求。
- 若响应为 2xx,则从上到下依次执行已添加的 WriteBack 动作(operation)。
- 各个动作彼此独立,即使其中一个失败,其余的也会继续执行。
- WriteBack 产生的创建、修改、删除、发布同样会被捕捉为变化,从而可以接连触发订阅了该变化的其他 Webhook。无止境循环的情况会在创建或修改 Webhook 时被自动检测并阻止。
由 WriteBack 创建或改变的资源,其创建者(createdBy)即为引发该变化的用户。
值表达式
要填的值用前面看到的那种占位符({ /… })来获取。不过在 WriteBack 中,可指向的根有两个。
| 根 | 指向的对象 |
|---|---|
{ /response/… } | 外部程序返回的响应正文 |
{ /payload/… } | 发生变化的原始项目(Content/Media) |
- 仅单独使用一个占位符时(
{ /response/url }),会原样获取值的原本形态(文本、数字、对象)。 - 与文本混用时(
"已创建: { /payload/sys/id }"),会拼接成一段文本。 - 当响应不是 JSON 而是纯文本时,用
{ /response }把整个响应作为文本接收(无法指向其中的下级路径)。
处理 Content($content)
用响应来创建或改变 Content 的动作。需设定的项目如下。
| 项目 | 说明 |
|---|---|
action | Create 、 Update 、 Delete 、 Publish 、 Unpublish 、 Archive 、 Unarchive 中的一个(不区分大小写) |
contentType | 要创建的 Content 的 Content Type。Create 时必填,只需有 sys.id 即可。 |
target | 要改变的目标 Content 的 ID(用占位符指定)。省略时,发生变化的那个项目即为目标。(Update、Delete、Publish、Unpublish、Archive、Unarchive) |
locale | 记录 fields 值的语言。代码(例如 ko-KR)或可解析为该代码的占位符。省略时为 Space 的默认语言。(Create、Update) |
fields | 栏名 → 要填的值(占位符)。(Create、Update) |
publish | 在 Create、Update 后是否立即发布(默认开启)。关闭则不发布,保留为 Draft。 |
unpublish | Delete 时是否先自动取消发布再删除(默认开启)。关闭后,若目标尚未处于可删除的状态,则删除会失败。 |
处理 Media($media)
把响应中收到的文件导入为 Media,或改变 Media 状态的动作。
| 项目 | 说明 |
|---|---|
action | Create 、 Delete 、 Publish 、 Unpublish 、 Archive 、 Unarchive(没有修改动作 Update) |
source | 指向要导入的文件的占位符。(Create) |
encoding | 接收文件的方式:Url(从地址下载)或 Base64(把响应中携带的文件数据解码后保存) |
locale | 记录导入的文件及标题、说明的语言。与 Content 相同的规则。(Create) |
title 、 description | 该语言的媒体标题、说明(占位符,可选)。(Create) |
target | 要改变的目标 Media 的 ID。省略时为发生变化的那个项目。(Delete、Publish、Unpublish、Archive、Unarchive) |
publish | Create 后处理完成时是否立即发布(默认开启)。 |
unpublish | Delete 时是否先取消发布再删除(默认开启)。 |
$media 也可以用作 Content 的栏值。把响应中收到的文件导入为 Media 后,直接把该 Media 连接到栏上,就能一次性创建出"包含图片的 Content"。
Media 的
Delete、Archive、Unarchive不仅处理列表上的信息,还会一并处理存储中的实际文件。
设置方法与示例
在内容工作室的 WriteBack 中,用 + 添加操作逐个添加动作。您可以在屏幕上填写各项的 Visual 方式和直接编写下面这种 writeBacks 块的 JSON 方式之间切换。无论用哪种,结果都一样。
把外部 LLM 生成的图片附上去,创建新商品。 把响应中携带的图片地址导入为 Media,从而创建一个拥有该图片的 Content。
{
"writeBacks": [
{
"$content": {
"action": "Create",
"contentType": { "sys": { "id": "<商品 Content Type 的 sys.id>" } },
"fields": {
"productName": "{ /payload/fields/productName/ko-KR }",
"photo": { "$media": { "source": "{ /response/data/0/url }", "encoding": "Url" } }
}
}
}
]
}增补发生变化的那个商品。 省略 target 时,发生变化的 Content 即为目标。把响应中的值填入该商品的栏。
{
"writeBacks": [
{
"$content": {
"action": "Update",
"locale": "en-US",
"fields": { "productName": "{ /response/translated }" }
}
}
]
}为了审核后再发布而只创建为 Draft。 关闭 publish 后就不发布,而是保留为草稿,可在人工确认后再发布。
{
"writeBacks": [
{
"$content": {
"action": "Create",
"contentType": { "sys": { "id": "<Content Type 的 sys.id>" } },
"fields": { "text": "{ /response/choices/0/message/content }" },
"publish": false
}
}
]
}把响应图片导入为独立的 Media。 用地址接收时把 encoding 设为 Url,用响应中携带的文件数据接收时设为 Base64。
{
"writeBacks": [
{ "$media": { "action": "Create", "source": "{ /response/data/0/url }", "encoding": "Url" } }
]
}Delete、Publish、Unpublish、Archive、Unarchive 形状相同。只需写上 action 和要改变的目标 target,就只改变该目标的状态(省略目标时为发生变化的那个项目)。例如要发布响应所告知的 Content,就这样写。
{
"writeBacks": [
{ "$content": { "action": "Publish", "target": "{ /response/contentId }" } }
]
}添加多个动作时,会按写入的顺序执行。比如可以这样接连排布:"把翻译结果填入商品,接着把宣传图片导入为 Media"。
查看执行结果
各个 WriteBack 动作的执行情况,可在 Webhook 的调用记录中查看。每个动作都会留下以下内容。
| 项目 | 说明 |
|---|---|
| 顺序 | 在已添加的动作中是第几个 |
| 目标 | 是 Content 还是 Media |
| 动作 | 执行的 action |
| 状态 | Success(成功)、 Failed(失败)、 Skipped(跳过) |
| 结果 ID | 被创建或改变的资源的 ID(有时) |
| 错误 | 失败时的消息 |
成功的动作可以通过结果 ID 追踪到哪个资源被创建或改变了。如果响应不是 2xx,WriteBack 根本不会执行,结果记录也会是空的。
需要知道的事
- 触发请求的变化只设一个。 如果一个 Webhook 同时捕捉"新建(
Create)"和"发布(Publish)",外部程序可能被调用两次。使用 WriteBack 的 Webhook 请只选择一个变化。 - 只能搬运值,不能做运算。 它只做到从响应中取值填入为止,不进行条件分支、循环之类的处理。
- 不会重试。 处理过程中一旦出问题,那个动作可能就此丢失。
- 不要让人随意创建。 对于只由 WriteBack 创建的 Content Type,最好收窄权限,使普通用户无法直接创建。
创建服装店 Webhook
现在来在服装店 Space 里创建一个 Webhook。这是一个"新商品被上架时,就把这件事通知给预先准备好的外部翻译程序"的 Webhook。我们假设接收请求的外部程序的地址为 https://example.com/translate。
- 在服装店 Space 的设置中打开 Webhook 画面。
- 按右上角的创建按钮。
- 在名称栏中输入
新商品翻译通知。这个名称是为了日后辨认这是哪个 Webhook。 - 设定要发送请求的变化。如果只想对特定变化发送,就选择选择特定触发事件后指定想要的变化(这里是商品(Content)的
Create);如果想对所有变化都发送,就选择为所有事件触发。 - 在 URL 栏中输入接收请求的外部程序的地址
https://example.com/translate。 - 开启启用后,创建完成的瞬间就会发送请求(ACTIVE)。如果只想暂时测试,就把它关闭(INACTIVE)。
- 按创建按钮来创建 Webhook。

当列表中出现处于 ACTIVE 状态的 新商品翻译通知 时,Webhook 就创建好了。

创建之后,请在服装店实际上架一个新商品试试。上架的那一刻,Webhook 就会向填入的地址发送请求。请求是否成功送达、外部程序如何响应,都可以在 Webhook 的调用记录中查看。
开启关闭与修改
Webhook 创建之后也可以随时开启和关闭。想暂时停止发送请求时,不要删除,而是把它关闭为 INACTIVE。关闭期间,即使上架新商品也不会发送请求。再次开启为 ACTIVE 后,就会从那时起重新发送请求。
重新打开已创建的 Webhook 后,可以关闭或重新开启启用。名称、要发送请求的地址、要触发的变化等内容日后也可以修改;不再使用的 Webhook 删除即可。
接下来要做的事
- Content 建模:介绍如何创建"商品"这类 Content 的表单模板,它正是 Webhook 触发请求的对象。
- 编写 Content:可以实际上架商品,确认 Webhook 是否正常运作。
- API 参考:介绍在程序中直接创建和管理 Webhook 时所用的请求、响应格式和字段规范。
