PROVIDER GUIDE
向 ERP 开放你的应用能力
能力是第三方应用提供、但可直接嵌入 ERP 业务页面调用的服务,例如以图搜索、快速翻译、图片处理或地址校验。开放平台负责路由与授权,应用负责业务执行、套餐和额度。
企业仍然只在 ERP 官方安装页确认一次权限。能力调用不会跳到第三方再次授权,也不能由第三方隐藏或修改 Scope。
ERP 调用方的完整请求流程见 ERP 内嵌能力接入指南 →
提供能力的六个步骤
- 为能力确定稳定 Key、允许的 ERP Surface、输入输出和所需 Scope。
- 在应用服务端实现公网 Provider Endpoint。
- 使用对应环境 Client Credential 向开放平台登记能力。
- 收到调用后,用一次性 Ticket 换取可信企业和输入。
- 按 Installation 检查设置、订阅和额度,并以 Invocation ID 幂等执行。
- 返回标准同步、异步或业务拒绝结果;Production 随应用版本提交审核。
1. 登记能力
能力 Key 应使用命名空间形式,例如 image-search.search。Surface 表示能力获准出现的 ERP 业务位置,例如 order.quote.product-picker。
curl --request PUT \
--url https://open.dsfulfill.io/v1/capabilities/image-search.search \
--user "$CLIENT_ID:$CLIENT_SECRET" \
--header 'Content-Type: application/json' \
--data '{
"version": "1.0",
"title": "以图搜索本地商品",
"description": "在订单报价中按图片搜索当前企业商品库",
"mode": "sync",
"endpoint_url": "https://app.example.com/api/capabilities/image-search",
"timeout_seconds": 10,
"required_scopes": ["products:read"],
"surfaces": ["order.quote.product-picker"],
"input_schema": {
"type": "object",
"required": ["image_url"],
"properties": {
"image_url": { "type": "string", "format": "uri" },
"limit": { "type": "integer", "minimum": 1, "maximum": 50 }
}
},
"output_schema": { "type": "object", "required": ["items"] }
}'凭证决定登记环境。Sandbox 能力登记后立即生效并允许 localhost;Production Endpoint 必须是公网 HTTPS,登记或变更后进入待审核状态。
2. 接收调用并兑换 Ticket
POST /api/capabilities/image-search
X-DSFulfill-Environment: production
X-DSFulfill-Capability: image-search.search
X-DSFulfill-Invocation-Id: inv_xxx
{
"invocation_id": "inv_xxx",
"ticket": "ds_cap_xxx"
}Header 可用于追踪日志,但不能代替换票。应用后端应立即用同环境 Client Credential 请求:
curl --request POST \
--url https://open.dsfulfill.io/v1/capability-invocations/tickets/exchange \
--user "$CLIENT_ID:$CLIENT_SECRET" \
--header 'Content-Type: application/json' \
--data '{"ticket":"ds_cap_xxx"}'{
"data": {
"invocation_id": "inv_xxx",
"application_id": "app_xxx",
"installation_id": "ins_xxx",
"company_id": "company_xxx",
"actor_id": "admin_xxx",
"environment": "production",
"capability": "image-search.search",
"surface": "order.quote.product-picker",
"input": { "image_url": "https://cdn.example.com/query.jpg", "limit": 12 },
"expires_at": "2026-09-06T12:00:00.000Z"
}
}Ticket 有效期 60 秒,并绑定应用、Installation 和环境。不要从 Cookie、邮箱、请求 Header 或输入字段推断企业;只认换票响应中的上下文。
3. 执行、租户隔离与计费
- 校验换票结果中的 capability、surface 和 environment 与 Endpoint 预期一致。
- 用
company_id + installation_id加载应用工作区、设置和套餐。 - 以
invocation_id建立唯一执行记录;存在完成结果时直接重放。 - 在同一事务中检查额度、写额度流水并标记消费,避免并发重复扣费。
- 所有商品查询必须带可信 company_id,禁止跨企业索引或缓存命中。
免费额度应归属 Installation 或 ERP Company,而不是第三方登录账号。用户退出后换账号、重新打开应用,都不能重新获得同一企业的首赠额度。
4. 返回标准结果
{
"status": "completed",
"data": {
"items": [
{ "product_id": "19550", "title": "Example", "image_url": "https://...", "score": 0.94 }
]
},
"usage": { "charged": 1, "remaining": 99 }
}{
"status": "accepted",
"job_id": "job_xxx"
}异步任务完成后,使用对应 Installation Access Token 回调 POST /v1/capability-invocations/{invocation_id}/complete。同一 Invocation 的完成回调也必须幂等。
{
"status": "denied",
"reason": "SUBSCRIPTION_REQUIRED",
"action": {
"type": "open_app",
"label": "选择套餐",
"launch_path": "/billing"
}
}允许的拒绝原因只有 SUBSCRIPTION_REQUIRED、INSUFFICIENT_CREDITS 和 SETUP_REQUIRED。launch_path 必须是本站相对路径,不能返回任意外部 URL。
5. Sandbox、Production 与验收
- 先用 Sandbox Client Credential 登记 localhost 或测试 HTTPS Endpoint。
- 把应用安装到绑定的 ERP 测试企业,完成正常安装授权。
- 测试成功、重复请求、未订阅、额度不足、未初始化、Ticket 过期和 Provider 超时。
- 再用 Production Client Credential 登记公网 HTTPS Endpoint。
- 提交 Production Release;平台审核 Scope、Surface、Schema、Endpoint 和用途。
- 发布后用真实 Production Installation 验证,并继续保留 Sandbox 用于下一版本开发。
日志至少记录 invocation_id、环境、耗时和内部结果状态,但必须隐藏 Ticket、Client Secret、Access Token 及用户敏感输入。