本页面是 集成方案 中 方案二:API + SDK v2 集成 的前端接入补充说明。
方案二告诉您如何获取 SDK URL 并让用户完成 KYC;本页告诉您在接入方前端页面上:
- 如何嵌入 SDK URL
- 如何监听 SDK 发出的关闭请求,正确销毁 SDK 页面
- 联调阶段可用的 URL 参数
集成方式
从 POST /kyc/individual/sdk/url 获取到 SDK URL(形如 https://otc.legendtrading.com/v2/kyc/s/{code})后,推荐通过以下两种方式在您的前端页面呈现:
方式一:iframe 嵌入
在您的页面用 <iframe> 承载 SDK URL,SDK 作为您页面的一部分展示(适合放在弹窗、抽屉、侧边栏里)。
<iframe
src="https://otc.legendtrading.com/v2/kyc/s/{code}"
allow="camera; geolocation"
style="width: 100%; height: 100%; border: 0;"
></iframe>方式二:打开链接
用 window.open() 打开 SDK URL,把 KYC 流程独立到新窗口完成(适合弹出窗口 / 新标签页场景)。
window.open("https://otc.legendtrading.com/v2/kyc/s/{code}")
SDK 内部在流程结束、或用户主动退出时,需要关闭承载它的 iframe / 弹窗。但浏览器安全策略不允许 SDK 页面直接关闭您的宿主窗口,所以 SDK 会通过消息通知您、由您来完成关闭动作。详见下文close-requested事件章节。
URL 参数
在 SDK URL 后可以追加以下 query 参数,用于联调、布局适配、品牌定制、消息安全加固:
| 参数 | 取值 | 是否必填 | 说明 |
|---|---|---|---|
mode | dev | 否 | 切换到联调环境。不传 = 生产环境 |
remote | sandboxapi | 否 | 联调环境的后端子域,必须与 mode=dev 同时传 |
layout | mobile | desktop | 否 | SDK 布局形态。不传或其它值 = desktop |
primary-color | 十六进制颜色 #RGB 或 #RRGGBB(URL 中 # 需转义为 %23,例:%23FF6600) | 否 | 自定义 SDK 主题色(按钮、链接、进度等主色)。仅接受严格的十六进制格式,非法值会被忽略并回退到默认主题色 |
parentOrigin | 您页面的完整 origin(如 https://a.com) | 否(强烈建议填) | 收窄 SDK 向宿主 postMessage 时的 targetOrigin。不传时 SDK 会用 *,意味着任意 origin 都能收到消息 |
联调环境完整示例
https://otc.legendtrading.com/v2/kyc/s/{code}?mode=dev&remote=sandboxapi&layout=mobile&primary-color=%23FF6600&parentOrigin=https://a.com
mode=dev&remote=sandboxapi— 前后端都指向联调环境,不影响生产数据layout=mobile— 使用移动端布局(适合嵌入手机 App WebView 或较窄的容器)primary-color=%23FF6600— 自定义 SDK 主题色为橙色#FF6600(#必须转义为%23)parentOrigin=https://a.com— 只允许https://a.com收到 SDK 发出的关闭请求消息
生产环境示例
生产环境不需要传 mode / remote,直接使用原始 SDK URL 即可。仍然强烈建议追加 parentOrigin 参数以提高安全性,并按需追加 layout / primary-color 完成布局与品牌色适配:
https://otc.legendtrading.com/v2/kyc/s/{code}?layout=mobile&primary-color=%23FF6600&parentOrigin=https://your-domain.com
layout=mobile— 使用移动端布局(不传或其它值 = 桌面布局)primary-color=%23FF6600— 自定义 SDK 主题色,与您的品牌色保持一致(#必须转义为%23)parentOrigin=https://your-domain.com— 收窄 SDKpostMessage的targetOrigin
监听 close-requested 事件
close-requested 事件SDK 页面在流程结束或用户主动退出时,需要关闭承载它的 iframe / 弹窗。由于浏览器安全策略不允许 SDK 页面直接关闭您的宿主窗口,SDK 会通过 postMessage 向您的页面发一条 close-requested 消息,请您帮忙完成关闭动作。
您在宿主页面上监听这条消息,收到后销毁承载 SDK 的容器(并可以在这里衔接您自己的后续业务逻辑)。
消息格式
SDK 向宿主页面发送的 postMessage 消息统一如下:
{
source: "legend-kyc-relay", // 固定值,识别消息来源
type: "close-requested", // 固定值,当前只有这一种消息类型
detail: { // 附加信息,可能为 null
flow: "kyc" | "additional-kyc" | null
}
}字段说明:
source— 固定"legend-kyc-relay",用于将 SDK 消息与页面其它postMessage区分type— 目前只有"close-requested"一种detail.flow— 触发关闭时用户所处的 KYC 流程;kyc= 普通 KYC,additional-kyc= 续填 KYC,null= 用户还未进入 KYC 主流程(例如在初始拦截页触发关闭)
安全边界
监听器必须校验 event.origin === "https://otc.legendtrading.com",否则任意第三方页面都能通过 postMessage 伪造消息、诱发意外关闭行为。
同时建议在 SDK URL 上追加 parentOrigin 参数收窄 SDK 端的 targetOrigin,双向加固。
场景一:iframe 嵌入
假设您用 modal 承载 iframe,用户在 SDK 内触发关闭时需要销毁 iframe / 关闭 modal:
<div id="kyc-modal" class="modal hidden">
<iframe
id="kyc-iframe"
src="https://otc.legendtrading.com/v2/kyc/s/{code}?parentOrigin=https://a.com"
allow="camera; geolocation"
></iframe>
</div>window.addEventListener("message", (event) => {
// 1. 校验消息来源
if (event.origin !== "https://otc.legendtrading.com") return
// 2. 校验消息格式
const { source, type, detail } = event.data || {}
if (source !== "legend-kyc-relay") return
if (type !== "close-requested") return
// 3. 销毁承载 SDK 的 iframe / 关闭 modal
document.getElementById("kyc-iframe")?.remove()
document.getElementById("kyc-modal")?.classList.add("hidden")
// 4. 在这里衔接您自己的业务逻辑,例如:
// - 调用您的接口,重新拉取用户 KYC 状态
// - 跳转到"KYC 已提交"提示页
// - 更新前端 UI(按钮 disable / 显示 loading 等)
// - detail.flow 可以帮您区分是普通 KYC 还是续填 KYC
})场景二:popup 弹窗
您用 window.open() 打开 SDK。popup 端 SDK 收到关闭请求时会自己调用 window.close(),宿主端只做善后:
// 打开 SDK popup
const popup = window.open(
"https://otc.legendtrading.com/v2/kyc/s/{code}?parentOrigin=https://a.com"
)
// 监听 popup 发来的关闭请求
window.addEventListener("message", (event) => {
if (event.origin !== "https://otc.legendtrading.com") return
const { source, type, detail } = event.data || {}
if (source !== "legend-kyc-relay" || type !== "close-requested") return
// popup 端 SDK 自己会 window.close(),宿主端在这里做善后:
// - 调用您的接口,重新拉取用户 KYC 状态
// - 更新前端 UI / 跳转页面
// - detail.flow 可以帮您区分是普通 KYC 还是续填 KYC
// 兜底:如果 popup 因浏览器差异没能自关,宿主端主动关一次
if (popup && !popup.closed) popup.close()
})常见问题
收不到 close-requested 消息怎么排查?
close-requested 消息怎么排查?- 确认
window.addEventListener("message", ...)在 iframe / popup 打开之前就已挂上,避免消息比监听器早到 - 检查
event.origin校验值 —— 生产、联调都是https://otc.legendtrading.com(mode/remote只切换后端 API,不影响 SDK 页面 origin) - 检查
parentOrigin参数拼接是否正确 —— 必须是完整 origin(如https://a.com),不带路径、不带尾斜杠 - 打开浏览器 DevTools Console 查是否有
postMessage相关报错
primary-color 传了没生效怎么排查?
primary-color 传了没生效怎么排查?- 确认
#已在 URL 中转义为%23—— 直接写#会被浏览器当作 fragment 截断,SDK 收不到 - 确认取值符合
#RGB或#RRGGBB格式(3 位或 6 位十六进制)—— 其它写法(rgb()、颜色名、8 位带透明度等)都会被安全校验拦截、回退到默认色 - 确认参数名是
primary-color(中划线),不是primaryColor或primary_color
SDK URL 有效期是多久?
单个 SDK URL 有效期为 24 小时。过期后需要重新调用 POST /kyc/individual/sdk/url 获取新 URL。
用户中途关闭后再次打开同一个 SDK URL,进度还在吗?
在。同一个 URL 在 24 小时内可以重复打开,SDK 会自动恢复到用户上次的进度,无需您额外处理。
移动端 App 内嵌 WebView 需要注意什么?
- WebView 需要开启 JavaScript 与
postMessage支持(iOSWKWebView/ AndroidWebView默认已开启) - WebView 需要授予 摄像头 与 地理位置 权限,否则 IDV / GPS PoA 环节会失败
- 建议使用
?layout=mobileURL 参数切换到移动端布局
如何知道用户 KYC 最终审核结果?
close-requested 只表示用户从 SDK 侧完成或退出,不代表 KYC 已经通过。KYC 审核结果需要通过 kyc-status Webhook 或 POST /app/kyc-status 轮询获取,详见 集成方案 → 实时获取 KYC 审核状态。
