跳到主要内容

交易

本指南介绍如何集成交易:报告购买以便父母能够看到、在扣款前请求父母批准购买,以及让一笔已完成的卡支付替代父母同意。

关于交易是什么、以及 k-ID 与您的产品之间的职责边界在哪里,请先阅读交易概念。支付即验证有其自己的概念页面

开始之前

  • 确认您的组织已可使用交易。 如需为您的组织启用此能力,请联系 k-ID。
  • 启用您所使用的部分。 交易默认关闭,在 Compliance Studio 的 Transactions 部分中按产品配置,其中 Transactions 是另外两个所依赖的开关。在某个端点所需的开关打开之前,该端点会返回 FEATURE_DISABLED。三个开关分别控制什么,请参阅功能开关
  • 配置您的 Webhook 端点, 如果您使用购买批准。批准结果以 Webhook 形式到达。请在产品的 Developer Settings 中设置 URL 和密钥,并按照 Webhooks 概述的说明验证签名。
  • 订阅您所处理的事件。 端点只会接收它已订阅的事件类型,其余的会被 k-ID 丢弃,既不尝试投递也不报错。请在产品的 Developer Settings 页面为您的端点选择 Transaction.PurchaseApprovalResult

报告购买

/transaction/push 针对一个会话记录已完成的购买。请在购买完成后调用它,包括每次周期性购买续费时。

每个事件都带有用于幂等的 id、原样展示给父母的 title 和可选 description、以货币最小单位表示的 amount、一个 currency、完成时的 timestamp、一个父母可在此管理购买的可选 url,以及一个 status

字段说明
id由您的产品生成的 UUID。它与 sessionId 一起构成幂等键:重新提交一个已被接受的 id 会再次记为 accepted 且不会重复记录。
typepurchase
titledescription原样展示给父母。title 为必填;description 可选。
amount以货币的 ISO 4217 最小单位表示的整数,因此 499 在 USD 中是 4.99,在 JPY 中是 499。允许为零,用于免费物品。
currencyISO 4217 代码。大写为规范形式;小写会被接受并规范化。
timestampRFC 3339 UTC,位于过去 7 天内且不在未来。
url可选的 HTTPS 链接,父母可打开它来管理购买,例如取消订阅。
statussuccessful,或者对于尝试过但未完成的扣款为 failed。报告 failed 让父母能够区分一笔已完成的购买和一笔未完成的购买。

一次调用最多接收 100 个事件:

{
"sessionId": "b1a6482d-5242-4b4a-aa88-3fa52595a672",
"events": [
{
"id": "9d4e2f81-7a3b-4c56-8e90-1f2a3b4c5d6e",
"type": "purchase",
"title": "Starter Pack",
"description": "500 coins and a cosmetic item",
"amount": 499,
"currency": "USD",
"timestamp": "2026-06-24T09:00:00Z",
"status": "successful",
"url": "https://your-webstore.example.com/manage?ref=order-4455667"
}
]
}

事件是独立处理的,因此请读取每个事件的状态,而不要假设整批都已成功:

{
"sessionId": "b1a6482d-5242-4b4a-aa88-3fa52595a672",
"accepted": 1,
"rejected": 0,
"events": [
{ "id": "9d4e2f81-7a3b-4c56-8e90-1f2a3b4c5d6e", "status": "accepted" }
]
}

被拒绝事件的 reasoninvalid_input 表示它违反了校验规则,原样重试仍会失败。reasoninternal_error 属于临时性问题,可以安全重试。当会话不存在或已被撤销时,整批都会被拒绝,而不是逐个事件被拒绝。

报告的购买会作为 Family Connect 中按孩子的购买视图呈现给已关联的父母,其金额还会汇入受信任的成年人在那里以及在定期摘要邮件中所读到的活动

请求批准

当您希望在扣款前获得父母的决定时,/transaction/request-purchase 会发起一个批准请求。在扣款前询问,并且只有在 approved 结果到达后才完成购买。

{
"sessionId": "b1a6482d-5242-4b4a-aa88-3fa52595a672",
"id": "9d4e2f81-7a3b-4c56-8e90-1f2a3b4c5d6e",
"title": "Starter Pack",
"description": "500 coins and a cosmetic item",
"amount": 499,
"currency": "USD"
}

响应携带您发送的 id 和一个 expiresAt。请保存该 id;它用于关联结果 Webhook。

{
"id": "9d4e2f81-7a3b-4c56-8e90-1f2a3b4c5d6e",
"expiresAt": "2026-06-25T16:00:00Z"
}

k-ID 通过电子邮件将请求发送给会话登记在案的父母,父母在 Family Connect 中批准或拒绝。结果作为携带 approveddeniedexpiredTransaction.PurchaseApprovalResult Webhook 到达,通过 data.id 关联。

请针对该流程的以下特性进行设计:

  • 在扣款前批准。 该请求是购买之前的一道关卡,而不是购买的记录。在 approved 时扣款;把 deniedexpired 都当作“不要扣款”。
  • 请求会在 24 小时后到期。 到期会以 status: "expired" 触发 Webhook,是正常结果而非失败。可以再次向玩家提供该购买。请把 expiresAt 当作截止时间,而不要无限期等待 Webhook。
  • 请求按 id 幂等。 重新提交一个仍在等待决定的 id 会原样返回该待处理请求,而不会发起第二个请求,也不会两次提示父母。
  • 一位玩家最多持有 20 个待处理请求。 超过之后,调用会以 INVALID_INPUT 被拒绝,直到有一个请求得到处理。
  • 玩家需要有一位已关联的父母才能被提示。 请求会发送给会话登记在案的批准人。为一个父母未关联的玩家发起请求时无人可通知,因此请先建立父母关联。请参阅已验证家长关联

负载及每种状态请参阅 Transaction.PurchaseApprovalResult

支付即验证

在会话所在司法管辖区启用了信用卡验证方法的地方,一笔已完成的信用卡支付可以替代单独的验证来满足父母同意步骤。关于什么样的支付合格及其原因,请阅读支付即验证概念;本节是集成部分。

支付即验证附着于标准的父母同意挑战。在您本会用 /challenge/send-email 发送同意邮件的地方,改用 /challenge/send-email-with-payment-verification,并加上 paymentVerification 证明。挑战的其他方面均保持不变。

该证明用 k-ID 的字段描述支付,无论您使用哪个提供商:

字段说明
provider处理该支付的记录商户。用于限定 invoiceId 的范围。
invoiceId您的记录商户对该支付的标识符。k-ID 将其视为不透明值。
payerEmail付款所用的电子邮件地址。
instrument支付所用的方式:cardwalletother
funding卡的资金类型:creditdebitprepaidunknown。只有 credit 合格;当您的提供商不报告资金类型时,请发送 unknown

请像发送任何其他同意邮件那样在挑战上发送它,并把证明放在 paymentVerification 中:

{
"challengeId": "ae6d4729-af32-42ea-8ef2-ff46c7664802",
"email": "parent@example.com",
"paymentVerification": { "...": "the normalized attestation from your merchant of record" }
}

k-ID 既不处理也不见证支付,因此请仅对真实、已完成的支付进行证明。

规范化提供商的支付

各记录商户报告支付的方式各不相同。您可以选择使用 /transaction/lookup-provider 把来自您的记录商户的原始支付信号规范化为标准证明格式。

举例来说,对于 Xsolla,您发送原始的 payment webhook 主体,其中必须包含卡 BIN:

{
"provider": "xsolla",
"data": { "...": "the raw Xsolla payment webhook body" }
}

它会返回可放入同意邮件 paymentVerification 中的规范化证明:

{
"provider": "xsolla",
"invoiceId": "2110445753",
"payerEmail": "parent@example.com",
"instrument": "card",
"funding": "credit"
}

功能开关

交易有三个开关,而 Transactions 是另外两个所需要的开关:

开关启用的能力所控制的端点
Transactions报告购买以及规范化提供商的支付/transaction/push/transaction/lookup-provider
Purchase Controls请求父母批准购买/transaction/request-purchase
Payment-as-verification一笔合格的卡支付替代同意/challenge/send-email-with-payment-verification

某个开关关闭的端点会返回 FEATURE_DISABLED。Purchase Controls 和 Payment-as-verification 都还需要 Transactions,因此仅启用 Transactions 的产品可以报告购买和规范化支付,但无法请求批准,而未启用任何开关的产品无法调用其中任何一个。

上线前检查清单

  • 每次 /transaction/push 都读取每个事件的状态,而不是假设整批都已成功,并且只重试 internal_error 事件。
  • 购买带着真实的 status 报告,包括 failed 扣款,以便父母看到实际发生的情况。
  • 购买批准在扣款前询问,并且 deniedexpired 都被当作“不要扣款”处理。
  • 产品的 Webhook 已订阅 Transaction.PurchaseApprovalResult,处理逻辑按 data.id 幂等并验证签名。
  • 在您的产品为玩家发起批准请求之前,该玩家已有一位已关联的父母。

后续步骤