# Google Wallet API

Google Wallet API 允许您以编程方式创建、更新、列出和管理 [Google Wallet 卡券](/zh/product/messaging-channels/google-wallet-passes/)。它支持与控制面板中的[卡券构建器](/zh/product/messaging-channels/google-wallet-passes/pass-builder/)相同的操作。

使用它来发放会员卡、优惠、礼品卡、活动门票、登机牌、公交票和通用卡券，并向已保存在用户设备上的卡券推送实时更新。

<Aside type="note" title="前提条件：Google Wallet 配置">
在为应用程序创建卡券之前，必须在 Pushwoosh 控制面板中为该应用程序配置 Google Wallet **发行者 ID** 和**服务帐户密钥**。如果没有这些，`create` 和 `update` 请求将失败。请参阅 [Android 的 Google Wallet 卡券配置](/zh/developer/first-steps/connect-messaging-services/android-configuration/android-google-wallet-configuration/)。
</Aside>


## 基本 URL

```
https://apple-passkit.svc-nue.pushwoosh.com
```

所有端点都通过 HTTPS 提供服务。除非另有说明，否则请求和响应均使用 `application/json`。

## 身份验证

每个请求都必须包含一个带有您的 [Pushwoosh API 访问令牌](/zh/developer/api-reference/api-access-token/) 的 `Authorization` 标头：

```
Authorization: Token <api-token>
```

拥有令牌的帐户必须拥有由 `applicationCode` 引用的应用程序。对属于另一个帐户的应用程序的请求将返回 `403 Forbidden`。

## 约定

*   **字段命名：** JSON 字段使用 `lowerCamelCase`（例如，`serialNumber`、`hexBackgroundColor`、`logoUrl`）。
*   **未填充字段：** 响应包含所有字段，即使为空或值为零。
*   **身份：** `serialNumber` 总是在创建卡券时由服务器分配。您在创建时发送的任何值都将被忽略。完整的 Google Wallet 对象 ID 是 `{issuerId}.{serialNumber}`。
*   **图片：** `logoUrl` 和 `heroImageUrl` 是 Google 获取图片的公共 HTTPS URL，而不是上传的文件。
*   **卡券样式：** 卡券上必须且只能设置一个样式对象（`generic`、`offer`、`loyalty`、`eventTicket`、`giftCard`、`flight` 或 `transit`）。样式在创建后无法更改。

### 错误响应

| HTTP 状态 | 含义 |
| :---- | :---- |
| `400 Bad Request` | 无效参数——缺少必需字段或字段格式不正确。 |
| `401 Unauthorized` | 缺少或无效的 `Authorization` 标头。 |
| `403 Forbidden` | 该应用程序不属于调用者的帐户。 |
| `404 Not Found` | 未找到卡券、模板或应用程序。 |
| `503 Service Unavailable` | 服务已满负荷或暂时不可用。 |

## 端点

| 方法 | 路径 | 描述 |
| :---- | :---- | :---- |
| `POST` | `/api/google/pass/validate` | 验证卡券配置 |
| `POST` | `/api/google/pass/create` | 创建一个新的卡券对象并获取保存链接 |
| `POST` | `/api/google/pass/update/{serialNumber}` | 更新现有卡券；Google 将传递更改 |
| `GET` | `/api/google/pass/{applicationCode}/{serialNumber}/save-link` | 获取“添加到 Google Wallet”的保存链接 |
| `GET` | `/api/google/pass/{applicationCode}/{serialNumber}` | 获取单个卡券 |
| `GET` | `/api/google/passes` | 列出应用程序的所有卡券 |
| `POST` | `/api/google/pass/{applicationCode}/{serialNumber}/state` | 激活或作废卡券 |
| `DELETE` | `/api/google/pass/{applicationCode}/{serialNumber}` | 删除卡券 |
| `GET` | `/api/google/config` | 获取应用程序的 Google Wallet 配置 |
| `GET` | `/api/google/templates` | 列出可用的卡券模板 |
| `GET` | `/api/google/templates/{filename}` | 获取单个模板 |

## 创建卡券

在 Google Wallet 中创建卡券类和对象，然后返回服务器分配的序列号、完整的对象 ID 和“添加到 Google Wallet”的保存链接。

`POST` `/api/google/pass/create`

### 请求正文

| 参数 | 类型 | 必需 | 描述 |
| :---- | :---- | :---- | :---- |
| `pass` | object | 是 | 描述卡券的[卡券对象](#pass-object)。必须且只能设置一种样式。 |
| `userId` | string | 是 | 卡券发放到的 [Pushwoosh User ID](/zh/developer/api-reference/api-identifiers/#user-id)。 |
| `applicationCode` | string | 是 | [Pushwoosh 应用程序代码](/zh/developer/api-reference/api-identifiers/#application-code)。 |

##### 请求示例

```json
{
  "applicationCode": "XXXXX-XXXXX",
  "userId": "user-123",
  "pass": {
    "hexBackgroundColor": "#3c414c",
    "logoUrl": "https://cdn.acme.com/logo.png",
    "loyalty": {
      "programName": "Acme Rewards",
      "accountName": "Jane Doe",
      "accountId": "1234567890",
      "pointsLabel": "Points",
      "pointsBalance": "1200",
      "rewardsTier": "Gold"
    },
    "barcode": {
      "format": "QR_CODE",
      "value": "1234567890"
    }
  }
}
```

### 响应

| 字段 | 类型 | 描述 |
| :---- | :---- | :---- |
| `serialNumber` | string | 服务器分配的已创建卡券的唯一身份。 |
| `objectId` | string | 完整的 Google Wallet 对象 ID：`{issuerId}.{serialNumber}`。 |
| `saveLink` | string | “添加到 Google Wallet”链接：`https://pay.google.com/gp/v/save/{jwt}`。 |
| `message` | string | 结果消息。 |

##### 响应示例

```json
{
  "serialNumber": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
  "objectId": "XXXXXXXXXXXXXXX.XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
  "saveLink": "https://pay.google.com/gp/v/save/{jwt}",
  "message": "Pass created successfully"
}
```

## 验证卡券

根据 Google 的要求检查卡券配置，而无需创建它。在调用 create 之前很有用。

`POST` `/api/google/pass/validate`

### 请求正文

| 参数 | 类型 | 必需 | 描述 |
| :---- | :---- | :---- | :---- |
| `pass` | object | 是 | 要验证的[卡券对象](#pass-object)。 |

### 响应

| 字段 | 类型 | 描述 |
| :---- | :---- | :---- |
| `valid` | boolean | 卡券是否通过验证。 |
| `errors` | array of strings | 必须修复的阻塞性问题。 |
| `warnings` | array of strings | 非阻塞性建议。 |

## 更新卡券

用新内容修补卡券对象。然后，Google 会将更新后的版本分发到保存了该卡券的每台设备。可以选择性地发送带有更新的 Android 通知。

`POST` `/api/google/pass/update/{serialNumber}`

### 路径参数

| 参数 | 类型 | 描述 |
| :---- | :---- | :---- |
| `serialNumber` | string | 创建卡券时返回的序列号。 |

### 请求正文

| 参数 | 类型 | 必需 | 描述 |
| :---- | :---- | :---- | :---- |
| `updates` | object | 是 | 包含新内容的[卡券对象](#pass-object)。样式无法更改。 |
| `applicationCode` | string | 是 | [Pushwoosh 应用程序代码](/zh/developer/api-reference/api-identifiers/#application-code)。 |
| `notifyMessage` | string | 否 | 当非空时，向所有保存了该卡券的人推送包含此文本的 Android 通知。空表示静默更新。 |
| `notifyOnUpdate` | boolean | 否 | 请求字段更新通知。只有 `loyalty`、`eventTicket` 和 `flight` 卡券会实际通知；其他样式接受该标志但从不发送通知。通知仅在相关开始时间的 3 小时内触发，并且 Google 将其限制为每张卡券每 24 小时 3 次通知。 |

<Aside type="note" title="两种更新通知方式">
`notifyMessage` 会向所有保存了该卡券的人发送自定义 Android 通知，并适用于任何卡券样式。`notifyOnUpdate` 要求 Google 发送其自己的字段更新通知，该通知仅对 `loyalty`、`eventTicket` 和 `flight` 卡券触发。
</Aside>

### 响应

| 字段 | 类型 | 描述 |
| :---- | :---- | :---- |
| `success` | boolean | 更新是否成功。 |
| `message` | string | 结果消息。 |

## 获取保存链接

为已创建的卡券返回“添加到 Google Wallet”的保存链接。卡券对象必须已存在（通过[创建卡券](#create-a-pass)创建）。

`GET` `/api/google/pass/{applicationCode}/{serialNumber}/save-link`

### 响应

| 字段 | 类型 | 描述 |
| :---- | :---- | :---- |
| `saveLink` | string | `https://pay.google.com/gp/v/save/{jwt}`。 |

<Aside type="tip" title="分享链接或将其渲染为二维码">
将 `saveLink` 放在“添加到 Google Wallet”按钮后面，或使用任何 QR 库将其渲染为二维码。当用户打开它时，Google 会提示他们保存卡券并注册其设备以接收更新。
</Aside>

## 获取卡券

返回单个存储的卡券，包括其完整的卡券对象。

`GET` `/api/google/pass/{applicationCode}/{serialNumber}`

### 响应

返回 `{ "pass": { ... } }`，一个[卡券记录](#pass-record-object)对象。

## 列出卡券

返回为应用程序存储的卡券的分页、排序列表。

`GET` `/api/google/passes?applicationCode=XXXXX-XXXXX&page=0&perPage=20`

### 查询参数

| 参数 | 类型 | 必需 | 描述 |
| :---- | :---- | :---- | :---- |
| `applicationCode` | string | 是 | [Pushwoosh 应用程序代码](/zh/developer/api-reference/api-identifiers/#application-code)。 |
| `orderBy` | string | 否 | 排序字段：`UPDATED`（默认）或 `CREATED`。 |
| `orderDirection` | string | 否 | 排序方向：`DESC`（默认，最新在前）或 `ASC`。 |
| `page` | integer | 否 | 从零开始的页面索引。默认为 `0`。 |
| `perPage` | integer | 否 | 页面大小。`0` 或省略将使用服务器默认值。 |

### 响应

| 字段 | 类型 | 描述 |
| :---- | :---- | :---- |
| `passes` | array of objects | 当前页的[卡券记录](#pass-record-object)。 |
| `page` | integer | 返回的页面索引。 |
| `perPage` | integer | 此响应使用的页面大小。 |
| `total` | integer | 应用程序在所有页面上的卡券总数。 |

## 设置卡券状态

激活或作废卡券。作废的（非活动）卡券会移动到用户在 Google Wallet 中的**已过期卡券**部分；记录会保留，以便可以重新激活。

`POST` `/api/google/pass/{applicationCode}/{serialNumber}/state`

### 请求正文

| 参数 | 类型 | 必需 | 描述 |
| :---- | :---- | :---- | :---- |
| `active` | boolean | 是 | `true` 将卡券设置为 `ACTIVE`；`false` 将其作废 (`INACTIVE`)。 |

### 响应

成功时返回一个空对象 `{}`。

## 删除卡券

在 Google 中作废卡券并删除其在 Pushwoosh 中存储的记录。

`DELETE` `/api/google/pass/{applicationCode}/{serialNumber}`

<Aside type="caution" title="已保存的卡券无法强制移除">
Google 不允许移除已保存在用户设备上的卡券。删除操作会作废该卡券（它会移动到**已过期卡券**）并删除 Pushwoosh 记录。
</Aside>

### 响应

成功时返回一个空对象 `{}`。

## 获取配置

返回应用程序的 Google Wallet 配置状态。

`GET` `/api/google/config?applicationCode=XXXXX-XXXXX`

### 响应

| 字段 | 类型 | 描述 |
| :---- | :---- | :---- |
| `hasServiceAccount` | boolean | 是否配置了服务帐户密钥。 |
| `issuerId` | string | 已配置的 [Google Pay & Wallet Console 发行者 ID](/zh/developer/first-steps/connect-messaging-services/android-configuration/android-google-wallet-configuration/#create-the-issuer-account)。 |
| `serviceAccountEmail` | string | 已配置的[服务帐户](/zh/developer/first-steps/connect-messaging-services/android-configuration/android-google-wallet-configuration/#create-the-service-account-key)的 `client_email`。 |

## 模板

列出可用的示例卡券模板，或获取一个作为您可以作为起点的[卡券对象](#pass-object)。

`GET` `/api/google/templates` — 返回 `{ "templates": [ { "filename", "name", "description", "style" } ] }`。

`GET` `/api/google/templates/{filename}` — 返回 `{ "template": { ...卡券对象... } }`。

## 对象参考

### 卡券对象

| 字段 | 类型 | 描述 |
| :---- | :---- | :---- |
| `serialNumber` | string | 在创建时由服务器分配；用于标识卡券。 |
| `generic` / `offer` / `loyalty` / `eventTicket` / `giftCard` / `flight` / `transit` | object | 卡券样式。**必须且只能**设置一个。请参阅下面的样式对象。 |
| `hexBackgroundColor` | string | 卡片背景颜色，`#rrggbb`。 |
| `logoUrl` | string | 徽标图片的公共 HTTPS URL。会员卡和公交票必需。 |
| `heroImageUrl` | string | 宽幅横幅图片的公共 HTTPS URL。 |
| `barcode` | object | 显示在卡券上的[条形码](#barcode-object)。 |
| `textModules` | array | 显示在详情视图中的[文本模块](#text-module-object)。 |
| `links` | array | 显示在详情视图中的[链接模块](#link-module-object)。 |
| `expirationTime` | string | Google 自动使卡券过期的 ISO 8601 时间。空表示无有效期。 |
| `appLink` | object | [应用链接](#app-link-object)：卡券正面的 CTA 按钮。 |
| `locations` | array | 触发地理围栏通知的[位置](#location-object)（最多 10 个）。 |
| `holdersPolicy` | string | 谁可以保存卡券：`ONE_USER_ALL_DEVICES`（默认）、`ONE_USER_ONE_DEVICE` 或 `MULTIPLE_HOLDERS`。 |

### 通用对象

| 字段 | 类型 | 描述 |
| :---- | :---- | :---- |
| `cardTitle` | string | 必需。卡片顶部的发行者/计划名称。 |
| `header` | string | 必需。卡片的主标题。 |
| `subheader` | string | 副标题。 |
| `cardFields` | array | 最多 6 个固定在正面的[文本模块](#text-module-object)（最多 3 行，每行 2 个）。 |

### 优惠对象

| 字段 | 类型 | 描述 |
| :---- | :---- | :---- |
| `title` | string | 必需。例如，`全场八折`。 |
| `provider` | string | 必需。商家名称。 |
| `details` | string | 优惠详情。 |
| `finePrint` | string | 条款和条件。 |
| `redemptionChannel` | string | `ONLINE`、`INSTORE`、`BOTH`（默认）或 `TEMPORARY_PRICE_REDUCTION`。 |
| `issuerName` | string | 显示在 Google 的“发行者”界面上；默认为 `provider`。 |

### 会员卡对象

| 字段 | 类型 | 描述 |
| :---- | :---- | :---- |
| `programName` | string | 必需。要求卡券上有 `logoUrl`。 |
| `accountName` | string | 显示在卡片上的会员姓名。 |
| `accountId` | string | 显示在卡片上的会员 ID。 |
| `pointsLabel` | string | 例如，`积分`。仅在有余额时显示。 |
| `pointsBalance` | string | 积分余额。 |
| `rewardsTier` | string | 例如，`黄金`。 |
| `rewardsTierLabel` | string | 等级旁边的标签；默认为 `Tier`。 |
| `issuerName` | string | 默认为 `programName`。 |

### 活动门票对象

| 字段 | 类型 | 描述 |
| :---- | :---- | :---- |
| `eventName` | string | 必需。 |
| `venueName` / `venueAddress` | string | 场馆详情。 |
| `startDateTime` / `endDateTime` | string | 带偏移量的 ISO 8601（例如，`2026-07-01T19:30:00+02:00`）。 |
| `ticketHolderName` / `ticketNumber` / `ticketType` | string | 持票人和门票详情。 |
| `section` / `row` / `seat` / `gate` | string | 座位详情。 |
| `issuerName` | string | 默认为 `eventName`。 |

### 礼品卡对象

| 字段 | 类型 | 描述 |
| :---- | :---- | :---- |
| `merchantName` | string | 必需。 |
| `cardNumber` | string | 必需。 |
| `pin` | string | 卡片 PIN 码。 |
| `balance` | string | 十进制金额，例如 `25.00`。需要 `balanceCurrency`。 |
| `balanceCurrency` | string | ISO 4217 货币代码，例如 `USD`。 |
| `issuerName` | string | 默认为 `merchantName`。 |

### 航班对象

| 字段 | 类型 | 描述 |
| :---- | :---- | :---- |
| `carrierIataCode` | string | 必需。2 个字母的 IATA 代码，例如 `LX`。 |
| `airlineName` | string | 航空公司显示名称。 |
| `flightNumber` | string | 必需。仅数字，例如 `113`。 |
| `originAirportCode` / `destinationAirportCode` | string | 必需。3 个字母的 IATA 代码。 |
| `originTerminal` / `originGate` / `destinationTerminal` | string | 航站楼和登机口详情。 |
| `departureDateTime` | string | 必需。始发机场**当地**时间，ISO 8601 **不带**偏移量（例如，`2026-09-01T06:30:00`）。 |
| `boardingTime` / `arrivalDateTime` | string | 相同的本地格式。`arrivalDateTime` 是目的地当地时间。 |
| `passengerName` | string | 必需。 |
| `confirmationCode` / `seatNumber` / `seatClass` / `boardingGroup` | string | 乘客详情。 |
| `issuerName` | string | 默认为 `airlineName`，然后是航空公司代码。 |

### 公交对象

| 字段 | 类型 | 描述 |
| :---- | :---- | :---- |
| `transitType` | string | 必需。`BUS`、`RAIL`、`TRAM`、`FERRY` 或 `OTHER`。 |
| `transitOperatorName` | string | 必需。要求卡券上有 `logoUrl`。 |
| `passengerName` | string | 必需。 |
| `ticketNumber` | string | 票号。 |
| `tripType` | string | `ONE_WAY`（默认）或 `ROUND_TRIP`。 |
| `legs` | array | 按旅行顺序列出的一个或多个[公交路段](#transit-leg-object)。 |
| `issuerName` | string | 默认为 `transitOperatorName`。 |

### 公交路段对象

| 字段 | 类型 | 描述 |
| :---- | :---- | :---- |
| `originName` / `destinationName` | string | 必需。 |
| `departureDateTime` / `arrivalDateTime` | string | ISO 8601；偏移量可选（省略时为当地时间）。 |
| `platform` / `coach` / `seat` | string | 登车/船/机详情。 |
| `fareName` | string | 例如，`Anytime Single`。 |

### 条形码对象

| 字段 | 类型 | 描述 |
| :---- | :---- | :---- |
| `format` | string | `QR_CODE`、`PDF_417`、`AZTEC`、`CODE_128`、`EAN_13` 以及其他 Google Wallet 条形码类型。 |
| `value` | string | 条形码中编码的数据。 |
| `altText` | string | 条形码下方显示的文本。 |

### 文本模块对象

| 字段 | 类型 | 描述 |
| :---- | :---- | :---- |
| `id` | string | 模块的标识符。 |
| `header` | string | 模块标题。 |
| `body` | string | 模块文本。 |

### 链接模块对象

| 字段 | 类型 | 描述 |
| :---- | :---- | :---- |
| `uri` | string | 外部链接 URL。 |
| `description` | string | 显示在详情视图中的链接标签。 |

### 应用链接对象

| 字段 | 类型 | 描述 |
| :---- | :---- | :---- |
| `uri` | string | Web URL 或深层链接目标 URI。 |
| `androidPackageName` | string | 可选。设置后，将打开 Android 应用。 |
| `description` | string | 目标 URI 的内部描述（不是可见的按钮标签）；默认为 URI。 |

### 位置对象

| 字段 | 类型 | 描述 |
| :---- | :---- | :---- |
| `latitude` | number | `-90.0` 到 `+90.0`。 |
| `longitude` | number | `-180.0` 到 `+180.0`。 |

### 卡券记录对象

由 list/get 端点返回。

| 字段 | 类型 | 描述 |
| :---- | :---- | :---- |
| `serialNumber` | string | 卡券序列号。 |
| `objectId` | string | 完整的 Google Wallet 对象 ID `{issuerId}.{serialNumber}`。 |
| `cardTitle` | string | 卡券的显示标题/标头。 |
| `header` | string | 次要显示标题。 |
| `userId` | string | 卡券发放到的 [Pushwoosh User ID](/zh/developer/api-reference/api-identifiers/#user-id)。 |
| `createdAt` / `updatedAt` | string | 创建和最后更新的时间戳。 |
| `state` | string | `ACTIVE` 或 `INACTIVE`。 |
| `style` | string | `generic`、`offer`、`loyalty`、`eventTicket`、`giftCard`、`flight` 或 `transit`。 |
| `pass` | object | 完整的[卡券对象](#pass-object)，用于编辑。 |