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/sendOtpemail 统一改为 identifier,支持邮箱或美国 +1 手机号;新增统一登录注册场景
POST/auth/loginemail 兼容升级为 identifier,支持邮箱或手机号密码登录
POST/auth/resetPasswordemail 改为 identifier,支持邮箱或手机号找回密码
POST/security/sendOtpscene 扩展联系方式 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
  • 手机号:本期只支持美国号码,必须能规范化为 +1 E.164,例如 +14155552671
  • identifier 由后端自动识别邮箱或手机号,前端不再额外传联系方式类型。
  • OTP 为 6 位验证码;预校验接口只校验、不消费,真实业务成功后才消费。

3. 登录注册一体化

3.1 发送登录/注册或找回密码验证码(修改)

POST /auth/sendOtp

请求参数:

字段类型必填说明
identifierstring邮箱或美国 +1 手机号
scenestringCONTACT_LOGIN_REGISTERFORGOT_PASSWORD
turnstileTokenstring否/按环境Cloudflare Turnstile Token
validateEmailSuffixOnlyboolean邮箱兼容参数,默认 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,前端登录后引导设置密码。

请求参数:

字段类型必填说明
identifierstring邮箱或美国 +1 手机号
otpCodestringCONTACT_LOGIN_REGISTER 场景验证码
inviteCodestring邀请码
landingIdstring落地页/归因标识
utmSourcestringUTM 来源
utmMediumstringUTM 媒介
utmCampaignstringUTM 活动
utmContentstringUTM 内容
utmTermstringUTM 关键词

示例:

{
  "identifier": "user@example.com",
  "otpCode": "888888",
  "inviteCode": "INVITE001",
  "landingId": "home",
  "utmSource": "link-share"
}

响应 data

字段类型说明
userIdstring用户 ID
tokenstring登录 Token
tokenExpirationnumberToken 剩余秒数
needSetPasswordboolean是否需要首次设置密码
hasTotpBoundboolean是否已绑定 2FA
ageCheckResultstringKYC 年龄校验结果

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/sendOtpPOST /security/verifyOtp 共用以下 scene

scene验证对象identityTypeidentifier
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

请求参数:

字段类型必填说明
identityTypestring普通场景可选EMAIL / PHONE;联系方式场景由 scene 推导
scenestring见上一节
turnstileTokenstring否/按环境人机验证 Token
identifierstring仅 TARGET新邮箱或新手机号
validateEmailSuffixOnlyboolean邮箱兼容参数

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

请求参数:

字段类型必填说明
identityTypestring普通场景可选EMAIL / PHONE;联系方式场景由 scene 推导
scenestring必须与发码场景一致
identifierstring仅 TARGET必须与发码时的新联系方式一致
otpCodestring验证码

TARGET 示例:

{
  "scene": "BIND_PHONE_TARGET",
  "identifier": "+14155552671",
  "otpCode": "654321"
}

响应 data=true 表示校验成功。该接口不消费验证码;绑定流程可以直接调用确认接口,不强制先调本接口。

4.4 确认绑定或换绑(新增)

POST /auth/contact/binding/confirm

请求参数:

字段类型必填说明
operationstringBIND_PHONEBIND_EMAILCHANGE_PHONE
currentOtpCodestring当前联系方式验证码
targetIdentifierstring新邮箱或新手机号
targetOtpCodestring新联系方式验证码

示例:

{
  "operation": "BIND_PHONE",
  "currentOtpCode": "123456",
  "targetIdentifier": "+14155552671",
  "targetOtpCode": "654321"
}

无账号冲突:

{
  "status": "BOUND",
  "associationProof": null,
  "expiresInSeconds": null
}

账号冲突:

{
  "status": "ASSOCIATION_REQUIRED",
  "associationProof": "一次性凭证",
  "expiresInSeconds": 300
}

前端处理:

  • BOUND:绑定完成,刷新账号安全信息。
  • ASSOCIATION_REQUIRED:保存原 currentOtpCodetargetOtpCodeassociationProof,进入账号冲突页。
  • 冲突时后端不会消费两个验证码,不要重新发送或主动清理验证码。

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

请求参数:

字段类型必填说明
mainAccountstringCURRENTTARGET
associationProofstring绑定冲突凭证
currentOtpCodestring绑定阶段当前账号验证码
targetOtpCodestring绑定阶段目标联系方式验证码
confirmTextstring固定 CONFIRM

示例:

{
  "mainAccount": "CURRENT",
  "associationProof": "一次性凭证",
  "currentOtpCode": "123456",
  "targetOtpCode": "654321",
  "confirmText": "CONFIRM"
}

响应关键字段:

字段类型说明
associationNostring客服排查编号
mainUserIdnumber主账号 ID
secondaryUserIdnumber次账号 ID
clientStatusstringSUCCESSPROCESSINGFAILED
messagestring前端展示文案
blockerCodesstring[]阻断原因

blockerCodes 可能值:

含义
ACCOUNT_STATE账号状态不允许合并
BACKPACK_OR_DELIVERY存在背包处置或提货阻断
WITHDRAW_PROCESSING存在提现处理中
KYC_CONFLICTKYC 状态冲突,需要人工处理
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 合并中的联系方式限制

当前账号作为主账号或次账号处于 PREPAREDEXECUTINGFAILED_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

响应:

字段说明
resultStatusPROCESSINGCOMPLETED
orderStatus当前订单状态;完成后为 USER_CANCELLED
itemStatusRETURNINGRETURNED_AVAILABLE
completedAt完成时间
refundBizNo退款幂等业务号
refundStatusPROCESSINGSUCCESS

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用户输入提现金额
referenceRateToCrypto1 USD 可兑换的币数量
feeRate手续费率,0~1 小数;展示百分比时乘 100
feeAmountUsd手续费金额 USD
netExchangeAmountUsd扣除手续费后的净兑换金额 USD
estimatedPayAmount预计链上到账币数量
requires2fa是否需要 2FA
requiresReview是否需要人工审核
message提示文案

金额全部使用后端返回值,前端不要自行重算。

7.2 创建提现订单(修改响应)

POST /wallet/withdraw/orders

响应 data 新增或明确返回:

  • referenceRateToCrypto
  • feeRate
  • feeAmountUsd
  • netExchangeAmountUsd
  • estimatedPayAmount

7.3 提现订单列表和详情(修改响应)

GET /wallet/withdraw/orders

GET /wallet/withdraw/orders/{withdrawOrderNo}

每个提现订单新增:

  • feeRate
  • feeAmountUsd
  • netExchangeAmountUsd

以上字段是下单快照,费率配置变化后不重新计算历史订单。

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/resetPassword

10.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 端按充值订单号在本地保存并消费来源路由,服务端无新增字段。