Source: transpayrent.js

/**
 * @copyright Transpayrent ApS 2021
 * @license Common Transpayrent API license
 * @version 1.0.0
 * 
 * @class
 * @classdesc   The Transpayrent SDK simplifies the [strong consumer authentication (SCA)]{@link https://en.wikipedia.org/wiki/Strong_customer_authentication} and [payment authorization]{@link https://en.wikipedia.org/wiki/Authorization_hold} through the consumer's browser
 * while handling [PCI DSS compliance]{@link https://www.pcisecuritystandards.org/}.
 * The SDK handles the secure communication with Transpayrent's Payment Gateway and orchestrates the integration into 3 simple steps for the scenarios summarized in the table below.
 * | Authorize Payment | Store Payment Card |
 * | ----------------- | ------------------ |
 * | The payment maybe be authorized for a payment transaction using the card details entered by the consumer in the following simple steps:  <ol><li>[Create a new payment transaction]{@link Transpayrent#createTransaction}</li><li>[Authenticate the consumer using 3D Secure or equivalent]{@link Transpayrent#authenticate}</li><li>[Authorize the payment for the payment transaction]{@link Transpayrent#authorize}</li></ol> | The consumer's payment card may be securely stored in Transpayrent's Secure Vault and added to the consumer's wallet in the following simple steps:  <ol><li>[Create a new payment transaction]{@link Transpayrent#createTransaction}</li><li>[Authenticate the consumer using 3D Secure or equivalent]{@link Transpayrent#authenticate}</li><li>[Save the consumer's payment card]{@link Transpayrent#save}</li></ol> |
 * 
 * ***Please note that the SDK is intended to communicate directly with Transpayrent's Payment Gateway to handle [PCI DSS compliance]{@link https://www.pcisecuritystandards.org/} for authentication and authorization.***  
 * 
 * The SDK handles the authentication by orchestrating the calls to several methods internally and automatically performing the following actions if required:
 *  * [Fingerprint the consumer's brower]{@link Transpayrent#fingerprint} in an invisible iframe
 *  * [Display an authentication challenge]{@link Transpayrent#displayChallenge} to the consumer in an iframe
 * 
 * The *look'n'feel* of the authentication challenge may be fully customized using [CSS]{@link https://en.wikipedia.org/wiki/CSS} simply by passing the appropriate iframe configuration when invoking the SDK's [authenticate]{@link Transpayrent#authenticate} method.  
 * The SDK includes methods for performing each part *(initialization, authentication and verification)* of the strong consumer authentication process but it's strongly recommended to use the [authenticate]{@link Transpayrent#authenticate} to orchestrate the process.  
 * 
 * The code sample below provides a complete illustration of how the payment page should use the SDK to create a new payment transaction, authenticate the consumer, securely store the payment card and authorize the payment using the stored card for a payment transaction.  
 * Please note that the sample assumes a payment session has already been created.
 * <font size="-2">
 * ```
 *  <script src="https://storage.googleapis.com/static.[ENVIRONMENT].transpayrent.cloud/v1/swagger-client.js"></script>
 *  <script src="https://storage.googleapis.com/static.[ENVIRONMENT].transpayrent.cloud/v1/transpayrent.js"></script>
 *  <script>
 *      var transpayrentConfig = {
 *          merchantId: [UNIQUE MERCHANT ID ASSIGNED BY TRANSPAYRENT],
 *          sessionId: [ID IN THE RESPONSE FROM "Create Payment Session"],
 *          accessToken: '[x-transpayrent-access-token HTTP HEADER IN THE RESPONSE FROM "Create Payment Session"]'
 *      };
 *      var url = 'https://generator.[ENVIRONMENT].transpayrent.cloud/v1/'+ transpayrentConfig.merchantId +'/system/PAYMENT_GATEWAY/sdk/CLIENT';
 *      var body = { correlation_id : 'TP-103645',
 *                   amount: { currency : 208,          // DKK
 *                             value : 100 } };
 *      var card = { payment_method_id: 109,            // VISA
 *                   card_number: 4111111111111111,     // Successful Authorization: Manual Challenge with browser fingerprint
 *                   expiry_month: 9,
 *                   expiry_year: 22,
 *                   cvv: 987,
 *                   card_holder_name: 'John Doe',
 *                   save: true };
 *      var address = { street : 'Arne Jacobsens Allé 7',
 *                      appartment : '5. sal',
 *                      city : 'Copenhagen S',
 *                      postal_code : '2300',
 *                      state : 'CO',
 *                      country: 208 };                 // Denmark
 *      var phone = { international_dialing_code: 45,   // Denmark
 *                    phone_number: 12345678 };
 *      var email = 'hello@transpayrent.dk';
 *      var save = { card : card,
 *                   consumer_id : '[MERCHANT'S CONSUMER ID FROM PAYMENT SESSION]',
 *                   name : "My VISA Card" }
 *      var ssoToken = '[MERCHANT'S SINGLE SIGN-ON TOKEN FOR AUTHORIZING A PAYMENT WITH THE CONSUMER'S WALLET]';
 *  
 *      var sdk = new Transpayrent(url, transpayrentConfig);
 * 
 *      // Create payment transaction for securely storing the consumer's payment card and add the stored card to the consumer's wallet
 *      sdk.createTransaction(card.payment_method_id, { amount: { currency : 208,   // DKK
 *                                                                value : 0 } })
 *      .then(
 *          transaction => {
 *              // Creation of Payment Transaction failed - Display status message
 *              if (transaction.status) {
 *                  alert('API: '+ transaction.api +' failed with HTTP Status Code: '+ transaction.status);
 *                  return Promise.reject(null);
 *              }
 *              else {
 *                  var body = { card : card,
 *                               billing_address : address,
 *                               shipping_address : address,
 *                               contact : { mobile : phone,
 *                                           work : phone,
 *                                           home : phone,
 *                                           email : email } };
 *                  var iframeConfig = { container : document.body,
 *                                       css: 'challenge',
 *                                       callback : function (event, iframe) {
 *                                           switch (event) {
 *                                               case 'authentication-challenge-initiated':
 *                                                   // DO SOMETHING BEFORE THE AUTHENTICATION CHALLENGE IS DISPLAYED
 *                                                   break;
 *                                               case 'authentication-challenge-completed':
 *                                                   // DO SOMETHING AFTER THE AUTHENTICATION CHALLENGE IS COMPLETE
 *                                                   break;
 *                                           }
 *                                      } };
 *                  return sdk.authenticate(transaction.id, body, iframeConfig);
 *              }
 *          })
 *      .then(
 *          authentication => {
 *              // Consumer Authentication failed
 *              if (authentication.status) {
 *                  // Consumer failed authentication challenge
 *                  if (authentication.status == 511) {
 *                      alert('Consumer failed authentication challenge for payment transaction: '+ authentication.transaction_id);
 *                  }
 *                  // API request failed - Display status message
 *                  else {
 *                      alert('API: '+ authentication.api +' failed with HTTP Status Code: '+ authentication.status);
 *                  }
 *                  return Promise.reject(null);
 *              }
 *              // Consumer Authentication succesfully completed
 *              else {
 *                  save.card.cryptogram = authentication.cryptogram;
 *                  return sdk.save(authentication.transaction_id, save);
 *              }
 *          })
 *      .then(
 *          save => {
 *              // Saving Payment Card failed - Display status message
 *              if (save.status) {
 *                  alert('API: '+ save.api +' failed with HTTP Status Code: '+ save.status);
 *                  return Promise.reject(null);
 *              }
 *              // Payment card succesfully saved and added to the consumer's wallet
 *              else {
 *                  var request = { payment_method_id: 201,            // Consumer Wallet
 *                                  valuable_id : save.valuable_id,
 *                                  access_token : ssoToken }
 *                  
 *                  // Create new transaction for authorizing a payment with the stored card
 *                  return sdk.createTransaction(request.payment_method_id, body)
 *                      .then(
 *                          transaction => {
 *                              // Creation of Payment Transaction failed - Display status message
 *                              if (transaction.status) {
 *                                  alert('API: '+ transaction.api +' failed with HTTP Status Code: '+ transaction.status);
 *                                  return Promise.reject(null);
 *                              }
 *                              // Authorize the payment for the payment transaction using the consumer's stored card
 *                              else {
 *                                  return sdk.authorize(transaction.id, request);
 *                              }
 *                          });
 *              }
 *          })
 *      .then(
 *          authorization => {
 *              // Payment Authorization failed - Display status message
 *              if (authorization.status) {
 *                  alert('API: '+ authorization.api +' failed with HTTP Status Code: '+ authorization.status);
 *              }
 *              // Payment Authorization completed - Display success message
 *              else {
 *                  alert('Payment transaction: '+ authorization.transaction_id +' successfully authorized');
 *              }
 *          })
 *      .catch(reason => {
 *          // Low level error - Display error message
 *          if (reason) {
 *              console.error(reason);
 *          }
 *      });
 *  </script>
 * ```
 * </font>
 * 
 * @see [SwaggerClient] {@link https://github.com/swagger-api/swagger-js#swagger-client-}
 * 
 * @constructor
 * @description Creates a new instance of the Transpayrent SDK, which simplifies the strong consumer authentication (SCA) and payment authorization through the consumer's browser.
 * @example <caption>Instantiate the Transpayrent SDK</caption>
 *  <script src="https://storage.googleapis.com/static.[ENVIRONMENT].transpayrent.cloud/v1/swagger-client.js"></script>
 *  <script src="https://storage.googleapis.com/static.[ENVIRONMENT].transpayrent.cloud/v1/transpayrent.js"></script>
 *  <script>
 *      var transpayrentConfig = {
 *          merchantId: [UNIQUE MERCHANT ID ASSIGNED BY TRANSPAYRENT],
 *          sessionId: [ID IN THE RESPONSE FROM "Create Payment Session"],
 *          accessToken: '[x-transpayrent-access-token HTTP HEADER IN THE RESPONSE FROM "Create Payment Session"]'
 *      };
 *      var url = 'https://generator.[ENVIRONMENT].transpayrent.cloud/v1/'+ transpayrentConfig.merchantId +'/system/PAYMENT_GATEWAY/sdk/CLIENT';
 *      var sdk = new Transpayrent(url, transpayrentConfig);
 *  </script>
 * 
 * @param {String} url           The URL pointing to the Payment Gateway's OpenAPI service definitions.
 * @param {BaseConfig} config    The base configuration for the API requests.

 */
function Transpayrent(url, config) {
    /**
     * Base configuration for all requests made to the Payment Gateway APIs.
     * 
     * @typedef {Object} BaseConfig
     * @property {Integer} merchantId   Transpayrent's unique ID for the merchant.
     * @property {Long} sessionId       Transpayrent's unique ID for the payment session that was returned as the `id` property in the response from the "Create Payment Session" API.
     * @property {String} accessToken   The access token for the payment session that was returned in the HTTP Header: `x-transpayrent-access-token` in the response from the "Create Payment Session" API.
     */
    /**
     * The base configuration for the API requests.
     *
     * @private
     *
     * @type {BaseConfig}
     */
    this._config = config;

    this._config.url = url;

    /**
     * The Swagger Client that was generated from the provided URL.
     * The client is used to interact with the Payment Gateway APIs defined using [Open API]{@link https://www.openapis.org}
     *
     * @private
     *
     * @type {SwaggerClient}
     */
    this._client = new SwaggerClient(url, { requestInterceptor: (request) => {
                                                if (!request.loadSpec) {
                                                    request.headers['authorization'] = 'Bearer '+ this._config.accessToken;
                                                }
                                            },
                                            responseInterceptor: (response) => {
                                                if (response.ok) {
                                                    // Update the API access token the refreshed token returned by the server
                                                    if (response.headers['x-transpayrent-access-token']) {
                                                        this._config.accessToken = response.headers['x-transpayrent-access-token'];
                                                    }
                                                }
                                                // API request failed
                                                else if (this._config.url != response.url) {
                                                    var body = response.body;
                                                    if (Array.isArray(body) == false) {
                                                        body = new Array(body);
                                                    }
                                                    if (body[0].system || body[0].status_code) {
                                                        response.ok = true;
                                                    }
                                                }
                                            },
                                        });
    
                                        
    /**
     * A representation of a status message returned by the Transpayrent Payment Gateway.
     * 
     * @see [StatusMessage](/v1/model/common/status-message/status-message_v1.yaml#/StatusMessage)
     * @see [SYSTEM](/v1/model/common/status-message/system_v1.yaml#/SYSTEM)
     * @see [STATUS_CODE](/v1/model/common/status-message/status-code_v1.yaml#/STATUS_CODE)
     * 
     * @typedef {Object} StatusMessage
     */
    /**
     * A status response returned by the Payment Gateway when an API request fails.
     * 
     * @typedef {Object} Status
     * @property {String} api               The Payment Gateway API that returned the message(s).
     * @property {Integer} status           The HTTP Status Code returned by the Payment Gateway.
     * @property {Array.<StatusMessage>} messages A list of messages returned by the Payment Gateway.
     */
    /**
     * Normalizes the status message(s) returned by the Transpayrent Payment Gateway into an object with the following properties:
     * 
     * @private
     * 
     * @param {String} api 
     * @param {Integer} status 
     * @param {Any} messages 
     * @returns {Status} A normalized object with the status message(s) returned by the Payment Gateway
     */
    Transpayrent.prototype._normalizeStatus = function (api, status, messages) {
        return { api : api,
                 status : status,
                 messages : Array.isArray(messages) ? messages : new Array(messages) };
    };

    /**
     * Constructs an iframe which sends an HTTP POST request to enable the Access Control Server (ACS) to fingerprint the consumer's browser.
     * 
     * @public
     * 
     * @param {String} url      The URL to the Access Control Server (ACS), which will create a fingerprint of the consumer's browser as part of the 3D Secure process for strong consumer authentication.
     * @param {String} data     The base64 encoded request data that must be sent to the Access Control Server (ACS).
     *                          The data will be sent to the ACS in the `threeDSMethodData` field for 3D Secure v2 and in the `pareq` field for 3D Secure v1.
     * @returns {HTMLIFrameElement} The constructed iframe element
     */
    Transpayrent.prototype.fingerprint = function (url, data) {
        var iframe = document.createElement('iframe');
        iframe.style.display = 'none';
        iframe.style.visibility = 'hidden';
        iframe.setAttribute('id', 'threeDSMethodIframe');
        iframe.setAttribute('name', 'threeDSMethodIframe');
        document.body.appendChild(iframe);
        var form = document.createElement('form');
        form.setAttribute('id', 'threeDSMethodForm');
        form.setAttribute('name', 'threeDSMethodForm');
        form.setAttribute('method', 'post');
        form.setAttribute('target', 'threeDSMethodIframe');
        form.setAttribute('action', url);
        var input = document.createElement('input');
        input.setAttribute('type', 'hidden');
        input.setAttribute('id', 'threeDSMethodData');
        input.setAttribute('name', 'threeDSMethodData');
        input.setAttribute('value', data);
        form.appendChild(input);
        document.body.appendChild(form);
        form.submit();
        
        return iframe;
    };
    
    /**
     * Configuration for the constructed iframe element which will be used to display the authentication challenge.
     * 
     * @example <caption>Example callback function</caption>
     *  function (event, iframe) {
     *      switch (event) {
     *          case 'authentication-challenge-initiated':
     *              // DO SOMETHING BEFORE THE AUTHENTICATION CHALLENGE IS DISPLAYED
     *              break;
     *          case 'authentication-challenge-completed':
     *              // DO SOMETHING AFTER THE AUTHENTICATION CHALLENGE IS COMPLETE
     *              break;
     *  }
     * 
     * @typedef {Object} IFrameConfig
     * @property {Element} container    The container element in which the constructed iframe will be displayed. Defaults to `document.body`.
     * @property {String} css           Optional CSS class(es) that will be applied to the constructed iframe.
     * @property {String} callback      An optional callback function which will be invoked just before the authentication challenge is initiated and just after the challenge is completed.
     *                                  The callback function accepts 2 arguments:
     *                                      - event: The event that triggered the callback, will be either `authentication-challenge-initiated` or `authentication-challenge-completed`
     *                                      - iframe: The constructed iframe that is used for the authentication challenge
     */
    /**
     * Constructs the iframe element for displaying the authentication challenges and attaches it inside the provided container element.
     * 
     * @public
     * 
     * @param {String} url          The URL to the Access Control Server (ACS) will use for the challenge during the strong consumer authentication (SCA) process.
     * @param {String} data         The base64 encoded request data that must be sent to the Access Control Server (ACS).
     *                              The data will be sent to the ACS in the `creq` field.
     * @param {IFrameConfig} config The configuration for the constructed iframe element
     * @returns {HTMLIFrameElement} The constructed iframe element
     */
    Transpayrent.prototype.displayChallenge = function (url, data, config) {
        if (!config.container) {
            config.container = document.body;
        }
        else {
            config.container.style.visibility = 'visible';
        }
        var iframe = document.createElement('iframe');
        if (config.css) {
            iframe.className = config.css;
        }
        iframe.setAttribute('id', 'challengeIframe');
        iframe.setAttribute('name', 'challengeIframe');
        config.container.appendChild(iframe);
        if (config.callback) {
            config.callback('authentication-challenge-initiated', iframe);
        }
        var form = document.createElement('form');
        form.setAttribute('id', 'challengeForm');
        form.setAttribute('name', 'challengeForm');
        form.setAttribute('method', 'post');
        form.setAttribute('target', 'challengeIframe');
        form.setAttribute('action', url);
        var input = document.createElement('input');
        input.setAttribute('type', 'hidden');
        input.setAttribute('id', 'creq');
        input.setAttribute('name', 'creq');
        input.setAttribute('value', data);
        form.appendChild(input);
        input = document.createElement('input');
        input.setAttribute('type', 'hidden');
        input.setAttribute('id', 'threeDSSessionData');
        input.setAttribute('name', 'threeDSSessionData');
        form.appendChild(input);
        document.body.appendChild(form);
        form.submit();

        return iframe;
    };

    /**
     * The unique id for the payment method (AMEX, MasterCard, VISA etc.).
     * Please refer to the [online documentation](/api-docs/index.html) for details on the object properties.
     * 
     * @see [PAYMENT_METHOD_ID](/v1/model/payment-gateway/payment-method/payment-method-id_v1.yaml#/PAYMENT_METHOD_ID)
     * 
     * @enum
     * @typedef {Enum} PAYMENT_METHOD_ID
     */
    /**
     * A representation of the consumer's payment transaction.
     * Please refer to the [online documentation](/api-docs/index.html) for details on the object properties.
     * 
     * @see [CreatePaymentTransactionRequest](/v1/model/payment-gateway/payment-transaction/payment-transaction_v1.yaml#/CreatePaymentTransactionRequest)
     * @see [Amount](/v1/model/common/amount/amount_v1.yaml#/Amount)
     * @see [CURRENCY](/v1/model/common/currency/currency_v1.yaml#/CURRENCY)
     * 
     * @typedef {Object} CreatePaymentTransactionRequest
     */
    /**
     * A simplified representation of the created payment transaction.
     * Please refer to the [online documentation](/api-docs/index.html) for details on the object properties.
     * 
     * @see [CreatePaymentTransactionResponse](v1/model/payment-gateway/payment-transaction/payment-transaction_v1.yaml#/CreatePaymentTransactionResponse)
     * @see [RecordEntityId](/v1/model/common/record-entity-id/record-entity-id_v1.yaml#/RecordEntityId)
     * 
     * @typedef {Object} CreatePaymentTransactionResponse
     */
    /**
     * Creates a new payment transaction through the Transpayrent Payment Gateway
     * by invoking the [Create Payment Transaction API](/webjars/swagger-ui/index.html?configUrl=/v3/api-docs/swagger-config#/payment_transaction_v1/create_payment_transaction).  
     * This is the 1st method that should be called by the payment page.
     * 
     * @public
     * @example <caption>Create a new payment transaction using the Transpayrent SDK</caption>
     *  var paymentMethodId = 108;                      // VISA
     *  var body = { correlation_id : 'TP-103645',
     *               amount: { currency : 208,          // DKK
     *                         value : 100 } };
     *  sdk.createTransaction(paymentMethodId, body)
     *  .then(
     *      transaction => {
     *          // Creation of Payment Transaction failed - Display status message
     *          if (transaction.status) {
     *              // HANDLE FAILURE
     *              return Promise.reject(null);
     *          }
     *          else {
     *              // AUTHENTICATE CONSUMER BY INVOKING METHOD: authenticate
     *          }
     *      })
     *  .catch(reason => {
     *      // Low level error - Display error message
     *      if (reason) {
     *          console.error('Internal error: '+ reason);
     *      }
     *  });
     * 
     * @param {PAYMENT_METHOD_ID} paymentMethodId       The unique id of the payment method which will be used to authorize the payment for the payment transaction.
     * @param {CreatePaymentTransactionRequest} body    A representation of the consumer's payment transaction.
     * @returns {CreatePaymentTransactionResponse|Status}
     */
    Transpayrent.prototype.createTransaction = function (paymentMethodId, body) {
        return this._client
            .then(
                client => {
                    var parameters = { merchant_id : this._config.merchantId,
                                       session_id : this._config.sessionId,
                                       payment_method_id : paymentMethodId };
                    return client.apis.payment_transaction_v1.create_payment_transaction(parameters, { requestBody : body });
                },
                // Error: Failed to load OpenAPI specification from url
                reason => {
                    console.error('Failed to load OpenAPI specification from url: '+ this._config.url +' due to: '+ reason);
                    return Promise.reject(reason);
                })
            .then(
                result => {
                    if (result.status == 201) {
                        return result.body;
                    }
                    // API request failed
                    else {
                        return this._normalizeStatus('create_payment_transaction', result.status, result.body);
                    }
                },
                // Low level error
                reason => {
                    reason.api = 'create_payment_transaction';
                    return Promise.reject(reason);
                });
    };

    /**
     * A representation of the payment details provided by the consumer for strong authentication of a payment transaction using 3D Secure or equivalent.
     * Please refer to the [online documentation](/api-docs/index.html) for details on the object properties.
     * 
     * @see [InitializeAuthenticationRequest](/v1/model/service-bus/consumer-authentication/initialize-authentication_v1.yaml#/InitializeAuthenticationRequest)
     * @see [PaymentCard](/v1/model/common/payment-details/payment-card_v1.yaml#/PaymentCard)
     * @see [PaymentDetails](/v1/model/common/payment-details_v1.yaml#/PaymentDetails)
     * @see [PAYMENT_METHOD_ID](#PAYMENT_METHOD_ID)
     * 
     * @typedef {Object} InitializeAuthenticationRequest
     */
    /**
     * A representation of the details required to progress the 3D Secure process for strong consumer authentication.
     * Please refer to the [online documentation](/api-docs/index.html) for details on the object properties.
     * 
     * @see [InitializeAuthenticationResponse](/v1/model/service-bus/consumer-authentication/initialize-authentication_v1.yaml#/InitializeAuthenticationResponse)
     * 
     * @typedef {Object} InitializeAuthenticationResponse
     */
    /**
     * Initializes strong consumer authentication for the specified payment transaction through the Transpayrent Payment Gateway using 3D secure or equivalent
     * by invoking the [Initialize Authentication For Transaction API](/webjars/swagger-ui/index.html?configUrl=/v3/api-docs/swagger-config#/consumer_authentication_v1/initialize_authentication_for_transaction).  
     * Calling this method directly is **not** recommended, instead call method: {@link Transpayrent#authenticate} to orchestrate the complete flow for strong consumer authentication (SCA).  
     * ***Please note that API calls made using this method falls under [PCI DSS]{@link https://www.pcisecuritystandards.org/}.***
     * 
     * @see {@link Transpayrent#authenticate}
     * 
     * @public
     * 
     * @param {Long} transactionId                          The unique id of the payment transaction for which strong consumer authentication using 3D secure or equivalent is required
     * @param {InitializeAuthenticationRequest} body     A representation of the payment details provided by the consumer for strong authentication of a payment transaction using 3D Secure or equivalent.
     * @returns {InitializeAuthenticationResponse|Status}
     */
    Transpayrent.prototype.initializeAuthentication = function (transactionId, body) {
        return this._client
            .then(
                client => {
                    var parameters = { merchant_id : this._config.merchantId,
                                       session_id : this._config.sessionId,
                                       transaction_id : transactionId };
                    return client.apis.consumer_authentication_v1.initialize_authentication_for_transaction(parameters, { requestBody : body });
                },
                // Error: Failed to load OpenAPI specification from url
                reason => {
                    console.error('Failed to load OpenAPI specification from url: '+ this._config.url +' due to: '+ reason);
                    return Promise.reject(reason);
                })
            .then(
                result => {
                    if (result.status == 200) {
                        return result.body;
                    }
                    // API request failed
                    else {
                        return this._normalizeStatus('initialize_authentication', result.status, result.body);
                    }
                },
                // Low level error
                reason => {
                    reason.api = 'initialize_authentication';
                    return Promise.reject(reason);
                });
    };
    
    /**
     * A representation of the entered payment details and details of the consumer's browser attributes required for strong authentication of a payment transaction using 3D Secure or equivalent.
     * Please refer to the [online documentation](/api-docs/index.html) for details on the object properties.
     * 
     * @see [AuthenticateConsumerRequest](/v1/model/service-bus/consumer-authentication/consumer-authentication_v1.yaml#/AuthenticateConsumerRequest)
     * @see [Browser](/v1/model/common/browser-details/browser-details_v1.yaml#/Browser)
     * @see [PaymentCard](/v1/model/common/payment-details/payment-card_v1.yaml#/PaymentCard)
     * @see [PaymentDetails](/v1/model/common/payment-details_v1.yaml#/PaymentDetails)
     * @see [PAYMENT_METHOD_ID](#PAYMENT_METHOD_ID)
     * @see [Address](/v1/model/common/address/address_v1.yaml#/Address)
     * @see [ContactDetails](/v1/model/common/contact-details/contact-details_v1.yaml#/ContactDetails)
     * @see [COUNTRY](/v1/model/common/country/country_v1.yaml#/COUNTRY)
     * @see [PhoneNumber](/v1/model/common/phone-number/phone-number_v1.yaml#/PhoneNumber)
     * @see [INTERNATIONAL_DIALING_CODE](/v1/model/common/international-dialing-code_v1.yaml#/INTERNATIONAL_DIALING_CODE)
     * @see [Email](/v1/model/common/email/email_v1.yaml#/Email)
     * 
     * @typedef {Object} AuthenticateConsumerRequest
     */
    /**
     * A representation of the successful authentication of the consumer for a payment transaction using 3D Secure.
     * The payment for the payment transaction should be authorized upon receiving a successful authentication result.  
     * Please refer to the [online documentation](/api-docs/index.html) for details on the object properties.
     * 
     * @see [AuthenticationSuccessResult](/v1/model/service-bus/consumer-authentication/authentication-result_v1.yaml#/AuthenticationSuccessResult)
     * @see [AbstractAuthenticationResult](/v1/model/service-bus/consumer-authentication/authentication-result_v1.yaml#/AbstractAuthenticationResult)
     * @see [AUTHENTICATION_TYPE](/v1/model/service-bus/consumer-authentication/authentication-type_v1.yaml#/AUTHENTICATION_TYPE)
     * @see [STATUS_CODE](/v1/model/common/status-message/status-code_v1.yaml#/STATUS_CODE)
     * 
     * @typedef {Object} AuthenticationSuccessResult
     */
    /**
     * A representation of an attempted authentication of the consumer for a payment transaction,
     * which requires the consumer to complete an additional authentication challenge as part of the strong consumer authentication process using 3D Secure.  
     * Please refer to the [online documentation](/api-docs/index.html) for details on the object properties.
     * 
     * @see [AuthenticationChallengeResult](/v1/model/service-bus/consumer-authentication/authentication-result_v1.yaml#/AuthenticationChallengeResult)
     * @see [AbstractAuthenticationResult](/v1/model/service-bus/consumer-authentication/authentication-result_v1.yaml#/AbstractAuthenticationResult)
     * @see [AUTHENTICATION_TYPE](/v1/model/service-bus/consumer-authentication/authentication-type_v1.yaml#/AUTHENTICATION_TYPE)
     * @see [STATUS_CODE](/v1/model/common/status-message/status-code_v1.yaml#/STATUS_CODE)
     * 
     * @typedef {Object} AuthenticationChallengeResult
     */
    /**
     * A representation of a failed authentication of the consumer for a payment transaction using 3D Secure.
     * The consumer should be informed of the authentication failure and asked to enter the details of another card upon
     * receiving a failure authentication result or the payment transaction should be abandoned so no authorization is attempted.  
     * Please refer to the [online documentation](/api-docs/index.html) for details on the object properties.
     * 
     * @see [AuthenticationFailureResult](/v1/model/service-bus/consumer-authentication/authentication-result_v1.yaml#/AuthenticationFailureResult)
     * @see [AbstractAuthenticationResult](/v1/model/service-bus/consumer-authentication/authentication-result_v1.yaml#/AbstractAuthenticationResult)
     * @see [AUTHENTICATION_TYPE](/v1/model/service-bus/consumer-authentication/authentication-type_v1.yaml#/AUTHENTICATION_TYPE)
     * @see [STATUS_CODE](/v1/model/common/status-message/status-code_v1.yaml#/STATUS_CODE)
     * 
     * @typedef {Object} AuthenticationFailureResult
     */
    /**
     * Authenticates the consumer of the specified payment transaction through the Transpayrent Payment Gateway using 3D secure or equivalent
     * by invoking the [Authenticate Consumer API](/webjars/swagger-ui/index.html?configUrl=/v3/api-docs/swagger-config#/consumer_authentication_v1/authenticate_consumer).   
     * Calling this method directly is **not** recommended, instead call method: {@link Transpayrent#authenticate} to orchestrate the complete flow for strong consumer authentication (SCA).  
     * ***Please note that API calls made using this method falls under [PCI DSS]{@link https://www.pcisecuritystandards.org/}.***
     * 
     * @see {@link Transpayrent#authenticate}
     * 
     * @public
     * 
     * @param {Long} transactionId                      The unique id of the payment transaction for which strong consumer authentication using 3D secure or equivalent is required
     * @param {AuthenticateConsumerRequest} body     A representation of the entered payment details and details of the consumer's browser attributes required for strong authentication of a payment transaction using 3D Secure or equivalent.
     * @returns {AuthenticationSuccessResult|AuthenticationChallengeResult|AuthenticationFailureResult|Status}
     */
    Transpayrent.prototype.authenticateConsumer = function (transactionId, body) {
        return this._client
            .then(
                client => {
                    var parameters = { merchant_id : this._config.merchantId,
                                       session_id : this._config.sessionId,
                                       transaction_id : transactionId,
                                       'user-agent' : '',
                                       accept : '' };
                    return client.apis.consumer_authentication_v1.authenticate_consumer_for_transaction(parameters, { requestBody : body });
                },
                // Error: Failed to load OpenAPI specification from url
                reason => {
                    console.error('Failed to load OpenAPI specification from url: '+ this._config.url +' due to: '+ reason);
                    return Promise.reject(reason);
                })
            .then(
                result => {
                    // Strong Consumer Authentication Success or Challenge
                    if (result.status == 200) {
                        result.body.transaction_id = transactionId;
                        return result.body;
                    }
                    // Strong Consumer Authentication Failure
                    else if (result.status == 511) {
                        result.body.transaction_id = transactionId;
                        result.body.status = result.status;
                        return result.body;
                    }
                    // // API request failed
                    else {
                        return this._normalizeStatus('authenticate_consumer', result.status, result.body);
                    }
                },
                // Low level error
                reason => {
                    reason.api = 'authenticate_consumer';
                    return Promise.reject(reason);
                });
    };
    
    /**
     * Retrieves the strong consumer authentication (SCA) result for the specified payment transaction through the Transpayrent Payment Gateway using 3D secure or equivalent.
     * The method will invoke the [Get Authentication Result For Transaction API](/webjars/swagger-ui/index.html?configUrl=/v3/api-docs/swagger-config#/consumer_authentication_v1/get_authentication_result_for_transaction).  
     * Please note that calling this method directly is **not** recommended, instead call method: {@link Transpayrent#authenticate} to orchestrate the complete flow for strong consumer authentication (SCA).  
     * 
     * @see {@link Transpayrent#authenticate}
     * 
     * @public
     * 
     * @param {Long} transactionId  The unique id of the payment transaction for which the strong consumer authentication using 3D secure or equivalent is required should be verified
     * @returns {AuthenticationSuccessResult|AuthenticationFailureResult|Status}
     */
    Transpayrent.prototype.getAuthenticationResult = function (transactionId) {
        return this._client
            .then(
                client => {
                    var parameters = { merchant_id : this._config.merchantId,
                                       session_id : this._config.sessionId,
                                       transaction_id : transactionId };
                    return client.apis.consumer_authentication_v1.get_authentication_result_for_transaction(parameters);
                },
                // Error: Failed to load OpenAPI specification from url
                reason => {
                    console.error('Failed to load OpenAPI specification from url: '+ this._config.url +' due to: '+ reason);
                    return Promise.reject(reason);
                })
            .then(
                result => {
                    // Strong Consumer Authentication Success
                    if (result.status == 200) {
                        result.body.transaction_id = transactionId;
                        return result.body;
                    }
                    // Strong Consumer Authentication Failure
                    else if (result.status == 511) {
                        result.body.transaction_id = transactionId;
                        result.body.status = result.status;
                        return result.body;
                    }
                    // // API request failed
                    else {
                        return this._normalizeStatus('get_authentication_result', result.status, result.body);
                    }
                },
                // Low level error
                reason => {
                    reason.api = 'get_authentication_result';
                    return Promise.reject(reason);
                });
    };

    /**
     * Convenience method for authenticating the consumer of the specified payment transaction through the Transpayrent Payment Gateway using 3D secure or equivalent.  
     * The method orchestrates each part *(initialization, authentication and verification)* of the strong consumer authentication process
     * by calling several methods internally in the SDK and automatically performs the following actions if required:
     *  * [Fingerprint the consumer's brower]{@link Transpayrent#fingerprint} in an invisible iframe
     *  * [Display an authentication challenge]{@link Transpayrent#displayChallenge} to the consumer in an iframe
     * 
     * The *look'n'feel* of the authentication challenge may be fully customized using [CSS]{@link https://en.wikipedia.org/wiki/CSS} simply by passing the appropriate iframe configuration as the 3rd argument to this method.  
     * This is the 2nd method that should be called by the payment page.  
     * Please note that:
     *  * Calling [createTransaction]{@link Transpayrent#createTransaction} should be done prior to calling this method to create a new payment transaction and obtain a transaction id
     *  * Calling this method is the recommended way to complete the strong consumer authentication (SCA) flow
     *  * The method will register [event listeners]{@link https://developer.mozilla.org/en-US/docs/Web/API/EventListener} and listen for the following events:
     *      * 3DS-authentication-complete
     *      * 3DS-fingerprint-complete
     *  * ***API calls made using this method falls under [PCI DSS]{@link https://www.pcisecuritystandards.org/}.***
     * 
     * @see {@link Transpayrent#initializeAuthentication}
     * @see {@link Transpayrent#authenticateConsumer}
     * @see {@link Transpayrent#getAuthenticationResult}
     * @see {@link Transpayrent#fingerprint}
     * @see {@link Transpayrent#displayChallenge}
     * 
     * @public
     * 
     * @example <caption>Authenticate consumer with 3D Secure or equivalent using the Transpayrent SDK</caption>
     *  var card = { payment_method_id: 108,            // VISA
     *               card_number: 4111111111111111,     // Successful Authorization: Manual Challenge with browser fingerprint
     *               expiry_month: 9,
     *               expiry_year: 22,
     *               cvv: 987,
     *               card_holder_name: "John Doe",
     *               save: true };
     *  var address = { street : 'Arne Jacobsens Allé 7',
     *                  appartment : '5. sal',
     *                  city : 'Copenhagen S',
     *                  postal_code : '2300',
     *                  state : 'CO',
     *                  country: 208 };                 // Denmark
     *  var phone = { international_dialing_code: 45,   // Denmark
     *                phone_number: 12345678 };
     *  var email = 'hello@transpayrent.dk';
     *  var body = { card : card,
     *               billing_address : address,
     *               shipping_address : address,
     *               contact : { mobile : phone,
     *                           work : phone,
     *                           home : phone,
     *                           email : email } };
     *  var iframeConfig = { container : document.body,
     *                       css: 'challenge',
     *                       callback : function (event, iframe) {
     *                           switch (event) {
     *                               case 'authentication-challenge-initiated':
     *                                   // DO SOMETHING BEFORE THE AUTHENTICATION CHALLENGE IS DISPLAYED
     *                                   break;
     *                               case 'authentication-challenge-completed':
     *                                   // DO SOMETHING AFTER THE AUTHENTICATION CHALLENGE IS COMPLETE
     *                                   break;
     *                           }
     *                       } };
     *  sdk.authenticate(transaction.id, body, iframeConfig);
     *  .then(
     *      authentication => {
     *          // Consumer Authentication failed
     *          if (authentication.status) {
     *              // Consumer Authentication failure
     *              if (authentication.status == 511) {
     *                  // HANDLE AUTHENTICATION FAILURE
     *                  return Promise.reject(null);
     *              }
     *              // API request failed - Display status message
     *              else {
     *                  // HANDLE COMMUNICATION ERROR
     *                  return Promise.reject(null);
     *              }
     *          }
     *          // Consumer Authentication succesfully completed
     *          else {
     *              // AUTHORIZE PAYMENT BY INVOKING METHOD: authorize
     *          }
     *      })
     *  .catch(reason => {
     *      // Low level error - Display error message
     *      if (reason) {
     *          console.error('Internal error: '+ reason);
     *      }
     *  });
     * 
     * @listens message:'3DS-fingerprint-complete'
     * @listens message:'3DS-authentication-complete'
     * 
     * @param {Long} transactionId                  The unique id of the payment transaction for which strong consumer authentication using 3D secure or equivalent is required
     * @param {AuthenticateConsumerRequest} body	A representation of the entered payment details required for strong authentication of a payment transaction using 3D Secure or equivalent.
     *                                              Please note that the `browser` property will be constructed automatically.
     * @param {IFrameConfig} config              	The configuration for the iframe which will be constructed in case the consumer needs to be presented with an authentication challenge
     * @returns {AuthenticationSuccessResult|AuthenticationFailureResult|Status}
     */
    Transpayrent.prototype.authenticate = function (transactionId, body, config) {
        body.device_channel_id = 2;	// Browser based 3D Secure authentication
        body.browser = { java_enabled : false,
                         javascript_enabled : true,
                         language : navigator.language,
                         color_depth : screen.colorDepth,
                         screen_height : screen.height,
                         screen_width : screen.width,
                         timezone_offset : new Date().getTimezoneOffset() };
        return this.initializeAuthentication(transactionId, { card : body.card })
            .then(
                result => {
                    // Failure while initializing strong consumer authentication (SCA) using 3D Secure
                    if (result.status) {
                        return result;
                    }
                    else {
                        // Fingerprint browser
                        if (result.acs_url) {
                            var _handler = function (resolver, iframe, event) {
                                if (event.data != null && event.data.toLowerCase() == '3ds-fingerprint-complete') {
                                    iframe.remove();
                                    resolver();
                                }
                            }
                            var resolver;
                            var promise = new Promise( (resolve, reject) => {
                                resolver = resolve;
                            });
                            setTimeout( () => { iframe.remove(); resolver(); }, 10000);
                            var iframe = this.fingerprint(result.acs_url, result.request_data);
                            window.addEventListener('message', _handler.bind(null, resolver, iframe), false);
                            return promise.then(r => this.authenticateConsumer(transactionId, body),
                                                e => e);
                        }
                        else {
                            return this.authenticateConsumer(transactionId, body);
                        }
                    }
                },
                // Low level error
                reason => Promise.reject(reason) )
            .then(
                authentication => {
                    // Consumer Authentication requires challenge
                    if (authentication.result && authentication.result == "C") {
                        var _handler = function (resolver, iframe, event) {
                            if (event.data != null && event.data.toLowerCase() == '3ds-authentication-complete') {
                                if (config.callback) {
                                    config.callback('authentication-challenge-completed', iframe);
                                }
                                iframe.remove();
                                resolver();
                            }
                        }
                        var resolver;
                        var promise = new Promise( (resolve, reject) => {
                            resolver = resolve;
                        });
                        var iframe = this.displayChallenge(authentication.acs_url, authentication.request_data, config);
                        window.addEventListener('message', _handler.bind(null, resolver, iframe), false);
                        return promise.then(r => this.getAuthenticationResult(transactionId),
                                            e => e);
                    }
                    // Consumer Authentication complete
                    else {
                        return authentication;
                    }
                },
                // Low level error
                reason => Promise.reject(reason) );
    };

    /**
     * A representation of a payment made using a payment card such as a MasterCard credit card or a VISA debit card.
     * Please refer to the [online documentation](/api-docs/index.html) for details on the object properties.
     * 
     * @see [PaymentCard](/v1/model/common/payment-details/payment-card_v1.yaml#/PaymentCard)
     * @see [PaymentDetails](/v1/model/common/payment-details_v1.yaml#/PaymentDetails)
     * @see [PAYMENT_METHOD_ID](#/PAYMENT_METHOD_ID)
     * 
     * @typedef {Object} PaymentCard
     */
    /**
     * A representation of the details for the successful authorization of a payment transaction.
     * Please refer to the [online documentation](/api-docs/index.html) for details on the object properties.
     * 
     * @see [AuthorizePaymentResponse](/v1/model/service-bus/payment-authorization/payment-authorization_v1.yaml#/AuthorizePaymentResponse)
     * @see [RecordEntityId](/v1/model/common/record-entity-id/record-entity-id_v1.yaml#/RecordEntityId)
     * @see [STATUS_CODE](/v1/model/common/status-message/status-code_v1.yaml#/STATUS_CODE)
     * 
     * @typedef {Object} AuthorizePaymentResponse
     */
    /**
     * Authorizes the payment for the specified payment transaction through the Transpayrent Payment Gateway using the provided payment details by 
     * invoking the [Authorize Payment For Transaction API](/webjars/swagger-ui/index.html?configUrl=/v3/api-docs/swagger-config#/authorize_payment_v1/authorize_payment_for_transaction).  
     * This is the 3rd method that should be called by the payment page when authorizing a payment without storing the consumer's payment card.  
     * Please note that:
     *  * Calling [authenticate]{@link Transpayrent#authenticate} should be done prior to calling this method to authenticate the consumer and obtain a cryptogram
     *  * Call [save]{@link Transpayrent#save} prior to calling this method to securely store the consumer's payment card in Transpayren's Secure Vault and add the stored payment card to the consumer's wallet
     *  * ***API calls made using this method falls under [PCI DSS]{@link https://www.pcisecuritystandards.org/}.***
     * 
     * @see {@link Transpayrent#authenticate}
     * 
     * @public
     * 
     * @example <caption>Authorize payment with payment card details using the Transpayrent SDK</caption>
     *  var card = { payment_method_id: 108,            // VISA
     *               card_number: 4111111111111111,     // Successful Authorization: Manual Challenge with browser fingerprint
     *               expiry_month: 9,
     *               expiry_year: 22,
     *               cvv: 987,
     *               card_holder_name: "John Doe",
     *               save: true,
     *               cryptogram : [CRYPTOGRAM RETURNED BY STRONG CONSUMER AUTHENTICATION] };
     *  sdk.authorize(authentication.transaction_id, card)
     *  .then(
     *      authorization => {
     *          // Payment Authorization failed - Display status message
     *          if (authorization.status) {
     *              // HANDLE AUTHORIZATION FAILURE
     *          }
     *          // Payment Authorization completed - Display success message
     *          else {
     *              // HANDLE AUTHORIZATION SUCCESS
     *          }
     *      })
     *  .catch(reason => {
     *      // Low level error - Display error message
     *      if (reason) {
     *          console.error('Internal error: '+ reason);
     *      }
     *  });
     * 
     * @example <caption>Authorize payment with stored payment card using the Transpayrent SDK</caption>
     *  var request = { payment_method_id: 201,            // Consumer Wallet
     *                  valuable_id: [VALUABLE ID RETURNED BY SDK METHOD: save] };
     *  sdk.authorize(save.transaction_id, request)
     *  .then(
     *      authorization => {
     *          // Payment Authorization failed - Display status message
     *          if (authorization.status) {
     *              // HANDLE AUTHORIZATION FAILURE
     *          }
     *          // Payment Authorization completed - Display success message
     *          else {
     *              // HANDLE AUTHORIZATION SUCCESS
     *          }
     *      })
     *  .catch(reason => {
     *      // Low level error - Display error message
     *      if (reason) {
     *          console.error('Internal error: '+ reason);
     *      }
     *  });
     *  
     * @param {Long} transactionId     The unique id of the payment transaction for which the payment should be authorized
     * @param {PaymentCard} card    A representation of a payment made using a payment card such as a MasterCard credit card or a VISA debit card
     * @returns {AuthorizePaymentResponse|Status}
     */
    Transpayrent.prototype.authorize = function (transactionId, card) {
        return this._client.then(
            client => {
                var parameters = { merchant_id : this._config.merchantId,
                                   session_id : this._config.sessionId,
                                   transaction_id : transactionId };
                var body = { payment_details : card };
                return client.apis.authorize_payment_v1.authorize_payment_for_transaction(parameters, { requestBody : body });
            },
            // Error: Failed to load OpenAPI specification from url
            reason => {
                console.error('Failed to load OpenAPI specification from url: '+ this._config.url +' due to: '+ reason);
                return Promise.reject(reason);
            })
            .then(
                result => {
                    if (result.status == 200) {
                        return result.body;
                    }
                    // API request failed
                    else {
                        return this._normalizeStatus('authorize_payment', result.status, result.body);
                    }
                },
                // Low level error
                reason => {
                    reason.api = 'authorize_payment';
                    return Promise.reject(reason);
                });
    };

    /**
     * A representation of the payment details for the payment instrument, such as a MasterCard credit card or a VISA debit card, which will be saved.
     * Please refer to the [online documentation](/api-docs/index.html) for details on the object properties.
     * 
     * @see [SaveConsumerValuableRequest](/v1/model/service-bus/consumer-valuable-storage/consumer-valuable-storage_v1.yaml#/SaveConsumerValuableRequest)
     * @see [PaymentCard](/v1/model/common/payment-details/payment-card_v1.yaml#/PaymentCard)
     * @see [PaymentDetails](/v1/model/common/payment-details_v1.yaml#/PaymentDetails)
     * @see [PAYMENT_METHOD_ID](#/PAYMENT_METHOD_ID)
     * 
     * @typedef {Object} SaveConsumerValuableRequest
     */
    /**
     * A representation of the details for successfully saving the provided payment card.
     * Please refer to the [online documentation](/api-docs/index.html) for details on the object properties.
     * 
     * @see [SaveConsumerValuableResponse](/v1/model/service-bus/consumer-valuable-storage/consumer-valuable-storage_v1.yaml#/SaveConsumerValuableResponse)
     * @see [RecordEntityId](/v1/model/common/record-entity-id/record-entity-id_v1.yaml#/RecordEntityId)
     * @see [STATUS_CODE](/v1/model/common/status-message/status-code_v1.yaml#/STATUS_CODE)
     * 
     * @typedef {Object} SaveConsumerValuableResponse
     */
    /**
     * Securely stores the provided payment instrument for the specified payment transaction into Transpayrent's Secure Vault
     * by invoking the [Save Consumer Valuable For Transaction API](/webjars/swagger-ui/index.html?configUrl=/v3/api-docs/swagger-config#/consumer_wallet_v1/save_consumer_valuable_for_transaction).  
     * The saved payment instrument is automatically added to the consumer's wallet if a consumerId is provided in the request or was specified for the Payment Session.  
     * This is the 3rd method that should be called by the payment page when storing the consumer's payment card.  
     * Please note that:
     *  * Calling [authenticate]{@link Transpayrent#authenticate} should be done prior to calling this method to authenticate the consumer and obtain a cryptogram
     *  * Merchants can only save a payment instrument for a payment transaction that is part of a payment session owned by the merchant
     *  * ***API calls made using this method falls under [PCI DSS]{@link https://www.pcisecuritystandards.org/}.***
     * 
     * @see {@link Transpayrent#authenticate}
     * 
     * @public
     * 
     * @example <caption>Save payment instrument using the Transpayrent SDK</caption>
     *  var card = { payment_method_id: 108,            // VISA
     *               card_number: 4111111111111111,     // Successful Authorization: Manual Challenge with browser fingerprint
     *               expiry_month: 9,
     *               expiry_year: 22,
     *               cvv: 987,
     *               card_holder_name: "John Doe",
     *               cryptogram : [CRYPTOGRAM RETURNED BY STRONG CONSUMER AUTHENTICATION] };
     *  var body = { card : card,
     *               consumer_id : "CID-12345",         // Defaults to the Consumer ID from the Payment Session if omitted
     *               name : "My VISA Card" }
     *  sdk.save(authentication.transaction_id, body)
     *  .then(
     *      save => {
     *          // Saving payment instrument failed - Display status message
     *          if (save.status) {
     *              // HANDLE SAVE FAILURE
     *          }
     *          // Payment instrument successfully saved
     *          else {
     *              // AUTHORIZE PAYMENT BY INVOKING METHOD: authorize
     *          }
     *      })
     *  .catch(reason => {
     *      // Low level error - Display error message
     *      if (reason) {
     *          console.error('Internal error: '+ reason);
     *      }
     *  });
     *  
     * @param {Long} transactionId                  The unique id of the payment transaction for which the payment card was authenicated
     * @param {SaveConsumerValuableRequest} body    The payment details for the payment card which will be securely stored in Transpayrent's Secure Valut and added to the consumer's wallet
     * @returns {SaveConsumerValuableResponse|Status}
     */
     Transpayrent.prototype.save = function (transactionId, body) {
        return this._client.then(
            client => {
                var parameters = { merchant_id : this._config.merchantId,
                                   session_id : this._config.sessionId,
                                   transaction_id : transactionId };
                return client.apis.consumer_wallet_v1.save_consumer_valuable_for_transaction(parameters, { requestBody : body });
            },
            // Error: Failed to load OpenAPI specification from url
            reason => {
                console.error('Failed to load OpenAPI specification from url: '+ this._config.url +' due to: '+ reason);
                return Promise.reject(reason);
            })
            .then(
                result => {
                    if (result.status == 200) {
                        result.body.transaction_id = transactionId;
                        return result.body;
                    }
                    // API request failed
                    else {
                        return this._normalizeStatus('save_consumer_valuable', result.status, result.body);
                    }
                },
                // Low level error
                reason => {
                    reason.api = 'save_consumer_valuable';
                    return Promise.reject(reason);
                });
    };
}