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.
attention
This guide uses Node.js (Express) as the server-side language for the implementation.
1. Obtain IDs and API keys
- Obtain your organization ID and website ID:
- In the left navigation bar, click
.
- Click My organization & websites.
- In the Organization info section, note the ID value.
- In the Website section, note the ID value. A website and organization is created automatically when you sign up to Rebilly. For more information, see Organizations and websites.
- In the left navigation bar, click
- Obtain your publishable API key:
- In the left navigation bar, click
, then click API keys.
- Optionally, if you have not created a publishable key:
- In top right of the screen, click Add API Key.
- In the API Key Type section, select Publishable, then complete the form and click Save API key.
- Go back to the API Keys page.
- Select a publishable key and copy the Key value.
- In the left navigation bar, click
- Obtain your secret API key:
- In the left navigation bar, click
, then click API keys.
- Optionally, if you have not created a secret key:
- In top right of the screen, click Add API Key.
- In the API Key Type section, select Secret, then complete the form and click Save API key.
- Go back to the API Keys page.
- Select a secret key and copy the Key value.
- In the left navigation bar, click
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.
attention
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 the package, import it in to your code, and then initialize 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
1. Add an endpoint on your server that creates a transaction. This endpoint must receive the FramePay-generated token as the payload
2. Create a controller:
- Create a customer using the billing address and the payment token.
- Using the
customerId
, createsale
transaction.
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 Rebilly
.
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
Create a payment token
To send the form data to FramePay, call Rebilly.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 Rebilly.createToken(form).
Create a payment token
Once FramePay has return 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.
- server.js
- checkout.html
- client.js
- style.css
1const RebillyAPI = require("rebilly-js-sdk").default;2const express = require("express");3const app = express();4const port = 3000;56app.use(express.static("client"));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 WEBISTE_ID = "WEBISTE_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 primaryAddress 33 },34 });3536 const { fields: transaction } = await api.transactions.create({37 data: {38 type: "sale",39 websiteId: WEBISTE_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});
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/rebilly.css" rel="stylesheet" />9 <script src="https://framepay.rebilly.com/rebilly.js"></script>1011 <link href="./style.css" rel="stylesheet" />12 <script src="./script.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>
1Rebilly.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");1819Rebilly.on("ready", function () {20 Rebilly.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 Rebilly.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");49 50 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}
Interactive example
This is an interactive example of an end-to-end FramePay integration, including a sample Express server file.