跳到正文

Raise Open API

查看 Markdown

版本 1.2.0。下载 OpenAPI 文件(YAML)

概述

给应用后端用的开放接口(主版本 v1)。调用根地址是 https://api.{域名}/open/v1(https://app.{域名}/open/v1 同样可用)。 本文件里的路径已经去掉了这个前缀:GET /whoami 就是 GET https://api.{域名}/open/v1/whoami。

第一次调用

  1. 在开发者平台创建应用,拿到 client_id 和密钥(测试环境以 kwo_test_ 开头,正式以 kwo_live_ 开头;旧密钥 kwo_ 也是正式)。
  2. POST /oauth/token,grant_type=client_credentials。商店应用(应用级凭证)必须带 tenant;租户自建应用(绑定在一个组织上)不要带,或只能带它自己的组织。
  3. 用返回的 access_token 调 GET /whoami 或 GET /ping。令牌 300 秒过期,SDK 会在到期前 60 秒自动换。

代表一位终端客户(小程序用户)调用 /me… 时,用 grant_type=urn:raise:grant-type:customer,带上后台已经验证过的 phone。

约定

  • 认证 Authorization: Bearer <access_token>。换令牌本身用 HTTP Basic(client_id:client_secret)或把这两个字段放在正文里。
  • 错误 状态 ≥ 400 的正文都是 {"error":{"code","message","requestId","docUrl","details"}}。code 稳定,用它分支;message 给人看。details 没内容时是 {}。requestId 与响应头 X-Request-Id 相同,报问题时带上。
  • 列表 ?limit=(默认 20,最大 100)&cursor= → {"data":[…],"nextCursor":"…" 或 null}。没有下一页时 nextCursor 为 null。会员 /me 下的短列表(自己的会员、课包等)不翻页,字段名见各操作。
  • 幂等 除 /oauth/token 外每个 POST 收 Idempotency-Key(1–255 字符)。范围是应用 + 组织(客户令牌再加上客户)。保存 24 小时。同键同方法同路径同正文 → 重放第一次的回答,并带 Idempotent-Replayed: true。同键不同正文 → 409 idempotency_conflict。第一次还在处理 → 409 idempotency_in_progress。状态 ≥ 500 的回答不保存。SDK 会在 POST 上自动生成 uuid v4。
  • 限流 认证过的调用都带 X-RateLimit-Limit、X-RateLimit-Remaining、X-RateLimit-Reset。429 另带 Retry-After(秒)。Raise-Environment: test|live 说明这把令牌属于哪边。
  • 时间 RFC 3339 UTC。金额 整数最小货币单位 + currency。JSON 字段 camelCase;令牌接口的成功正文用 RFC 6749 的名字(access_token、expires_in…)。

用 Go 模块 github.com/21stware/raise-go 或 npm 包 @21stware/raise-sdk,不要自己拼签名和重试。

地址

  • https://api.{domain}/open/v1
    • domain:平台域名(默认 example.com)

认证方式

名称类型说明
bearerhttp bearerPOST /oauth/token 换到的短令牌。Authorization: Bearer <access_token>
basichttp basic换令牌时的应用密钥。用户名是 client_id,密码是 client_secret。也可以把这两个字段放进正文。

oauth

用应用密钥换短令牌。SDK 内部调用,应用代码不要自己打这条

POST /oauth/token

用应用密钥换一把短令牌(租户令牌或客户令牌)

这条接口不要用 Bearer,也不要带 Idempotency-Key。SDK 的传输层会调它。

认证:HTTP Basic(client_id:client_secret)或把 client_id、client_secret 放进正文。未知的 id 和错误的密钥都回答 401 invalid_client,并带 WWW-Authenticate: Basic。

正文 application/x-www-form-urlencoded 或 application/json 都可以。

grant_type=client_credentials:换租户令牌,300 秒。tenant 对应用级凭证(商店应用、凭证不绑在一个组织上)是必填;对租户绑定凭证必须省略或等于它自己的组织,否则 400 tenant_required。scope 可选,空格分隔,只能是已经授予的子集。

grant_type=urn:raise:grant-type:customer:换客户令牌,900 秒。phone 必填(后台自己验证过的号码,平台不再验)。customer_id 可选,在 409 ambiguous_customer 之后用来指定是哪一位。需要范围 customer:assert。没有对应会员时 200 {"matched":false},不发令牌、不建客户。

grant_type=authorization_code:员工授权(代某位员工,在工作台之外:手机、桌面、命令行、外部 agent)。先把人带到身份服务的授权地址(client_id = 应用的 OIDC 客户端,code_challenge + S256,redirect_uri 必须在开发者平台登记过);人登录、在同意页看过范围并同意后,回调带回 code。再到这里换:code、code_verifier、redirect_uri、client_id 必填;机密客户端另用应用密钥认证(HTTP Basic 或 client_secret),公开客户端不带密钥。得到员工令牌(600 秒,sub 是这个人)与 refresh_token。人没同意过是 403 consent_required。

grant_type=refresh_token:用 refresh_token 续员工令牌。每用一次换一把新的(30 天滚动);用过的再用一次,整条链作废(400 invalid_grant)。人或管理员吊销授权、应用停用、凭证吊销后都是 400 invalid_grant,已发出的员工令牌 30 秒内失效(401 consent_revoked)。员工令牌能做的 = 人同意的范围 ∩ 组织此刻授予应用的范围 ∩ 这个人此刻的角色与数据范围。

测试密钥只能打测试企业;正式密钥不能打测试企业。否则 403 wrong_environment。应用没装、关掉、组织停用是 403 not_installed。一把范围都没授是 403 no_scope。密钥吊销或过期是 401 credential_ended。来源 IP 不在允许名单是 403 address_not_allowed。

同一地址失败太多次是 429 too_many_attempts(Retry-After: 60)。换令牌本身也有次数限制(429 rate_limited)。

  • 认证:basic 或 不带凭证
  • operationId:createToken

请求正文(必填)(application/x-www-form-urlencoded、application/json)

字段类型必填说明
grant_typestring是client_credentials 换租户令牌;urn:raise:grant-type:customer 换客户令牌;authorization_code / refresh_token 换员工令牌
可选值:client_credentials、urn:raise:grant-type:customer、authorization_code、refresh_token
client_idstring未用 HTTP Basic 时必填
client_secretstring未用 HTTP Basic 时必填
tenantstring应用级凭证必填。租户绑定凭证必须省略或等于它自己的组织
scopestring空格分隔的范围子集。省略则给已授予的全部
phonestring客户授权必填。数字,可带前导 +。空格和短横忽略。大陆手机也可写成 86… / +86…
customer_idstring客户授权可选。在 ambiguous_customer 之后指定是哪一位
codestringauthorization_code 必填。身份服务回调带回的授权码
code_verifierstringauthorization_code 必填。PKCE 原文(S256)
redirect_uristringauthorization_code 必填。与授权请求里的一致,且在开发者平台登记过
refresh_tokenstringrefresh_token 必填。kwr_ 开头,只能用一次

响应

状态说明
200换到令牌:access_token、token_type=Bearer、expires_in、scope、tenant、environment。客户授权另带 customer。 客户授权找不到人:{"matched":false},没有令牌。
400invalid_request:查询或正文读不出来。见 BadRequest
401invalid_client:client_id 不存在或 client_secret 不对。见 InvalidClient
403见 Forbidden
409见 Conflict
422见 Unprocessable
429见 RateLimited
500internal:平台出错。见 Internal
501not_implemented。见 NotImplemented
503unavailable:暂时不可用(读凭证、读授权、读库失败)。见 Unavailable

200 响应正文(application/json)

以下其一:

Token:RFC 6749 成功正文。customer 只在客户授权时出现

字段类型必填说明
access_tokenstring是
token_typestring是固定为 "Bearer"
expires_ininteger是秒。租户令牌 300,客户令牌 900,员工令牌 600
scopestring是空格分隔。客户令牌不含 customer:assert
tenantstring是
environmentstring是可选值:test、live
customerstring客户中心 id。仅客户授权
refresh_tokenstring仅员工授权。下一次续期用它,30 天不用就过期
userstring仅员工授权。这位员工的用户 id

CustomerMiss:客户授权找不到这个号码下的会员。不发令牌、不建客户

字段类型必填说明
matchedboolean是固定为 false

platform

令牌身份与连通性

GET /whoami

这把令牌现在是谁:组织、应用、凭证和仍然有效的范围

不需要特定范围。任何还活着的集成令牌都可以调。返回的 scopes 是令牌里的范围与此刻授予的交集:管理员收回的范围最多 30 秒内从这里消失。 用它确认换到的令牌打的是哪个组织和哪把凭证。

  • 认证:bearer
  • operationId:getWhoami

响应

状态说明
200{tenant, app, credential, scopes}
401见 Unauthorized
429见 RateLimited
503unavailable:暂时不可用(读凭证、读授权、读库失败)。见 Unavailable

200 响应正文(application/json)

字段类型必填说明
tenantstring是
appstring是
credentialstring是换出这把令牌的 client_id
scopesstring[]是令牌范围与此刻授予的交集
userstring员工令牌的员工;租户令牌为空
rolesstring[]员工令牌:这个人此刻在组织里的角色(每次调用现读);租户令牌为空
environmentstring可选值:test、live

GET /ping

连通性探测,需要范围 platform:ping,正文只有 {ok:true}

需要范围 platform:ping。不返回组织里的任何数据,只说明这把令牌还能用。没有该范围是 403 scope_required(这次调用已经计入限流)。

  • 认证:bearer
  • operationId:getPing

响应

状态说明
200{ok: true}
401见 Unauthorized
403见 Forbidden
429见 RateLimited
503unavailable:暂时不可用(读凭证、读授权、读库失败)。见 Unavailable

200 响应正文(application/json)

字段类型必填说明
okboolean是固定为 true

tables

多维表只读(必须经视图;个人字段永远不返回)

GET /tables/{table}/views/{view}/rows

经视图列出一张多维表的行(不含个人字段)

需要这张表的范围:租户自建表是 tables.base:read;系统表 sys_<id> 是 tables.<id>:read。表还必须「开放给项目」。缺范围是 403 scope_required(消息里会写出缺的那条,方便你去要)。

后台模式令牌(租户令牌)按视图自己的筛选读行,员工专属视图也可以。客户模式令牌按视图的行规则来(own-read / own-write 只看见断言客户的行)。个人(PII)列永远不返回。

表、视图不存在,或表未开放,或这条令牌进不了这个视图:一律 404 not_found,避免探测。

查询与造物的 data.list 相同:limit(默认 20,1–100)、cursor、sort(字段 id,前面加 - 表示降序,逗号分隔)、filter[字段][运算符]=值。运算符:eq、ne、in、lt、lte、gt、gte、contains、between。只能筛、只能排视图里出现的字段,否则 400 invalid_request。

列表形状是 data + nextCursor。每一行是 {id, version, fields, createdAt},fields 只有视图里的列。

  • 认证:bearer
  • operationId:listTableRows

参数

名称位置类型必填说明
tablepathstring是表名。系统表以 sys_ 开头;否则是租户自建表
viewpathstring是视图 id
limitqueryinteger每页条数,默认 20,最大 100
默认 20
最小 1,最大 100
cursorquerystring上一页返回的 nextCursor。第一页省略
sortquerystring字段 id,逗号分隔;前面加 - 表示降序。只能是视图里的字段。
filterquerymap[string, map[string, string]]只按视图里的字段筛选。写成 filter[字段][运算符]=值。 例:filter[status][eq]=active。in 的值用逗号分隔;between 的值是 lo,hi。

响应

状态说明
200一页行
400invalid_request:查询或正文读不出来。见 BadRequest
401见 Unauthorized
403见 Forbidden
404not_found:不存在,或你不该知道它存在(别人的会员、未开放的表、进不了的视图)。见 NotFound
429见 RateLimited
503unavailable:暂时不可用(读凭证、读授权、读库失败)。见 Unavailable

200 响应正文(application/json)

字段类型必填说明
dataRow[]是
data[].idstring是
data[].versioninteger是乐观并发版本
data[].fieldsobject是
data[].createdAtstring(date-time)
nextCursorstring,可为 null是

GET /tables/{table}/views/{view}/rows/{id}

经视图读取多维表的一行

范围和可见性与列表相同。行不在视图里、不是这位客户的、或 id 不存在:404 not_found。个人字段不返回。

  • 认证:bearer
  • operationId:getTableRow

参数

名称位置类型必填说明
tablepathstring是表名。系统表以 sys_ 开头;否则是租户自建表
viewpathstring是视图 id
idpathstring是行 id

响应

状态说明
200这一行
401见 Unauthorized
403见 Forbidden
404not_found:不存在,或你不该知道它存在(别人的会员、未开放的表、进不了的视图)。见 NotFound
429见 RateLimited
503unavailable:暂时不可用(读凭证、读授权、读库失败)。见 Unavailable

200 响应正文(application/json)

字段类型必填说明
idstring是
versioninteger是乐观并发版本
fieldsobject是
createdAtstring(date-time)

customers

客户档案。电话按员工界面打码;customer:write 可按手机号创建或找到,并改姓名与标签

GET /customers

列出组织里的客户(电话已打码)

需要范围 customer:read。租户令牌。列表形状是 data + nextCursor。默认 20 条,最大 100。

phone 按客户中心的查找:整段号码(大陆 11 位或带国家码)走身份查找;也可以是屏幕上打码后仍能看见的数字。updatedSince 是 RFC 3339,只留下 lastTouchAt(没有则 createdAt)不早于该时刻的客户。

phone 是员工列表上的打码形式(与 customer:write 无关;揭开号码仍是员工在客户应用里的 reveal)。tags 是标签 id。不返回明文号码、邮箱、备注(客户中心没有备注字段)。

  • 认证:bearer
  • operationId:listCustomers

参数

名称位置类型必填说明
limitqueryinteger每页条数,默认 20,最大 100
默认 20
最小 1,最大 100
cursorquerystring上一页返回的 nextCursor。第一页省略
phonequerystring按号码查找(整段或打码后仍可见的数字)
updatedSincequerystring(date-time)RFC 3339 UTC。只列出该时刻及之后有过接触(或新建)的客户

响应

状态说明
200一页客户。没有下一页时 nextCursor 为 null
400invalid_request:查询或正文读不出来。见 BadRequest
401见 Unauthorized
403见 Forbidden
429见 RateLimited
500internal:平台出错。见 Internal
503unavailable:暂时不可用(读凭证、读授权、读库失败)。见 Unavailable

200 响应正文(application/json)

字段类型必填说明
dataCustomer[]是
data[].idstring是
data[].namestring是
data[].phonestring员工列表上的打码形式。没有电话则省略
data[].stagestring是lead、customer 或 dormant(按最近接触算)
data[].tagsstring[]是标签 id
data[].createdAtstring(date-time)是
data[].lastTouchAtstring(date-time)是
data[].identitiesCustomerIdentity[]详情才有。masked 已打码,没有明文 value
data[].identities[].kindstring是phone、email、openid 等
data[].identities[].maskedstring是
data[].identities[].verifiedboolean是
nextCursorstring,可为 null是

POST /customers

按手机号创建客户,或返回已经存在的那位

需要范围 customer:write。租户令牌。phone 必填,否则 422。走客户中心的 Resolve:号码已有客户则 200 并返回那位(不改姓名、不加标签、不发事件);没有则 201 并写入 customer.created。

新建时可选 name、tags(标签 id)。请带 Idempotency-Key。返回的 phone 已打码。

  • 认证:bearer
  • operationId:createCustomer

参数

名称位置类型必填说明
Idempotency-Keyheaderstring除 /oauth/token 外每个 POST 都收。SDK 未传入时会生成 uuid v4。24 小时内同键同正文重放第一次的回答
最短 1,最长 255

请求正文(必填)(application/json)

字段类型必填说明
phonestring是必填。大陆 11 位或带国家码
namestring新建时使用。号码已有客户时忽略
tagsstring[]标签 id。只在新建时加上

响应

状态说明
200这个号码已经有客户,返回那位(未改)
201新建的客户
400invalid_request:查询或正文读不出来。见 BadRequest
401见 Unauthorized
403见 Forbidden
409见 Conflict
413payload_too_large:正文太大。见 PayloadTooLarge
422见 Unprocessable
429见 RateLimited
500internal:平台出错。见 Internal
503unavailable:暂时不可用(读凭证、读授权、读库失败)。见 Unavailable

200 响应正文(application/json)

字段类型必填说明
idstring是
namestring是
phonestring员工列表上的打码形式。没有电话则省略
stagestring是lead、customer 或 dormant(按最近接触算)
tagsstring[]是标签 id
createdAtstring(date-time)是
lastTouchAtstring(date-time)是
identitiesCustomerIdentity[]详情才有。masked 已打码,没有明文 value
identities[].kindstring是phone、email、openid 等
identities[].maskedstring是
identities[].verifiedboolean是

201 响应正文(application/json)

字段类型必填说明
idstring是
namestring是
phonestring员工列表上的打码形式。没有电话则省略
stagestring是lead、customer 或 dormant(按最近接触算)
tagsstring[]是标签 id
createdAtstring(date-time)是
lastTouchAtstring(date-time)是
identitiesCustomerIdentity[]详情才有。masked 已打码,没有明文 value
identities[].kindstring是phone、email、openid 等
identities[].maskedstring是
identities[].verifiedboolean是

GET /customers/{id}

读取一位客户(电话已打码)

需要范围 customer:read。不存在是 404 not_found。phone 与 identities[].masked 是打码形式;identities 不含明文 value。揭开号码不是这个接口的事。

  • 认证:bearer
  • operationId:getCustomer

参数

名称位置类型必填说明
idpathstring是客户中心 id

响应

状态说明
200这位客户
401见 Unauthorized
403见 Forbidden
404not_found:不存在,或你不该知道它存在(别人的会员、未开放的表、进不了的视图)。见 NotFound
429见 RateLimited
500internal:平台出错。见 Internal
503unavailable:暂时不可用(读凭证、读授权、读库失败)。见 Unavailable

200 响应正文(application/json)

字段类型必填说明
idstring是
namestring是
phonestring员工列表上的打码形式。没有电话则省略
stagestring是lead、customer 或 dormant(按最近接触算)
tagsstring[]是标签 id
createdAtstring(date-time)是
lastTouchAtstring(date-time)是
identitiesCustomerIdentity[]详情才有。masked 已打码,没有明文 value
identities[].kindstring是phone、email、openid 等
identities[].maskedstring是
identities[].verifiedboolean是

PATCH /customers/{id}

改客户的姓名或标签

需要范围 customer:write。可改 name、tags(标签 id 列表;空数组表示去掉全部可改的标签)。带上 phone 是 422(号码不能改)。带上 notes 是 422(客户中心没有备注字段)。其它未知字段忽略。

改了字段时写入 customer.updated。企业微信等外来标签不能在这里摘掉,会 422。

  • 认证:bearer
  • operationId:updateCustomer

参数

名称位置类型必填说明
idpathstring是客户中心 id

请求正文(必填)(application/json)

字段类型必填说明
namestring
tagsstring[]标签 id。空数组表示去掉全部可改的标签

响应

状态说明
200改完后的客户
400invalid_request:查询或正文读不出来。见 BadRequest
401见 Unauthorized
403见 Forbidden
404not_found:不存在,或你不该知道它存在(别人的会员、未开放的表、进不了的视图)。见 NotFound
422见 Unprocessable
429见 RateLimited
500internal:平台出错。见 Internal
503unavailable:暂时不可用(读凭证、读授权、读库失败)。见 Unavailable

200 响应正文(application/json)

字段类型必填说明
idstring是
namestring是
phonestring员工列表上的打码形式。没有电话则省略
stagestring是lead、customer 或 dormant(按最近接触算)
tagsstring[]是标签 id
createdAtstring(date-time)是
lastTouchAtstring(date-time)是
identitiesCustomerIdentity[]详情才有。masked 已打码,没有明文 value
identities[].kindstring是phone、email、openid 等
identities[].maskedstring是
identities[].verifiedboolean是

org

组织通讯录(成员与组织名)。电话与邮箱只在同时持有 org.contacts:read 时返回

GET /members

列出组织通讯录里的成员

需要范围 org.members:read。租户令牌。返回 {data:[{id, name, title, departments, status}], nextCursor}。默认 20 条,最大 100。按账号 id。

email 与 phone 只在同时持有 org.contacts:read 时出现。生产环境的通讯录是在职的人(不含机器账号);状态以目录为准。

  • 认证:bearer
  • operationId:listMembers

参数

名称位置类型必填说明
limitqueryinteger每页条数,默认 20,最大 100
默认 20
最小 1,最大 100
cursorquerystring上一页返回的 nextCursor。第一页省略

响应

状态说明
200一页成员。没有下一页时 nextCursor 为 null
400invalid_request:查询或正文读不出来。见 BadRequest
401见 Unauthorized
403见 Forbidden
429见 RateLimited
500internal:平台出错。见 Internal
503unavailable:暂时不可用(读凭证、读授权、读库失败)。见 Unavailable

200 响应正文(application/json)

字段类型必填说明
dataMember[]是
data[].idstring是账号 id
data[].namestring是
data[].titlestring是职务。没有则是空字符串
data[].departmentsstring[]是部门名称,主部门在前
data[].statusstring是目录里的状态,如 active、invited
data[].emailstring
data[].phonestring
nextCursorstring,可为 null是

GET /org

当前令牌所在组织的 id 与名称

需要范围 org.members:read。返回 {tenant, name}。名称来自组织档案;没有名称时是空字符串。

  • 认证:bearer
  • operationId:getOrg

响应

状态说明
200{tenant, name}
401见 Unauthorized
403见 Forbidden
429见 RateLimited
500internal:平台出错。见 Internal
503unavailable:暂时不可用(读凭证、读授权、读库失败)。见 Unavailable

200 响应正文(application/json)

字段类型必填说明
tenantstring是
namestring是组织显示名。没有则是空字符串

me

会员客户模式:这位客户自己的会员、课包、预约和待确认核销。新地址是会员应用自己的域名 https://membership.apps.{domain}/open/v1/me…(同一组路由、同一把客户令牌);api.{domain} 上的旧地址照常应答到 2027-05-01,应答带 Deprecation、Sunset 与指向新地址的 Link: rel=successor-version

GET /me

这把客户令牌对应的会员(id、编号、姓名、状态)

需要范围 membership.me:read。只要客户令牌(租户令牌是 403 customer_token_required)。读操作不检查断言有多老。

members 是这个组织里 customer_id 为令牌客户的全部会员,按创建时间,不含已合并、已关闭。一个号码在多家店可以是多条会员,只要客户 id 相同。没有会员时是 []。

不返回:电话、备注、标签、教练、核销码、金额、病历。

  • 认证:bearer
  • operationId:listMeMembers

响应

状态说明
200{members: [MeMember]}
401见 Unauthorized
403见 Forbidden
429见 RateLimited
500internal:平台出错。见 Internal
503unavailable:暂时不可用(读凭证、读授权、读库失败)。见 Unavailable

200 响应正文(application/json)

字段类型必填说明
membersMeMember[]是
members[].idstring是
members[].nostring是会员编号
members[].namestring是
members[].statusstring是merged 和 closed 不会出现
可选值:active、frozen、expired

GET /me/packages

这位客户名下会员的有效或冻结课包

需要范围 membership.me:read。认证与 GET /me 相同。

只列出存储状态为 active 或 frozen 的课包(已退、作废、已转让不出现)。status 是读的时候算出来的,存储仍是 active 时也可能是 not_started、expired、used_up。unlimited 仅在 kind 为 period(期卡)时为 true。courses 为空表示适用全部课程。

不返回:备注、金额、销售、流水、券、每日/每周上限。

  • 认证:bearer
  • operationId:listMePackages

响应

状态说明
200{packages: [MePackage]}
401见 Unauthorized
403见 Forbidden
429见 RateLimited
500internal:平台出错。见 Internal
503unavailable:暂时不可用(读凭证、读授权、读库失败)。见 Unavailable

200 响应正文(application/json)

字段类型必填说明
packagesMePackage[]是
packages[].idstring是
packages[].memberIdstring是
packages[].namestring是
packages[].kindstring是可选值:count、period、count_period
packages[].unlimitedboolean是仅 kind 为 period 时为 true
packages[].totalTimesinteger是
packages[].remaininginteger是
packages[].coursesstring[]是课程 id。空表示全部课程
packages[].startsOnstringYYYY-MM-DD。未设则省略
packages[].endsOnstringYYYY-MM-DD。未设则省略
packages[].statestring是存储状态。只列出这两种
可选值:active、frozen
packages[].statusstring是读的时候算出来
可选值:active、not_started、frozen、expired、used_up

GET /me/bookings

这位客户在一个日期窗口里的预约,并给出此刻取消要扣几次

需要范围 membership.me:read。from、to 是门店时区的日期 YYYY-MM-DD,两端都包含。省略 from 为昨天;省略 to 为 from 加 62 天。to 早于 from、不是日期、或跨度超过 124 天:422 validation_failed。

status 有值时按精确状态过滤(未知值得到空列表,不是 422)。最多 200 条,按开始时间再按 id。

cancelCharge 只在 status 为 booked 时计算(免费取消窗口内是 0,否则是门店的晚取消扣次,0 或 1)。coachName 是员工显示名,没有则省略。

不返回:备注、会员姓名或编号、教练 id、金额、颜色、课包 id、核销 id。

  • 认证:bearer
  • operationId:listMeBookings

参数

名称位置类型必填说明
fromquerystringYYYY-MM-DD,门店时区。默认昨天
toquerystringYYYY-MM-DD,包含。默认 from 加 62 天。跨度最多 124 天
statusquerystring精确预约状态。未知值得到空列表

响应

状态说明
200{bookings: [MeBooking]}
401见 Unauthorized
403见 Forbidden
422见 Unprocessable
429见 RateLimited
500internal:平台出错。见 Internal
503unavailable:暂时不可用(读凭证、读授权、读库失败)。见 Unavailable

200 响应正文(application/json)

字段类型必填说明
bookingsMeBooking[]是
bookings[].idstring是
bookings[].memberIdstring是
bookings[].sessionIdstring是
bookings[].courseNamestring是
bookings[].coachNamestring员工显示名。没有则省略
bookings[].startsAtstring(date-time)是
bookings[].endsAtstring(date-time)是
bookings[].roomstring是总是出现,可能是空字符串
bookings[].statusstring是可选值:booked、waitlist、attended、completed、cancelled、no_show
bookings[].cancelChargeinteger是现在取消要扣几次。非 booked 为 0。门店设置为 0 或 1

POST /me/bookings

以这位客户的一名会员预约一节未开始的开放课(满员进候补)

需要范围 membership.booking:write。这是写操作:客户断言超过 10 分钟是 401 assertion_stale,请重新断言。

正文 {memberId, sessionId},都必填,否则 422 validation_failed。memberId 必须是 GET /me 里的会员,否则 404 not_found。课次不存在是 422,不是 404。走门店自己的预约规则(会员状态、课次开放且未开始、预约窗口、时间重叠、可用课包、容量)。满员时 201 且 status 为 waitlist。

已经预约过是 422;并发下唯一约束冲突是 409 conflict。请带 Idempotency-Key。

  • 认证:bearer
  • operationId:createMeBooking

参数

名称位置类型必填说明
Idempotency-Keyheaderstring除 /oauth/token 外每个 POST 都收。SDK 未传入时会生成 uuid v4。24 小时内同键同正文重放第一次的回答
最短 1,最长 255

请求正文(必填)(application/json)

字段类型必填说明
memberIdstring是GET /me 返回的会员 id
sessionIdstring是GET /me/sessions 返回的课次 id

响应

状态说明
201预约本身(MeBooking),不包裹。status 为 booked 或 waitlist
400invalid_request:查询或正文读不出来。见 BadRequest
401见 Unauthorized
403见 Forbidden
404not_found:不存在,或你不该知道它存在(别人的会员、未开放的表、进不了的视图)。见 NotFound
409见 Conflict
413payload_too_large:正文太大。见 PayloadTooLarge
422见 Unprocessable
429见 RateLimited
500internal:平台出错。见 Internal
503unavailable:暂时不可用(读凭证、读授权、读库失败)。见 Unavailable

201 响应正文(application/json)

字段类型必填说明
idstring是
memberIdstring是
sessionIdstring是
courseNamestring是
coachNamestring员工显示名。没有则省略
startsAtstring(date-time)是
endsAtstring(date-time)是
roomstring是总是出现,可能是空字符串
statusstring是可选值:booked、waitlist、attended、completed、cancelled、no_show
cancelChargeinteger是现在取消要扣几次。非 booked 为 0。门店设置为 0 或 1

POST /me/bookings/{id}/cancel

取消这位客户的预约;晚取消且要扣次时必须 acceptCharge

需要范围 membership.booking:write。写操作(10 分钟后 assertion_stale)。{id} 必须是这位客户的预约,否则 404 not_found。

正文可选 {acceptCharge, reason}。可以不带正文。reason 最多 200 字,否则 422 validation_failed。

预约是 booked 且现在取消要扣次(与列表里的 cancelCharge 相同)且 acceptCharge 不是 true:409 conflict,什么都不取消。候补的 cancelCharge 为 0,不需要 acceptCharge。已到场或已完成不能取消(422)。

200 里的 charged 是实际扣掉的次数,即使带了 acceptCharge: true 也可能是 0(没有可扣的课包,或期卡)。

  • 认证:bearer
  • operationId:cancelMeBooking

参数

名称位置类型必填说明
idpathstring是预约 id
Idempotency-Keyheaderstring除 /oauth/token 外每个 POST 都收。SDK 未传入时会生成 uuid v4。24 小时内同键同正文重放第一次的回答
最短 1,最长 255

请求正文(application/json)

字段类型必填说明
acceptChargeboolean列表里 cancelCharge 大于 0 时必须为 true
reasonstring最多 200 字

响应

状态说明
200{cancelled: true, charged}。charged 是实际扣次,可以为 0
400invalid_request:查询或正文读不出来。见 BadRequest
401见 Unauthorized
403见 Forbidden
404not_found:不存在,或你不该知道它存在(别人的会员、未开放的表、进不了的视图)。见 NotFound
409见 Conflict
413payload_too_large:正文太大。见 PayloadTooLarge
422见 Unprocessable
429见 RateLimited
500internal:平台出错。见 Internal
503unavailable:暂时不可用(读凭证、读授权、读库失败)。见 Unavailable

200 响应正文(application/json)

字段类型必填说明
cancelledboolean是固定为 true
chargedinteger是实际扣次,可以为 0

GET /me/sessions

这位客户还能预约的开放课次,尚未开始,最多 31 天

需要范围 membership.me:read。from、to 是门店时区日期,两端包含。省略 from 为今天;省略 to 为 from 加 6 天。日期不合法、to 早于 from、或超过 31 天:422 validation_failed。

只返回 status=open 且开始时间仍在未来的课次(今天已经开始的不算)。可选 course 为课程 id(未知 id 得到空列表)。最多 500 条,按开始时间再按课程名。

spotsLeft 为 max(0, 容量 − booked/attended/completed)。0 表示再预约会进候补。候补不占 spotsLeft。

  • 认证:bearer
  • operationId:listMeSessions

参数

名称位置类型必填说明
fromquerystringYYYY-MM-DD。默认今天(门店时区)
toquerystringYYYY-MM-DD,包含。默认 from 加 6 天。跨度最多 31 天
coursequerystring课程 id。精确过滤

响应

状态说明
200{sessions: [MeSession]}
401见 Unauthorized
403见 Forbidden
422见 Unprocessable
429见 RateLimited
500internal:平台出错。见 Internal
503unavailable:暂时不可用(读凭证、读授权、读库失败)。见 Unavailable

200 响应正文(application/json)

字段类型必填说明
sessionsMeSession[]是
sessions[].idstring是
sessions[].courseIdstring是
sessions[].courseNamestring是
sessions[].coachNamestring员工显示名。没有则省略
sessions[].startsAtstring(date-time)是
sessions[].endsAtstring(date-time)是
sessions[].roomstring是总是出现,可能是空字符串
sessions[].spotsLeftinteger是max(0, 容量 − booked/attended/completed)。0 表示再预约会进候补

GET /me/redemption-requests

前台请这位客户确认的核销(轮询;没有推送)

需要范围 membership.me:read。没有推送,小程序轮询这一条。

state 省略或 pending:仍待确认且未过期。all:最近 30 天,最新在前;过了 expiresAt 的 pending 读出来是 expired(当场计算,后台没有定时任务)。其他 state 是 422 validation_failed。最多 100 条。

不返回:备注、预约 id、课程 id、课包 id、会员编号、谁发起、谁决定、拒绝原因、核销 id。

  • 认证:bearer
  • operationId:listMeRedemptionRequests

参数

名称位置类型必填说明
statequerystring默认 pending(未过期)。all 是最近 30 天,含计算出来的 expired
可选值:pending、all

响应

状态说明
200{requests: [MeRedemptionRequest]}
401见 Unauthorized
403见 Forbidden
422见 Unprocessable
429见 RateLimited
500internal:平台出错。见 Internal
503unavailable:暂时不可用(读凭证、读授权、读库失败)。见 Unavailable

200 响应正文(application/json)

字段类型必填说明
requestsMeRedemptionRequest[]是
requests[].idstring是
requests[].memberIdstring是
requests[].memberNamestring是
requests[].courseNamestring课程没有名字则省略
requests[].timesinteger是
requests[].statestring是expired 是读的时候算的
可选值:pending、confirmed、declined、cancelled、expired
requests[].expiresAtstring(date-time)是
requests[].createdAtstring(date-time)是

POST /me/redemption-requests/{id}/confirm

确认前台的核销申请;次数只在此刻扣,记在发起的员工名下

需要范围 membership.redemption:confirm。写操作(10 分钟后 assertion_stale)。没有正文。

{id} 必须是这位客户的申请,否则 404。只有仍 pending(且未过期)能确认;否则 409 conflict。第二次确认也是 409,不会把第一次的 JSON 再给一遍。

扣次就是前台自己的核销,同一事务,幂等键 rr:<申请 id>,核销记在发起员工名下。200 是 {confirmed: true, remaining, notices}。remaining 是扣完后的课包余额;期卡扣 0,所以这不是到店次数。notices 可能为空。

与前台核销相同的拒绝是 422 validation_failed(候补、已取消、缺席、课次取消、不是上课当天、超过 7 天、会员冻结/过期/关闭、课包不可用、剩余次数不足)。

  • 认证:bearer
  • operationId:confirmMeRedemption

参数

名称位置类型必填说明
idpathstring是核销申请 id
Idempotency-Keyheaderstring除 /oauth/token 外每个 POST 都收。SDK 未传入时会生成 uuid v4。24 小时内同键同正文重放第一次的回答
最短 1,最长 255

响应

状态说明
200{confirmed: true, remaining, notices}
401见 Unauthorized
403见 Forbidden
404not_found:不存在,或你不该知道它存在(别人的会员、未开放的表、进不了的视图)。见 NotFound
409见 Conflict
422见 Unprocessable
429见 RateLimited
500internal:平台出错。见 Internal
503unavailable:暂时不可用(读凭证、读授权、读库失败)。见 Unavailable

200 响应正文(application/json)

字段类型必填说明
confirmedboolean是固定为 true
remaininginteger是扣完后的课包余额。期卡扣 0
noticesstring[]是可能为空。否则是用完、只剩 N 次、今天到期、N 天后到期

POST /me/redemption-requests/{id}/decline

拒绝前台的核销申请;不扣次

需要范围 membership.redemption:confirm。写操作(10 分钟后 assertion_stale)。

正文可选 {reason},最多 200 字,否则 422 validation_failed。可以不带正文。404 / 409 与确认相同(只有仍 pending 的申请)。不扣次。

  • 认证:bearer
  • operationId:declineMeRedemption

参数

名称位置类型必填说明
idpathstring是核销申请 id
Idempotency-Keyheaderstring除 /oauth/token 外每个 POST 都收。SDK 未传入时会生成 uuid v4。24 小时内同键同正文重放第一次的回答
最短 1,最长 255

请求正文(application/json)

字段类型必填说明
reasonstring最多 200 字

响应

状态说明
200{declined: true}
400invalid_request:查询或正文读不出来。见 BadRequest
401见 Unauthorized
403见 Forbidden
404not_found:不存在,或你不该知道它存在(别人的会员、未开放的表、进不了的视图)。见 NotFound
409见 Conflict
413payload_too_large:正文太大。见 PayloadTooLarge
422见 Unprocessable
429见 RateLimited
500internal:平台出错。见 Internal
503unavailable:暂时不可用(读凭证、读授权、读库失败)。见 Unavailable

200 响应正文(application/json)

字段类型必填说明
declinedboolean是固定为 true

事件(Webhooks)

平台向你登记的 https 地址推送的事件。每个事件是一个 POST 请求。

app.installed

一个组织装上了这个应用

只发给这个应用自己的开发者订阅,不需要范围。data 是 {version, scopes}。信封带 tenant(正式环境也会带:租户装了你的应用,你要用这个 id 去换该组织的令牌)、environment、app。 用 X-Kwork-Signature: t=<unix>,v1=<hex HMAC-SHA256(secret, "<t>.<body>")> 验签,拒绝过期的时间戳。另有 X-Kwork-Event、X-Kwork-Delivery。

  • operationId:receiveAppInstalled

参数

名称位置类型必填说明
X-Kwork-Signatureheaderstring是t=<unix>,v1=<hex HMAC-SHA256(secret, "<t>.<body>")>
X-Kwork-Eventheaderstring是事件类型,与正文 type 相同
X-Kwork-Deliveryheaderstring是这一次投递的 id(重投会变;事件 id 在正文里,重试不变)

请求正文(必填)(application/json)

字段类型必填说明
idstring是evt_…,同一事件每次重试、每个订阅都相同,按它去重
typestring是固定为 "app.installed"
createdAtstring(date-time)是
apiVersionstring是固定为 "2026-10-28"
tenantstring租户范围的事件有。发给商店应用的正式事件也会带(租户装了你的应用)
environmentstring可选值:test、live
appstring
dataAppInstalledData是
data.versionstring是
data.scopesstring[]是

响应

状态说明
200接收方已收下。非 2xx 会按退避重投

app.uninstalled

一个组织卸载了这个应用

只发给这个应用自己的开发者订阅,不需要范围。data 是 {}。验签同 app.installed。

  • operationId:receiveAppUninstalled

参数

名称位置类型必填说明
X-Kwork-Signatureheaderstring是t=<unix>,v1=<hex HMAC-SHA256(secret, "<t>.<body>")>
X-Kwork-Eventheaderstring是事件类型,与正文 type 相同
X-Kwork-Deliveryheaderstring是这一次投递的 id(重投会变;事件 id 在正文里,重试不变)

请求正文(必填)(application/json)

字段类型必填说明
idstring是evt_…,同一事件每次重试、每个订阅都相同,按它去重
typestring是固定为 "app.uninstalled"
createdAtstring(date-time)是
apiVersionstring是固定为 "2026-10-28"
tenantstring租户范围的事件有。发给商店应用的正式事件也会带(租户装了你的应用)
environmentstring可选值:test、live
appstring
dataAppUninstalledData是

响应

状态说明
200接收方已收下

app.upgraded

一个组织把这个应用升到了新版本

只发给这个应用自己的开发者订阅。data 是 {from, to, scopes}。

  • operationId:receiveAppUpgraded

参数

名称位置类型必填说明
X-Kwork-Signatureheaderstring是t=<unix>,v1=<hex HMAC-SHA256(secret, "<t>.<body>")>
X-Kwork-Eventheaderstring是事件类型,与正文 type 相同
X-Kwork-Deliveryheaderstring是这一次投递的 id(重投会变;事件 id 在正文里,重试不变)

请求正文(必填)(application/json)

字段类型必填说明
idstring是evt_…,同一事件每次重试、每个订阅都相同,按它去重
typestring是固定为 "app.upgraded"
createdAtstring(date-time)是
apiVersionstring是固定为 "2026-10-28"
tenantstring租户范围的事件有。发给商店应用的正式事件也会带(租户装了你的应用)
environmentstring可选值:test、live
appstring
dataAppUpgradedData是
data.fromstring是
data.tostring是
data.scopesstring[]是

响应

状态说明
200接收方已收下

app.scopes_changed

管理员改了同意给这个应用的权限范围

只发给这个应用自己的开发者订阅。data 是 {scopes, added, removed}。

  • operationId:receiveAppScopesChanged

参数

名称位置类型必填说明
X-Kwork-Signatureheaderstring是t=<unix>,v1=<hex HMAC-SHA256(secret, "<t>.<body>")>
X-Kwork-Eventheaderstring是事件类型,与正文 type 相同
X-Kwork-Deliveryheaderstring是这一次投递的 id(重投会变;事件 id 在正文里,重试不变)

请求正文(必填)(application/json)

字段类型必填说明
idstring是evt_…,同一事件每次重试、每个订阅都相同,按它去重
typestring是固定为 "app.scopes_changed"
createdAtstring(date-time)是
apiVersionstring是固定为 "2026-10-28"
tenantstring租户范围的事件有。发给商店应用的正式事件也会带(租户装了你的应用)
environmentstring可选值:test、live
appstring
dataAppScopesChangedData是
data.scopesstring[]是
data.addedstring[]是
data.removedstring[]是

响应

状态说明
200接收方已收下

dev.version.approved

平台审核通过了一个版本,可以上架了

开发者订阅,不需要租户授予的范围。data 是 {app, version, decision},decision 为 approved。同一审核结果的 id 在每次重试、每个订阅上都相同,接收方按 id 去重。

  • operationId:receiveDevVersionApproved

参数

名称位置类型必填说明
X-Kwork-Signatureheaderstring是t=<unix>,v1=<hex HMAC-SHA256(secret, "<t>.<body>")>
X-Kwork-Eventheaderstring是事件类型,与正文 type 相同
X-Kwork-Deliveryheaderstring是这一次投递的 id(重投会变;事件 id 在正文里,重试不变)

请求正文(必填)(application/json)

字段类型必填说明
idstring是evt_…,同一事件每次重试、每个订阅都相同,按它去重
typestring是固定为 "dev.version.approved"
createdAtstring(date-time)是
apiVersionstring是固定为 "2026-10-28"
tenantstring租户范围的事件有。发给商店应用的正式事件也会带(租户装了你的应用)
environmentstring可选值:test、live
appstring
dataDevVersionData是
data.appstring是
data.versionstring是
data.decisionstring是可选值:approved、rejected
data.reasonstring驳回时的审核意见

响应

状态说明
200接收方已收下

dev.version.rejected

平台审核驳回了一个版本

开发者订阅。data 是 {app, version, decision, reason?},decision 为 rejected,reason 是审核意见(改好后重新提交)。

  • operationId:receiveDevVersionRejected

参数

名称位置类型必填说明
X-Kwork-Signatureheaderstring是t=<unix>,v1=<hex HMAC-SHA256(secret, "<t>.<body>")>
X-Kwork-Eventheaderstring是事件类型,与正文 type 相同
X-Kwork-Deliveryheaderstring是这一次投递的 id(重投会变;事件 id 在正文里,重试不变)

请求正文(必填)(application/json)

字段类型必填说明
idstring是evt_…,同一事件每次重试、每个订阅都相同,按它去重
typestring是固定为 "dev.version.rejected"
createdAtstring(date-time)是
apiVersionstring是固定为 "2026-10-28"
tenantstring租户范围的事件有。发给商店应用的正式事件也会带(租户装了你的应用)
environmentstring可选值:test、live
appstring
dataDevVersionData是
data.appstring是
data.versionstring是
data.decisionstring是可选值:approved、rejected
data.reasonstring驳回时的审核意见

响应

状态说明
200接收方已收下

membership.redeem_request.created

前台请客户确认一次核销

需要范围 membership.redemption:confirm。租户集成订阅与商店应用的开发者订阅(按安装且授予了该范围的组织)都会收到。 data 含 customer(客户中心 id)、member、request、course(课程名)、times、expiresAt。没有电话、没有姓名。客户该去小程序里确认。

  • operationId:receiveMembershipRedeemRequestCreated

参数

名称位置类型必填说明
X-Kwork-Signatureheaderstring是t=<unix>,v1=<hex HMAC-SHA256(secret, "<t>.<body>")>
X-Kwork-Eventheaderstring是事件类型,与正文 type 相同
X-Kwork-Deliveryheaderstring是这一次投递的 id(重投会变;事件 id 在正文里,重试不变)

请求正文(必填)(application/json)

字段类型必填说明
idstring是evt_…,同一事件每次重试、每个订阅都相同,按它去重
typestring是固定为 "membership.redeem_request.created"
createdAtstring(date-time)是
apiVersionstring是固定为 "2026-10-28"
tenantstring租户范围的事件有。发给商店应用的正式事件也会带(租户装了你的应用)
environmentstring可选值:test、live
appstring
dataRedeemRequestCreatedData是
data.customerstring是客户中心 id
data.memberstring是
data.requeststring是
data.coursestring课程名
data.timesinteger是
data.expiresAtstring(date-time)

响应

状态说明
200接收方已收下

membership.redeem_request.cancelled

前台取消了请客户确认的核销

需要范围 membership.redemption:confirm。data 含 customer、member、request。客户不用再确认。

  • operationId:receiveMembershipRedeemRequestCancelled

参数

名称位置类型必填说明
X-Kwork-Signatureheaderstring是t=<unix>,v1=<hex HMAC-SHA256(secret, "<t>.<body>")>
X-Kwork-Eventheaderstring是事件类型,与正文 type 相同
X-Kwork-Deliveryheaderstring是这一次投递的 id(重投会变;事件 id 在正文里,重试不变)

请求正文(必填)(application/json)

字段类型必填说明
idstring是evt_…,同一事件每次重试、每个订阅都相同,按它去重
typestring是固定为 "membership.redeem_request.cancelled"
createdAtstring(date-time)是
apiVersionstring是固定为 "2026-10-28"
tenantstring租户范围的事件有。发给商店应用的正式事件也会带(租户装了你的应用)
environmentstring可选值:test、live
appstring
dataRedeemRequestCancelledData是
data.customerstring是
data.memberstring是
data.requeststring是

响应

状态说明
200接收方已收下

membership.booking.created

客户有了新的预约或候补

需要范围 membership.me:read。前台或客户自己预约都会发。data 含 customer、member、booking、session、course(课程名)、startsAt、status(booked 或 waitlist)。

  • operationId:receiveMembershipBookingCreated

参数

名称位置类型必填说明
X-Kwork-Signatureheaderstring是t=<unix>,v1=<hex HMAC-SHA256(secret, "<t>.<body>")>
X-Kwork-Eventheaderstring是事件类型,与正文 type 相同
X-Kwork-Deliveryheaderstring是这一次投递的 id(重投会变;事件 id 在正文里,重试不变)

请求正文(必填)(application/json)

字段类型必填说明
idstring是evt_…,同一事件每次重试、每个订阅都相同,按它去重
typestring是固定为 "membership.booking.created"
createdAtstring(date-time)是
apiVersionstring是固定为 "2026-10-28"
tenantstring租户范围的事件有。发给商店应用的正式事件也会带(租户装了你的应用)
environmentstring可选值:test、live
appstring
dataBookingCreatedData是
data.customerstring是
data.memberstring是
data.bookingstring是
data.sessionstring是
data.coursestring是课程名
data.startsAtstring(date-time)是
data.statusstring是booked 或 waitlist

响应

状态说明
200接收方已收下

membership.booking.cancelled

客户的预约或候补被取消

需要范围 membership.me:read。前台、客户自己或课次取消都会发。data 含 customer、member、booking、session、course、charged(实际扣次)。

  • operationId:receiveMembershipBookingCancelled

参数

名称位置类型必填说明
X-Kwork-Signatureheaderstring是t=<unix>,v1=<hex HMAC-SHA256(secret, "<t>.<body>")>
X-Kwork-Eventheaderstring是事件类型,与正文 type 相同
X-Kwork-Deliveryheaderstring是这一次投递的 id(重投会变;事件 id 在正文里,重试不变)

请求正文(必填)(application/json)

字段类型必填说明
idstring是evt_…,同一事件每次重试、每个订阅都相同,按它去重
typestring是固定为 "membership.booking.cancelled"
createdAtstring(date-time)是
apiVersionstring是固定为 "2026-10-28"
tenantstring租户范围的事件有。发给商店应用的正式事件也会带(租户装了你的应用)
environmentstring可选值:test、live
appstring
dataBookingCancelledData是
data.customerstring是
data.memberstring是
data.bookingstring是
data.sessionstring是
data.coursestring是
data.chargedinteger是

响应

状态说明
200接收方已收下

membership.redemption.created

客户有一次核销(到店核销,或客户确认了申请)

需要范围 membership.me:read。data 含 customer、member、redemption、course、times、remaining(扣完后的课包余额)。

  • operationId:receiveMembershipRedemptionCreated

参数

名称位置类型必填说明
X-Kwork-Signatureheaderstring是t=<unix>,v1=<hex HMAC-SHA256(secret, "<t>.<body>")>
X-Kwork-Eventheaderstring是事件类型,与正文 type 相同
X-Kwork-Deliveryheaderstring是这一次投递的 id(重投会变;事件 id 在正文里,重试不变)

请求正文(必填)(application/json)

字段类型必填说明
idstring是evt_…,同一事件每次重试、每个订阅都相同,按它去重
typestring是固定为 "membership.redemption.created"
createdAtstring(date-time)是
apiVersionstring是固定为 "2026-10-28"
tenantstring租户范围的事件有。发给商店应用的正式事件也会带(租户装了你的应用)
environmentstring可选值:test、live
appstring
dataRedemptionCreatedData是
data.customerstring是
data.memberstring是
data.redemptionstring是
data.coursestring
data.timesinteger是
data.remaininginteger是

响应

状态说明
200接收方已收下

customer.created

组织里新建了一位客户

需要范围 customer:read。本批只在开放接口 POST /customers 新建时发出(员工在客户应用里新建不走这条)。 data 是 {customer, id}(同一客户中心 id),没有电话、没有姓名。

  • operationId:receiveCustomerCreated

参数

名称位置类型必填说明
X-Kwork-Signatureheaderstring是t=<unix>,v1=<hex HMAC-SHA256(secret, "<t>.<body>")>
X-Kwork-Eventheaderstring是事件类型,与正文 type 相同
X-Kwork-Deliveryheaderstring是这一次投递的 id(重投会变;事件 id 在正文里,重试不变)

请求正文(必填)(application/json)

字段类型必填说明
idstring是evt_…,同一事件每次重试、每个订阅都相同,按它去重
typestring是固定为 "customer.created"
createdAtstring(date-time)是
apiVersionstring是固定为 "2026-10-28"
tenantstring租户范围的事件有。发给商店应用的正式事件也会带(租户装了你的应用)
environmentstring可选值:test、live
appstring
dataCustomerCreatedData是
data.customerstring是客户中心 id
data.idstring是与 customer 相同

响应

状态说明
200接收方已收下

customer.updated

一位客户的姓名或标签改了

需要范围 customer:read。本批只在开放接口 PATCH /customers/{id} 改了字段时发出。 data 是 {customer, id, fields},fields 为 name、tags 中实际改过的项。没有电话、没有姓名。

  • operationId:receiveCustomerUpdated

参数

名称位置类型必填说明
X-Kwork-Signatureheaderstring是t=<unix>,v1=<hex HMAC-SHA256(secret, "<t>.<body>")>
X-Kwork-Eventheaderstring是事件类型,与正文 type 相同
X-Kwork-Deliveryheaderstring是这一次投递的 id(重投会变;事件 id 在正文里,重试不变)

请求正文(必填)(application/json)

字段类型必填说明
idstring是evt_…,同一事件每次重试、每个订阅都相同,按它去重
typestring是固定为 "customer.updated"
createdAtstring(date-time)是
apiVersionstring是固定为 "2026-10-28"
tenantstring租户范围的事件有。发给商店应用的正式事件也会带(租户装了你的应用)
environmentstring可选值:test、live
appstring
dataCustomerUpdatedData是
data.customerstring是客户中心 id
data.idstring是与 customer 相同
data.fieldsstring[]是实际改过的字段,name 和/或 tags}

响应

状态说明
200接收方已收下

通用响应

多个接口共用的响应。

BadRequest

400 invalid_request:查询或正文读不出来。换令牌时还有 unsupported_grant_type(不认识的 grant_type)和 tenant_required(应用级凭证必须带 tenant;或带了但不是这个凭证能用的组织)。多维表筛/排了视图里没有的字段也是这一条。

正文(application/json)

字段类型必填说明
errorErrorBody是
error.codestring是稳定错误码。用它分支,不要解析 message。
可选值:invalid_request、invalid_grant、consent_required、consent_revoked、person_gone、unauthorized、forbidden、not_found、method_not_allowed、conflict、payload_too_large、validation_failed、rate_limited、internal、not_implemented、unavailable、token_required、invalid_token、invalid_credential、invalid_client、unsupported_grant_type、tenant_required、wrong_environment、credential_ended、address_not_allowed、not_installed、no_scope、scope_required、customer_token_required、assertion_stale、invalid_phone、ambiguous_customer、too_many_attempts、idempotency_conflict、idempotency_in_progress、condition_failed
error.messagestring是给人看的说明,并写出下一步
error.requestIdstring与 X-Request-Id 相同
error.docUrlstring这条错误的文档,形如 https://dev.{domain}/docs/errors#scope_required
error.detailsobject没有内容时是 {}。ambiguous_customer 时含 candidates(客户 id 列表)

Conflict

409。conflict:和当前状态冲突(已经预约、申请已经处理、晚取消未带 acceptCharge)。ambiguous_customer:同一号码对应多个客户,details.candidates 列出 id,下次带上 customer_id。idempotency_conflict:同一 Idempotency-Key 不同正文。idempotency_in_progress:第一次还在处理,稍后再读或换新键。

正文(application/json)

字段类型必填说明
errorErrorBody是
error.codestring是稳定错误码。用它分支,不要解析 message。
可选值:invalid_request、invalid_grant、consent_required、consent_revoked、person_gone、unauthorized、forbidden、not_found、method_not_allowed、conflict、payload_too_large、validation_failed、rate_limited、internal、not_implemented、unavailable、token_required、invalid_token、invalid_credential、invalid_client、unsupported_grant_type、tenant_required、wrong_environment、credential_ended、address_not_allowed、not_installed、no_scope、scope_required、customer_token_required、assertion_stale、invalid_phone、ambiguous_customer、too_many_attempts、idempotency_conflict、idempotency_in_progress、condition_failed
error.messagestring是给人看的说明,并写出下一步
error.requestIdstring与 X-Request-Id 相同
error.docUrlstring这条错误的文档,形如 https://dev.{domain}/docs/errors#scope_required
error.detailsobject没有内容时是 {}。ambiguous_customer 时含 candidates(客户 id 列表)

Forbidden

403。scope_required:缺了操作描述里写的范围,去开发者平台或请管理员勾。customer_token_required:/me 只要客户令牌,用客户授权再调。wrong_environment:测试密钥打了正式组织,或正式密钥打了测试企业。not_installed:应用没装、关掉,或组织停用。no_scope:一把范围都没授。address_not_allowed:来源 IP 不在凭证允许名单。

正文(application/json)

字段类型必填说明
errorErrorBody是
error.codestring是稳定错误码。用它分支,不要解析 message。
可选值:invalid_request、invalid_grant、consent_required、consent_revoked、person_gone、unauthorized、forbidden、not_found、method_not_allowed、conflict、payload_too_large、validation_failed、rate_limited、internal、not_implemented、unavailable、token_required、invalid_token、invalid_credential、invalid_client、unsupported_grant_type、tenant_required、wrong_environment、credential_ended、address_not_allowed、not_installed、no_scope、scope_required、customer_token_required、assertion_stale、invalid_phone、ambiguous_customer、too_many_attempts、idempotency_conflict、idempotency_in_progress、condition_failed
error.messagestring是给人看的说明,并写出下一步
error.requestIdstring与 X-Request-Id 相同
error.docUrlstring这条错误的文档,形如 https://dev.{domain}/docs/errors#scope_required
error.detailsobject没有内容时是 {}。ambiguous_customer 时含 candidates(客户 id 列表)

Internal

500 internal:平台出错。带上 X-Request-Id 报给我们。不要立刻换一种写法重试同一把幂等键。

正文(application/json)

字段类型必填说明
errorErrorBody是
error.codestring是稳定错误码。用它分支,不要解析 message。
可选值:invalid_request、invalid_grant、consent_required、consent_revoked、person_gone、unauthorized、forbidden、not_found、method_not_allowed、conflict、payload_too_large、validation_failed、rate_limited、internal、not_implemented、unavailable、token_required、invalid_token、invalid_credential、invalid_client、unsupported_grant_type、tenant_required、wrong_environment、credential_ended、address_not_allowed、not_installed、no_scope、scope_required、customer_token_required、assertion_stale、invalid_phone、ambiguous_customer、too_many_attempts、idempotency_conflict、idempotency_in_progress、condition_failed
error.messagestring是给人看的说明,并写出下一步
error.requestIdstring与 X-Request-Id 相同
error.docUrlstring这条错误的文档,形如 https://dev.{domain}/docs/errors#scope_required
error.detailsobject没有内容时是 {}。ambiguous_customer 时含 candidates(客户 id 列表)

InvalidClient

401 invalid_client:client_id 不存在或 client_secret 不对。两种情况同一句,避免探测。带 WWW-Authenticate: Basic。密钥已吊销或过期是 credential_ended(也是 401)。

正文(application/json)

字段类型必填说明
errorErrorBody是
error.codestring是稳定错误码。用它分支,不要解析 message。
可选值:invalid_request、invalid_grant、consent_required、consent_revoked、person_gone、unauthorized、forbidden、not_found、method_not_allowed、conflict、payload_too_large、validation_failed、rate_limited、internal、not_implemented、unavailable、token_required、invalid_token、invalid_credential、invalid_client、unsupported_grant_type、tenant_required、wrong_environment、credential_ended、address_not_allowed、not_installed、no_scope、scope_required、customer_token_required、assertion_stale、invalid_phone、ambiguous_customer、too_many_attempts、idempotency_conflict、idempotency_in_progress、condition_failed
error.messagestring是给人看的说明,并写出下一步
error.requestIdstring与 X-Request-Id 相同
error.docUrlstring这条错误的文档,形如 https://dev.{domain}/docs/errors#scope_required
error.detailsobject没有内容时是 {}。ambiguous_customer 时含 candidates(客户 id 列表)

NotFound

404 not_found:不存在,或你不该知道它存在(别人的会员、未开放的表、进不了的视图)。不要靠 403 去区分「没有」和「没权限」。

正文(application/json)

字段类型必填说明
errorErrorBody是
error.codestring是稳定错误码。用它分支,不要解析 message。
可选值:invalid_request、invalid_grant、consent_required、consent_revoked、person_gone、unauthorized、forbidden、not_found、method_not_allowed、conflict、payload_too_large、validation_failed、rate_limited、internal、not_implemented、unavailable、token_required、invalid_token、invalid_credential、invalid_client、unsupported_grant_type、tenant_required、wrong_environment、credential_ended、address_not_allowed、not_installed、no_scope、scope_required、customer_token_required、assertion_stale、invalid_phone、ambiguous_customer、too_many_attempts、idempotency_conflict、idempotency_in_progress、condition_failed
error.messagestring是给人看的说明,并写出下一步
error.requestIdstring与 X-Request-Id 相同
error.docUrlstring这条错误的文档,形如 https://dev.{domain}/docs/errors#scope_required
error.detailsobject没有内容时是 {}。ambiguous_customer 时含 candidates(客户 id 列表)

NotImplemented

501 not_implemented。客户授权在这个部署不可用时会出现(代码仍可能是 unavailable)。

正文(application/json)

字段类型必填说明
errorErrorBody是
error.codestring是稳定错误码。用它分支,不要解析 message。
可选值:invalid_request、invalid_grant、consent_required、consent_revoked、person_gone、unauthorized、forbidden、not_found、method_not_allowed、conflict、payload_too_large、validation_failed、rate_limited、internal、not_implemented、unavailable、token_required、invalid_token、invalid_credential、invalid_client、unsupported_grant_type、tenant_required、wrong_environment、credential_ended、address_not_allowed、not_installed、no_scope、scope_required、customer_token_required、assertion_stale、invalid_phone、ambiguous_customer、too_many_attempts、idempotency_conflict、idempotency_in_progress、condition_failed
error.messagestring是给人看的说明,并写出下一步
error.requestIdstring与 X-Request-Id 相同
error.docUrlstring这条错误的文档,形如 https://dev.{domain}/docs/errors#scope_required
error.detailsobject没有内容时是 {}。ambiguous_customer 时含 candidates(客户 id 列表)

PayloadTooLarge

413 payload_too_large:正文太大。会员写接口上限 1 MiB。

正文(application/json)

字段类型必填说明
errorErrorBody是
error.codestring是稳定错误码。用它分支,不要解析 message。
可选值:invalid_request、invalid_grant、consent_required、consent_revoked、person_gone、unauthorized、forbidden、not_found、method_not_allowed、conflict、payload_too_large、validation_failed、rate_limited、internal、not_implemented、unavailable、token_required、invalid_token、invalid_credential、invalid_client、unsupported_grant_type、tenant_required、wrong_environment、credential_ended、address_not_allowed、not_installed、no_scope、scope_required、customer_token_required、assertion_stale、invalid_phone、ambiguous_customer、too_many_attempts、idempotency_conflict、idempotency_in_progress、condition_failed
error.messagestring是给人看的说明,并写出下一步
error.requestIdstring与 X-Request-Id 相同
error.docUrlstring这条错误的文档,形如 https://dev.{domain}/docs/errors#scope_required
error.detailsobject没有内容时是 {}。ambiguous_customer 时含 candidates(客户 id 列表)

RateLimited

429。rate_limited:这把凭证的调用预算用完,看 Retry-After 和 X-RateLimit-*。too_many_attempts:这个地址失败太多次,等 Retry-After(换令牌时常见 60 秒)。

正文(application/json)

字段类型必填说明
errorErrorBody是
error.codestring是稳定错误码。用它分支,不要解析 message。
可选值:invalid_request、invalid_grant、consent_required、consent_revoked、person_gone、unauthorized、forbidden、not_found、method_not_allowed、conflict、payload_too_large、validation_failed、rate_limited、internal、not_implemented、unavailable、token_required、invalid_token、invalid_credential、invalid_client、unsupported_grant_type、tenant_required、wrong_environment、credential_ended、address_not_allowed、not_installed、no_scope、scope_required、customer_token_required、assertion_stale、invalid_phone、ambiguous_customer、too_many_attempts、idempotency_conflict、idempotency_in_progress、condition_failed
error.messagestring是给人看的说明,并写出下一步
error.requestIdstring与 X-Request-Id 相同
error.docUrlstring这条错误的文档,形如 https://dev.{domain}/docs/errors#scope_required
error.detailsobject没有内容时是 {}。ambiguous_customer 时含 candidates(客户 id 列表)

Unauthorized

401。token_required:没带 Bearer,先 POST /oauth/token。invalid_token:令牌无效或过期,重新换(SDK 会自动换一次再重试)。credential_ended:凭证吊销、过期,或应用关掉、范围被收光。写 /me 时还有 assertion_stale:客户断言超过 10 分钟,重新断言再写。

正文(application/json)

字段类型必填说明
errorErrorBody是
error.codestring是稳定错误码。用它分支,不要解析 message。
可选值:invalid_request、invalid_grant、consent_required、consent_revoked、person_gone、unauthorized、forbidden、not_found、method_not_allowed、conflict、payload_too_large、validation_failed、rate_limited、internal、not_implemented、unavailable、token_required、invalid_token、invalid_credential、invalid_client、unsupported_grant_type、tenant_required、wrong_environment、credential_ended、address_not_allowed、not_installed、no_scope、scope_required、customer_token_required、assertion_stale、invalid_phone、ambiguous_customer、too_many_attempts、idempotency_conflict、idempotency_in_progress、condition_failed
error.messagestring是给人看的说明,并写出下一步
error.requestIdstring与 X-Request-Id 相同
error.docUrlstring这条错误的文档,形如 https://dev.{domain}/docs/errors#scope_required
error.detailsobject没有内容时是 {}。ambiguous_customer 时含 candidates(客户 id 列表)

Unavailable

503 unavailable:暂时不可用(读凭证、读授权、读库失败)。按 Retry-After 重试;没有该头时 SDK 用指数退避。

正文(application/json)

字段类型必填说明
errorErrorBody是
error.codestring是稳定错误码。用它分支,不要解析 message。
可选值:invalid_request、invalid_grant、consent_required、consent_revoked、person_gone、unauthorized、forbidden、not_found、method_not_allowed、conflict、payload_too_large、validation_failed、rate_limited、internal、not_implemented、unavailable、token_required、invalid_token、invalid_credential、invalid_client、unsupported_grant_type、tenant_required、wrong_environment、credential_ended、address_not_allowed、not_installed、no_scope、scope_required、customer_token_required、assertion_stale、invalid_phone、ambiguous_customer、too_many_attempts、idempotency_conflict、idempotency_in_progress、condition_failed
error.messagestring是给人看的说明,并写出下一步
error.requestIdstring与 X-Request-Id 相同
error.docUrlstring这条错误的文档,形如 https://dev.{domain}/docs/errors#scope_required
error.detailsobject没有内容时是 {}。ambiguous_customer 时含 candidates(客户 id 列表)

Unprocessable

422。validation_failed:字段或门店规则不接受(日期窗口、课次不存在、会员状态、剩余次数不足、原因超长)。换客户令牌时电话读不出来是 invalid_phone:带国家码,或按大陆手机号发。

正文(application/json)

字段类型必填说明
errorErrorBody是
error.codestring是稳定错误码。用它分支,不要解析 message。
可选值:invalid_request、invalid_grant、consent_required、consent_revoked、person_gone、unauthorized、forbidden、not_found、method_not_allowed、conflict、payload_too_large、validation_failed、rate_limited、internal、not_implemented、unavailable、token_required、invalid_token、invalid_credential、invalid_client、unsupported_grant_type、tenant_required、wrong_environment、credential_ended、address_not_allowed、not_installed、no_scope、scope_required、customer_token_required、assertion_stale、invalid_phone、ambiguous_customer、too_many_attempts、idempotency_conflict、idempotency_in_progress、condition_failed
error.messagestring是给人看的说明,并写出下一步
error.requestIdstring与 X-Request-Id 相同
error.docUrlstring这条错误的文档,形如 https://dev.{domain}/docs/errors#scope_required
error.detailsobject没有内容时是 {}。ambiguous_customer 时含 candidates(客户 id 列表)

本页目录