End-to-end FramePay integration
This topic describes how to implement:
- FramePay in a checkout page and use it to tokenize payments.
- A server-side controller to complete a purchase transaction.
This guide uses Node.js (Express) as the server-side language for the implementation.
1. Obtain IDs and API keys
When you first log in to Rebilly, you create an organization as part of the setup process. A default website is created when a new organization is created. For more information, see Organizations and websites.
Obtain your organization ID and website ID
- In the left navigation bar, press Settings .
- In the Management section, press My organization & websites.
- In the Organization details section, note the ID value.
- In the Website section, note the ID value.
Obtain your publishable API key
- In the left navigation bar, press Automations .
- In the Development section, press API keys.
- Optionally, if you have not created a publishable key:
- In top right of the screen, press Create API key.
- In the API key type section, select Publishable.
- Optionally, in the Organizations dropdown, select the organizations that can use the API key.
- Optionally, in the Allowed IPs field, enter the IP addresses that are permitted to use the API key.
- Press Save API key.
- Go to the API keys page.
- Select a publishable key and copy the Key value.
Obtain your secret API key
- In the left navigation bar, press Automations .
- In the Development section, press API keys.
- Optionally, if you have not created a secret key:
- In top right of the screen, press Create API key.
- In the API key type section, select Secret.
- Optionally, in the Organizations dropdown, select the organizations that can use the API key.
- Optionally, in the Allowed IPs field, enter the IP addresses that are permitted to use the API key.
- Press Save API key.
- Go to the API keys page.
- Select a secret key and copy the Key value.
2. Set up FramePay
This step describes how to:
- Use FramePay to tokenize payment card information.
- Set up a simple server using the Rebilly JS SDK.
- Complete a purchase transaction using the tokenized payment.
The codes described in this topic is available in the Rebilly framepay-integrated-example GitHub repository.
Set up the server
Install Rebilly JS SDK.
Install Rebilly JS SDK
Install the package, import it into your code, and then initialize it with your secret key and organization ID
To install, run:
yarn add rebilly-js-sdk@^46.4.0
For more information, see JS SDK quickstart guide.
Create a transaction
- Add an endpoint on your server that creates a transaction. This endpoint must receive the FramePay-generated token as the payload.
- Create a controller:
- Create a customer using the billing address and the payment token.
- Using the
customerId
, create asale
transaction.
Create a checkout page
Create a checkout page.
Include the FramePay stylesheet
This adds default styles to FramePay elements on the page.
Include the FramePay script
This exposes FramePay in the global JS scope as Framepay
.
Create your checkout form
FramePay automatically gathers data from your checkout form.
To enable this, you must use data-rebilly
attributes on your input fields.
Include the HTML mounting points
Add an empty div
to your checkout form.
This is where FramePay will render the card field by injecting an iframe.
Initialize FramePay
Initialize FramePay with a configuration object.
Provide your publishable API key, organization ID, and website ID to connect with the Rebilly API.
For more information, see FramePay configuration reference.
Optional: Style the card input
Customize the card payment field to match the look and feel of the rest of your form.
To customize, add the style
property in your configuration object.
For all available properties, see Style reference.
Mount the card field
After initialization, mount the payment card field. For more information, see:
Handle the form submit event
Listen to the form's submit event to determine when the user is ready to make the payment.
Create a payment token
To send the form data to FramePay, call Framepay.createToken()
.
- If the collected form data is valid, you will receive a successful result with a new payment token.
- If the collected form data is not valid, you will receive an error explaining why.
For more information, see Framepay.createToken(form).
Create a payment token
Once FramePay has returned the payment token, you are now able to complete the purchase.
To do this, make a request to the POST /create-transaction
endpoint.
Pass the token as part of the request payload, together with other properties.
Handle the API response
If no error occurs, inform your customer that the payment is successful. This example redirects the customer to a thank you (success) page, or to an approvalUrl
if it exists.
- checkout.html
- server.js
- client.js
- style.css
1<!DOCTYPE html>2<html>3 <head>4 <meta charset="UTF-8" />5 <title>End-to-end FramePay integration</title>6 <meta name="viewport" content="width=device-width, initial-scale=1" />78 <link href="https://framepay.rebilly.com/framepay.css" rel="stylesheet" />9 <script src="https://framepay.rebilly.com/framepay.js"></script>1011 <link href="./style.css" rel="stylesheet" />12 <script src="./client.js" defer></script>13 </head>14 <body>15 <div class="container">1617 <!-- Product Information -->18 <div class="product">19 <div class="product-name">20 Product name21 </div>22 <div class="product-total">23 $100.0024 </div>25 </div>2627 <!-- Payment form -->28 <form id="checkout-form" class="form">29 <div class="error-message hidden"></div>30 <div class="field">31 <input required data-rebilly="firstName" placeholder="First name" />32 </div>33 <div class="field">34 <input required data-rebilly="lastName" placeholder="Last name" />35 </div>36 <div class="field">37 <div id="mounting-point">38 </div>39 </div>40 <div class="action">41 <button>Make payment</button>42 </div>43 </form>4445 </div>46 </body>47</html>
1const RebillyAPI = require("rebilly-js-sdk").default;2const express = require("express");3const app = express();4const port = 3000;56app.use(express.static("client.js"));7app.use(express.json());89// Use your own secret key, organization and website id10const API_SECRET_KEY = "API_SECRET_KEY";11const ORGANIZATION_ID = "ORGANIZATION_ID";12const WEBSITE_ID = "WEBSITE_ID";1314const api = RebillyAPI({15 apiKey: API_SECRET_KEY,16 organizationId: ORGANIZATION_ID,17 sandbox: true,18});1920app.post("/create-transaction", async (req, res) => {21 try {22 const {23 paymentToken,24 billingAddress: primaryAddress,25 currency,26 amount,27 } = req.body;2829 const { fields: customer } = await api.customers.create({30 data: {31 paymentToken,32 primaryAddress33 },34 });3536 const { fields: transaction } = await api.transactions.create({37 data: {38 type: "sale",39 websiteId: WEBSITE_ID,40 customerId: customer.id,41 currency,42 amount,43 },44 });4546 res.status(201).send(transaction);47 } catch (error) {48 const message = err.details ?? "Internal Server Error";49 const code = err.status ?? 500;50 res.status(500).send({ code, message });51 }52});5354app.listen(port, () => {55 console.log(`App listening at port: ${port}`);56});
1Framepay.initialize({2 // Use your own publishable key:3 publishableKey: "pk_publishableKey",4 icon: {5 color: "#2c3e50",6 },7 style: {8 base: {9 fontSize: "16px",10 boxShadow: "none",11 },12 },13});1415const form = document.getElementById('checkout-form');16const errorMessageBox = document.querySelector(".error-message");17const btnSubmit = document.querySelector(".action button");1819Framepay.on("ready", function () {20 Framepay.card.mount("#mounting-point");21});2223form.addEventListener('submit', (e) => {24 e.preventDefault();25 e.stopPropagation();2627 try {28 btnSubmit.disabled = true;2930 const {id: paymentToken, billingAddress} = await Framepay.createToken(form);3132 const purchase = {33 paymentToken,34 billingAddress,35 currency: 'USD',36 amount: 100,37 }3839 const response = await fetch("/create-transaction", {40 method: "POST",41 headers: {42 "Content-Type": "application/json",43 },44 body: JSON.stringify(purchase),45 });4647 const transaction = await response.json();48 const approvalUrl = transaction?._links.find(({rel}) => rel === "approvalUrl");4950 if (approvalUrl) {51 window.location = approvalUrl.href;52 } else {53 window.location = "/thank-you.html";54 }55 } catch (error) {56 console.log(error);57 errorMessageBox.innerText = "Something went wrong, please try again.";58 errorMessageBox.classList.remove("hidden");59 } finally {60 btnSubmit.disabled = false;61 }62});
1/* Variables */2:root {3 --color-primary: #0044D4;4 --color-text: #2c3e50;5 --color-border: #ccc;6 --color-danger: #e74c3c;7}8* {9 box-sizing: border-box;10}1112body {13 color: var(--color-text);14 font: 16px -apple-system, Avenir, Helvetica, Arial, sans-serif;15 -webkit-font-smoothing: antialiased;16 background-color: #ffffff;17 margin: 0;18 padding: 0;19 background: #eee;20}21.container {22 max-width: 500px;23 width: 100%;24 background-color: #fff;25 padding: 30px 20px;26 margin: 40px auto;27 box-shadow: 0 0 30px rgba(0,0,0,0.1);28}2930/* Product information */31.product {32 display: flex;33 align-items: center;34 justify-content: space-between;35 margin-bottom: 20px;36}37.product-name {38 font-weight: 600;39 font-size: 18px;40}41.product-total {42 font-weight: bold;43 font-size: 24px;44}4546/* Form elements */47.error-message {48 margin-bottom: 20px;49 padding: 15px;50 background-color:var(--color-danger);51 text-align: center;52 font-weight: bold;53 color: #fff;54}55.form .field + .field,56.form .field + .action {57 margin-top: 10px;58}59.form input,60.form button {61 -webkit-appearance: none;62 -moz-appearance: none;63 appearance: none;64 outline: none;65 border-style: none;66}67.form input {68 border: none;69 font-size: 16px;70 margin: 0;71 outline: 0;72 padding: 15px 20px;73 width: 100%;74 color: var(--color-text);75 border: 1px solid var(--color-border);76}77.form input:focus {78 color: var(--color-text);79 border-color: var(--color-primary);80}81.form input::placeholder {82 color: #aaa;83}84.form button {85 display: block;86 padding: 15px;87 font-weight: bold;88 font-size: 18px;89 background: var(--color-primary);90 color: #fff;91 width: 100%;92 cursor:pointer;93}94.form button:disabled {95 opacity: 0.5;96}9798/* FramePay-specific styling */99.form .rebilly-framepay {100 padding: 15px 20px;101 height: 55px;102 border: 1px solid var(--color-border);103 border-radius: 0;104 box-shadow: none;105}106107.form .rebilly-framepay.rebilly-framepay-focus {108 color: var(--color-text);109 border-color: var(--color-primary);110 box-shadow: none;111}112113114/* Thank you page */115.thank-you {116 text-align: center;117}118119/* Helpers */120.hidden {121 display: none;122}123
Interactive example
This is an interactive example of an end-to-end FramePay integration, including a sample Express server file.