如何获取 Google Play 订阅的 Transaction ID
支付阿杰
结论
该接口不会返回 transactionId 或 originalTransactionId 字段。这两个字段名主要用于 Apple 的订阅体系。
在 Google Play 中:
orderId是当前订阅交易的订单编号,可以近似对应 “Transaction ID”。- Google Play 没有与
originalTransactionId直接对应的字段。 - 追踪订阅生命周期时,应以
purchaseToken为主要标识,并结合linkedPurchaseToken、服务端保存的首次购买记录和实时开发者通知,处理续订、升级、降级及重新订阅。
从旧版接口读取订单编号
调用:
GET https://www.googleapis.com/androidpublisher/v3/applications/{packageName}/purchases/subscriptions/{subscriptionId}/tokens/{token}
响应类型是 SubscriptionPurchase。如果这笔购买已经生成订单,响应中可能会包含:
{
"kind": "androidpublisher#subscriptionPurchase",
"startTimeMillis": "1710000000000",
"expiryTimeMillis": "1712678400000",
"autoRenewing": true,
"paymentState": 1,
"orderId": "GPA.1234-5678-9012-34567",
"purchaseType": 0,
"acknowledgementState": 1
}
可以直接读取 orderId:
const purchase = response.data;
const transactionId = purchase.orderId ?? null;
const purchaseToken = token;
if (!transactionId) {
// 某些购买状态下可能尚未生成 orderId,不能假定该字段始终存在。
}
这里的 orderId 是 Google Play 的订单编号。即使将它映射为 transactionId,也不能把它当成 Apple 定义的 Transaction ID。如果数据库需要统一字段,可以建立自己的映射:
provider_transaction_id = orderId
provider_purchase_token = purchaseToken
provider = google_play
Original Transaction ID 应如何处理
Google Play API 不提供 Apple 风格的 originalTransactionId。如果业务需要稳定的“订阅链 ID”,可以在服务端自行维护:
- 用户首次购买时,保存
purchaseToken和orderId。 - 收到续订信息或实时开发者通知后,再查询 Google Play Developer API,更新订阅状态。
- 如果响应中有
linkedPurchaseToken,通过该字段关联旧的购买记录。 - 找到订阅链中最早的一条记录,将其内部 ID 作为自己的
original_transaction_id。
例如:
async function resolveSubscriptionChain(purchase) {
if (!purchase.linkedPurchaseToken) {
return {
originalPurchaseToken: purchase.purchaseToken,
originalOrderId: purchase.orderId ?? null
};
}
const previous = await findPurchaseByToken(
purchase.linkedPurchaseToken
);
return {
originalPurchaseToken:
previous?.originalPurchaseToken ??
previous?.purchaseToken ??
purchase.linkedPurchaseToken,
originalOrderId:
previous?.originalOrderId ??
previous?.orderId ??
null
};
}
linkedPurchaseToken 通常用于关联订阅替换、升级、降级或重新订阅等情况,但不能假定每次普通续订都会生成一条带有该字段的新购买记录。
建议使用 subscriptionsv2.get
新的服务端实现可以优先考虑较新的接口:
GET https://androidpublisher.googleapis.com/androidpublisher/v3/applications/{packageName}/purchases/subscriptionsv2/tokens/{token}
该接口的路径中不需要传入 subscriptionId,响应中可以读取 latestOrderId:
{
"kind": "androidpublisher#subscriptionPurchaseV2",
"latestOrderId": "GPA.1234-5678-9012-34567",
"linkedPurchaseToken": "previous-purchase-token",
"subscriptionState": "SUBSCRIPTION_STATE_ACTIVE",
"lineItems": [
{
"productId": "premium_monthly",
"expiryTime": "2026-09-29T08:00:00Z"
}
]
}
示例:
const purchase = response.data;
const latestTransactionId = purchase.latestOrderId ?? null;
const previousPurchaseToken = purchase.linkedPurchaseToken ?? null;
const productId = purchase.lineItems?.[0]?.productId ?? null;
注意事项
- 不要只根据
orderId判断订阅是否有效,还要检查订阅状态、到期时间和取消等信息。 purchaseToken是验证和管理 Google Play 购买时最重要的值,应保存在服务端,不能只保存在客户端。- 不建议拆分
GPA...订单编号来推导首次订单。某些续订订单编号可能带有可观察的后缀规律,但不能将其当作稳定的业务协议。 - 在部分未完成、待处理或特殊状态下,
orderId或latestOrderId可能不存在,代码需要允许这些字段为空。 - 升级、降级或替换套餐后,购买令牌可能会发生变化。应通过
linkedPurchaseToken或自己的订阅关系表串联相关记录。 - 如果需要同时支持 Google Play 和 App Store,最好建立内部统一模型,同时保留各平台的原始字段,不要假定两边的交易标识具有完全相同的语义。
备注:内容仅供参考。
