Adding a card to the wallet

As for PCI compliance we're not allowed to store sensitive card details, the user should register the card to the payment provider to use it, in a process called Tokenization.

Creating a token in place of a credit card replaces sensitive payment data with a unique token that cannot be mathematically reversed. The actual payment data is securely stored in the payment services data centers.

The tokenization will encrypt the sensitive card data on the client side before sending it. The operation varies regarding the payment service that the location is using to process the payment. At the moment, the available options are Adyen and Cybersource.

Because of this, means that every payment service will follow a different tokenisation process and the card will have a different token for each payment service.

Tokenizing a card for Adyen

Tokenizing a card for Adyen is quite simple process, but requires to create a public key that will be used to encrypt the credit card details to generate a token that will be stored on our database.

To check how to obtain the encryption key from Adyen, please check this document.

Tokenization Flow Adyen

The Adyen public key will be used to encrypt the card details on client side, to generate the AdyenCSE. This string it then passed to the endpoint to add a card into the wallet (wallet/card/insert). The flypay backend will send the encrypted information to Adyen, that replies with a token that is stored in the database, ready to be used by location configured to use Adyen as payment service.

To encrypt the card details to generate the requested CSE you should use of the Adyen libraries created ad-hoc:

Once you have the card CSE, you can add the card to the wallet by calling the endpoint:

curl -X "POST" "https://api.flypaythis.com/v3/user/me/wallet/card/insert?accessToken={accessToken}" \\
     -H 'Content-Type: application/json' \\
     -d $'{
  "expiryMonth": 12,
  "expiryYear": 19,
  "first6Digits": "400000",
  "nickname": "My Visa",
  "save": true,
  "last4Digits": "0002",
  "default": true,
  "adyenCse": "adyenan0_1_1$ZJ0x8OsJb4Vhb1sXjCRS1La1vRhBH6MuMxXYvdBPCssbW6dYMVTvUMqjwfDSqFQ1Krl3X2eC9HiLHkJOOs2Qu5kFcvTFZnYOYRdHsJyN25/IZOHBkUDd/KKQQ1XopGHmfYtwKMwTDEucDoBxRiwIyUdKLhnCkwadTJGWESwvQnUI/BCAja/eymReU1ujE2rxr2OOSHFZW08leiQLESGkuULRGOMS+TDW0cWPyhFxDgSNNPv3QO78JxMorc+WRiefEhFr38Q6/OGqugGK8okrYyvHrVrmfl+XlNwflWzrPP+AS+csYm9528xXEwJrbn0GdyztGX+NBoosTha2LhT22A==$5Cn0nfH3aI9c7ul0e6WND8Dr7TllDw2sfEWXXfc61kDPigpx26000cbvXw6/WlsA4nMrftRW9sB42IfKeddcRH15FZSrxCUXKL/iG1rgphqIQ+40CaoiNGcViF9DLYPYkc7sIj0+bRUeP397vCBtckyDKwtl7TwEtuEUdNtE/I4Hp+WH15bR/V2222WGdOese/mVy+rcIK8lscO+Hio4XZGJ+D9Aliw="
}'

The user of course should be logged in to have a valid accessToken to perform this operation.

Result of the previous endpoint will be the user wallet with the new inserted card, if that worked correctly:

{
  "wallet": [
    {
      "cardId": 1,
      "last4Digits": "0002",
      "nickname": "My Visa",
      "cardTypeId": "2",
      "cardStatusId": 1,
      "default": true,
      "expiryMonth": "12",
      "expiryYear": "19",
      "gateways": {
        "verifone": false,
        "adyen": true,
        "braintree": false,
        "cybersource": false,
        "smartpay": false
      }
    }
  ],
  "requestInfo": {
    "accessTokenStatus": "authenticated",
    "serverTime": 1518603361,
    "requestId": null,
    "apiVersion": 3
  }
}

Tokenizing a card for Cybersource

Tokenizing a card for Cybersource requires a slightly more complex flow, because involves 2 operations on your side.

Tokenization Flow Cybersource

1. Require the JWK data

First step of the operations is requiring a JWK data used by your app to obtain the tokenization URL and the required keyId. This operation stores the encryption key that will be used to decrypt the token generated before saving it in the database.

Call the following endpoint to start the flow:

curl "http://api.flypaythis.com/v2/payment/cybersource/keys?accessToken={accessToken}" 

The response is the following:

{
  "key": {
    "keyId": "08kEf6RTafGDnpP3O5CnUkDynIItsEw0",
    "jwk": {
      "kty": "RSA",
      "use": "enc",
      "kid": "08kEf6RTafGDnpP3O5CnUkDynIItsEw0",
      "n":
        "zM8XWdWtHralkY0SMYiCKNXj4dK41IR7f9YVyO-JxblV99Fs4kEzFJWPRYX_Y-La3uw1NFbbLbAuhQUPEoWqxJxIvL2zkn1MxMiMAt8jk_D261yUjoDInhlXT8t1A0Ahdj4bBlWnkszAAq6n97PQwe-EWii-iE1fZpbcYCwKlfERf4Zwxkrn5j3uT_RCO2uAkit4UYF3W1rp7OVVxtvPc86EsJN-jfeH-8zhBrQoC0ZBsmV535hOisx2oNas32VfOd2OVpE87lnvPGVZN6YA7pC3I3pYKURrz9N-qtI0QMWfmpGXYRmoN609eRpaQ3EWtBuduykAejK9AR-yv-HCKw",
      "e": "AQAB"
    }
  },
  "tokenisationUri":
    "https:\\/\\/testflex.cybersource.com\\/cybersource\\/flex\\/v1\\/tokens",
  "requestInfo": {
    "accessTokenStatus": "authenticated",
    "serverTime": 1518442362,
    "requestId": null,
    "apiVersion": 2
  }
}

The tokenisationUri is different accordingly to the environment used (staging or production). Different environment generates a different token, keep in mind for the next step.

2. Call the tokenization endpoint on Cybersource and store the card details on Flyt wallet

NOTE - This operation MUST be done using a HTTPS connection and directly from the Client Side application!

As it happens for Adyen, Cybersource provide APIs and SDKs to help you to tokenize a card and get the cybersourceToken that you need to pass to the wallet endpoint.

This resource can be found here. Two parameters from the previous call (to /v2/payment/cybersource/keys) are necessary at this step: the tokenisationUri and the keyId

By integrating this in your application, you should be able to generate a cybersourceToken that can be passed to the wallet in order to store the card token:

curl -X "POST" "https://api.flypaythis.com/v3/user/me/wallet/card/insert?accessToken={accessToken}" \\
     -H 'Content-Type: application/json' \\
     -d $'{
    "expiryMonth": 12,
  "expiryYear": 19,
  "first6Digits": "400000",
  "nickname": "My Visa",
  "save": true,
  "last4Digits": "0002",
  "default": true,
  "cybersourceToken": "eyJjYXJkVHlwZSI6IjAwMiIsImtleUlkIjoiMDRFc1hSajQ4Y1o5SWtnSTl6NGFMZmJFN1JBY1hIbFIiLCJzaWduYXR1cmUiOiJYYkY5cVh3eER3elZTUUZWWmo4aXRpNVI2ZURsc2V1TUs3M1VHa3Eyd1k3RmltQU9XaUl0SlNwUWZoXC90VG4zZXZpcU9wRjRhc0U2dGhwWjBwSkhBTjh1dVFUaTZKck13NmtsNlwvZ3ZvZU9qVElJUU4rVGZZOG1LaVQweHZVZFRHSENsQmlMTExGWmZEVFM4Szg1QTVtcmJaMjRHNVBDNGp6VUVPTVFDZU44UGV4RzEzZTJPd3FoaGszVnI1MzFcL0xErFU4a29aSU81RDlQRE5Lc2NBaFJkMzcyeThcL05NN0ttd2tlOFE4ZUNMcmNkbFpQbmhXWUlYMjBFalBsZEdzdmx3K2xMeGJNK2ZyRFhacndDNTFReWJmblZmbDRoRWV6UDMxbHBCQ2ZVVHh44GNJNGJNaEhiVG1oblUydENCOG94VkFhTjYzNk0yVHhNenZmTGgrUFpnPT0iLCJtYXNrZWRQYW4iOiI1MjUzMDNYWFhYWFgzNDM0IiwiZGlzY292ZXJhYmxlU2VydmljZXMiOnt9LCJ0b2tlbiI6IjUxODU0NDE1MzA3ODY3NTQ5MDM1OTMiLCJ0aW1lc3RhbXAiOjE1MTg1NDQxNTMxMzEsInNpZ25lZEZpZWxkcyI6InRva2VuLGNhcmRUeXBlLG1hc2tlZFBhbix0aW1lc3RhbXAiLCJfZW1iZWRkZWQiOnsiaWNzUmVwbHkiOnsicmVxdWVzdElkIjoiNTE4NTQ0MTUzMDc4Njc1NDkwMzU5Mi9sIl9saW5rcyI6eyJzZWxmIjp7ImhyZWYiOiJcL2N5YmVyc291cmNlXC9mbGV4XC9zZWFyY2hcL3YxXC9sb2dzXC90b2tlblByb3ZpZGVyXC81MTg1NDQxNTMwNzg2NzU0OTAzNTkzIn19fX19"
}'

The response will contain the details about the card been tokenized and ready to be used to make payments in locations setup with Cybersource:

{
  "wallet": [
    {
      "cardId": 1,
      "last4Digits": "0002",
      "nickname": "My Visa",
      "cardTypeId": "2",
      "cardStatusId": 1,
      "default": true,
      "expiryMonth": "12",
      "expiryYear": "19",
      "gateways": {
        "verifone": false,
        "adyen": false,
        "braintree": false,
        "cybersource": true,
        "smartpay": false
      }
    }
  ],
  "requestInfo": {
    "accessTokenStatus": "authenticated",
    "serverTime": 1518603361,
    "requestId": null,
    "apiVersion": 3
  }
}

The user wallet

Adding a card will return the user wallet with all the tokenized cards. Please note that if the tokanization for the different payment services happens at a different time, the wallet will show two cards, even if the card details are the same.

The wallet could be retrieved at any time by calling the endpoint:

curl "http://api.flypaythis.com/v1/user/me?scope=wallet&accessToken={accessToken}"

The response will be the user object containing the wallet:

{
  "user": {
    "userId": 1,
    "userStatus": 1,
    "dateCreated": 1518430040,
    "lastUpdated": 1518430040,
    "defaultCardId": 2,
    "wallet": [
      {
        "cardId": 1,
        "last4Digits": "0002",
        "nickname": "My Visa",
        "cardTypeId": "2",
        "cardStatusId": 1,
        "default": true,
        "expiryMonth": "12",
        "expiryYear": "19",
        "gateways": {
          "verifone": false,
          "adyen": true,
          "braintree": false,
          "cybersource": true,
          "smartpay": false
        }
      }
    ]
  },
  "requestInfo": {
    "accessTokenStatus": "authenticated",
    "serverTime": 1526397623,
    "requestId": null,
    "apiVersion": 1
  }
}

The gateway section of the response contains the details of which payment providers will support the token just generated.

Card statuses:

Card Status Description
1 Live
2 User Cancelled
3 System Cancelled
4 Temporary Card
5 Blocked due to fraud

Card types:

Card Type Description
0 Unknown
1 American Express
2 Visa
3 Mastercard
4 Apple Pay
5 Android Pay

FAQ

Can I tokenize a card for two payment gateways at the same time?

Yes, you can, just providing both adyenCse and cybersourceToken on the same request to wallet/card/insert, but the process to generate them will be the same. We actually encourage you to tokenize the card in all the supported gateway when the card details are entered in the application, because for PCI compliance we can't store the card details and generate a different token in a second time means that the user must re-insert his card details.

How do I know if I have to tokenize a card? And for which payment gateway?

Payments API will highlight this missing token when the endpoint /payments/v1/payment is called. The returned exception in this case is the following one:

{
  "error": true,
  "code": 404006,
  "message": "Payment card not tokenised.",
  "contextData": null,
  "displayString": null,
  "requestInfo": {
    "accessTokenStatus": "authenticated",
    "serverTime": 1518787025,
    "requestId": null,
    "apiVersion": 0
  }
}

In order to find out which token a location requires, get the location details and the payment gateway used by the location. That could be done by calling the

https://api.flypaythis.com/v1/location/{id}

endpoint and check the gateway under locationPaymentDetails field.

However, we always encourage to tokenize the card in all the supported payment gateways.