ravelinjs Usage Guide

Getting Started

Ravelin provides a means of adding cards to Ravelin without having to handle PCI-compliant data. The library is intended to work on web pages where you have access to the PAN that the customer has entered. Passing through the encrypted values provided by this library avoids your servers handling any sensitive data, helping reduce the scope of your PCI compliance.

This is achieved through our publically available ravelinjs library which is responsible for performing the client-side encryption, as well as loading in Ravelin’s device tracking and session tracking functionality.

We recommend using ravelinjs in scenarios for which you are currently using the client-side encryption or client-side tokenisation features provided by your payment gateway. For scenarios in which payment details are captured within an iframe or a hosted payment form that contains iframe inputs, ravelinjs will not have access to the card details, and no effort should be made to attempt to circumvent the additional security these iframes provide.

Installing ravelinjs

The ravelinjs library can be used as a dependency in AMD modules; imported into scripts bundled using webpack; or by dropping a script tag into your web page.

We strongly advise reading our security recommendations before implementing ravelinjs to ensure any security risks involved in this process are minimised.

Installing as a dependency in AMD modules

src/index.html

...
    <script src="./common.js"></script>
    <script src="./require.js"></script>
    <script>
        require(['ravelin'], function(ravelin) {
            ravelin.setRSAKey('REDACTED');
            document.getElementById('form').onsubmit = function() {
                var month = document.getElementById('month');
                output(function() {
                    return ravelin.encrypt({
                        nameOnCard: document.getElementById('name').value,
                        pan: document.getElementById('number').value,
                        month: month.options[month.selectedIndex].value,
                        year: document.getElementById('year').value,
                    });
                });
                return false;
            };
        })
    </script>

Importing using webpack

src/index.js

import ravelin from './ravelin.js';
import output from './common.js';

ravelin.setRSAKey('REDACTED');
document.getElementById('form').onsubmit = function() {
    var month = document.getElementById('month');
    output(function() {
        return ravelin.encrypt({
            nameOnCard: document.getElementById('name').value,
            pan: document.getElementById('number').value,
            month: month.options[month.selectedIndex].value,
            year: document.getElementById('year').value,
        });
    });
    return false;
};

src/index.html

...
    <script src="bundle.js"></script>
...

Importing using a script tag

src/index.html

    ...
    <script src="./ravelin.js"></script>
    ...

Usage Guide

Required Variables

In order for ravelinjs to perform optimally and correctly associate events to specific customers and orders, several variables need to be set. These are described below:

Public API Key

Before any other methods are called, setPublicAPIKey() should be called with the publishable API key found in the Developer section of your account. This authenticates subsequent method calls to our API, and is therefore required.

If you are carrying out any testing, please ensure that the publishable API key from your Sandbox account is used.

Important: Please ensure that only the Publishable API key is used. The secret API key should never be used.

<script src="ravelin.min.js"></script>
<script>
    // Setting public API key
    ravelinjs.setPublicAPIKey("pk_live_...");
    ...
</script>

Public RSA Key

If card encryption is to be used, setRSAKey() needs to be called with the RSA key found in the Developer section of your account. If this is not present, please let us know and we can create one for you. The RSA public key that is set encrypts the PAN passed to the encrypt method.

<script src="ravelin.min.js"></script>
<script>
    // Setting RSA key
    ravelinjs.setPublicAPIKey("pk_live_...");
    ravelinjs.setRSAKey('10010|abc123...xyz789');
    ...
</script>

Device ID

When the public API key has been set, ravelinjs generates and stores a cookie containing the customer’s deviceID in the customer’s browser. Within this cookie is a field called ravelinDeviceId, which contains the deviceId that should be sent in requests to the Ravelin API for this customer.

In order for the cookie containing the customer’s deviceId to be valid for your domain name, setCookieDomain() should be called and set at as high a level as possible, e.g. mysite.com rather than subdomain.mysite.com.

<script src="ravelin.min.js"></script>
<script>
    // Setting cookie domain
    ravelinjs.setPublicAPIKey("pk_live_...");
    ravelinjs.setCookieDomain('mysite.com');
    ...
</script>

CustomerId

For Ravelin to associate tracked pages to specific clients, the customerId should be set using setCustomerId() before either of the tracking methods are called.

<script src="ravelin.min.js"></script>
<script>
    // Set customerId
    ravelinjs.setPublicAPIKey("pk_live_...");
    ravelinjs.setCustomerId("example@ravelin.com");
    ...
</script>

If the customerId is not known, for example if the customer is not logged in, then a temporary customerId can be set with setTempCustomerId().

<script src="ravelin.min.js"></script>
<script>
    // Set temporary customerId
    ravelinjs.setPublicAPIKey("pk_live_...");
    ravelinjs.setTempCustomerId("SESSION_12345");
    ...
</script>

As soon as a customerId is available, a (/v2/login) request should be sent that associates the tempCustomerId to the customerId:

{
    "timestamp": 1552400674,
    "customerId": "example@ravelin.com",
    "tempCustomerId": "SESSION_12345"
}

OrderId

For site activity to be associated to a particular order, setOrderId() should be called with the appropriate orderId before either of the tracking methods are called.

<script src="ravelin.min.js"></script>
<script>
    // Set orderId
    ravelinjs.setPublicAPIKey("pk_live_...");
    ravelinjs.setOrderId("order_12345");
    ...
</script>

Encrypting Cards

The primary goal of ravelinjs is to allow the secure sharing of card information with Ravelin without handling PCI-compliant data. Prior to calling ravelinjs.encrypt(), the RSA key from your developer dashboard should be set using the setRSAKey() method.

When this is set and card details are available, encrypt the values to send to Ravelin using ravelinjs.encrypt({pan, month, year, nameOnCard}).

pan, month, year are required, while nameOnCard is optional, and no other properties are allowed on the object. Validation is performed, confirming that expiry dates are valid, the PAN is at least 13 characters, and that no addition fields are present. Should any validation checks fail, an exception is raised.

For a worked example of how cards should be encrypted, please see the end-to-end example.

Browser Fingerprinting

A crucial part of device tracking with ravelinjs is the fingerprinting process, whereby information about the customer’s browser is extracted and sent to the Ravelin API. Ensure that the customerId is set before trackFingerprint() is called. If it is not set, it can also be set when calling trackFingerprint().

<script src="ravelin.min.js"></script>
<script>
    // Fingerprinting
    ravelinjs.setPublicAPIKey("pk_live_...");
    ravelinjs.setCustomerId("examplecustomer@ravelin.com")
    ravelinjs.trackFingerprint();

    // Setting customerId on method call:
    // ravelinjs.trackFingerprint("examplecustomer@ravelin.com")
    ...
</script>

Tracking Activity

Tracking Pages

The following code snippet demonstrates how Ravelin can be notified of the current page the customer is on. Typically we suggest this is called on page load on pages involved in the order flow – search result, basket, billing/payment and shipping info pages, and so on.

In order for Ravelin to associate the tracked page to a particular customer and order, ensure that setCustomerId() and setOrderId() are called if the customer and order IDs are known.

<script src="ravelin.min.js"></script>
<script>
    // Tracking
    ravelinjs.setPublicAPIKey("pk_live_...");
    ravelinjs.setCustomerId("examplecustomer@ravelin.com");
    ravelinjs.setOrderId("order_12345");
    ravelinjs.trackPage();
    ...
</script>

The track() method is similar to trackPage() but takes an additional parameter which can be used to set the name of the event being tracked. As with trackPage(), setCustomerId() and setOrderId() should be called first.

<script src="ravelin.min.js"></script>
<script>
    // Tracking
    ravelinjs.setPublicAPIKey("pk_live_...");
    ravelinjs.setCustomerId("examplecustomer@ravelin.com");
    ravelinjs.setOrderId("order_12345";
    ravelinjs.track('Checkout page');
    ...
</script>

Custom Events and Metadata

Both the track() and trackPage() methods can be passed a JSON object containing additional metadata about the page being tracked. This is particularly useful if the URL or page title provides basic information about the page being tracked.

<script src="ravelin.min.js"></script>
<script>
    // Tracking
    ravelinjs.setPublicAPIKey("pk_live_...");
    ravelinjs.track('CUSTOMER_SEARCHED', { searchTerm: 'product' });
    ...
</script>

End-To-End Example

In the following form, we collect card details from the customer, encrypt them and send the encrypted values (the ciphertext) back to your server.

<!-- Browser -->
<form id="form-payment-card">
    Card Number: <input name="pan" />
    CVV: <input name="cvv" />
    Name: <input name="nameOnCard" />
    Month: <input name="month" />
    Year: <input name="year" />
    <input type="hidden" name="ravelinCipherText" />
    <input type="submit" />
</form>

<script src="ravelin.min.js"></script>
<script>
    // Encryption
    ravelinjs.setRSAKey("..|.....")
    document.getElementById('form-payment-card').onsubmit = function() {

        this.ravelinCipherText.value = ravelinjs.encrypt({
            pan: this.pan.value,
            month: this.month.value,
            year: this.year.value,
            nameOnCard: this.nameOnCard.value,
        });

        // Avoid sending sensitive data to your server.
        this.pan.value = this.cvv.value = this.name.value = '';
    };
</script>

Once the ciphertext is received by your server, the API request to Ravelin in which a fraud recommendation is requested should use this ciphertext value:

/* Server-side */

var card = JSON.parse(form.getValue('ravelinCipherText'));
var action = request("https://api.ravelin.com/v2/checkout?score=true", {
    // ...
    "paymentMethod": card,
});