Link Search Menu Expand Document

The Flow

Table of contents
  1. Participants
    1. Merchant mobile/web application
    2. uSDK 7.X
    3. cAPI / Split SDK Server
    4. Merchant Backend
    5. 3DS Server
  2. The Callouts
    1. Callout #1 - The Authenticate method
      1. AuthenticateSpec
      2. AuthenticateCallback
      3. Complete Example (Android)
      4. Complete Example (Browser)
      5. Complete Example (iOS)
    2. Callout #2 - The Exhange Transaction Details request
    3. Callout #3 - The Exhange Transaction Details response
      1. ThreeDsData elements
    4. Callout #4 - The Transaction Result request
    5. Callout #5 - The Transaction Result response

Participants

The diagram below introduces the participants of the flow as well as their interactions. Note, the blue boxes represent the services/components that merchant is responsible to maintain while the white ones are provided by mSIGNIA - the cAPI Server, as well a normal 3DS Server provided by a 3DS Server vendor:

click here to open a bigger image

This diagram is referenced in other sections of the documentation so it is recommended to keep it around.

Merchant mobile/web application

This assumes that a merchant has one or more apps be it mobile apps or web sites. For mobile apps the merchant uses Android or iOS uSDK while for web sites the uSDK Browser is used.

uSDK 7.X

This is the uSDK the merchant downloads and integrates into its mobile and/or web applications.

cAPI / Split SDK Server

This server-side component is essentially a companion to the uSDK 7.X. The uSDK and the cAPI / Split SDK Server work as a whole abstracting the merchant from authentication protocols complexities. mSIGNIA usually provides this component to its uSDK customers. Please contact mSIGNIA administration for deployment options of the cAPI / Split SDK Server component.

Merchant Backend

This is a server-side component that merchant runs as a backend system. The cAPI / Split SDK Server calls it out in two cases:

  1. When it exchanges transaction data with the merchant - the Exchange Transaction Data callout
  2. When it notified the merchant about transaction completion - the Transaction Result callout

3DS Server

This is a usual 3DS Server that actually kicks off a 3DS transaction by forming an AReq and sending it over to a Directory Server.

The Callouts

There’re a couple of numbered callouts on the diagram, this section details them out.

Callout #1 - The Authenticate method

The uSDK has a public method called authenticate. This method is called by the merchant mobile or web application. Prior to that, the uSDK needs to be initialized as documented in the Obtaining and Installing section.

The authenticate method expects two arguments, the AuthenticateSpec as well as the AuthenticateCallback:

usdk.authenticate(authenticateSpec, authenticateCallback);

AuthenticateSpec

This argument is used to let merchant convey some configuration data for the uSDK to perform authentication:

Field Platform(s) Required Description
activity Android YES A referece to an Android Activity
iframeRef Browser YES The iFrame element reference for browser uSDK to operate within. Merchant Merchant app is responsible to creating an iFrame of certain size and make it visible before calling authenticate
viewController iOS YES A reference to a UIViewController
userId All NO User identifier, can be an email or any other ID
cardId All YES A card number identifier. This must NOT be the actual number. It has to be either a unique ID or four last digist of the actual one
orderId All YES An identifier of the order within merchant’s database. The uSDK sends it over to exhangeTransactionDetails and transactionResult on the merchant backend so it is possible to reconcile the order/purchase being authenticated.
splitSdkServerUrl All YES The URL for cAPI / SplitSDK Server for uSDK to use
exchangeTransactionDetailsUrl All YES The URL of exchangeTransactionDetails endpoint on merchant backend
transactionResultUrl All YES The URL of transactionResult endpoint on merchant backend
threeDsData All NO Additional 3DS related data passed from app. It will be conveyed to merchant backend via exchangeTransactionDetailsUrl call. See ThreeDsData Elements below for more details
merchantAuthInfo All NO An additional information that merchant would use to authenticate itself to SplitSDK Server. This is a way to convey an API KEY or stuff like that to SplitSDK Server backend.

AuthenticateCallback

This is a callback for uSDK to call when the authenticate method finishes. It is an interface with the following signature (a java/Android code snippet is used):

public interface AuthenticateCallback {
    void authenticated(AuthenticationResult authenticationResult);
    void notAuthenticated(AuthenticationResult authenticationResult);
    void decoupledAuthBeingPerformed(AuthenticationResult authenticationResult);
    void cancelled(AuthenticationResult authenticationResult);
    void error(AuthenticationResult authenticationResult);
}

The method names are self-descriptive. When authentication succeeds the uSDK calls the authenticated method back, when user cancelled a challenge flow, the uSDK calls cancelled and so on and so forth.

The AuthenticationResult should be inspected to get more details about the actual result. Here’s AuthenticationResult definition:

// Android
public class AuthenticationResult {
    private String splitSdkServerTransID;
    private String threeDSServerTransID;
    private TransStatus status;
    private String cardholderInfo;
    private ShellSdkException error;
}

// Browser (typescript)
export interface AuthenticationResult {
    splitSdkServerTransID?: string;
    threeDSServerTransID?: string;
    status?: string;
    cardholderInfo?: string;
    errorDescription?: string;
    errorCode?: string;
    errorDetails?: string
}

// iOS (Swift)
public struct AuthenticationResult: Decodable {
    public let threeDSServerTransID: String?
    public let splitSdkServerTransID: String?
    public let status: TransStatus?
    public let cardholderInfo: String?
    public let error: AuthenticationResult.Error?

    public struct Error: Decodable {
        public let errorCode: String
        public let errorDescription: String
        public let errorDetails: String?
    }
}

Complete Example (Android)

AuthenticateSpec authSpec = new AuthenticateSpec();
    authSpec.setActivity(this);
    authSpec.setUserId("pavlo-elrosado-demo@msignia.com");
    authSpec.setCardId("4533");
    authSpec.setOrderId("420e1eea-84d3-4f74-8c11-776cec65a047");
    authSpec.setSplitSdkServerUrl("https://my-split-sdk-server.com/split-sdk-client/v1");
    authSpec.setExchangeTransactionDetailsUrl("https://my-merchant.com/exchange-transaction-details");
    authSpec.setTransactionResultUrl("https://my-merchant.com/transaction-result");

    // OPTIONAL. More 3DS data can be passed to the uSDK. 
    // It then will be conveyed back to the `exchangeTransactionDetailsUrl` of merchant backend
    authSpec.setThreeDsData(new ThreeDsData()
          .acctID("96645-12-3456")
          .threeDSRequestorAppURL("https://merchant.app.com/oob-callback")
          // other data elements may go here
    );

    this.threeDS2Service.authenticate(authSpec, new AuthenticateCallback() {
    @Override
    public void authenticated(AuthenticationResult authenticationResult) {
        Log.i("APP", "authenticated: " + authenticationResult);
    }

    @Override
    public void notAuthenticated(AuthenticationResult authenticationResult) {
        Log.i("APP", "notAuthenticated: " + authenticationResult);
    }

    @Override
    public void decoupledAuthBeingPerformed(AuthenticationResult authenticationResult) {
        Log.i("APP", "decoupledAuthBeingPerformed: " + authenticationResult);
    }

    @Override
    public void cancelled(AuthenticationResult authenticationResult) {
        Log.i("APP", "cancelled: " + authenticationResult);
    }

    @Override
    public void error(AuthenticationResult authenticationResult) {
        Log.i("APP", "error: " + authenticationResult);
    }
    });

Complete Example (Browser)

const authenticateSpec = {
    userId: "pavlo-elrosado-demo@msignia.com",
    cardId: "4533",
    orderId: "420e1eea-84d3-4f74-8c11-776cec65a047",
    exchangeTransactionDetailsUrl: "https://my-merchant.com/exchange-transaction-details",
    transactionResultUrl: "https://my-merchant.com/transaction-result",
    iframeRef: document.getElementById('3ds-iframe'),
    splitSdkServerUrl: "https://my-split-sdk-server.com/split-sdk-client/v1",

    // OPTIONAL. More 3DS data can be passed to the uSDK. 
    // It then will be conveyed back to the `exchangeTransactionDetailsUrl` of merchant backend
    threeDsData: new ThreeDsData()
        .acctID("96645-12-3456")
        .threeDSRequestorAppURL("https://merchant.app.com/oob-callback")
        // other data elements may go here
};

const authenticateCallback = {
    authenticated: function (authenticationResult) {
        console.log('authenticated successfully! authenticationResult: ', authenticationResult);
    },
    notAuthenticated: function (authenticationResult) {
        console.log('not authenticated! authenticationResult: ', authenticationResult);
    },
    decoupledAuthBeingPerformed: function (authenticationResult) {
        console.log('decoupled authentication being performed! authenticationResult: ', authenticationResult);
    },
    cancelled: function (authenticationResult) {
        console.log('authentication cancelled! authenticationResult: ', authenticationResult);
    },
    error: function (authenticationResult) {
        console.log('authentication erred! authenticationResult ', authenticationResult);
    }
};

usdk.authenticate(authenticateSpec, authenticateCallback);

Note that for Browser, the merchant application has to provide a reference to an iFrame for the uSDK to work with. The iframe lifecycle is maintained by the merchant, so that is its responsibility to make the iframe right size, visible before authenticate method called as well as hide it when the callback from the uSDK is received. A sample iframe definition would look like this:

<iframe 
  name="my-iframe"
  sandbox="allow-forms allow-scripts allow-same-origin allow-pointer-lock"
  style="border: 1px lightgray dashed; width: 600px; height: 400px;"></iframe>

Complete Example (iOS)

@IBAction func authenticate(_ sender: Any) {    
    do {
        let authSpec = AuthenticateSpec(
            viewController: self,
            cardId: "420e1eea-84d3-4f74-8c11-776cec65a047",
            orderId: "4533",
            exchangeTransactionDetailsUrl: "https://my-merchant.com/exchange-transaction-details",
            transactionResultUrl: "https://my-merchant.com/transaction-result",
            splitSdkServerUrl: "https://my-split-sdk-server.com/split-sdk-client/v1",
            userId: "pavlo-elrosado-demo@msignia.com",

            // OPTIONAL. More 3DS data can be passed to the uSDK. 
            // It then will be conveyed back to the `exchangeTransactionDetailsUrl` of merchant backend
            threeDsData: ThreeDsData()
                .acctID("96645-12-3456")
                .threeDSRequestorAppURL("https://merchant.app.com/oob-callback")
                // other data elements may go here
            )

        try threeDS2Service.authenticate(spec: authSpec) { result in
            switch result {
                case .success(let authResult):
                    
                    switch authResult {
                        case .authenticated(let authenticationResult):
                            print("authenticated: \(authenticationResult)")
                        case .notAuthenticated(let authenticationResult):
                            print("notAuthenticated: \(authenticationResult)")
                        case .cancelled(let authenticationResult):
                            print("cancelled: \(authenticationResult)")
                        case .decoupledAuthBeingPerformed(let authenticationResult):
                            print("decoupledAuthBeingPerformed: \(authenticationResult)")
                        case .error(let authenticationResult):
                            print("notAuthenticated: \(authenticationResult)")
                    }
                case.failure(let error):
                    print("erred: \(error)")
            }
        }
    }
    catch {
      print("An exception caught during `authenticate` call: \(error)")
    }
}

Callout #2 - The Exhange Transaction Details request

The cAPI / SplitSDK Server sends an HTTP request to merchant backend using the URL provided to the uSDK via AuthenticateSpec.exchangeTransactionDetailsUrl field. The details of this request are these:

  1. URL: uses AuthenticateSpec.exchangeTransactionDetailsUrl field value
  2. Method: POST
  3. Content-type: application/json
  4. Body - a JSON document like shown below
{
  v: 1,
  orderId: "420e1eea-84d3-4f74-8c11-776cec65a047",	
  splitSdkServerTransId: "75f6f8ab-794e-4e24-95f2-3aee188a4408",
  // an object with device attributes as per 3DS specification
  threeDsData: {
    deviceInfo: { },
    acctID: "96645-12-3456"
  }
  userId: "john.doe@gmail.com"
}

Callout #3 - The Exhange Transaction Details response

Merchant Backend is replying to the Exhange Transaction Details request with a datum whose structure is shown below. Note the threeDsData data element, here the merchant should provide all necessary transaction and configuration information for the SplitSDK Server to form an initial request to send to a 3DS Server.

{
  v: 1,
  authentication: "3DS",
  threeDsData: {
    acctNumber: "532223423444234",
    deviceInfo: { },
    acctID: "96645-12-3456",
    threeDSRequestorChallengeInd: "03",
    threeDSRequestorID: "MC-99304",
    // and so on
  },
}

If merchant backend encounters an error its response is supposed to have non 2XX status code (40X, 50X are usually a good choice) in the following form:

{
  payload: {
    message: "Error message: i.e. Bad request received, a valid ID expected"
  }	
}

ThreeDsData elements

The threeDsData data element in the response should contain all required elements shown in the table below.

Data Element Required? Platform Description Sample/Format
threeDSRequestorAppURL N APP Merchant app declaring their URL within the CReq message so that the Authentication app can call the Merchant app after OOB authentication has occurred. String. Variable, maximum 256 characters 2 characters.
threeDSRequestorAuthenticationInd Y APP, BRW Indicates the type of Authentication request. 2 characters. 01 = Payment transaction, 02 = Recurring transaction, 03 = Instalment transaction, 04 = Add card, 05 = Maintain card, 06 = Cardholder verification as part of EMV token ID&V
threeDSRequestorAuthenticationInfo N APP, BRW    
threeDSRequestorChallengeInd N APP, BRW    
threeDSRequestorID (**) Y APP, BRW, 3RI DS assigned 3DS Requestor identifier.  
threeDSRequestorName (**) Y APP, BRW, 3RI DS assigned 3DS Requestor name.  
threeDSRequestorPriorAuthenticationInfo N APP, BRW, 3RI    
threeDSRequestorURL Y APP, BRW, 3RI Fully qualified URL of 3DS Requestor website or customer care site. String. Variable, maximum 2048 characters
threeRIInd Y 3RI Indicates the type of 3RI request. Not applicable for APP nor BRW  
acctType N APP, BRW, 3RI    
acquirerBIN (**) Y APP, BRW, 3RI Acquiring institution identification code as assigned by the DS receiving the AReq message  
acquirerMerchantID (**) Y APP, BRW, 3RI Acquirer-assigned Merchant identifier.  
addrMatch N APP, BRW Indicates whether the Cardholder Shipping Address and Cardholder Billing Address are the same. Length: 1 character. Y = match, N = not match
cardExpiryDate Y APP, BRW, 3RI Expiry Date of the PAN or token supplied to the 3DS Requestor by the Cardholder. Format: YYMM
acctInfo N APP, BRW, 3RI    
acctNumber Y APP, BRW, 3RI Account number that will be used in the authorisation request for payment transactions. String. Variable, 13–19 characters
acctID N APP, BRW, 3RI    
billAddrCity Y APP, BRW, 3RI   Variable, maximum 50 characters
billAddrCountry Y APP, BRW, 3RI   3 characters (ISO 3166-1)
billAddrLine1 Y APP, BRW, 3RI   Variable, maximum 50 characters
billAddrLine2 Y APP, BRW, 3RI   Variable, maximum 50 characters
billAddrLine3 Y APP, BRW, 3RI   Variable, maximum 50 characters
billAddrPostCode Y APP, BRW, 3RI   Variable, maximum 16 characters
billAddrState Y APP, BRW, 3RI Should be the country subdivision code defined in ISO 3166-2. 3 characters.
deviceInfo Y APP At minimum the merchant is supposed to return back the deviceInfo data element it received in Callout #2  
email Y APP, BRW, 3RI   Variable, maximum 254 characters
homePhone N APP, BRW, 3RI The home phone number provided by the Cardholder. See ThreeDsData section for more details
mobilePhone N APP, BRW, 3RI The mobile phone number provided by the Cardholder. See ThreeDsData section for more details
cardholderName Y APP, BRW, 3RI Name of the Cardholder. Variable, 2–45 characters
shipAddrCity Y APP, BRW, 3RI   Variable, maximum 50 characters
shipAddrCountry Y APP, BRW, 3RI   3 characters (ISO 3166-1)
shipAddrLine1 Y APP, BRW, 3RI   Variable, maximum 50 characters
shipAddrLine2 Y APP, BRW, 3RI   Variable, maximum 50 characters
shipAddrLine3 Y APP, BRW, 3RI   Variable, maximum 50 characters
shipAddrPostCode Y APP, BRW, 3RI   Variable, maximum 16 characters
shipAddrState Y APP, BRW, 3RI Should be the country subdivision code defined in ISO 3166-2. 3 characters.
workPhone Y if available APP, BRW, 3RI    
purchaseInstalData Y if available APP, BRW, 3RI Indicates the maximum number of authorisations permitted for instalment payments. Only for installments payments  
mcc (**) Y APP, BRW, 3RI DS-specific code describing the Merchant’s type of business, product or service. 4 characters
merchantCountryCode (**) Y APP, BRW, 3RI Country Code of the Merchant. 3 characters
merchantName (**) Y APP, BRW, 3RI Merchant name assigned by the Acquirer or Payment System Variable, maximum 40 characters
merchantRiskIndicator N APP, BRW, 3RI    
messageCategory Y APP, BRW, 3RI Identifies the category of the message for a specific use case. 2 characters. 01 = Payment, 02 = Non payment
purchaseAmount Y APP, BRW, 3RI Purchase amount in minor units of currency with all punctuation removed. Variable, maximum 48 characters. Examples: 12345
purchaseCurrency Y APP, BRW, 3RI Currency in which purchase amount is expressed. Numeric. 3 characters. See ISO 4217
purchaseExponent Y APP, BRW, 3RI Minor units of currency as specified in the ISO 4217 currency exponent. String. 1 character. ISO 4217
purchaseDate Y APP, BRW, 3RI Date and time of the purchase expressed in UTC. Format: YYYYMMDDHHMMSS
recurringExpiry Y if recurring APP, BRW, 3RI Date after which no further authorisations shall be performed. Format: YYYYMMDD
recurringFrequency Y if recurring APP, BRW, 3RI Indicates the minimum number of days between authorisations. Variable, maximum 4 characters
transType N APP, BRW, 3RI Identifies the type of transaction being authenticated. 2 characters. 01 = Goods/ Service Purchase, 03 = Check Acceptance, 10 = Account Funding, 11 = Quasi-Cash Transaction, 28 = Prepaid Activation and Load
whiteListStatus N APP, BRW, 3RI    
whiteListStatusSource N APP, BRW, 3RI    

Callout #4 - The Transaction Result request

When done authenticating the user, the cAPI / SplitSDK Server sends a request to merchant backend notifying it about the fact. Here’re the details of the request:

  1. URL: uses AuthenticateSpec.transactionResultUrl field value
  2. Method: POST
  3. Content-type: application/json
  4. Body - a JSON document like shown below.
{
  threeDSServerTransID: "420e1eea-84d3-4f74-8c11-776cec65a047",
  dsTransID: "b986150f-ed28-4fa1-bf3e-b4f17dc81dab",
  acsTransID: "01e59f17-cb9c-4c17-967b-6f1ed9cbea98",
  splitSdkServerTransId: "75f6f8ab-794e-4e24-95f2-3aee188a4408",
  transStatus: "Y",
  transStatusReason: "01", // may not present for certain transStatuses
  transStatusReasonInfo: "some string here", // may not present for certain transStatuses
  authenticationValue: "XXX", // may not present for certain transStatuses
  eci: "YYY" // may not present for certain transStatuses
}

Callout #5 - The Transaction Result response

Merchant, up on receiving the transaction result request is supposed to reply with any 200 response. A response with no body or with empty body or empty JSON document (i.e. a {}) is okay.