> For the complete documentation index, see [llms.txt](https://docs.webtonative.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.webtonative.com/javascript-apis/wallet.md).

# Wallet

Functions to add passes — loyalty cards, tickets, boarding passes, coupons, and similar — to the device's built-in wallet app: Google Wallet on Android and Apple Wallet on iOS.

Your backend creates the actual pass (a signed Google Wallet JWT on Android, a signed `.pkpass` file on iOS); WebToNative's job is handing that ready-made pass to the OS wallet app and reporting back whether it was saved.

> You'll need to import the javascript file in your website before starting from this [link](https://docs.webtonative.com/javascript-apis/getting-started).

> **Platform support:** `isSupported` and `addPasses` work on both Android and iOS. `getName` is Android-only. `getPasses`, `checkPassExists`, `removePass`, and `replacePass` are iOS-only — see [Platform Differences](#platform-differences).

***

## Before You Start

WebToNative doesn't create or sign passes for you — you need one already built per platform:

* **Android (Google Wallet):** a signed JWT from the [Google Wallet Issuer API](https://developers.google.com/wallet), or the `https://pay.google.com/gp/v/save/<jwt>` save link Google returns for one.
* **iOS (Apple Wallet):** a signed `.pkpass` file, either as a URL your server hosts or as base64-encoded data — built with a Pass Type ID from your Apple Developer account.

Building and signing that pass — setting up your Issuer account and pass classes on Android, or generating and signing the `.pkpass` bundle on iOS — is covered step by step, with backend code examples, on [Creating & Signing Wallet Passes](/javascript-apis/wallet/wallet-creating-passes.md). Come back here once you have a JWT (Android) or a `.pkpass` URL/base64 string (iOS) in hand.

***

## Setting Up Wallet

1. Go to your **WebToNative dashboard** → **Add-ons** → **Wallet** and enable it.
2. No further credentials are required on the WebToNative side — pass creation and signing happens on your own backend.

{% hint style="info" %}
Every function below is a no-op unless the add-on is enabled in the dashboard.
{% endhint %}

***

## JavaScript API Reference

### isSupported

Checks whether the device has a wallet available to add passes to.

{% tabs %}
{% tab title="Plain Javascript" %}

```javascript
window.WTN.Wallet.isSupported({
  callback: function (response) {
    console.log(response.isSupported);
  },
});
```

{% endtab %}

{% tab title="npm" %}

```javascript
import { isSupported } from "webtonative/Wallet";

isSupported({
  callback: (response) => {
    console.log(response.isSupported);
  },
});
```

{% endtab %}
{% endtabs %}

**Parameters:**

| Key        | Type       | Required | Description                                  |
| ---------- | ---------- | -------- | -------------------------------------------- |
| `callback` | `Function` | No       | Callback function invoked with the response. |

**Callback Response:**

| Key           | Type      | Description                             |
| ------------- | --------- | --------------------------------------- |
| `type`        | `String`  | Always `"isWalletSupported"`.           |
| `isSupported` | `Boolean` | `true` if the device can accept passes. |

***

### getName

Returns the name of the wallet product available on the device (e.g. `"Google Wallet"`).

> Android only. The callback is never invoked on iOS.

{% tabs %}
{% tab title="Plain Javascript" %}

```javascript
window.WTN.Wallet.getName({
  callback: function (response) {
    console.log(response.productName);
  },
});
```

{% endtab %}

{% tab title="npm" %}

```javascript
import { getName } from "webtonative/Wallet";

getName({
  callback: (response) => {
    console.log(response.productName);
  },
});
```

{% endtab %}
{% endtabs %}

**Parameters:**

| Key        | Type       | Required | Description                                  |
| ---------- | ---------- | -------- | -------------------------------------------- |
| `callback` | `Function` | No       | Callback function invoked with the response. |

**Callback Response:**

| Key           | Type     | Description                        |
| ------------- | -------- | ---------------------------------- |
| `type`        | `String` | Always `"getWalletName"`.          |
| `productName` | `String` | The wallet product's display name. |

***

### addPasses

Adds one or more passes to the device wallet. This is the main function of the add-on — works cross-platform, but the pass format each platform expects is different, so give each platform the field it understands:

* **Android:** put the pass string(s) — signed JWT, or a `pay.google.com/gp/v/save/...` save link — in `passes`. `urls` / `base64s` are also accepted and merged in, since Android doesn't distinguish them; use `passes` for clarity.
* **iOS:** use `urls` for a hosted `.pkpass` file, or `base64s` for base64-encoded `.pkpass` data.

{% tabs %}
{% tab title="Plain Javascript" %}

```javascript
// Android: a signed Google Wallet JWT
window.WTN.Wallet.addPasses({
  passes: [googleWalletJwt],
  callback: function (response) {
    console.log(response.success);
  },
});

// iOS: a hosted .pkpass file
window.WTN.Wallet.addPasses({
  urls: ["https://example.com/passes/loyalty-card.pkpass"],
  callback: function (response) {
    console.log(response.success, response.data);
  },
});

// iOS: base64-encoded .pkpass data
window.WTN.Wallet.addPasses({
  base64s: [pkpassBase64String],
  callback: function (response) {
    console.log(response.success, response.data);
  },
});
```

{% endtab %}

{% tab title="npm" %}

```javascript
import { addPasses } from "webtonative/Wallet";

// Android: a signed Google Wallet JWT
addPasses({
  passes: [googleWalletJwt],
  callback: (response) => {
    console.log(response.success);
  },
});

// iOS: a hosted .pkpass file
addPasses({
  urls: ["https://example.com/passes/loyalty-card.pkpass"],
  callback: (response) => {
    console.log(response.success, response.data);
  },
});

// iOS: base64-encoded .pkpass data
addPasses({
  base64s: [pkpassBase64String],
  callback: (response) => {
    console.log(response.success, response.data);
  },
});
```

{% endtab %}
{% endtabs %}

**Parameters:**

| Key        | Type       | Required | Description                                                                                                                       |
| ---------- | ---------- | -------- | --------------------------------------------------------------------------------------------------------------------------------- |
| `passes`   | `String[]` | No\*     | Android: signed JWTs or Google Wallet save links, one per pass. iOS: any mix of `.pkpass` URLs or base64 strings — auto-detected. |
| `urls`     | `String[]` | No\*     | iOS: `.pkpass` file URLs. Android: merged into `passes` if given.                                                                 |
| `base64s`  | `String[]` | No\*     | iOS: base64-encoded `.pkpass` data. Android: merged into `passes` if given.                                                       |
| `callback` | `Function` | No       | Callback function invoked with the response.                                                                                      |

\* Provide at least one of `passes` / `urls` / `base64s`.

**Callback Response:** see [Callback Response Format](#callback-response-format) — the shape differs by platform.

***

### getPasses

Reads passes already in the wallet — every pass of a given type, or one specific pass.

> iOS only.

{% tabs %}
{% tab title="Plain Javascript" %}

```javascript
// A specific pass
window.WTN.Wallet.getPasses({
  passTypeIdentifier: "pass.com.example.loyalty",
  serialNumber: "12345",
  callback: function (response) {
    console.log(response);
  },
});

// Every pass of a type
window.WTN.Wallet.getPasses({
  passType: "all",
  callback: function (response) {
    console.log(response);
  },
});
```

{% endtab %}

{% tab title="npm" %}

```javascript
import { getPasses } from "webtonative/Wallet";

// A specific pass
getPasses({
  passTypeIdentifier: "pass.com.example.loyalty",
  serialNumber: "12345",
  callback: (response) => console.log(response),
});

// Every pass of a type
getPasses({
  passType: "all",
  callback: (response) => console.log(response),
});
```

{% endtab %}
{% endtabs %}

**Parameters:**

| Key                  | Type       | Required | Description                                                       |
| -------------------- | ---------- | -------- | ----------------------------------------------------------------- |
| `passTypeIdentifier` | `String`   | No       | Paired with `serialNumber` to look up one specific pass.          |
| `serialNumber`       | `String`   | No       | Paired with `passTypeIdentifier`.                                 |
| `passType`           | `String`   | No       | Use `"all"` for every pass, or a specific pass type to filter by. |
| `callback`           | `Function` | No       | Callback function invoked with the response.                      |

***

### checkPassExists

Checks whether a pass is already in the wallet — either by identifier, or by handing over the pass itself (its URL or base64 data).

> iOS only.

{% tabs %}
{% tab title="Plain Javascript" %}

```javascript
window.WTN.Wallet.checkPassExists({
  passTypeIdentifier: "pass.com.example.loyalty",
  serialNumber: "12345",
  callback: function (response) {
    console.log(response);
  },
});
```

{% endtab %}

{% tab title="npm" %}

```javascript
import { checkPassExists } from "webtonative/Wallet";

checkPassExists({
  passTypeIdentifier: "pass.com.example.loyalty",
  serialNumber: "12345",
  callback: (response) => console.log(response),
});
```

{% endtab %}
{% endtabs %}

**Parameters:**

| Key                  | Type       | Required | Description                                    |
| -------------------- | ---------- | -------- | ---------------------------------------------- |
| `passTypeIdentifier` | `String`   | No\*     | Paired with `serialNumber`.                    |
| `serialNumber`       | `String`   | No\*     | Paired with `passTypeIdentifier`.              |
| `url`                | `String`   | No\*     | Alternatively, the pass's `.pkpass` URL.       |
| `base64`             | `String`   | No\*     | Alternatively, the pass's base64-encoded data. |
| `callback`           | `Function` | No       | Callback function invoked with the response.   |

\* Provide either `passTypeIdentifier` + `serialNumber`, or `url`, or `base64`.

***

### removePass

Removes a pass from the wallet — either by identifier, or by handing over the pass itself.

> iOS only.

{% tabs %}
{% tab title="Plain Javascript" %}

```javascript
window.WTN.Wallet.removePass({
  passTypeIdentifier: "pass.com.example.loyalty",
  serialNumber: "12345",
  callback: function (response) {
    console.log(response.success);
  },
});
```

{% endtab %}

{% tab title="npm" %}

```javascript
import { removePass } from "webtonative/Wallet";

removePass({
  passTypeIdentifier: "pass.com.example.loyalty",
  serialNumber: "12345",
  callback: (response) => console.log(response.success),
});
```

{% endtab %}
{% endtabs %}

**Parameters:**

| Key                  | Type       | Required | Description                                    |
| -------------------- | ---------- | -------- | ---------------------------------------------- |
| `passTypeIdentifier` | `String`   | No\*     | Paired with `serialNumber`.                    |
| `serialNumber`       | `String`   | No\*     | Paired with `passTypeIdentifier`.              |
| `url`                | `String`   | No\*     | Alternatively, the pass's `.pkpass` URL.       |
| `base64`             | `String`   | No\*     | Alternatively, the pass's base64-encoded data. |
| `callback`           | `Function` | No       | Callback function invoked with the response.   |

\* Provide either `passTypeIdentifier` + `serialNumber`, or `url`, or `base64`.

***

### replacePass

Replaces a pass already in the wallet with an updated version — e.g. after a loyalty card's points balance changes.

> iOS only.

{% tabs %}
{% tab title="Plain Javascript" %}

```javascript
window.WTN.Wallet.replacePass({
  url: "https://example.com/passes/loyalty-card.pkpass",
  callback: function (response) {
    console.log(response.success);
  },
});
```

{% endtab %}

{% tab title="npm" %}

```javascript
import { replacePass } from "webtonative/Wallet";

replacePass({
  url: "https://example.com/passes/loyalty-card.pkpass",
  callback: (response) => console.log(response.success),
});
```

{% endtab %}
{% endtabs %}

**Parameters:**

| Key        | Type       | Required | Description                                            |
| ---------- | ---------- | -------- | ------------------------------------------------------ |
| `url`      | `String`   | No\*     | The updated pass's `.pkpass` URL.                      |
| `base64`   | `String`   | No\*     | Alternatively, the updated pass's base64-encoded data. |
| `callback` | `Function` | No       | Callback function invoked with the response.           |

\* Provide `url` or `base64`.

***

## Callback Response Format

`addPasses` reports back differently per platform, and differently again depending on how many passes you sent.

### Android — single pass

```json
{ "type": "addWalletPasses", "success": true }
```

```json
{
  "type": "addWalletPasses",
  "success": false,
  "error": { "code": "SAVE_ERROR", "message": "..." }
}
```

### Android — multiple passes

All succeeded:

```json
{ "type": "addWalletPasses", "success": true }
```

One or more failed — `data` is keyed by the index of the pass in the array you sent, `true` for a pass that saved and an error object for one that didn't:

```json
{
  "type": "addWalletPasses",
  "success": false,
  "data": {
    "0": true,
    "1": { "code": "INVALID_PASS", "message": "..." }
  }
}
```

**Android error codes:** `NOT_INITIALIZED`, `AVAILABILITY_CHECK_FAILED`, `INVALID_PASS`, `CANCELED`, `SAVE_ERROR`, `EMPTY_BATCH`, `BATCH_IN_PROGRESS`, `UNEXPECTED_ERROR`.

### iOS — single pass

```json
{ "type": "addWalletPasses", "isSuccess": true, "data": { "status": "added" } }
```

```json
{
  "type": "addWalletPasses",
  "isSuccess": false,
  "error": { "code": "invalid_pass", "message": "..." }
}
```

`status` is one of: `added`, `cancelled`, `already_exists`, `unsupported`, `invalid_pass`, `error`.

### iOS — multiple passes

All succeeded — minimal response:

```json
{ "type": "addWalletPasses", "isSuccess": true, "data": {} }
```

Partial or total failure:

```json
{
  "type": "addWalletPasses",
  "isSuccess": true,
  "data": {
    "total": 3,
    "succeededCount": 2,
    "failedCount": 1,
    "failedPasses": [{ "identifier": "...", "code": "invalid_pass", "message": "..." }]
  }
}
```

Every other function (`isSupported`, `getName`, `getPasses`, `checkPassExists`, `removePass`, `replacePass`) reports `{ type, isSuccess/success, ...data }` on success and `{ type, isSuccess/success: false, error: { code, message } }` on failure, following the same pattern as above for its platform.

***

## Platform Differences

| Function          | Android | iOS |
| ----------------- | :-----: | :-: |
| `isSupported`     |    ✅    |  ✅  |
| `getName`         |    ✅    |  ❌  |
| `addPasses`       |    ✅    |  ✅  |
| `getPasses`       |    ❌    |  ✅  |
| `checkPassExists` |    ❌    |  ✅  |
| `removePass`      |    ❌    |  ✅  |
| `replacePass`     |    ❌    |  ✅  |

***

## Implementation Checklist

### WebToNative Dashboard

* [ ] Wallet add-on enabled

### Your Backend

* [ ] Android: signing Google Wallet JWTs via the Google Wallet Issuer API
* [ ] iOS: signing `.pkpass` files with a Pass Type ID from your Apple Developer account

### Your Website

* [ ] Imported the [WebToNative JavaScript bridge](https://docs.webtonative.com/javascript-apis/getting-started)
* [ ] Calling `isSupported` before showing an "Add to Wallet" button, so it isn't shown where there's nothing to add to
* [ ] Sending the pass in the field each platform expects — `passes` (Android) vs. `urls`/`base64s` (iOS) — rather than assuming one shape works everywhere
* [ ] Handling the batch response shape (`data` keyed by index on Android, `failedPasses` on iOS) if adding more than one pass at a time

***

## Frequently Asked Questions

<details>

<summary>Can WebToNative generate or sign the pass for me?</summary>

No. Your backend builds and signs the pass (a Google Wallet JWT on Android, a `.pkpass` file on iOS) using Google's or Apple's own tools. WebToNative only hands the finished pass to the device's wallet app.

</details>

<details>

<summary>Why does `getName`'s callback never fire?</summary>

`getName` is Android-only — on iOS it's simply never called.

</details>

<details>

<summary>I sent one pass to `addPasses` — why does the failure response look different from a batch failure?</summary>

A single pass reports a top-level `error`/`status`. Two or more passes report a `data` object summarizing every pass in the batch (`data` keyed by index on Android, `failedPasses` on iOS) — see [Callback Response Format](#callback-response-format).

</details>

<details>

<summary>Does WebToNative validate the pass before sending it?</summary>

Only structurally, and only on Android — a malformed JWT/URL/claims payload is caught locally as `INVALID_PASS` instead of reaching the Wallet API. Neither platform verifies your pass's signature; an incorrectly signed pass will still fail, just with a native `SAVE_ERROR` / `invalid_pass` instead.

</details>
