连接器开发工具手册介绍

一:平台概述

纷享销客集成平台IPaas是面向软件开发商的低代码集成平台。开发者通过可视化界面配置连接器的授权、触发器和动作,无需编写任何代码或者部分代码即可完成系统对接。连接器上线后,用户可在集成平台中通过可视化画布编排业务流程,实现系统间的数据互通。

二:应用类型说明

类型说明
内部连接器仅在企业内部使用,创建后实时上线无需审核
全网发布连接器面向纷享销客全部用户,上线前需经过审核和测试

三:创建连接器

经过研发灰度企业:管理后台->系统集成平台->连接器开发 ,后续连接器开发工作都是基于这个页面
按照真实信息填写即可

四:授权方式

  1. OAuth授权方式:
      OAuth2.0授权配置需要以下几个步骤:
  • 设置填写授权字段 (非必填,仅在OAuth2.0登录授权前需要额外参数时添加)
  • 复制回调地址:将自动生成的集成平台授权回调地址添加到您的应用中
  • 设置授权参数:一般为Client Key和 Client Secret
  • 设置接口参数:配置授权接口需要的参数,Access Token换取和刷新参数等
  • 账号授权测试 (模拟账户授权,测试是否可以调取成功)
选择对应授权方式:
1:添加字段(非必要)
此步骤非必须,仅在OAuth2.0登录授权前需要额外参数时添加。例如部分系统可能需要选择某些地区或者某些域名
OAuth基础配置:
开发者统一创建,一般就是作为集成平台ISV服务商才需要选择这个,如果用户自定义应用可以选择用户自行创建,区别就是开发者统一创建,那么授权应用都是沿用同一套应用信息
OAuth授权类型:
OAuth 授权类型:用于指定连接器接入第三方平台时使用的 OAuth 2.0 授权方式。
OAuth 2.0(授权码模式):用户完成登录授权后获取访问令牌。
OAuth 2.0(客户端凭证模式):系统使用客户端凭证直接获取访问令牌,无需用户参与。
OAuth 2.0(PKCE 模式):在授权码模式基础上增加 PKCE 校验,适用于前端或移动端场景。
字段怎么使用,统一参考后面章节【字段说明】
认证地址授权:
获取token地址
刷新token地址

其他授权方式

可以具体授权类型以及AI辅助理解一下
授权选择授权机制
OAuth2-AuthorizationCode三步授权流程:获取授权码 → 换取 Access Token → 使用 Refresh Token 自动刷新;支持 PKCE 自动处理,适用于需要用户登录授权的第三方平台
OAuth2-ClientCredentials机器对机器授权,无需用户交互;平台直接使用 Client ID / Client Secret 获取 Token,并按过期时间重新申请
APIKey通过 API Key 进行认证;可将 Key 注入到 Header、Query 参数,适用于 OpenAPI、Server API 等简单鉴权场景
BasicAuthHTTP Basic 认证;使用用户名 + 密码生成 Authorization Header 进行请求认证
SessionAuth先调用登录接口获取 Session / Cookie,再携带 Session 信息访问后续接口;适用于传统 Web 系统或 Cookie 会话型接口
DigestAuthHTTP Digest 认证;基于服务端 challenge 机制完成摘要签名认证,适用于部分老系统或特定安全要求接口
CustomAuth自定义认证;通过平台函数模式实现任意认证逻辑,可覆盖自定义签名、登录换票据、多步认证、混合认证等复杂场景

五:Trigger/Action类型

触发动作是指当一个事件发生时,触发数据流程。 而产生触发事件的应用系统就是触发系统。
实时触发:由应用系统自动在触发事件产生时推送数据到集成平台,集成平台自动响应并且执行。
根据真实系统需求,选择哪些事件作为trigger(触发事件),选择新建
根据接口要求,配置对应字段:
如果事件需要实时触发,需要选择【Rest Hook】,hook地址有两种级别,按照集成流生成,那么就是每个集成流都有不同hook地址,用于不同事件区分
如果选择账号生成,那么就是系统级别(系统授权对应账号),多个事件共用一个hook地址
hook地址需要连接器配置完成,进到集成流选择对应事件,生成对应hook地址:
部分saas系统支持根据接口动态将这些hook地址注册到对方系统,那么就可以按照对方系统接口文档要求,配置对应接口以及参数:
订阅请求中需要将平台生成的回调地址传给外部系统,使用 path("['input_data']['bundleUrl']") 引用 
如果事件需要轮训:
占位符 含义 取值说明
path("['input_data']['pollingTimeArg']['startTime']") 本次查询的时间窗口起点 毫秒时间戳(13 位数字)。取“上次拉到数据的时间”,没拉到过数据则往前回溯约 28 小时
path("['input_data']['pollingTimeArg']['endTime']") 本次查询的时间窗口终点 毫秒时间戳,即本次轮询的执行时刻
path("['input_data']['pollingTimeArg']['limit']") 每页条数 平台固定为 100,不需要你设置
path("['input_data']['pollingTimeArg']['offset']") 翻页偏移量 第一页从 0 开始,每翻一页自动 +100,框架持续翻页直到取完(单轮上限 100 万条)

先搞懂:轮询时平台帮你做了什么

当你把一个连接器触发器配置成轮询触发(配置轮询间隔或 cron 表达式)后,平台的轮询框架每次执行时会自动算好一组查询参数,塞进一个叫 pollingTimeArg 的参数包里。你不需要自己填值,只需要在连接器的请求配置(URL、Query 参数、Header、请求体)里用占位符把它们“接”出来,传给目标系统的查询接口。

四个占位符的含义:

占位符 含义 取值说明
path("['input_data']['pollingTimeArg']['startTime']") 本次查询的时间窗口起点 毫秒时间戳(13 位数字)。取“上次拉到数据的时间”,没拉到过数据则往前回溯约 28 小时
path("['input_data']['pollingTimeArg']['endTime']") 本次查询的时间窗口终点 毫秒时间戳,即本次轮询的执行时刻
path("['input_data']['pollingTimeArg']['limit']") 每页条数 平台固定为 100,不需要你设置
path("['input_data']['pollingTimeArg']['offset']") 翻页偏移量 第一页从 0 开始,每翻一页自动 +100,框架持续翻页直到取完(单轮上限 100 万条)

你只要按目标接口的要求,把这四个值摆到正确的位置就行——是放 Query 参数、放 Header 还是放 JSON 体,完全由目标接口决定。


四种典型写法(可直接抄)

写法 1:GET + Query 参数(最常用,推荐)

在“参数(Query Params)”列表里配置:

参数名 参数值
startTime path("['input_data']['pollingTimeArg']['startTime']")
endTime path("['input_data']['pollingTimeArg']['endTime']")
limit path("['input_data']['pollingTimeArg']['limit']")
offset path("['input_data']['pollingTimeArg']['offset']")

实际发出的请求等价于:

GET https://api.example.com/orders?startTime=1757337600000&endTime=1757341200000&limit=100&offset=0

写法 2:直接拼在 URL 里

https://api.example.com/orders?startTime=path("['input_data']['pollingTimeArg']['startTime']")&endTime=path("['input_data']['pollingTimeArg']['endTime']")&limit=path("['input_data']['pollingTimeArg']['limit']")&offset=path("['input_data']['pollingTimeArg']['offset']")

URL 里可以正常这样写,系统会把每个 path(...) 片段替换成实际值。

写法 3:POST + JSON 请求体(自动保持数字类型)

在“请求体(JSON)”里写 JSON 模板,path(...) 会作为 JSON 值被替换,类型不丢(时间戳和 limit/offset 保持为数字,不会变成带引号的字符串):

{
  "query": {
    "startTime": path("['input_data']['pollingTimeArg']['startTime']"),
    "endTime": path("['input_data']['pollingTimeArg']['endTime']"),
    "pageSize": path("['input_data']['pollingTimeArg']['limit']"),
    "pageStart": path("['input_data']['pollingTimeArg']['offset']")
  }
}

发送出去的真实请求体:

{"query":{"startTime":1757337600000,"endTime":1757341200000,"pageSize":100,"pageStart":0}}

写法 4:表单(form-urlencoded)请求体

在“请求体”键值对里配置,值填占位符,和写法 1 的参数表一样填即可。


几个容易踩的坑

  1. 时间单位是毫秒。如果目标接口要的是秒级时间戳,不能用 URL 直拼(URL 里只能做替换、不能做运算),要把参数放到 Query 参数或请求体的值里,用整条表达式做除法:

    path("['input_data']['pollingTimeArg']['startTime']") / 1000
    

    或者目标接口要求格式化字符串时:

    "查询时间:" + path("['input_data']['pollingTimeArg']['startTime']")
    

    只要这个“值”整体是一条合法表达式(且不是完整 URL),就支持运算和字符串拼接。

  2. limit 不用也不能改,永远是 100。如果你的接口页大小写死,请在接口侧兼容 100。

  3. 调试模式的取值:在页面上点“调试”触发时,系统固定注入「过去 1 小时」窗口:startTime = 当前时间-1小时endTime = 当前时间limit = 100offset = 0,此时没有 conditions(见下文)。所以调试时引用 conditions 的占位符会得到空值,属正常现象。

  4. 参数名对不上接口没关系:占位符只负责取值,参数名叫 startTimebeginTimepageSize 还是别的,由你在参数名/JSON 字段名里自己定义。


conditions 自定义查询条件怎么用

“自定义查询条件”分两种完全不同的需求,配置方法也不一样,请对号入座:

需求 A:固定过滤条件(每次轮询都带上的筛选条件)

比如“只查已审核的订单”。这类条件不要用 pollingTimeArg,直接配置在触发器节点的输入参数里(固定值或表达式),然后在连接器请求配置中引用 input_data.<参数名>

  • 触发器输入参数里配置:orderStatus = 固定值 AUDITED
  • 连接器请求配置里引用:
path("['input_data']['orderStatus']")

如果筛选条件是一整个对象(由使用流程的用户填写),把输入参数定义成对象类型,可以整体引用并放进 JSON 体:

{
  "queryFilter": path("['input_data']['queryFilter']"),
  "startTime": path("['input_data']['pollingTimeArg']['startTime']"),
  "endTime": path("['input_data']['pollingTimeArg']['endTime']")
}

queryFilter 会原样展开成嵌套 JSON 对象传给接口。

需求 B:游标式翻页(下一页要带上一页返回的“游标/条件”)

有些接口不是靠 offset 翻页,而是“本次响应里返回下一次查询要用的条件(如 nextCursorscrollId)”。平台已经内置了这条自动接力通道,名字就叫 conditions

工作流程(你只需做两件事):

  1. 让接口的响应能被正确解析——平台会从触发器查询接口的响应里找数据数组和条件,两种响应结构都支持:

    • 结构一(推荐,最清晰):响应体直接返回标准结构,dataItems 是数据、conditions 里放你下一页要用的任何字段:
      {
        "dataItems": [ {"id": "1"}, {"id": "2"} ],
        "conditions": { "nextCursor": "abc123" }
      }
      
    • 结构二(普通业务响应,自动拆解):响应是 {code, msg, data:{list:[...], nextCursor}} 这类结构时,平台自动把最浅层的对象数组(这里是 data.list)当作数据,其余所有字段(去掉 list 后的 codemsgdata.nextCursor……)整体作为 conditions。
  2. 在请求配置里引用下一页要用的字段

    • 响应用结构一时,引用路径为:
      path("['input_data']['pollingTimeArg']['conditions']['nextCursor']")
      
    • 响应用结构二时,conditions 里保留了原始层级,路径要带全:
      path("['input_data']['pollingTimeArg']['conditions']['data']['nextCursor']")
      

    平台每拉完一页,就把上一页响应解析出的 conditions 自动注入下一页查询的 pollingTimeArg.conditions,你不用做任何额外配置。

一个完整的游标分页触发器示例(POST + JSON 体):

{
  "startTime": path("['input_data']['pollingTimeArg']['startTime']"),
  "endTime": path("['input_data']['pollingTimeArg']['endTime']"),
  "limit": path("['input_data']['pollingTimeArg']['limit']"),
  "offset": path("['input_data']['pollingTimeArg']['offset']"),
  "cursor": path("['input_data']['pollingTimeArg']['conditions']['nextCursor']")
}

配合约定响应:

{
  "dataItems": [ ...本页数据... ],
  "conditions": { "nextCursor": "平台会把这里原样带给下一页" }
}

第一页怎么办? 第一页(以及调试模式)没有 conditions,cursor 会被替换为 JSON 的 null(多数游标接口首次传 null 是合法的)。如果接口不接受 null 字段,在 HTTP 配置里打开“空值字段移除”(removeMissingValues,对 body/params 生效),第一页请求会自动丢掉这个字段。

两点边界要知道:

  • conditions 是同一轮轮询内翻页的接力棒:本轮取完就结束,下一个轮询周期从新时间窗口的第一页重新开始(此时长期增量的起点由平台按“最后拉到数据的时间”自动推进,无需你配置)。
  • 你也可以把固定筛选条件放进响应的 conditions 里返回,实现“首轮计算、后续每页复用”的动态条件——conditions 内容完全由你的接口决定,平台只负责透传。

['xxx']`,一个字符都不能差)

  • 接口接受毫秒时间戳;要秒级时改用参数值表达式 / 1000,而不是 URL 直拼
  • 用了 conditions 时,响应结构符合约定,且引用路径与响应层级一致
  • 先用“调试”跑一次(窗口=近 1 小时、limit=100、offset=0、无 conditions),确认请求和响应解析都正确,再启用正式轮询

一句话总结startTime/endTime/limit/offset 是平台算好给你的“时间窗口 + 翻页坐标”,用 path("['input_data']['pollingTimeArg'][...]") 在请求配置任意位置取用(JSON 体里自动保数字类型);固定筛选条件配在触发器输入参数(input_data.<参数名>);游标式翻页则通过响应里的 conditions → 下一页 pollingTimeArg.conditions 的自动透传实现,路径多套一层 ['conditions'][...] 即可。

Action类型 

action执行动作跟上面trigger操作基本操作差别不大,只是trigger回作为集成流第一个节点可选,如果这个接口配置action,那么在集成流就不能选择第一个作为触发事件

六:字段说明:

1:授权页面配置字段:
如果用户配置授权接口,页面表单字段,那么怎么能够在后续接口配置用到呢?
授权表单配置参数以及授权接口返回任何参数,都会包装进去auth_data: 
path("['auth_data']['access_token']")   集成平台用的表达式一定需要带有前缀path,后续就是具体参数路径
普通trigger以及action配置表单参数:
1:接口需要拿到授权参数:也是按照之前约束:path("['auth_data']['xxxxxxx']")
2.trigger/action页面表单填写参数:接口需要用到input_data表达式 

七:函数模式:

每一个接口如果页面UI满足不了,都可以切换代码模型:
函数参数透传对应页面配置参数以及授权参数
Map<String, Object> authData = (Map<String, Object>) syncArg.get("auth_data"); Map<String, Object> inputData = (Map<String, Object>) syncArg.get("input_data"); String tenantId = (String) syncArg.get("tenantId"); String connectorKey = (String) syncArg.get("connectorKey"); String operation = (String) syncArg.get("operation"); String connectionId = (String) syncArg.get("connectionId"); String type = (String) syncArg.get("type"); Map<String, Object> extra = (Map<String, Object>) syncArg.get("extra"); Map<String, Object> http = (Map<String, Object>) syncArg.get("http");

函数返回值格式要求:

trigger返回格式要求,需要返回数据列表

字段说明: dataItems:必须,触发出来的数据列表 privateKeys:推荐,去重主键字段 nameKeys:推荐,调试展示名称字段 conditions:推荐,下一次轮询继续查询用 return [ outputData: [ triggerOperation: "instant.created", dataItems: [ [ id: "1", event: "created", name: "test order" ], [ id: "2", event: "created", name: "test order 2" ] ], privateKeys: ["id"], nameKeys: ["name"], conditions: [ nextCursor: "cursor_123" ] ] ]

获取认证授权地址:

return [ outputData: [ authorizeUrl: "https://example.com/oauth/authorize?client_id=xxx&state=xxx&redirect_uri=xxx" ] ]

获取token

return [ outputData: [ access_token: "access_token_xxx", refresh_token: "refresh_token_xxx", token_type: "Bearer", expires_in: 7200, scope: "crm" ] ]

刷新token

return [ outputData: [ access_token: "new_access_token_xxx", refresh_token: "new_refresh_token_xxx", token_type: "Bearer", expires_in: 7200 ] ]
普通接口函数返回内容:返回 outputData
return [ outputData: [ id: "123", name: "test", status: "success" ] ]

八:skill自动创建连接器

1:需要找到值班同学拿到创建连接器skill,目前还在内测,只能部分同学测试
2:需要有个好用agent,codex,Qoder,claudecode等等都可以
3:用户企业需要灰度CLI:https://help.fxiaoke.com/ee88/a823/ce56

九:常见问题:

2026-09-09
0 0