Single Card Enrollment

Introduction

Customers with personal cards or business cards not eligible for Commercial Card Bulk Enrollment can add their cards individually. Cardholders are required to complete a verification process to ensure they are the owner of the card when they link it.

This can be done either using Astrada's pre-built Card enrollment SDK, or you can alternatively build your own card enrollment UI using our API endpoints.

This page walks you through the process and steps that cardholders will take when linking cards through a Single Card Enrollment experience.

Single Card Enrollment Walkthrough

1. Customer Introduction

The first stage we recommend in any card enrollment journey is to clearly outline to your customers the scope of the data sharing they are about to consent to and any important information about how their data will be used.

This step improves user conversion by providing a feeling of trust and security.

2. Card Data Collection

The second stage of the card linking journey requires the collection of card data and consent. It is at this stage that a user provides you with their sensitive data and opts into the terms of the data sharing arrangement explicitly.

API Request

POST https://api.astrada.co/card-subscriptions
{
    "subaccountId": "<SUBACCOUNT_ID>",
    "country": "<ISSUING COUNTRY>",
    "expiryMonth": "<EXP_MONTH>",
    "expiryYear": "<EXP_YEAR>",
    "pan": "<CARD_NUMBER>",
    "cvc": "<CVC_NUMBER>",
    "cardholderName": "<HOLDER NAME>"
}

By making this call, you will be able to start the card enrollment process onto a specific Subaccount.

3. Start card verification

Card verification steps:

As mentioned here, this is the expected 3DS card verification flow:

  1. Device fingerprint is collected;
  2. Device fingerprint is transmitted to the issuer's Access Control System (ACS)
  3. Depending on issuer response a (3DS) challenge is required
    1. If the fingerprint is determined low risk, this skip is stepped. (Risk Assessment factors here)
    2. If the fingerprint is approved but higher risk, the challenge is initiated
    3. If the fingerprint fails, it is usually due to a lost/stolen card, an inactive card, or a card that is otherwise unable to transact.

Given that every card subscription created through Single Card Enrollment needs to be subject to card holder verification, you will have to subsequently make the call to start card verification:

API Request

POST https://api.astrada.co/card-verifications/3ds
{
    "subaccountId": "<SUBACCOUNT_ID>",
    "country": "<ISSUING COUNTRY>",
    "expiryMonth": "<EXP_MONTH>",
    "expiryYear": "<EXP_YEAR>",
    "pan": "<CARD_NUMBER>",
    "cvc": "<CVC_NUMBER>",
    "cardholderName": "<HOLDER NAME>"
}

As a successful result of this API call, you'll be returned with a Card Verification ID (id), which you'll use throughout the subsequent steps to understand the current card verification step.

In case you want to start card verification on an previously created subscription, you should also use this endpoint.

If at any given point in time you want to check the card verification status on a particular subscription, you can either make the GET Card Verification request, or a List a Card Verification steps (below)

GET https://api.astrada.co/card-verifications/3ds/{verificationId}
GET https://api.astrada.co/card-verifications/3ds/{verificationId}/steps

In most successful cases, the response for this request will direct the card holder verification to perform device fingerprint. This should be evident through the currentStep property in the response, with a link to the fingerprint step. If this is the case, follow steps outlined on step 3.1 below.

{
  "id": "9fab1bea-bc1e-4757-bd47-479422e5983b",
  "subaccountId": "f297d659-c13d-4219-aeaa-e10a845140a5",
  "cardId": "8309b5f8-d5d8-49bb-9001-38bf1bb0f1e4",
  "type": "3DS",
  "currentStepId": "fingerprint",
  "state": "completed",
  "createdAt": "2024-01-04T18:53:32.000Z",
  "updatedAt": "2023-01-04T10:55:12.000Z",
  "_links": {
    "self": {
      "href": "/card-verifications/3ds/9fab1bea-bc1e-4757-bd47-479422e5983b"
    },
    "steps": {
      "href": "/card-verifications/3ds/9fab1bea-bc1e-4757-bd47-479422e5983b/steps"
    },
    "currentStep": {
      "href": "/card-verifications/3ds/9fab1bea-bc1e-4757-bd47-479422e5983b/steps/fingerprint"
    }
  }
}

3.1 Device Fingerprint

As mentioned here, the card verification flow follows a 1 or 2 step process, depending on the risk appreciation of the 3DS provider (Issuer).

The first step is to attempt a frictionless verification flow by collating device and browser data to infer identity verification, known as Device Fingerprinting. In order to trigger this you will have to make the following API call:

GET https://api.astrada.co/card-verifications/3ds/{verificationId}/steps/fingerprint

Use the Card Verification ID (id) mentioned on step 3 above

{
  "id": "fingerprint",
  "subaccountId": "f297d659-c13d-4219-aeaa-e10a845140a5",
  "verificationId": "9fab1bea-bc1e-4757-bd47-479422e5983b",
  "type": "fingerprint",
  "state": "in-progress",
  "data": {
    "threeDSMethodData": "eyJ0aHJlZURTTWV0aG9kTm90aWZpY2F0aW9uVVJMIjoiaHR0cHM6Ly9zYW5kYm94LmFwaS5tYXN0ZXJjYXJkLmNvbS9vcGVuYXBpcy9hdXRoZW50aWNhdGlvbi9jYWxsYmFja3MvdGhyZWVEU01ldGhvZE5vdGlmaWNhdGlvbiIsInRocmVlRFNTZXJ2ZXJUcmFuc0lEIjoiOTNhN2NjNzUtY2I3Yy00Y2QzLWEwNTMtYjJjNGMxODZiZTVmIn0=",
    "threeDsMethodUrl": "https://acs-public.tp.mastercard.com/api/v1/3ds_method",
    "threeDSMethodNotificationURL": "https://sandbox.api.mastercard.com/openapis/authentication/callbacks/threeDSMethodNotification",
    "threeDSServerTransID": "93a7cc75-cb7c-4cd3-a053-b2c4c186be5f"
  },
  "createdAt": "2024-01-05T14:46:50.000Z",
  "updatedAt": "2024-01-05T14:46:51.000Z",
  "_links": {
    "self": {
      "href": "/card-verifications/9fab1bea-bc1e-4757-bd47-479422e5983b/3ds/steps/fingerprint"
    },
    "nextStep": {
      "href": "/card-verifications/9fab1bea-bc1e-4757-bd47-479422e5983b/3ds/steps/challenge"
    }
  }
}

You should use the data properties to open an iframe in the background, and collect the users browser information. This hidden iframe POSTS to ACS (Access Control System) and the response is a page that collects the device information and sends it to ACS. The fingerprint iframe posts a message to the window (threeDSMethodNotificationURL) when it is complete.

In order to do so, you should run a HTML code such as the one below:

<html>
    <head>
        <script src="/static/fingerprint.js"></script>
        <script>
            window.onload = function() {
                doFingerprint(
                    '{{ threeDsMethodUrl }}',
                    '{{ threeDSMethodNotificationURL }}',
                    '{{ threeDSMethodData }}',
                    '{{ threeDSServerTransID }}');
            }
        </script>
    </head>
</html>

On load calls the doFingerprint javascript function as such:

// This listener receives events from the window.
// On the arrival of threeds-method-notification event, it forwards 
// the required data to the server to start authentication.
function fingerprintCompleteListener(m) {
    if (m.data.type === 'threeds-method-notification') {
        console.log('fingerprintCompleteListener called');
        proceedAfterFingerprint('complete');
    }
};

Once fingerprinting is complete you need to send the browser details to the ACS, so that the ACS can correctly size the challenge iframe that will be prompted next.

You do so by making the following request:

POST https://api.astrada.co/card-verifications/3ds/{verificationId}/steps/fingerprint
{
   "fingerprintStatus":"unavailable",
   "browserData":{
      "colorDepth":24,
      "language":"en-US",
      "timezone":-120,
      "screenHeight":1080,
      "screenWidth":1920,
      "challengeWindowSize":"05",
      "javaEnabled":false,
      "acceptHeader":"application/json",
      "userAgent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36",
      "ip":"123.0.0.0"
   }
}

No further action: If the card verification provider and the card issuer feel this information is sufficient to successfully verify the cardholder, you should receive a response such as the one below, with an outcome set to completed (example below).

{
  "id": "fingerprint",
  "subaccountId": "f297d659-c13d-4219-aeaa-e10a845140a5",
  "verificationId": "9fab1bea-bc1e-4757-bd47-479422e5983b",
  "type": "fingerprint",
  "state": "completed",
  "outcome": "completed",
  "createdAt": "2024-01-05T14:46:50.000Z",
  "updatedAt": "2024-01-05T14:46:51.000Z",
  "_links": {
    "self": {
      "href": "/card-verifications/9fab1bea-bc1e-4757-bd47-479422e5983b/3ds/steps/fingerprint"
    },
    "nextStep": {
      "href": "/card-verifications/9fab1bea-bc1e-4757-bd47-479422e5983b/3ds/steps/challenge"
    }
  }
}

Challenge is required: If the card verification provider and the card issuer feel that they still need the card holder to perform a card verification challenge, then this should be evident in the response where the outcome says requires-challenge (example below).

If this is the case, follow the steps outlined in 3.2.

{
  "id": "fingerprint",
  "subaccountId": "f297d659-c13d-4219-aeaa-e10a845140a5",
  "verificationId": "9fab1bea-bc1e-4757-bd47-479422e5983b",
  "type": "fingerprint",
  "state": "completed",
  "outcome": "requires-challenge",
  "createdAt": "2024-01-05T14:46:50.000Z",
  "updatedAt": "2024-01-05T14:46:51.000Z",
  "_links": {
    "self": {
      "href": "/card-verifications/9fab1bea-bc1e-4757-bd47-479422e5983b/3ds/steps/fingerprint"
    },
    "nextStep": {
      "href": "/card-verifications/9fab1bea-bc1e-4757-bd47-479422e5983b/3ds/steps/challenge"
    }
  }
}

3.2 3DS Challenge

In some instances of single card enrollment where device fingerprinting information needs to be complemented with more data, the cardholder will need to provide this additional verification data to their issuer through the embedded iframe portal. The card holder will be prompted with a token-based challenge, which they will need to provide through this iframe.

When the token-based challenge is executed, it will go to the registered cardholder, generally in the form of a push notification on the issuer app, or text SMS.

The iframe is completely controlled by the card verification provider, and therefore it is expected that you use the URL that is provided by them (example below).

In order to retrieve the URL for the challenge iframe, you should use the Get Card Verification step challenge data endpoint, and use the acsUrl property nested under data.

GET https://api.astrada.co/card-verifications/3ds/{verificationId}/steps/challenge
{
  "id": "challenge",
  "subaccountId": "f297d659-c13d-4219-aeaa-e10a845140a5",
  "verificationId": "9fab1bea-bc1e-4757-bd47-479422e5983b",
  "type": "challenge",
  "state": "in-progress",
  "data": {
    "acsUrl": "https://acs-public.tp.mastercard.com/api/v1/browser_challenges",
    "encodedCReq": "eyJ0aHJlZURTU2VydmVyVHJhbnNJRCI6IjkzYTdjYzc1LWNiN2MtNGNkMy1hMDUzLWIyYzRjMTg2YmU1ZiIsImFjc1RyYW5zSUQiOiJiODBkNTZkNy01N2I1LTRhMzAtYmYwZC0xNzE4ZDlmNzI1ZTYiLCJjaGFsbGVuZ2VXaW5kb3dTaXplIjoiMDQiLCJtZXNzYWdlVHlwZSI6IkNSZXEiLCJtZXNzYWdlVmVyc2lvbiI6IjIuMi4wIn0"
  },
  "createdAt": "2024-01-05T14:46:51.000Z",
  "updatedAt": "2024-01-05T18:47:22.000Z",
  "_links": {
    "self": {
      "href": "/card-verifications/9fab1bea-bc1e-4757-bd47-479422e5983b/3ds/steps/challenge"
    }
  }
}

In order to display the 3DS challenge iframe, you should run a HTML code such as the one below.

<html>
    <head>
        <script src="/static/challenge.js"></script>
        <script>
            window.onload = function() {
                doChallenge('{{ acsUrl }}', '{{ encodedCReq }}');
            }
        </script>
    </head>
    <body>
        Performing 3DS challenge.
    </body>
</html>

On page load it calls doChallenge javascript function:

// This listener receives messages posted to the window. After listening 
// threeds-challenge-notification message, the challenge results window will pop-up.
function challengeCompleteListener(m) {
    if (m.data.type === 'threeds-challenge-notification') {
        console.log("challengeCompleteListener called");
        window.location = "/verify-authentication";
    }
};

// Opens 3DS challenge iframe and listens to event completion.
function doChallenge(acsUrl, encodedCReq) {

    const html = `<script>
            document.addEventListener("DOMContentLoaded", function () {
                var form = document.createElement("form");
                form.method = "POST";
                form.action = "${acsUrl}";
                form.appendChild(createInput("creq", "${encodedCReq}"));
                document.body.appendChild(form);
                form.submit();
                document.body.removeChild(form);
            });
            function createInput(name, value) {
                var result = document.createElement("input");
                result.name = name;
                result.value = value;
                return result;
            }
        </script>`

    const iframe = document.createElement("iframe");
    iframe.id = "3ds-challenge";
    iframe.width = "600px";
    iframe.height = "400px";
    iframe.frameBorder = "0";
    iframe.style.display = 'block';
    iframe.style.position = 'absolute';
    iframe.style.top = "100px";
    iframe.style.left = "50%";
    iframe.style.transform = "translate(-50%, 0%)";
    iframe.style.background = "white";
    document.body.appendChild(iframe);
    const win = iframe.contentWindow;

    if (win != null) {
        const doc = win.document;
        win.name = "3DS Challenge";
        doc.open();
        doc.write(html);
        doc.close();
    }

    window.addEventListener("message", challengeCompleteListener);
};


Once the challenge iframe is complete it posts a message to the window (threeDSMethodNotificationURL) to get the results of the challenge (step 5 below).

5. Success & Completion

Once the cardholder has successfully provided the challenge data to their issuer, a success state is returned.

In order to complete the Card verification you are expected to make the following API request, and check for the state property for either a completed or a failed state.

POST https://api.astrada.co/card-verifications/3ds/{verificationId}/steps/challenge
{
  "id": "challenge",
  "subaccountId": "f297d659-c13d-4219-aeaa-e10a845140a5",
  "verificationId": "9fab1bea-bc1e-4757-bd47-479422e5983b",
  "type": "challenge",
  "state": "completed",
  "createdAt": "2024-01-05T14:46:51.000Z",
  "updatedAt": "2024-01-05T18:47:22.000Z",
  "_links": {
    "self": {
      "href": "/card-verifications/9fab1bea-bc1e-4757-bd47-479422e5983b/3ds/steps/challenge"
    }
  }
}

Errors

Card Enrollment

ValidationMessage detail (API)Message detail (SDK)
Incorrect subaccount IdInvalid uuidSomething went wrong
Ineligible country of IssueRequest object failed validationSomething went wrong
Incorrect expiry dateAn unexpected error happened while creating a card subscriptionSomething went wrong
Incorrect / Invalid PANInvalid PANSomething went wrong
Incorrect / Invalid CVCCVC must be 3 or 4 digitsSomething went wrong
Card subscription already existsThere is already a card subscription for the specified cardYou're all set
Card not supportedInvalid PANSomething went wrong

Consent

What is Card Holder Consent?

Card holder consent refers to the approval a card holder gives to allow their transaction data to be accessed and used by third parties like Astrada. This consent is essential for complying with card network requirements and ensuring data security.

Why We Collect Consent

Contractual Requirement from Card Networks

Card networks mandate obtaining card holder consent to ensure that their transaction data is shared responsibly and ethically.

Through Astrada's APIs and SDK, card holders can opt in and authorize the sharing of their data. This opt-in process is crucial for Astrada and our customers to access such data legitimately.

Data Security and Best Practices

Collecting consent ensures that sensitive card holder data is not accessed or shared inappropriately, adhering to stringent data security standards.

How We Collect Consent

Astrada initiates the consent collection process when a customer enrolls a card for the first time.

Consent is gathered through a clear and conspicuous request, ensuring the card holder is fully informed and has the freedom to either consent or refuse. The request will explain the purpose of data collection and the specifics of how data will be used.

We use consent language approved by card networks to ensure uniformity and compliance (find here). This language is integrated into our card enrollment SDK by default.

Card holders must agree to Network-specific and Astrada-specific terms separately, ensuring clarity and compliance with privacy laws.

Upon receiving affirmative opt-in consent, Astrada verifies the identity of the card holder to ensure the consent is valid and associated with the correct individual.

We maintain detailed records of consents, including date and time stamps, to comply with legal requirements and for audit purposes.

By integrating with Astrada, our customers ensure that all data is fully compliant with both legal and network requirements.