V1.1.4 C 端接口变更文档122
本文只描述 C 端 App/Web 需要调用或适配的 HTTP 接口,不包含任何管理端接口、内部 Dubbo Facade、数据库、定时任务及部署配置。
接口定义以 2026-07-30 当前代码为准;账号合并采用“复用绑定阶段双验证码”的最新方案,不再使用旧的 trigger/main 二次验证流程。
1. 接口变更总览
1.1 新增接口
| 方法 | 接口 | 用途 |
|---|---|---|
| POST | /auth/contact/continue | 邮箱/手机号验证码登录注册一体化 |
| POST | /auth/contact/binding/confirm | 确认绑定或换绑联系方式;冲突时返回账号关联凭证 |
| POST | /auth/account/association/preview | 查询冲突双方脱敏身份和 A/B 钱包余额 |
| POST | /auth/account/association/confirm | 选择主账号并执行账号、钱包合并 |
| POST | /blind-box/backpack/delivery/cancel | 用户取消自己的待发货提货单并返还背包 |
1.2 修改接口
| 方法 | 接口 | 主要变化 |
|---|---|---|
| POST | /auth/sendOtp | email 统一改为 identifier,支持邮箱或美国 +1 手机号;新增统一登录注册场景 |
| POST | /auth/login | email 兼容升级为 identifier,支持邮箱或手机号密码登录 |
| POST | /auth/resetPassword | email 改为 identifier,支持邮箱或手机号找回密码 |
| POST | /security/sendOtp | scene 扩展联系方式 CURRENT/TARGET 场景;TARGET 新增 identifier |
| POST | /security/verifyOtp | 同步支持联系方式 CURRENT/TARGET 场景;TARGET 新增 identifier |
| GET | /blind-box/backpack/delivery/page | 提货单状态新增 USER_CANCELLED |
| GET | /blind-box/backpack/delivery/detail | 状态新增 USER_CANCELLED,销毁取消时可返回 cancelExplanation |
| POST | /wallet/withdraw/orders | 返回提现费率、手续费、净兑换金额和参考汇率 |
| GET | /wallet/withdraw/orders | 历史订单项增加手续费快照字段 |
| GET | /wallet/withdraw/orders/{withdrawOrderNo} | 详情增加手续费快照字段 |
| GET | /wallet/welcome-gift/status | 删除 needPopup;倒计时兼容字段固定为关闭值 |
2. 通用约定
2.1 响应结构
{
"code": "SUCCESS",
"success": true,
"message": "SUCCESS",
"data": {},
"traceId": "链路追踪ID"
}前端必须先判断 success。失败时使用 code 做流程分支,message 用于提示;不要仅根据 HTTP 200 判断业务成功。
2.2 联系方式格式
- 邮箱:后端统一执行
trim + lowercase。 - 手机号:本期只支持美国号码,必须能规范化为
+1E.164,例如+14155552671。 identifier由后端自动识别邮箱或手机号,前端不再额外传联系方式类型。- OTP 为 6 位验证码;预校验接口只校验、不消费,真实业务成功后才消费。
3. 登录注册一体化
3.1 发送登录/注册或找回密码验证码(修改)
POST /auth/sendOtp
请求参数:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
identifier | string | 是 | 邮箱或美国 +1 手机号 |
scene | string | 是 | CONTACT_LOGIN_REGISTER 或 FORGOT_PASSWORD |
turnstileToken | string | 否/按环境 | Cloudflare Turnstile Token |
validateEmailSuffixOnly | boolean | 否 | 邮箱兼容参数,默认 false;手机号忽略 |
示例:
{
"identifier": "+14155552671",
"scene": "CONTACT_LOGIN_REGISTER",
"turnstileToken": "turnstile-token",
"validateEmailSuffixOnly": false
}响应 data:
{
"validated": true,
"sent": true
}3.2 验证码登录注册一体化(新增)
POST /auth/contact/continue
联系方式已存在时直接登录;不存在时注册后登录。新注册用户没有密码,响应中的 needSetPassword=true,前端登录后引导设置密码。
请求参数:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
identifier | string | 是 | 邮箱或美国 +1 手机号 |
otpCode | string | 是 | CONTACT_LOGIN_REGISTER 场景验证码 |
inviteCode | string | 否 | 邀请码 |
landingId | string | 否 | 落地页/归因标识 |
utmSource | string | 否 | UTM 来源 |
utmMedium | string | 否 | UTM 媒介 |
utmCampaign | string | 否 | UTM 活动 |
utmContent | string | 否 | UTM 内容 |
utmTerm | string | 否 | UTM 关键词 |
示例:
{
"identifier": "user@example.com",
"otpCode": "888888",
"inviteCode": "INVITE001",
"landingId": "home",
"utmSource": "link-share"
}响应 data:
| 字段 | 类型 | 说明 |
|---|---|---|
userId | string | 用户 ID |
token | string | 登录 Token |
tokenExpiration | number | Token 剩余秒数 |
needSetPassword | boolean | 是否需要首次设置密码 |
hasTotpBound | boolean | 是否已绑定 2FA |
ageCheckResult | string | KYC 年龄校验结果 |
3.3 密码登录(修改)
POST /auth/login
{
"identifier": "user@example.com",
"password": "******"
}identifier支持邮箱或美国手机号。- 兼容旧请求字段
email,新代码统一使用identifier。 - 响应仍为登录信息
LoginVO。
3.4 找回密码(修改)
POST /auth/resetPassword
{
"identifier": "+14155552671",
"otpCode": "888888",
"newPassword": "NewPass@12345"
}验证码必须通过 /auth/sendOtp 使用 scene=FORGOT_PASSWORD 发送。
4. 联系方式绑定与换绑
4.1 OTP 场景枚举
POST /security/sendOtp 和 POST /security/verifyOtp 共用以下 scene:
| scene | 验证对象 | identityType | identifier |
|---|---|---|---|
CHANGE_PASSWORD | 当前账号邮箱或手机号 | 必要时传 | 不使用 |
BIND_TOTP | 当前账号邮箱或手机号 | 必要时传 | 不使用 |
UNBIND_TOTP | 当前账号邮箱或手机号 | 必要时传 | 不使用 |
CHANGE_WITHDRAW_ADDRESS | 当前账号邮箱或手机号 | 必要时传 | 不使用 |
BIND_PHONE_CURRENT | 当前账号已绑定邮箱 | 忽略 | 不传/忽略 |
BIND_PHONE_TARGET | 准备绑定的新手机号 | 忽略 | 必填,新手机号 |
BIND_EMAIL_CURRENT | 当前账号已绑定手机号 | 忽略 | 不传/忽略 |
BIND_EMAIL_TARGET | 准备绑定的新邮箱 | 忽略 | 必填,新邮箱 |
CHANGE_PHONE_CURRENT | 当前账号旧手机号 | 忽略 | 不传/忽略 |
CHANGE_PHONE_TARGET | 准备替换的新手机号 | 忽略 | 必填,新手机号 |
本期不开放自助换绑邮箱,因此没有 CHANGE_EMAIL_CURRENT/TARGET。
4.2 发送安全/绑定验证码(修改)
POST /security/sendOtp
请求参数:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
identityType | string | 普通场景可选 | EMAIL / PHONE;联系方式场景由 scene 推导 |
scene | string | 是 | 见上一节 |
turnstileToken | string | 否/按环境 | 人机验证 Token |
identifier | string | 仅 TARGET | 新邮箱或新手机号 |
validateEmailSuffixOnly | boolean | 否 | 邮箱兼容参数 |
CURRENT 示例:
{
"scene": "BIND_PHONE_CURRENT",
"turnstileToken": "turnstile-token"
}TARGET 示例:
{
"scene": "BIND_PHONE_TARGET",
"identifier": "+14155552671",
"turnstileToken": "turnstile-token"
}响应 data:
{
"validated": true,
"sent": true
}4.3 预校验安全/绑定验证码(修改)
POST /security/verifyOtp
请求参数:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
identityType | string | 普通场景可选 | EMAIL / PHONE;联系方式场景由 scene 推导 |
scene | string | 是 | 必须与发码场景一致 |
identifier | string | 仅 TARGET | 必须与发码时的新联系方式一致 |
otpCode | string | 是 | 验证码 |
TARGET 示例:
{
"scene": "BIND_PHONE_TARGET",
"identifier": "+14155552671",
"otpCode": "654321"
}响应 data=true 表示校验成功。该接口不消费验证码;绑定流程可以直接调用确认接口,不强制先调本接口。
4.4 确认绑定或换绑(新增)
POST /auth/contact/binding/confirm
请求参数:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
operation | string | 是 | BIND_PHONE、BIND_EMAIL、CHANGE_PHONE |
currentOtpCode | string | 是 | 当前联系方式验证码 |
targetIdentifier | string | 是 | 新邮箱或新手机号 |
targetOtpCode | string | 是 | 新联系方式验证码 |
示例:
{
"operation": "BIND_PHONE",
"currentOtpCode": "123456",
"targetIdentifier": "+14155552671",
"targetOtpCode": "654321"
}无账号冲突:
{
"status": "BOUND",
"associationProof": null,
"expiresInSeconds": null
}账号冲突:
{
"status": "ASSOCIATION_REQUIRED",
"associationProof": "一次性凭证",
"expiresInSeconds": 300
}前端处理:
BOUND:绑定完成,刷新账号安全信息。ASSOCIATION_REQUIRED:保存原currentOtpCode、targetOtpCode和associationProof,进入账号冲突页。- 冲突时后端不会消费两个验证码,不要重新发送或主动清理验证码。
5. 账号冲突与合并
5.1 查询冲突双方和钱包余额(新增)
POST /auth/account/association/preview
请求:
{
"associationProof": "绑定确认返回的凭证"
}响应 data:
{
"currentAccount": {
"choice": "CURRENT",
"identityMasked": "u***@example.com",
"aPoolBalance": 126.40,
"bPoolBalance": 18.00
},
"targetAccount": {
"choice": "TARGET",
"identityMasked": "+1******2671",
"aPoolBalance": 42.00,
"bPoolBalance": 7.50
}
}注意:
- 只传
associationProof,不允许前端传用户 ID。 - 接口只读,不创建关联单,不消费凭证或验证码。
- A 池为
MAIN_LOCKED,B 池为MAIN_WITHDRAWABLE。 - 余额查询失败返回
ACCOUNT_ASSOCIATION_PREVIEW_UNAVAILABLE,前端提示稍后重试,不显示 0 兜底。
5.2 最终确认合并(新增)
POST /auth/account/association/confirm
请求参数:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
mainAccount | string | 是 | CURRENT 或 TARGET |
associationProof | string | 是 | 绑定冲突凭证 |
currentOtpCode | string | 是 | 绑定阶段当前账号验证码 |
targetOtpCode | string | 是 | 绑定阶段目标联系方式验证码 |
confirmText | string | 是 | 固定 CONFIRM |
示例:
{
"mainAccount": "CURRENT",
"associationProof": "一次性凭证",
"currentOtpCode": "123456",
"targetOtpCode": "654321",
"confirmText": "CONFIRM"
}响应关键字段:
| 字段 | 类型 | 说明 |
|---|---|---|
associationNo | string | 客服排查编号 |
mainUserId | number | 主账号 ID |
secondaryUserId | number | 次账号 ID |
clientStatus | string | SUCCESS、PROCESSING、FAILED |
message | string | 前端展示文案 |
blockerCodes | string[] | 阻断原因 |
blockerCodes 可能值:
| 值 | 含义 |
|---|---|
ACCOUNT_STATE | 账号状态不允许合并 |
BACKPACK_OR_DELIVERY | 存在背包处置或提货阻断 |
WITHDRAW_PROCESSING | 存在提现处理中 |
KYC_CONFLICT | KYC 状态冲突,需要人工处理 |
ASSOCIATION_PROCESSING | 账号已参与其他合并流程 |
合并规则:
CURRENT:当前登录账号保留为主账号。TARGET:冲突联系方式所属账号保留为主账号。- 次账号 A/B 钱包余额合并到主账号。
- 触发冲突的次账号手机号或邮箱迁移到主账号。
- 成功后次账号 Token 失效;主账号会话保持可用。
FAILED且提示联系客服时展示associationNo,不要展示内部失败步骤。
5.3 已废弃的旧账号关联调用
前端不再调用:
/auth/account/association/trigger/sendOtp/auth/account/association/trigger/verify/auth/account/association/prepare/auth/account/association/main/sendOtp
最终确认不再传 associationNo,由后端内部创建或复用关联单。
5.4 合并中的联系方式限制
当前账号作为主账号或次账号处于 PREPARED、EXECUTING、FAILED_MANUAL_REQUIRED 状态时:
/security/sendOtp的绑定/换绑场景返回ACCOUNT_ASSOCIATION_PROCESSING。/auth/contact/binding/confirm返回同一错误码。- 提示:
账号正在合并处理中,暂时无法修改联系方式。
主账号登录、钱包等其他功能不因此整体冻结。
5.5 验证码或凭证过期
用户在冲突页停留较长时间,任一原验证码或 associationProof 过期时,最终确认返回:
ACCOUNT_ASSOCIATION_PROOF_EXPIRED
绑定验证已失效,请重新验证当前账号和目标联系方式前端收到后应清空本次合并上下文,回到联系方式绑定页重新发送当前和目标验证码。
6. 用户取消待发货提货单
6.1 取消接口(新增)
POST /blind-box/backpack/delivery/cancel
请求:
{
"deliveryOrderNo": "DO202607300001"
}限制:
- 只能取消当前登录用户自己的订单。
- 只允许待发货阶段取消。
- C 端固定返还背包,不传
cancelMode。
响应:
| 字段 | 说明 |
|---|---|
resultStatus | PROCESSING 或 COMPLETED |
orderStatus | 当前订单状态;完成后为 USER_CANCELLED |
itemStatus | RETURNING 或 RETURNED_AVAILABLE |
completedAt | 完成时间 |
refundBizNo | 退款幂等业务号 |
refundStatus | PROCESSING 或 SUCCESS |
PROCESSING 时刷新订单详情/列表,不要重复创建另一笔取消或退款。
6.2 提货订单列表和详情(修改)
GET /blind-box/backpack/delivery/page
GET /blind-box/backpack/delivery/detail
新增订单状态:
USER_CANCELLED:用户主动取消完成。ADMIN_CANCELLED:运营取消完成,C 端只负责展示。
新增/扩展明细状态:
RETURNING:退回背包处理中。RETURNED_AVAILABLE:已退回背包,可继续操作。DESTROYING:销毁处理中。DESTROYED:已销毁。
详情字段 cancelExplanation 仅在销毁取消完成后返回用户可见英文说明。
7. 提现手续费展示
7.1 提现报价
POST /wallet/withdraw/quote
前端重点读取:
| 字段 | 说明 |
|---|---|
withdrawAmountUsd | 用户输入提现金额 |
referenceRateToCrypto | 1 USD 可兑换的币数量 |
feeRate | 手续费率,0~1 小数;展示百分比时乘 100 |
feeAmountUsd | 手续费金额 USD |
netExchangeAmountUsd | 扣除手续费后的净兑换金额 USD |
estimatedPayAmount | 预计链上到账币数量 |
requires2fa | 是否需要 2FA |
requiresReview | 是否需要人工审核 |
message | 提示文案 |
金额全部使用后端返回值,前端不要自行重算。
7.2 创建提现订单(修改响应)
POST /wallet/withdraw/orders
响应 data 新增或明确返回:
referenceRateToCryptofeeRatefeeAmountUsdnetExchangeAmountUsdestimatedPayAmount
7.3 提现订单列表和详情(修改响应)
GET /wallet/withdraw/orders
GET /wallet/withdraw/orders/{withdrawOrderNo}
每个提现订单新增:
feeRatefeeAmountUsdnetExchangeAmountUsd
以上字段是下单快照,费率配置变化后不重新计算历史订单。
8. 新人礼包状态
GET /wallet/welcome-gift/status
响应变化:
- 删除
needPopup。前端自行决定触达方式,不再根据该字段强制弹窗。 countdownStarted为兼容字段,固定false。countdownEndAtUtc为兼容字段,固定空字符串。- 资格、档位、支付和完成信息继续读取
activityStatus/state/tiers/lockedTier/paymentInfo/completedInfo。
9. 主要错误码与前端动作
| 错误码 | 前端动作 |
|---|---|
OTP_SCENE_INVALID | 检查 scene 是否使用本文枚举 |
LOGIN_PASSWORD_WRONG | 统一提示账号或密码错误 |
LOGIN_ACCOUNT_LOCKED | 提示 15 分钟后重试 |
ACCOUNT_DELETED | 提示账号已注销并清理登录态 |
ACCOUNT_FROZEN / ACCOUNT_FROZEN_LOGIN | 展示账号冻结提示 |
PASSWORD_NOT_SET | 引导验证码登录后设置密码 |
CONTACT_BINDING_INVALID | 回到绑定验证步骤重新操作 |
ACCOUNT_ASSOCIATION_PROOF_EXPIRED | 清空合并上下文,重新发送当前/目标验证码 |
ACCOUNT_ASSOCIATION_PREVIEW_UNAVAILABLE | 保留合并上下文,提示稍后重试余额预览 |
ACCOUNT_ASSOCIATION_DISABLED | 提示账号关联暂不可用 |
ACCOUNT_ASSOCIATION_PROCESSING | 禁止继续绑定/换绑,展示处理中提示 |
BLIND_BOX_BACKPACK_DELIVERY_CANCEL_CONFLICT | 刷新提货单状态,不重复提交取消 |
WALLET_WITHDRAW_2FA_REQUIRED | 进入 2FA 验证流程 |
10. 推荐调用流程
10.1 验证码登录注册
/auth/sendOtp(CONTACT_LOGIN_REGISTER)
-> /auth/contact/continue
-> needSetPassword=true 时引导设置密码10.2 找回密码
/auth/sendOtp(FORGOT_PASSWORD)
-> /auth/resetPassword10.3 绑定手机号
/security/sendOtp(BIND_PHONE_CURRENT)
-> /security/sendOtp(BIND_PHONE_TARGET, identifier=新手机号)
-> /auth/contact/binding/confirm
-> BOUND:结束
-> ASSOCIATION_REQUIRED:保存双验证码和 associationProof
-> /auth/account/association/preview
-> 用户选择 CURRENT/TARGET
-> /auth/account/association/confirm绑定邮箱使用 BIND_EMAIL_CURRENT/TARGET;换手机号使用 CHANGE_PHONE_CURRENT/TARGET。
10.4 提货取消
/盲盒背包提货单列表或详情
-> 仅待发货状态显示取消按钮
-> /blind-box/backpack/delivery/cancel
-> COMPLETED:刷新列表和背包
-> PROCESSING:轮询详情,不重复提交11. 本期无需 C 端新增接口的改动
- 邮件发送黑名单和邮件批量合并。
- 国际短信供应商接入及 OTP 限流实现;C 端仍通过统一 OTP 接口发码。
- 背包状态历史双写和历史基线任务。
- 账号关联钱包 Saga、内部幂等及人工续跑。
- 充值完成返回原页面:C 端按充值订单号在本地保存并消费来源路由,服务端无新增字段。