Multiple payment methods

This topic describes how to combine and use multiple payment methods in the one checkout form.

If you have not used FramePay previously, before you complete this tutorial, add FramePay to a form with one payment method in isolation. For tutorials, see Get started with FramePay.

For most payment methods, input mounting is not required, you only provide the method name when creating the token. However, some payment methods, such as: payment card and bank account, require inputs that must be mounted in your checkout form.

This topic describes how to set up your FramePay form to support 3 different payment methods:

  • Payment card (requires input mounting).
  • Bank account (requires input mounting).
  • PayPal (does not require input mounting).

1. Include FramePay

To enable FramePay, include the following line in your checkout page. This exposes the library in the global JS scope as Rebilly.

Copy
Copied
<script src="https://framepay.rebilly.com/rebilly.js"></script>
Automatic updates

Backward-compatible updates will be made available automatically without the need to change this URL.

2. Create your checkout form

2.1 Add customer information inputs to your form

FramePay automatically gathers data from your checkout form.

To enable this, you must use data-rebilly attributes on your input fields.

Create a basic customer information form:

Copy
Copied
<form>
    ...
    <!-- FramePay will automatically gather these input field's values. -->
    <input data-rebilly="firstName" placeholder="First Name">
    <input data-rebilly="lastName" placeholder="Last Name">
    ...
</form>

2.2 Add mounting points to your form

You have to add HTML elements for those payment methods that need input elements (payment card and bank account in this case).

Edit your checkout form to add those HTML elements with unique ids.

For example:

Copy
Copied
<form>
    ...
     <div id="payment-card"></div> 
    ...
    <label>Account Type</label>
    <div id="bank-account-type"/>
    
    <label>Account Number</label>
    <div id="bank-account-number"/>
    
    <label>Routing Number</label>
    <div id="bank-routing-number"/>
    ...
</form> 

If you enable multiple payment methods in your checkout form, you must detect which method your customer selects.

A common way to handle the selection of the payment method is to toggle the view between the different fields.

3. Initialize FramePay

In an earlier step, you included the rebilly.js script in your checkout page. In this step you will access the globally exposed Rebilly object to initialize it.

  1. If you do not have a sandbox API key, create one.
  2. Include the following line in the JS of your checkout page, and replace the publishableKey value with your API key:
Copy
Copied
Rebilly.initialize({
        // Use your own publishable key:
        publishableKey: 'pk_sandbox_Lvl5rm8lLrtAV6iSL3CIdYLAburumF4Ld8b1KDs',
});

You must replace the key pk_sandbox_Lvl5rm8lLrtAV6iSL3CIdYLAburumF4Ld8b1KDs with your own. We recommend starting with a sandbox key. To create a publishable key, check API keys section.

4. Mount elements

4.1 Payment card and bank account

After initializing, FramePay will emit a ready event.

Use Rebilly.on to listen to the ready event and determine when to mount the payment card and bank account elements:

Copy
Copied
 Rebilly.on('ready', function () {

    // mount payment card field
    Rebilly.card.mount('#payment-card');

    // mount the three separate bank account fields
    Rebilly.bban.mount('#bank-account-type', 'accountType');
    Rebilly.bban.mount('#bank-account-number', 'accountNumber');
    Rebilly.bban.mount('#bank-routing-number', 'routingNumber');
});

4.2 PayPal and other payment methods

Other payment methods, such as PayPal, do not require mounted elements.

5. Create the payment token

When a customer submits a valid FramePay form, use Rebilly.createToken(form, extraData) to create a payment token. In the second parameter (extraData), provide the method property, and use it to specify the payment method that is selected by the customer.

In this example, there are 3 possible method options (payment-card, ach, paypal):

JavaScriptJavaScriptJavaScript
Copy
Copied
    var extraData = {
        method: 'payment-card'
    };
    await Rebilly.createToken(form, extraData);
Copy
Copied
    var extraData = {
        method: 'ach'
    };
    await Rebilly.createToken(form, extraData);
Copy
Copied
    // Paypal method does not require elements within the form so you could pass null in the first parameter
    var extraData = {
        method: 'paypal'
    };
    await Rebilly.createToken(form, extraData);

Other payment methods

To use any other method supported by Rebilly just define its value when creating the payment token.

Copy
Copied
var extraData = {
    method: 'echeck'
};

Rebilly.createToken(form, extraData);

Interactive example

HTMLJavaScriptCSS
Copy
Copied
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Example 1</title>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link href="https://framepay.rebilly.com/rebilly.css" rel="stylesheet">
        <script src="https://framepay.rebilly.com/rebilly.js"></script>
    </head>
    <body>
        <div class="container">
            <div class="example-8">
                <form>
                    <fieldset>
                        <div class="field">
                            <label>First Name</label>
                            <input data-rebilly="firstName" name="field1" placeholder="John" type="text">
                        </div>
                        <div class="field">
                            <label>Last Name</label>
                            <input data-rebilly="lastName" name="field1" placeholder="Denver" type="text">
                        </div>
                        <div class="field">
                            <label>Email</label>
                            <input data-rebilly="emails" name="field2" placeholder="john.denver@example.com" type="text">
                        </div>
                    </fieldset>
                    <fieldset>
                        <label>Select your payment method</label>
                        <ul class="tab">
                            <li class="tab-item">
                                <a class="tab-link is-active" data-method="payment-card" href="#content-1">Credit Card</a>
                                <div class="tab-content-item is-active" id="content-1">
                                    <div class="field">
                                        <label>Payment Card</label>
                                        <div id="mounting-point"></div>
                                    </div>
                                </div>
                            </li>
                            <li class="tab-item">
                                <a class="tab-link" data-method="ach" href="#content-2">Bank Account</a>
                                <div class="tab-content-item" id="content-2">
                                    <div class="field">
                                        <label>Account Type</label>
                                        <div id="bank-account-type"></div>
                                    </div>
                                    <div class="field">
                                        <label>Account Number</label>
                                        <div id="bank-account-number"></div>
                                    </div>
                                    <div class="field">
                                        <label>Routing Number</label>
                                        <div id="bank-routing-number"></div>
                                    </div>
                                </div>
                            </li>
                            <li class="tab-item">
                                <a class="tab-link" data-method="paypal" href="#content-3"><img
                                        alt="paypal" src="/paypal.svg"></a>
                                <div class="tab-content-item" id="content-3"></div>
                            </li>
                            <li class="tab-item">
                                <a class="tab-link" data-method="bitcoin" href="#content-4"><img
                                        alt="bitcoin" src="/bitcoin.svg"></a>
                                <div class="tab-content-item" id="content-4"></div>
                            </li>
                            <li class="tab-item">
                                <a class="tab-link" data-method="China UnionPay" href="#content-5">China UnionPay</a>
                                <div class="tab-content-item" id="content-5"></div>
                            </li>
                        </ul>
                    </fieldset>
                    <button id="pay-now">Make Payment</button>
                </form>
            </div>
        </div>
        <link href="/examples/framepay-example-8-multiple.css" rel="stylesheet">
        <script src="/examples/framepay-example-8-multiple.js"></script>
    </body>
</html>
Copy
Copied
(function () {
    var selectedMethod;

    var tabListItems = document.querySelectorAll('.tab-link');
    var tabContent = document.querySelectorAll('.tab-content-item');

    var resetTabs = function resetTabs() {
        for (var i = 0; i < tabListItems.length; i++) {
            tabListItems[i].className = 'tab-link';
            if (tabContent[i]) {
                tabContent[i].className = 'tab-content-item';
            }
        }
    };

    var toggleTab = function tabs(event) {
        event.preventDefault();
        resetTabs();

        var target = event.target;
        var content = document.querySelector(target.getAttribute('href'));

        target.classList.add('is-active');
        if (content) {
            content.classList.add('is-active');
        }

        selectedMethod = target.getAttribute('data-method');
    };

    for (var i = 0; i < tabListItems.length; i++) {
        tabListItems[i].addEventListener('click', toggleTab, false);
    }

    var config = {
        publishableKey: 'pk_sandbox_Lvl5rm8lLrtAV6iSL3CIdYLAburumF4Ld8b1KDs',
        style: {
            buttons: {
                base: {
                    color: '#363636',
                    background: '#ffffff',
                    fontSize: '14px',
                    borderColor: '#dbdbdb',
                    height: '36px',
                    ':hover': {
                        background: '#ffffff',
                        borderColor: '#b5b5b5',
                    },
                },
                focus: {
                    background: '#ffffff',
                    borderColor: '#000000',
                },
                active: {
                    background: '#209cee',
                    borderColor: '#209cee',
                },
            },
        },
    };
    Rebilly.initialize(config);

    Rebilly.on('ready', function () {

        // mount framepay
        var card = Rebilly.card.mount('#mounting-point');
        var type = Rebilly.bankAccount.mount('#bank-account-type', 'bankAccountType');
        var number = Rebilly.bankAccount.mount('#bank-account-number', 'bankAccountNumber');
        var routing = Rebilly.bankAccount.mount('#bank-routing-number', 'bankRoutingNumber');
    });

    var form = document.querySelector('form');

    form.addEventListener('submit', function (e) {
        e.preventDefault();
        e.stopPropagation();

        var extraData = {
            // use the method selected by the customer
            method: selectedMethod,
        };

        Rebilly.createToken(form, extraData)
            .then(function (resp) {
                // we have a token field in the form
                // thus we can submit directly
                alert(JSON.stringify(resp, null, 2));
            })
            .catch(function (err) {
                alert(JSON.stringify(err, null, 2));
            });
    });
})();
Copy
Copied
html {
    height: 100%;
}

body {
    background-color: #ffffff;
    height: 100%;
    margin: 0;
}

.container {
    width: 100%;
    height: 100%;
    display: flex;
    border-radius: 8px;
    -webkit-box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1) inset;
    -moz-box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1) inset;
    box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1) inset;
    flex-direction: column;
    justify-content: center;
    align-items: center;
}

.example-8 {
    max-width: 500px;
    width: 100%;
    font-family: BlinkMacSystemFont, -apple-system, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
    padding: 20px;
    box-sizing: border-box;
    border-radius: 8px;
}

.example-8 * {
    font-family: BlinkMacSystemFont, -apple-system, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
}

.example-8 fieldset {
    border: none;
    margin: 0 0 40px 0;
    padding: 0;
}

.example-8 .field + .field {
    margin-top: 18px;
}

.example-8 label {
    display: block;
    margin-bottom: 12px;
    font-weight: bold;
}

.example-8 input,
.example-8 button {
    -webkit-appearance: none;
    -moz-appearance: none;
    appearance: none;
    outline: none;
    border-style: none;
}

.example-8 input {
    border: 1px solid #dbdbdb;
    border-radius: 4px;
    font-size: 15px;
    margin: 0;
    outline: 0;
    padding: 10px;
    width: 100%;
    box-sizing: border-box;
    -webkit-box-sizing: border-box;
    -moz-box-sizing: border-box;
    background-color: #ffffff;
    color: #8a97a0;
    -webkit-box-shadow: inset 0 1px 2px rgba(10, 10, 10, .1);
    -moz-box-shadow: inset 0 1px 2px rgba(10, 10, 10, .1);
    box-shadow: inset 0 1px 2px rgba(10, 10, 10, .1);
    -webkit-transition: all 0.4s;
    -o-transition: all 0.4s;
    -moz-transition: all 0.4s;
    transition: all 0.4s;
}

.example-8 input:focus {
    border-color: #3273dc;
    -webkit-box-shadow: 0 0 0 0.125em rgba(50, 115, 220, .25);
    -moz-box-shadow: 0 0 0 0.125em rgba(50, 115, 220, .25);
    box-shadow: 0 0 0 0.125em rgba(50, 115, 220, .25);
    color: #363636;
}

.example-8 input:-webkit-autofill {
    -webkit-text-fill-color: #000;
    transition: background-color 100000000s;
    -webkit-animation: 1ms void-animation-out;
}


.example-8 input::-webkit-input-placeholder {
    color: #8a97a0;
}

.example-8 input::-moz-placeholder {
    color: #8a97a0;
}

.example-8 input:-ms-input-placeholder {
    color: #8a97a0;
}

.tab {
    display: block;
}

.tab {
    margin: 0;
    padding: 0;
}

.tab .tab-item {
    width: 100%;
    list-style: none;
}

.tab .tab-item + .tab-item {
    margin-top: 4px;
}

.tab .tab-item .tab-link {
    display: block;
    background: #8a97a0;
    padding: 11px;
    color: #ffffff;
    text-decoration: none;
    text-align: center;
    border-radius: 4px;
    -webkit-transition: all 0.4s;
    -o-transition: all 0.4s;
    -moz-transition: all 0.4s;
    transition: all 0.4s;
}

.tab .tab-item .tab-link:hover {
    background: #2C3E50;
}

.tab .tab-item .tab-link.is-active {
    background: #2C3E50;
}

.tab .tab-item img {
    margin-top: 4px;
    max-height: 18px;
}

.tab-content-item {
    border: 0;
    clip: rect(0 0 0 0);
    height: 1px;
    overflow: hidden;
    position: absolute;
    opacity: 0;
    width: 1px;
    -webkit-transition: all 0.4s;
    -o-transition: all 0.4s;
    -moz-transition: all 0.4s;
    transition: all 0.4s;
}

.tab-content-item.is-active {
    clip: auto;
    height: auto;
    margin: auto;
    opacity: 1;
    overflow: visible;
    padding: 20px 0;
    position: relative;
    width: auto;
}

.example-8 button {
    position: relative;
    display: block;
    padding: 19px 39px 18px 39px;
    color: #FFF;
    margin: 0 auto;
    border-radius: 4px;
    background: #23d160;
    font-size: 18px;
    text-align: center;
    font-style: normal;
    width: 100%;
    -webkit-transition: all 0.4s;
    -o-transition: all 0.4s;
    -moz-transition: all 0.4s;
    transition: all 0.4s;
}

.example-8 button:hover {
    background: #20bc56;
    cursor: pointer;
}

.example-8 .rebilly-framepay {
    background: #ffffff;
    height: 40px;
    border: 1px solid #dbdbdb;
    padding: 0 10px;
    -webkit-box-shadow: inset 0 1px 2px rgba(10, 10, 10, .1);
    -moz-box-shadow: inset 0 1px 2px rgba(10, 10, 10, .1);
    box-shadow: inset 0 1px 2px rgba(10, 10, 10, .1);
    -webkit-transition: all 0.4s;
    -o-transition: all 0.4s;
    -moz-transition: all 0.4s;
    transition: all 0.4s;
}

.example-8 .rebilly-framepay.rebilly-framepay-focus {
    border-color: #3273dc;
    -webkit-box-shadow: 0 0 0 0.125em rgba(50, 115, 220, .25);
    -moz-box-shadow: 0 0 0 0.125em rgba(50, 115, 220, .25);
    box-shadow: 0 0 0 0.125em rgba(50, 115, 220, .25);
}

.example-8 .rebilly-framepay.rebilly-framepay-buttons {
    border: none;
    box-shadow: none;
    padding: 0;
}