Payment Instrument Tokenization (Checkout)
Let your customers save a card during a hosted-checkout payment and reuse it in one click next time. Card details are stored securely in our vault. Saved cards are represented by payment instrument tokens; the full stored card number is not returned when displaying or reusing saved cards.
How it works
In the hosted Checkout flow you make one API call — creating the payment intent. Everything else happens on the hosted form:
| Step | Description |
|---|---|
| 1 | You create a PaymentIntent and receive a checkout link. |
| 2 | You redirect the shopper to that link. |
| 3 | On the form the shopper saves a card, reuses a saved one, or removes one where the removal action is available — no extra API calls from your side. |
| 4 | You receive the result on your webhook. |
The shopper experience
Saving, selecting and removing cards happen on the hosted checkout. Below is what the shopper sees and can do.
List of Scenarios
| Scenario | Description |
|---|---|
| Saving a new card |
|
| Viewing saved cards |
|
| Paying with a saved card |
|
| Removing a saved card |
|
Consent
- The "Save card for future payments" option controls whether the card is added to the shopper's saved cards for future payments.
- Its initial state is configured in the Checkout form template.
- When the option is off, the card is not added to the shopper's saved-card list.
Limit on saved cards
- By default, the saved-card limit is 5 cards per shopper within a settlement account, shared across payment methods.
- The limit is configured in the Checkout form template. Your integration manager can adjust it.
- When the limit is reached, the shopper can still pay with a new card without adding it to their saved cards.
- Removing an existing saved card can make room for another card.
Unavailable cards
- Expired cards remain visible in the shopper's saved-card list and are marked "Expired".
- They appear after cards whose expiry date has not passed and cannot be selected for payment.
- In the current hosted Checkout, the removal menu is also disabled for expired cards.
Enabling saved cards
You are fully responsible for passing the correctmerchantPayerReference.Cards are shown to whoever the intent says the payer is. If you send a value that belongs to a different user (a wrong or mixed-up id), that user's saved cards will be exposed to the current shopper. Make sure the reference always matches the authenticated user in your system.
Two things are required for a shopper to see and reuse their saved cards:
1. Feature enabled on the form template.
- Card saving is off by default and must be enabled in the Checkout form template.
- Ask your integration manager to enable it, configure the saved-card limit, and set the initial state of the "Save card for future payments" option.
2. Identify the shopper in the intent.
- Saved cards are tied to
(settlement account + payer.merchantPayerReference). - Pass a stable
merchantPayerReference(the shopper's id in your system) when creating the intent. - Use the same settlement account and reference on future intents so the shopper's saved cards appear automatically.
- If you omit the reference, cards cannot be added to the shopper's saved-card list or reused through that list.
If card saving is enabled on the form but you omit
merchantPayerReference, the "Save card" option can still appear and the payment can proceed. However, the card will not be added to the shopper's saved cards. Always send a stable reference to enable saving and reuse.
Create the intent
Full list of parametersThe full list of parameters is available on the page: "Card" Payment Method
POST https://sandbox.carusell.world/processing/api/v1/intentscurl --request POST \
--url 'https://sandbox.carusell.world/processing/api/v1/intents' \
--header 'content-type: application/json' \
--header 'X-API-Key: <token>' \
--data '{
"clientReferenceId": "order_12345",
"useCheckoutForm": true,
"paymentIntent": {
"submittedAmount": { "value": 17.07, "currency": "USD" },
"description": "Order #12345",
"webhookUrl": "https://merchant.com/webhook",
"payer": {
"merchantPayerReference": "CUST_12345",
"email": "[email protected]"
},
"formDetails": {
"template": "checkout-light",
"displayedPaymentMethods": ["CARD", "SBP"],
"backToStoreRedirectUrl": "https://merchant.com/checkout"
}
}
}'Key fields
| Field | Required | Purpose |
|---|---|---|
useCheckoutForm | yes | Must be true for hosted Checkout. |
paymentIntent.payer.merchantPayerReference | for saving and reusing cards | Stable shopper id in your system. Together with the settlement account, it identifies the shopper's saved cards. |
Response — the intent contains the checkout session id and the hosted link to open:
{
"intentId": "<intent_id>",
"paymentIntent": {
"intentSessionId": "is_01JVM1PZ0J7B1Y9J6R3X2M8KQF",
"additionalData": {
"url": "https://checkout.carusell.world/is_01JVM1PZ0J7B1Y9J6R3X2M8KQF"
}
}
}Redirect the shopper to paymentIntent.additionalData.url.
Webhook
Full list of parametersThe full list of parameters is available on the page: Webhooks: Example
When the payment finishes, we call your webhookUrl. The webhook includes information about the card used. When saving is requested during Checkout, the paymentInstrument object also reports the saving result when it is available.
For a successful save request, paymentInstrument.isSaved is true and paymentInstrument.paymentInstrumentToken contains the saved payment instrument token with the pi_ prefix. This also covers a request to save a card that was already saved for the shopper.
Successful saving result
Example of a successful payment with a successful saving result, showing the relevant fields:
{
"transactionType": "PAYMENT",
"transactionId": "<payment_id>",
"intentId": "<intent_id>",
"status": "CAPTURED",
"paymentInstrument": {
"paymentMethodName": "BankCardRU",
"savingRequested": true,
"isSaved": true,
"paymentInstrumentToken": "pi_****YCH4"
}
}The webhook returns the full token. It is masked here for illustration.
Fields
| Field | Meaning |
|---|---|
paymentInstrument.savingRequested | Present as true when saving was requested for this payment; omitted otherwise. It does not confirm successful saving. |
paymentInstrument.isSaved | Reports the result of the save request. true means the card is on file for this shopper, including when the same card was already saved. It does not indicate that a new saved-card record was created. |
paymentInstrument.paymentInstrumentToken | The full pi_ token of the saved payment instrument used by this payment or associated with its successful save request. The token alone does not indicate a new save. |
isStoredCredential | true if the payment was made with a previously saved card. |
last4 | Last 4 digits of the card used. Returned on any card payment whenever we have the card data — both successful and declined — not only for saved cards. |
Check
paymentInstrument.isSavedfor the saving result. NeithersavingRequested: truenor a successful payment status alone confirms successful saving.
isSaved: truecan also mean that the card was already saved. It is not a separate "new card saved for the first time" flag.
isStoredCredentialindicates that the payment used a previously saved card. It does not report the result of a save request.
Paying with a saved card
For a payment made with a previously saved card, isStoredCredential is true.
Example showing the relevant fields:
{
"isStoredCredential": true,
"last4": "4242"
}The payment can also return paymentInstrument.paymentInstrumentToken for the saved instrument it used, without reporting a new save.
Retrieving the saving result via API
The saving result and payment instrument token are also available through GET intent and GET payment.
| Endpoint | Location of the saving fields and token |
|---|---|
GET /processing/api/v1/intents/{intentId} | payments[].paymentInstrument |
GET /processing/api/v1/payments/{paymentId} | paymentInstrument |
The examples below show the relevant fields for a successful payment with a successful saving result. The API returns the full token; tokens are masked here for illustration.
GET intent
GET /processing/api/v1/intents/{intentId}{
"id": "<intent_id>",
"intentStatus": "FINALIZED",
"payments": [
{
"id": "<payment_id>",
"status": "CAPTURED",
"paymentInstrument": {
"savingRequested": true,
"isSaved": true,
"paymentInstrumentToken": "pi_****YCH4"
}
}
]
}GET payment
GET /processing/api/v1/payments/{paymentId}{
"id": "<payment_id>",
"status": "CAPTURED",
"paymentInstrument": {
"paymentMethodName": "BankCardRU",
"savingRequested": true,
"isSaved": true,
"paymentInstrumentToken": "pi_****YCH4"
}
}The saving result also takes the saved card's current state into account. If the card is later removed, subsequent API responses for the payment that requested saving may report
isSaved: falseand omit its token. Do not treatisSavedas an unchanging historical flag.
Updated 17 days ago


