> For the complete documentation index, see [llms.txt](https://docs.commercelayer.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.commercelayer.io/core-api-reference/2026-05/payment_wallets.md).

# Payment wallets

The payment wallet object and the allowed CRUD operations on the related resource endpoint

A payment wallet stores a vaulted payment instrument — such as a tokenized credit card — on behalf of a [customer](/core-api-reference/2026-05/customers.md), enabling faster checkout by reusing saved payment details across multiple [payment sessions](/core-api-reference/2026-05/payment_sessions.md). Each wallet is associated with a [payment setting](/core-api-reference/2026-05/payment_settings.md) that supports vaulting.

A wallet is obtained in one of two ways:

1. You create it directly, which stores the instrument without charging the customer.
2. Commerce Layer creates it from a successful charge when the paying session [asks for vaulting](#wallets-created-by-a-payment-session).

{% hint style="info" %}
Whether a payment setting supports wallets depends on it being configured as *vaultable* — refer to the specific payment setting subtype's documentation to check.
{% endhint %}

{% hint style="success" %}
[Adyen](/core-api-reference/2026-05/payment_setting_adyens.md), [Braintree](/core-api-reference/2026-05/payment_setting_braintrees.md), [Checkout.com](/core-api-reference/2026-05/payment_setting_checkout_coms.md), [PayPal](/core-api-reference/2026-05/payment_setting_paypals.md), [Stripe](/core-api-reference/2026-05/payment_setting_stripes.md), and [external](/core-api-reference/2026-05/payment_setting_externals.md) payment settings with a `token_url` configured support wallet creation.
{% endhint %}

{% hint style="warning" %}
Creating a wallet against any other payment setting — including an external one without a `token_url` — is rejected with a `422 Unprocessable Entity` error.
{% endhint %}

## Token references

A wallet stores two references, `payment_token` and `customer_token`. Both can be passed explicitly when creating the wallet. For whichever one you omit, Commerce Layer attempts to obtain it automatically, but how that happens — and whether omitting it is realistic — differs by gateway:

{% tabs %}
{% tab title="Adyen" %}
Adyen has no stored customer profile of its own — Commerce Layer identifies the shopper using its own customer data instead.

* `payment_token` — Gateway-returned: produced when Commerce Layer stores the payment method with Adyen.
* `customer_token` — Commerce Layer-derived by default: the customer's own `shopper_reference`, sent to Adyen to identify the shopper. Adyen never generates or returns this value.
  {% endtab %}

{% tab title="Braintree" %}
Braintree also ties the payment method to a customer profile, but associates the two in a single step rather than a separate attach call.

* `payment_token` — Gateway-returned: produced when Commerce Layer vaults the payment method with Braintree.
* `customer_token` — Gateway-returned: if you don't supply one, Commerce Layer first creates a Braintree customer profile and stores its ID. The payment method is associated with it as part of the same vaulting request.
  {% endtab %}

{% tab title="Checkout.com" %}
Checkout.com also ties the payment method to a customer profile, similar to Braintree and Stripe.

* `payment_token` — Client-side: a card token from Checkout.com's Frames.js or mobile SDKs, submitted by the client.
* `customer_token` — Gateway-returned: if you don't supply one, Commerce Layer first creates a Checkout.com customer profile and stores its ID. The payment method is vaulted as an instrument associated with it as part of the same request.
  {% endtab %}

{% tab title="PayPal" %}
PayPal's flow starts with a client-side setup token rather than a payment method identifier, with the customer identifier traveling alongside it as a separate value.

* `payment_token` — Two-step exchange (full flow [here](/core-api-reference/2026-05/payment_setting_paypals.md#wallet-vaulting)): the client collects a setup token via the PayPal SDK and submits it through `_payment_details` — Commerce Layer exchanges it for a permanent payment token.
* `customer_token` — Commerce Layer-derived by default: the customer's own identifier, sent to PayPal alongside the setup token in that same exchange request. It's a separate input, not part of the token exchange itself.
  {% endtab %}

{% tab title="Stripe" %}
Stripe ties every vaulted payment method to a customer profile — Commerce Layer handles that attach step for you as part of the vaulting request.

* `payment_token` — Client-side: a payment method identifier from Stripe.js/Elements, submitted by the client.
* `customer_token` — Gateway-returned: if you don't supply one, Commerce Layer creates a Stripe customer profile and stores its ID. Either way, Commerce Layer attaches the payment method to that profile as part of the same vaulting request.
  {% endtab %}

{% tab title="External" %}
For external gateways, both values come from your own vaulting endpoint's response, though `customer_token` is optional.

* `payment_token` — Gateway-returned: read from your vaulting endpoint's response.
* `customer_token` — Gateway-returned, if your integration chooses to provide it, from the same response — otherwise left blank.
  {% endtab %}
  {% endtabs %}

{% hint style="warning" %}
For Stripe, this attach step happens automatically whether `customer_token` is auto-created or supplied manually — there's no need to pre-attach the payment method yourself. It only fails if the payment method is already attached to a different Stripe customer.
{% endhint %}

{% hint style="info" %}
The `payment_data` attribute contains parsed instrument metadata such as card type, the last four digits of the card number, and expiry.
{% endhint %}

## Lifecycle

A payment wallet transitions through the following statuses:

<table><thead><tr><th width="220">Status</th><th>Description</th></tr></thead><tbody><tr><td><strong><code>pending</code></strong></td><td>Wallet creation has been initiated.</td></tr><tr><td><strong><code>requires_action</code></strong></td><td>Customer action is required to complete vaulting (e.g., a 3DS challenge).</td></tr><tr><td><strong><code>processing</code></strong></td><td>The vault request is being processed.</td></tr><tr><td><strong><code>succeeded</code></strong></td><td>The payment instrument has been successfully vaulted.</td></tr><tr><td><strong><code>canceled</code></strong></td><td>The wallet was canceled and its payment instrument removed from the provider.</td></tr></tbody></table>

{% hint style="info" %}
Whenever a wallet reaches `succeeded` status — however it was created, directly or [by a payment session](#wallets-created-by-a-payment-session), and including after a completed [3DS challenge](#handling-3ds-and-customer-action) — Commerce Layer offers it, in the background, to the customer's [order subscriptions](/core-api-reference/2026-05/order_subscriptions.md#instrument-pending-subscriptions) still pending for want of a payment instrument, and activates the ones it can pay for. Expired wallets are skipped.
{% endhint %}

## Expiry

Wallets track an optional `expires_at` date derived from the vaulted payment instrument's expiry (e.g., card expiry month/year). Expired wallets cannot be used for new payment sessions.

## Handling 3DS and customer action

For payment providers that require Strong Customer Authentication (SCA/3DS), the wallet may transition to `requires_action` after creation. The customer must complete the challenge, after which the client must update the wallet and pass the `_payment_details` trigger attribute to finalize vaulting. Once in `succeeded` status, the wallet can be [linked to a payment session](/core-api-reference/2026-05/payment_sessions.md#paying-with-a-wallet) to pay without re-collecting payment details.

## Wallets created by a payment session

Everything above describes creating a wallet directly, which stores the instrument without charging the customer.

A wallet can also be obtained as a by-product of a payment: when a [payment session](/core-api-reference/2026-05/payment_sessions.md#vaulting-during-a-charge) sets its `vaulting` attribute, the request to store the instrument travels with the charge itself, and the instrument is stored only if that payment succeeds. You don't create this wallet — Commerce Layer does, from the token returned with the charge, already in `succeeded` status and linked to that session.

{% hint style="info" %}
Any asynchronous tokenization notification the gateway sends afterwards finds that same wallet by its token, rather than creating a second one.
{% endhint %}

{% hint style="warning" %}
Adyen, Checkout.com, PayPal, Stripe, and [external](/core-api-reference/2026-05/payment_setting_externals.md#storing-the-instrument-during-a-payment) sessions create wallets this way, and only when the session's order has a customer. Braintree sessions reject `vaulting`, and guest orders never get a wallet — create one explicitly as described above.
{% endhint %}

## Cancelling a wallet

A wallet that has been used by a payment session or an order subscription cannot be deleted — the request is rejected with a `423 Locked` error — so that the payment data those payments rely on is never lost. Cancel it instead, by updating the wallet with the `_cancel` trigger attribute: Commerce Layer removes the stored instrument from the payment provider and moves the wallet to `canceled`, keeping it — and its payment data — linked to the payments it made.

{% hint style="info" %}
Customers can cancel their own wallets with a sales channel access token [obtained with their credentials](https://docs.commercelayer.io/core/authentication/password), but not anyone else's.
{% endhint %}

{% hint style="warning" %}
If the provider fails to remove the instrument, the request is rejected with the provider's error and the wallet is left unchanged. A `canceled` wallet can't be used for new payment sessions — filter the list by `status` to show customers only their `succeeded` wallets. The same instrument can be stored again afterwards, in a new wallet.
{% endhint %}

## Gateway options

At creation time, a payment wallet accepts an `options` object whose values are passed straight through to the underlying payment provider, following the same rules as [payment sessions](/core-api-reference/2026-05/payment_sessions.md#gateway-options).

## Triggers

A payment wallet supports the following trigger attributes:

* `_refresh` — syncs wallet data with the provider.
* `_cancel` — [cancels](#cancelling-a-wallet) the wallet.
* `_internal_version` — forces a specific supported [internal payload version](/core-api-reference/2026-05/payment_settings.md#per-request-overrides) for this wallet's creation request.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.commercelayer.io/core-api-reference/2026-05/payment_wallets.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
