扣子(Coze)平台的 workflow 功能让不少人搭建出了自己的智能助手,但一个常见的问题是:对话中产生的内容,比如用户提交的表单信息、AI生成的总结、待办事项,往往只是停留在会话记录里。如果想把这些数据沉淀到Notion数据库中做统一管理,手动复制粘贴既低效又容易出错。好在Notion提供了完善的官方API,而扣子的工作流中正好有HTTP请求节点可以调用外部接口,两者结合就能实现一条全自动的数据同步链路。本文将完整演示从准备工作到落地调用的全过程。

一、准备工作:获取Notion API凭证与数据库授权
在正式写工作流之前,有两样东西必须先拿到手:一个是Notion的集成令牌(Internal Integration Token),另一个是目标数据库的database_id。很多人第一步就卡住,其实流程并不复杂。
先去Notion的官方开发者平台(notion.so/my-integrations)创建一个内部集成。创建时给它起个容易识别的名字,能力选项里务必勾选读写权限,创建完成后系统会生成一串以secret_开头的密钥,这就是后续调用API时放在请求头里的Bearer Token。注意这串密钥只在创建时完整展示一次,建议立即保存到安全的地方。
拿到令牌还不够,因为Notion的权限模型是“集成必须被显式授权才能访问页面”。打开你要同步的数据库页面,点击右上角的三个点菜单,依次找到“连接”或“添加连接”,把刚才创建的集成添加进去。这一步经常被忽略,如果跳过,后面调用API时会一直收到object is not found的错误,很多人误以为是令牌有问题,实际是数据库没授权给集成。
至于database_id,直接看数据库页面的URL即可。地址栏中页面名称后面那一串32位的字符就是数据库ID,复制时注意不要把问号后面的查询参数也带上。
二、核心API详解:创建、查询与更新条目
Notion API的基础地址是https://api.notion.com/v1,同步场景下最常用的是三个接口。第一个是创建条目的POST /v1/pages,请求体里需要传parent指定数据库ID,properties里逐个字段赋值。第二个是查询接口POST /v1/databases/{database_id}/query,可以按过滤条件查找已有条目,这在“存在则更新、不存在则新建”的场景里非常关键。第三个是更新接口PATCH /v1/pages/{page_id},用来修改已有条目的属性。
调用时有两个请求头必须写对。一个是Authorization,值为Bearer加令牌;另一个是Notion-Version,建议写2022-06-28,这是目前比较稳定的版本号。漏掉版本号的请求会直接返回400错误,这是新手最高频的踩坑点之一。
属性赋值的格式是调用中最容易出错的地方。Notion的每个属性类型对应不同的JSON结构,比如标题字段要写成{"title": [{"text": {"content": "值"}}]},富文本是{"rich_text": [{"text": {"content": "值"}}]},数字类型直接是{"number": 123},而日期则要传ISO 8601格式的字符串。下面是一个创建条目的完整请求体示例:
{
"parent": {
"database_id": "你的数据库ID"
},
"properties": {
"名称": {
"title": [
{
"text": {
"content": "来自扣子的任务"
}
}
]
},
"备注": {
"rich_text": [
{
"text": {
"content": "由工作流自动写入"
}
}
]
},
"优先级": {
"select": {
"name": "高"
}
},
"截止日期": {
"date": {
"start": "2025-01-20T18:00:00+08:00"
}
}
}
}需要特别说明的是,select下拉类型赋值时传的name必须与Notion中已配置的选项名称完全一致,包括空格。如果传了一个不存在的选项名,API会报validation error,而且Notion API默认不会自动创建新选项,这点与手动操作时的行为不同。
三、在扣子工作流中配置HTTP节点完成同步
凭证和接口都理清楚后,回到扣子平台。在编排工作流时,添加一个“HTTP请求”节点,方法选POST,URL填https://api.notion.com/v1/pages。请求头部分添加两组键值:Content-Type设为application/json,Authorization设为Bearer空格加令牌,Notion-Version设为2022-06-28。请求体选择JSON格式,把上面示例中的字段替换成工作流上游节点的变量引用,比如用{{start.input_title}}这样的表达式把用户输入注入到标题字段。
这里建议的做法是把Notion相关的配置项——数据库ID、令牌——放到工作流的输入参数或环境变量里管理,而不是硬编码在节点里。这样切换数据库或者令牌轮换时只需要改一处,调试和正式环境也能方便地区分。
如果业务需要“查重后更新”,可以在HTTP节点前再加一个查询节点。调用POST /v1/databases/{id}/query,请求体里通过filter按唯一键(比如用户ID或记录编号)过滤,再用一个代码节点判断返回的results数组长度:大于零说明条目已存在,取出page_id走更新分支;等于零则走创建分支。扣子的选择器节点可以很方便地实现这种条件路由。下面是查询请求体的写法:
{
"filter": {
"property": "记录编号",
"rich_text": {
"equals": "REC-20250120-001"
}
}
}最后别忘了处理HTTP节点的输出。Notion API返回的JSON比较嵌套,可以直接把整个响应体作为输出变量传给后续节点,也可以在代码节点里提取id、url等关键字段。把Notion返回的页面URL作为工作流最终输出,用户在对话里就能直接点击跳转到刚创建的记录,体验会好很多。
四、常见报错与排查思路
跑通链路的过程中,几类报错出现的频率最高。第一种是401 Unauthorized,基本是令牌写错或令牌前后多了空格,检查Authorization头的格式即可。第二种是404 object not found,九成以上是数据库没有连接集成,回到Notion页面重新授权就能解决。第三种是400 validation error,通常是属性名拼写与数据库中的实际字段名不一致,或者属性类型的JSON结构与Notion要求的不匹配,建议用官方文档对照逐一核对。
还有一种隐蔽的情况是429速率限制。Notion官方API对每个集成有每秒约3次请求的平均限制,如果工作流在循环里高频写入,就可能触发限流。应对方式是在代码节点里加入简单的重试与退避逻辑,或者把批量数据合并成一次请求。另外调试时建议先用一个测试数据库练手,确认属性结构无误后再切换到正式库,避免脏数据污染真实记录。
整体来看,扣子加Notion的组合把“对话产生数据、数据进入数据库”这条链路完全自动化了,后续不管是做内容收藏助手、客户登记机器人还是团队待办同步,这套模式都可以直接复用。核心难点集中在属性格式的对齐和权限配置上,把这两块吃透,剩下的就只是节点编排的问题了。