PAYATHON 2026

如何获取 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”,可以在服务端自行维护:

  1. 用户首次购买时,保存 purchaseToken 和 orderId。
  2. 收到续订信息或实时开发者通知后,再查询 Google Play Developer API,更新订阅状态。
  3. 如果响应中有 linkedPurchaseToken,通过该字段关联旧的购买记录。
  4. 找到订阅链中最早的一条记录,将其内部 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,最好建立内部统一模型,同时保留各平台的原始字段,不要假定两边的交易标识具有完全相同的语义。

备注:内容仅供参考。