Card on file

The "Card on file" functionality allows users to save credit card information for future use instead of repeatedly entering their credit card information.

Cards can be stored during each of the following flows:

  • Charge flow
  • From a client card
  • During checkout

Saving card during a charge flow

Client consent

For the payment gateway application to determine whether the user chose to save the card, the iFrame should listen to the following postMessage that indicates whether the “Client has consented to save this card on file” checkbox is checked or unchecked.

Code snippet for listening to save card checkbox events

window.addEventListener(
        'message',
        (event) => {
          // Save card checked/unchecked event
          if (event.data.type === 'generic' && event.data.func === 'setSaveCard') {
            const saveCard = event.data.params.checked.checked; // boolean
            return;
          }
        })

Cardholder name

Once the user clicks the Charge button, the charge flow will continue as described under the Charge section.
At that point, you want to save the payment details along with the credit card information, and make sure you can reference the credit card information based on the "charge token" - the token you provided via the JavaScript postMessage.

Note that this time, the postMessage emitted when the Charge CTA is clicked will indicate that "save_card: true":

{
  type: 'generic', 
  func: 'getToken', 
  params: {
    amount: number,
    save_card: true,
    pivot_id: string,
    client_id: string,
    currency: string
  } 
}

Also, when save_card is true, you'll need to pass a cardholder_name in the postMessage in addition to the token you'd pass in a charge flow.

window.addEventListener(
        'message',
        (event) => {
           if (event.data.type === 'generic' && event.data.func === 'getToken') {
            // Do some credit card number validations
            const cardValidationErrors = validateCard(); // Can be a function that returns an array of errors
            // if card validations checks error
            if (cardValidationErrors.length > 0) {
              const messageObj = {
                type: 'generic',
                func: 'validationFailure'
              }
              window.parent.postMessage(messageObj, '*')
              // present the errors in the iFrame
              return;
              // If the card checks correctly with no issues
            } else {
              const token = {TOKEN}
              const messageObj = {
                type: 'generic',
                token: {TOKEN}
              }
              // Add cardholder_name is save_card === true
              if (event.data.params.save_card) {
                messageObj['cardholder_name'] = this.cardHolderName;
              }
              window.parent.postMessage(messageObj, '*');
              // Store token and payment details in your database for later reference
              return;
            }
          }
        }
      )

POST /customer/:token/attach

In addition to the usual Charge flow, when the option to save a card is checked, inTandem will send another POST request to {redirect_uri}/customer/:token/attach.
The "token" param will correspond to the token you initially provided in the Charge event.

📘

customer_id

The request body will include a customer_id value. customer_id is the card identifier on the intandem end. You'll need to include that customer_id in the response so we can associated the card with the client and also reference it on future card-related actions.

POST {redirect_uri}/customer/:token/attach

Request payload:

{
	"customer_id": string // card identifier provided by inTandem
}

Expected response:

{
    "card": {
        "card_id": "addtkthQ16trAsldSar50v6sLfdmuQ", // card identifier provided by the payment gateway
        "card_info": {
            "card_brand": "visa",
            "last_4": 1217,
            "exp_month": 10,
            "exp_year": 2030,
            "cardholder_name": "John Doe"
        }
    },
    "customer_id": "49v0ud9YhquOoYTczn0PkwdRn9QRb7"
}

That's it. At that point, the card is saved and will appear as an optional payment option for future payments.

Saving card on file from the client card

Saving a card on file from the client card is identical to how you save a card on the Charge flow. On both, inTandem will embed the Payment Processing Page from {redirect_uri}/charge, emit the getToken postMessage when the ADD CTA is clicked (and expecting a following postMessage with a token), followed by a POST request to {redirect_uri}/charge/:token/attach.

For the payment processing page to differentiate between the two flows, when inTandem loads the payment processing page on the client card page, we'll append a query param to the iFrame URL indicating that this is a save-card-only operation and not a charge flow.

{redirect_uri}/charge?save_card=true&pivot_id=BUSINESS_UID

Delete saved cards

Removing saved cards is done by inTandem sending a request to:

POST {api_uri}/customer/:token/detach

Request payload

{
    "customer_id": "49v0ud9YhquOoYTczn0PkwdRn9QRb7"
}

Expected response:

{
    "customer_id": "49v0ud9YhquOoYTczn0PkwdRn9QRb7"
}

Saving card-on-file on checkout

Get payment information from inTandem (make sure that “allow_save_card” is true). If allow_save_card is false, either the client already has 3 cards saved, or the “checkout_vaulting” feature flag is missing for that account.

Saving cards on checkout is done in two steps:

  1. Make sure that the save card feature is available at the account level.
    When sending the GET request to /checkout/:url_key as part of the usual checkout flow, make sure that the value of the “allow_save_card” property is true.

    GET /checkout/:url_key body request:

{
    "status": "OK",
    "data": {
        "amount": "33.0",
        "currency": "USD",
        "name": "John Doe",
        "return_url": "https://clients.meet2know.com/portal/5e3c760d?fromCheckout=true#/loader",
        "email": "[email protected]",
        "client_id": "zlbsfegs493u9zmo",
        "invoice_id": null,
        "allow_save_card": true
    }
}
  1. If “allow_save_card” is true, you can proceed with the checkout flow by appending the customer id and the card information when sending the payment checkout update request.

    PUT https://api.vcita.biz/platform/v1/payment/checkout/ body request:

{
   "url_key": "ijGghOYFKTFClDWJQZSNzkaZDZNQOiksktubFXpXfWmdovxuSz",
   "card":{
       "card_id": "15dsanida54",
       "card_info": {
           "exp_month": "01",
           "exp_year": "2025",
           "last_4": "6666",
           "card_brand": "visa",
           "cardholder_name": "John Doe"
           }
   },
   "customer_id": "49v0ud9YhquOoYTczn0PkwdRn9QRb7",
   "created": "2020-11-26",
   "transaction_id": "12qw34rt56yu",
   "type": "checkout.session.completed"
}

Expected response:

{
    "status": "OK",
    "data": {}
}