Welcome to Xendit’s latest documentation. For legacy content, access the previous version here.

Save a card

Prev Next

To simplify the payment process for returning customers, Xendit's card tokenization offers a secure and efficient solution by allowing you to safely store customer card details. This eliminates the need for customers to re-enter their information for every purchase, leading to a smoother checkout process. You can store multiple cards per customer with One-Click Payments with CVN or Merchant-Initiated Transactions.

Store card flow

How to integrate

  1. Create a payment session

    To begin the tokenization process, you need to create a payment session with Xendit. The session_type must be SAVE, and the amount must be 0.

Request - POST /sessions

{
    "reference_id": "YOUR_PAYMENT_REFERENCE_ID",
    "session_type": "SAVE",
    "mode": "CARDS_SESSION_JS",
    "amount": 0,
    "currency": "IDR",
    "country": "ID",
    "customer": {
        "reference_id": "YOUR_CUSTOMER_REFERENCE",
        "type": "INDIVIDUAL",
        "email": "test@yourdomain.com",
        "mobile_number": "+6212345678",
        "individual_detail": {
            "given_names": "Jaap",
            "surname": "Stam"
        }
    },
    "cards_session_js": {
        "success_return_url": "https://yourcompany.com/success",
        "failure_return_url": "https://yourcompany.com/failure"
    }
}

Request - POST /sessions

{
    "payment_session_id": "YOUR_PAYMENT_SESSION_ID",
    "created": "2024-11-28T07:03:19.571Z",
    "updated": "2024-11-28T07:03:19.571Z",
    "status": "ACTIVE",
    "reference_id": "YOUR_CUSTOMER_REFERENCE",
    "currency": "IDR",
    "amount": 0,
    "country": "ID",
    "customer_id": "cust-d7b12124-3dd1-471a-bf37-c956f44c2a2c",
    "expires_at": "2024-11-28T07:33:19.376Z",
    "session_type": "SAVE",
    "mode": "CARDS_SESSION_JS",
    "locale": "en",
    "business_id": "YOUR_BUSINESS_ID",
    "channel_properties": {
        "cards": {
            "skip_three_ds": false
        }
    },
    "cards_session_js": {
        "success_return_url": "https://yourcompany.com/success",
        "failure_return_url": "https://yourcompany.com/failure"
    }
}
  1. Collect the card information

Implement card_session.js to collect card information.

Request - card_session.js

{ 
    card_number: "4000000000001091"
    cardholder_email: "sample@email.com"
    cardholder_first_name: "firstName"
    cardholder_last_name: "lastName"
    cardholder_phone_number: "+6512341234"
    cvn: "123",
    expiry_month: "12"
    expiry_year: "2040"
    payment_session_id: "YOUR_PAYMENT_SESSION_ID"
}

Response - card_session.js

{   "message": "Status updated. Wait for a callback or get the status using the Get API.", 
    "payment_token_id": "YOUR_PAYMENT_TOKEN_ID", 
    "action_url": "REDIRECT_URL" 
}

Important: You must store the payment_token_id returned in this response and send it to your server. This payment_token_id is crucial for tracking the status of the card tokenization and for future transactions.

  1. Redirect to the authentication page

    After collecting card information, your customer will be redirected to a 3D Secure (3DS) authentication page hosted by the issuing bank. Upon successful authentication, the customer will be redirected back to your specified success page (e.g. https://yourcompany.com/success).

  2. Receive the webhook

    Xendit sends a payment token webhook to your webhook endpoint providing updates on the activation progress of the payment token. Make sure to listen to the webhook to confirm the status of storing the card.

Example payment_token.activation webhook

{
    "created": "2024-12-18T03:57:21.601Z",
    "business_id": "62440e322008e87fb29c1fd0",
    "event": "payment_token.activation",
    "data": {
        "status": "ACTIVE",
        "country": "ID",
        "created": "2024-12-18T03:57:19.330Z",
        "updated": "2024-12-18T03:57:21.215Z",
        "currency": "IDR",
        "business_id": "62440e322008e87fb29c1fd0",
        "customer_id": "cust-9f02010d-1189-4f2c-95e9-fe7f52fdd29b",
        "channel_code": "CARDS",
        "reference_id": "efe51f0c-ea1f-45ec-96e4-5275db384d68_1b0d11cd-a",
        "token_details": {
            "authorization_data": {
                "reconciliation_id": "7344942402526026003955",
                "authorization_code": "831000",
                "acquirer_merchant_id": "xendit_ctv_agg",
                "network_response_code": "00",
                "network_transaction_id": "016153570198200",
                "cvn_verification_result": "M",
                "retrieval_reference_number": "435203752181",
                "address_verification_result": "M",
                "network_response_code_descriptor": "Approved and completed sucessfully"
            }
        },
        "payment_token_id": "pt-eda13864-5091-4bd2-b88d-ae640be90ee7",
        "channel_properties": {
            "card_details": {
                "type": "CREDIT",
                "issuer": "BRI",
                "country": "ID",
                "network": "VISA",
                "expiry_year": "2040",
                "fingerprint": "635a0be115cf90001ae83752",
                "expiry_month": "12",
                "cardholder_email": "test@yourdomain.com",
                "masked_card_number": "400000XXXXXX1091",
                "cardholder_last_name": "lastName",
                "cardholder_first_name": "firstName",
                "cardholder_phone_number": "+62812347290"
            },
            "skip_three_ds": true,
            "card_on_file_type": "CUSTOMER_UNSCHEDULED",
            "failure_return_url": "https://yourcompany.com/failure",
            "success_return_url": "https://yourcompany.com/success"
        }
    },
    "api_version": "v3"
}
  1. Retrieving the stored card

    After the card has been successfully tokenized (and you've received the payment_token.activation webhook), you can retrieve the token details by making a GET request to payment_tokens/YOUR_PAYMENT_TOKEN_ID.

Response - /v3/payment_tokens

{   
    "payment_token_id": "YOUR_PAYMENT_TOKEN_ID",
    "business_id": "YOUR_BUSINESS_ID",
    "customer_id": "YOUR_CUSTOMER_ID",
    "country": "ID",
    "reference_id": "YOUR_REFERENCE_ID",
    "currency": "IDR",
    "status": "ACTIVE",
    "actions": [],
    "created": "2024-12-05T02:05:56.176308Z",
    "updated": "2024-12-05T02:19:02.935905Z",
    "channel_properties": {
        "skip_three_ds": false,
        "success_return_url": "https://yourcompany.com/success",
        "failure_return_url": "https://yourcompany.com/failure",
        "card_details": {
            "masked_card_number": "400000XXXXXX1091",
            "cardholder_first_name": "Jaap",
            "cardholder_last_name": "Stam",
            "cardholder_email": "Jaap@stam.com",
            "cardholder_phone_number": "+6512341234",
            "expiry_month": "12",
            "expiry_year": "2040",
            "fingerprint": "635a0be115cf90001ae83752",
            "type": "CREDIT",
            "network": "VISA",
            "country": "ID",
            "issuer": "BRI"
        },
        "card_on_file_type": "CUSTOMER_UNSCHEDULED",
        "card_verification_results": {
            "three_ds_data": {
                "three_ds_flow": "CHALLENGE",
                "eci_code": "05",
                "three_ds_result": "AUTHENTICATED",
                "three_ds_result_reason": null,
                "three_ds_version": "2.1.0"
            },
            "cvn_result": null,
            "address_verification_result": "MATCH"
        }
    },
    "channel_code": "CARDS"
}

Use payment token for future transactions

Once a payment token is generated, it acts as a secure reference to the end user's stored card details. You can use this token for future transactions, based on your consent agreement with the end user.

Common Use Cases for Payment Tokens:

  1. Customer-Initiated Transactions (Returning Customers) - enables users to seamlessly use stored cards for their next purchase. To improve the success rate, we recommend prompting users to re-enter their CVN when completing the transaction. See our integration guide

  2. Merchant-Initiated Transactions (Recurring Payments) - you can initiate the transaction without end-user interaction (e.g., for subscriptions or auto-debits). Ideal for subscription-based services, memberships, and automated billing. See our integration guide