---
title: "Add a card to a digital wallet"
method: POST
path: "/cards/{id}/tokenize"
tags: ["Cards"]
---

# Add a card to a digital wallet

`POST /cards/{id}/tokenize`

## Request

- Base URL: `https://api.lightspark.com/grid/2025-10-13`
- URL: `https://api.lightspark.com/grid/2025-10-13/cards/{id}/tokenize`
- Auth: HTTP basic

Exchange the values your app received from Apple Pay, Google Pay, or Samsung Pay for the encrypted provisioning payload that completes adding the card to that wallet (in-app push provisioning). Call it from your backend inside the wallet SDK's credentials callback and hand the response straight back to the SDK.

The payload is encrypted to the wallet provider's keys, so neither your app nor your servers ever see card data. Do not store or log it; it is valid for one provisioning attempt.

Cardholders can always add a card to a wallet by typing its details in manually — that path needs nothing from you. This endpoint is for the in-app "Add to Wallet" button, which additionally requires approval from each wallet provider. See [Digital wallet tokenization](/cards/card-management/digital-wallet-tokenization).

Only `ACTIVE` cards can be added. Every call is audit-logged with the requesting actor and the target wallet.

## Request body

- union
  - ApplePayTokenizationRequest: Fields shared by every add-to-wallet request. The wallet SDK hands your app a set of values when the cardholder taps "Add to Wallet"; pass them here unchanged in the request shape for that `wallet`.
    - `wallet` 'APPLE_PAY', required: Discriminator value identifying an Apple Pay request.
    - `certificate` string, required: The leaf certificate from the `certificates` array Apple passes to your `PKAddPaymentPassViewControllerDelegate`, base64-encoded in PEM form.
    - `nonce` string, required: The `nonce` Apple passes to your delegate, base64-encoded.
    - `nonceSignature` string, required: The `nonceSignature` Apple passes to your delegate, base64-encoded.
  - GooglePayTokenizationRequest: Fields shared by every add-to-wallet request. The wallet SDK hands your app a set of values when the cardholder taps "Add to Wallet"; pass them here unchanged in the request shape for that `wallet`.
    - `wallet` 'GOOGLE_PAY', required: Discriminator value identifying a Google Pay request.
    - `walletAccountId` string, required: The stable identifier of the Google Wallet account the card is being added to, as reported by the TapAndPay client.
    - `serverSessionId` string, uuid, required: The `serverSessionId` Google supplies in the TapAndPay payment-credentials callback under Unified Push Provisioning.
    - `deviceId` string: The stable device identifier from `getStableHardwareId`, when the SDK supplies one. Unified Push Provisioning does not always.
    - `opaquePaymentCardRequested` boolean: Set to the value Google supplies in the payment-credentials callback. When `true`, the response also carries `googleAccountPayload`, which saves the card to the cardholder's Google Account for online payments in addition to the device token.
  - SamsungPayTokenizationRequest: Fields shared by every add-to-wallet request. The wallet SDK hands your app a set of values when the cardholder taps "Add to Wallet"; pass them here unchanged in the request shape for that `wallet`.
    - `wallet` 'SAMSUNG_PAY', required: Discriminator value identifying a Samsung Pay request.
    - `walletAccountId` string, required: The cardholder's Samsung Wallet identifier (`walletUserId`) reported by the Samsung Pay SDK.
    - `deviceId` string, required: The stable device identifier reported by the Samsung Pay SDK.

## Response `200`

Provisioning payload minted.

- union
  - ApplePayTokenizationResponse: Fields shared by every add-to-wallet response. The payload is encrypted to the wallet provider's keys: neither your app nor your servers can read the card data inside it. Hand it to the wallet SDK; it is valid for a single provisioning attempt.
    - `wallet` 'APPLE_PAY', required: Discriminator value identifying an Apple Pay response.
    - `applePay` CardTokenizationApplePayPayload, required: The encrypted pass data for Apple Wallet. Pass the three fields straight into the `PKAddPaymentPassRequest` your delegate's completion handler expects.
      - `activationData` string, required: Base64 `activationData` for `PKAddPaymentPassRequest`.
      - `encryptedPassData` string, required: Base64 `encryptedPassData` for `PKAddPaymentPassRequest`.
      - `ephemeralPublicKey` string, required: Base64 `ephemeralPublicKey` for `PKAddPaymentPassRequest`.
  - GooglePayTokenizationResponse: Fields shared by every add-to-wallet response. The payload is encrypted to the wallet provider's keys: neither your app nor your servers can read the card data inside it. Hand it to the wallet SDK; it is valid for a single provisioning attempt.
    - `wallet` 'GOOGLE_PAY', required: Discriminator value identifying a Google Pay response.
    - `provisioningPayload` string, required: Base64-encoded opaque payload for the device token. Return it from the TapAndPay payment-credentials callback.
    - `googleAccountPayload` string: Present when `opaquePaymentCardRequested` was `true`. Return it alongside `provisioningPayload` so Google also saves the card to the cardholder's Google Account.
  - SamsungPayTokenizationResponse: Fields shared by every add-to-wallet response. The payload is encrypted to the wallet provider's keys: neither your app nor your servers can read the card data inside it. Hand it to the wallet SDK; it is valid for a single provisioning attempt.
    - `wallet` 'SAMSUNG_PAY', required: Discriminator value identifying a Samsung Pay response.
    - `provisioningPayload` string, required: Base64-encoded opaque payload. Pass it to the Samsung Pay SDK's `addCard` call.

## Other responses

- `400`: Invalid input. The body does not match the request shape for its `wallet` (a required field is missing, or a field from another wallet's shape was supplied), or the wallet provider rejected the values (for example, an expired Apple nonce). Restart the add-to-wallet flow in the app to obtain fresh values.
- `401`: Unauthorized
- `403`: Forbidden. The session has no attributable actor to audit the request against (for example, an impersonated dashboard session).
- `404`: Card not found
- `409`: Conflict. `CARD_NOT_MUTABLE` when the card is `CLOSED`; `CONFLICT` when the card's `cardCapabilities.supportsDigitalWalletTokenization` is false or the card is not `ACTIVE`.
- `500`: Internal service error
- `501`: Not implemented in this environment. Cards are not enabled for every Grid deployment; environments without a configured card issuer return `501 NOT_IMPLEMENTED`.

## Changes

> 115 revisions in range; 2 not diffed.

- **2026-10-28** `d996ddfb9d2b`: 5 info
  - added the optional property `details/missingFields` to the response with the `400` status
  - added the optional property `details/permission` to the response with the `403` status
  - added the optional property `details/policyDenialReason` to the response with the `403` status
  - added the optional property `details/refusalReason` to the response with the `400` status
  - …1 more
- **2026-10-28** `5abf2bb56bcb`: 1 warning
  - added the new `CORRIDOR_UNDER_MAINTENANCE` enum value to the `code` response property for the response status `403`
- **2026-10-26** `f11f1e76bdd7`: 1 warning
  - added the new `PURCHASE_CARD_LIMIT_REACHED` enum value to the `code` response property for the response status `409`
- **2026-10-26** `0a6dad5815c7`: 1 warning
  - added the new `INVOICE_ALREADY_USED` enum value to the `code` response property for the response status `409`
- **2026-10-24** `715332dcb111`: 1 warning
  - added the new `EXACT_AMOUNT_UNAVAILABLE` enum value to the `code` response property for the response status `400`

[Operation history](https://skmtc.dev/lightsparkdev/apis/grid-api/changes/cards/:id/tokenize/post.md)

---

[API](https://skmtc.dev/lightsparkdev/apis/grid-api.md) - [All operations](https://skmtc.dev/lightsparkdev/apis/grid-api/llms.txt) - [OpenAPI document](https://skmtc.dev/lightsparkdev/apis/grid-api/revisions/7a1db46ec552?raw)
