Skip to main content

Elements

Learn how to receive payments through PayRex Elements by embedding a payment form in your application. The client and server-side code create a checkout form with PayRex Elements.

Checkout

1. Set up the server-side

Install the server-side SDK and initialize with your secret API key

Install the appropriate SDK for your programming language and import it. If we don't support your programming language yet, you may skip this step and use your preferred REST client.

  npm install payrex-node
create_payment_intent.js
// Protect your PayRex Secret API key at all costs. One common approach
// to store it in an environment variable.
// Add your PayRex test secret API key.
const payrexSecretApiKey = '';

const payrex = require('payrex-node')(payrexSecretApiKey);

// Create a PaymentIntent with amount and currency
const paymentIntent = await payrex.paymentIntents.create({
// Amount is in cents. The sample below is 100.00.
amount: 10000,
currency: 'PHP',
payment_methods: ['gcash', 'card'],
});

const output = {
clientSecret: paymentIntent.clientSecret,
}

console.log(JSON.stringify(output));

Create a payment intent

info

The example below creates a PaymentIntent via Ajax. If you prefer to create a payment intent before rendering your checkout page, you can adjust the code below.

Create a PaymentIntent on the server side. A PaymentIntent resource tracks the customer's payment lifecycle, identifying failed payment attempts and ensuring the customer is only charged once. In the response, return the PaymentIntent's client secret to finish the payment on the client.

After initializing the SDK with your secret API key, you must create a PaymentIntent. A PaymentIntent is a resource that manages your customer's payment lifecycle. It tracks all failed payment attempts and ensures your customer is charged correctly. Once a PaymentIntent is created, return the PaymentIntent's client_secret attribute in the response. The PaymentIntent's client_secret will be used on the client side, which is the next step of the integration process.

create_payment_intent.js
// Protect your PayRex Secret API key at all costs. One common approach
// to store it in an environment variable.
// Add your PayRex test secret API key.
const payrexSecretApiKey = '';

const payrex = require('payrex-node')(payrexSecretApiKey);

// Create a PaymentIntent with amount and currency
const paymentIntent = await payrex.paymentIntents.create({
// Amount is in cents. The sample below is 100.00.
amount: 10000,
currency: 'PHP',
payment_methods: ['gcash', 'card'],
});

const output = {
clientSecret: paymentIntent.clientSecret,
}

console.log(JSON.stringify(output));

2. Create a checkout page on the client-side.

Load Payrex.js

From the client side, load the PayRex javascript library called Payrex.js. This library helps you maintain compliance, such as PCI-DSS, by ensuring that payment information is not passed to your server but sent directly to PayRex.

About Payrex.js

Payrex.js domain is js.payrexhq.com, and you must load the javascript library from this domain. Do not store a copy of this javascript library.

CommonJS or ES6 modules

If you prefer CommonJS or ES6 modules when importing PayRex.JS, you can use our official library.

checkout.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="description" content="A demo application of PayRex payments product" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>PHP Demo Application for PayRex</title>
<link rel="stylesheet" href="checkout.css" />
</head>
<body>
<div class="container">
<button id="btn-pay" type="button" onClick="payAction()">
<div class="spinner hidden" id="spinner"></div>
<span id="btn-pay-text">Pay</span>
</button>
<div id="payment-element">
<!--Payrex.js will mount the Payment Element here. -->
</div>
</div>
<!-- Include PayRexJS script -->
<script type="text/javascript" src="https://js.payrexhq.com"></script>
<script type="text/javascript" src="checkout.js" defer></script>
</body>
</html>

Add a payment element placeholder div

Add an empty placeholder div within your checkout page where the Payment Element will be mounted. PayRex will insert the payment form to this placeholder div to collect payment information.

checkout.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="description" content="A demo application of PayRex payments product" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>PHP Demo Application for PayRex</title>
<link rel="stylesheet" href="checkout.css" />
</head>
<body>
<div class="container">
<button id="btn-pay" type="button" onClick="payAction()">
<div class="spinner hidden" id="spinner"></div>
<span id="btn-pay-text">Pay</span>
</button>
<div id="payment-element">
<!--Payrex.js will mount the Payment Element here. -->
</div>
</div>
<!-- Include PayRexJS script -->
<script type="text/javascript" src="https://js.payrexhq.com"></script>
<script type="text/javascript" src="checkout.js" defer></script>
</body>
</html>

Initialize Payrex.js

Once the payment form is created and Payrex.js is loaded, initialize Payrex.js with your public API key from the client side. You will use Payrex.js to create an instance of a Payment Element and complete the payment on the client.

checkout.js
// Add your PayRex Public API key.
const payrex = window.Payrex('');
let elements;

initialize();
checkPaymentIntentStatus();

async function payAction() {
showLoading(true)
await payrex.attachPaymentMethod({
elements,
options: {
// Return URL is where the customer will be redirected after completing a payment.
return_url: "http://localhost:4242/checkout.html",
},
});
showLoading(false)
}

function showLoading(flag) {
const btnPayText = document.querySelector("#btn-pay-text");
const spinner = document.querySelector("#spinner");

if (flag) {
// Disable the button and show a spinner
spinner.classList.remove("hidden");
btnPayText.classList.add("hidden");
} else {
spinner.classList.add("hidden");
btnPayText.classList.remove("hidden");
}
}

async function initialize() {
const {clientSecret} = await fetch(
"/create_payment_intent.php",
{
method: "POST",
}
).then((r) => r.json());

elements = payrex.elements({
clientSecret
});

const paymentElementOptions = {
layout: "accordion",
};

const paymentElement = elements.create(
"payment",
paymentElementOptions
);

paymentElement.mount("#payment-element");
}

// Fetches the payment intent status after payment submission
async function checkPaymentIntentStatus() {
const clientSecret = new URLSearchParams(window.location.search).get(
"payment_intent_client_secret"
);

if (!clientSecret) {
return;
}

const paymentIntent = await payrex.getPaymentIntent(clientSecret);

switch (paymentIntent.status) {
case "succeeded":
window.alert("Payment succeeded.")
break;
case "processing":
window.alert("Payment is still being processed.")
break;
case "awaiting_payment_method":
window.alert("Payment was not successful. Try again..")

break;
default:
window.alert("Something went wrong")

break;
}
}

Fetch the PaymentIntent from the server-side

Call the API endpoint you created from the server-side to create a PaymentIntent once your checkout page loads. The clientSecret attribute returned by your API endpoint completes the payment.

checkout.js
// Add your PayRex Public API key.
const payrex = window.Payrex('');
let elements;

initialize();
checkPaymentIntentStatus();

async function payAction() {
showLoading(true)
await payrex.attachPaymentMethod({
elements,
options: {
// Return URL is where the customer will be redirected after completing a payment.
return_url: "http://localhost:4242/checkout.html",
},
});
showLoading(false)
}

function showLoading(flag) {
const btnPayText = document.querySelector("#btn-pay-text");
const spinner = document.querySelector("#spinner");

if (flag) {
// Disable the button and show a spinner
spinner.classList.remove("hidden");
btnPayText.classList.add("hidden");
} else {
spinner.classList.add("hidden");
btnPayText.classList.remove("hidden");
}
}

async function initialize() {
const {clientSecret} = await fetch(
"/create_payment_intent.php",
{
method: "POST",
}
).then((r) => r.json());

elements = payrex.elements({
clientSecret
});

const paymentElementOptions = {
layout: "accordion",
};

const paymentElement = elements.create(
"payment",
paymentElementOptions
);

paymentElement.mount("#payment-element");
}

// Fetches the payment intent status after payment submission
async function checkPaymentIntentStatus() {
const clientSecret = new URLSearchParams(window.location.search).get(
"payment_intent_client_secret"
);

if (!clientSecret) {
return;
}

const paymentIntent = await payrex.getPaymentIntent(clientSecret);

switch (paymentIntent.status) {
case "succeeded":
window.alert("Payment succeeded.")
break;
case "processing":
window.alert("Payment is still being processed.")
break;
case "awaiting_payment_method":
window.alert("Payment was not successful. Try again..")

break;
default:
window.alert("Something went wrong")

break;
}
}

Initialize PayRex Elements

Initialize the PayRex Elements UI library with the PaymentIntent client secret. PayRex Elements manages the UI components that will help you collect payment details from your customers.

checkout.js
// Add your PayRex Public API key.
const payrex = window.Payrex('');
let elements;

initialize();
checkPaymentIntentStatus();

async function payAction() {
showLoading(true)
await payrex.attachPaymentMethod({
elements,
options: {
// Return URL is where the customer will be redirected after completing a payment.
return_url: "http://localhost:4242/checkout.html",
},
});
showLoading(false)
}

function showLoading(flag) {
const btnPayText = document.querySelector("#btn-pay-text");
const spinner = document.querySelector("#spinner");

if (flag) {
// Disable the button and show a spinner
spinner.classList.remove("hidden");
btnPayText.classList.add("hidden");
} else {
spinner.classList.add("hidden");
btnPayText.classList.remove("hidden");
}
}

async function initialize() {
const {clientSecret} = await fetch(
"/create_payment_intent.php",
{
method: "POST",
}
).then((r) => r.json());

elements = payrex.elements({
clientSecret
});

const paymentElementOptions = {
layout: "accordion",
};

const paymentElement = elements.create(
"payment",
paymentElementOptions
);

paymentElement.mount("#payment-element");
}

// Fetches the payment intent status after payment submission
async function checkPaymentIntentStatus() {
const clientSecret = new URLSearchParams(window.location.search).get(
"payment_intent_client_secret"
);

if (!clientSecret) {
return;
}

const paymentIntent = await payrex.getPaymentIntent(clientSecret);

switch (paymentIntent.status) {
case "succeeded":
window.alert("Payment succeeded.")
break;
case "processing":
window.alert("Payment is still being processed.")
break;
case "awaiting_payment_method":
window.alert("Payment was not successful. Try again..")

break;
default:
window.alert("Something went wrong")

break;
}
}

[OPTIONAL] Override the style of payment element

PayRex Elements allows you to match the color branding of your application so that the payment form looks like a part of your website. Suppose you want to override the default color of the payment form. In that case, you can add the style attribute when initializing an Element object.

checkout.js
// redacted code

async function initialize() {
const {clientSecret} = await fetch(
"/create_payment_intent.php",
{
method: "POST",
}
).then((r) => r.json());

elements = payrex.elements({
clientSecret: clientSecret,
style: {
variables: {
// Replace the hexadecimal color with your brand color
primaryColor: '#F63711'
}
}
});

// redacted code

Create an instance of a Payment Element

Create an instance of Payment Element and mount it to the placeholder <div> on your checkout page. This embeds a payment form, allowing your customer to select a payment method. The payment form collects the payment details for the selected payment method.

checkout.js
// Add your PayRex Public API key.
const payrex = window.Payrex('');
let elements;

initialize();
checkPaymentIntentStatus();

async function payAction() {
showLoading(true)
await payrex.attachPaymentMethod({
elements,
options: {
// Return URL is where the customer will be redirected after completing a payment.
return_url: "http://localhost:4242/checkout.html",
},
});
showLoading(false)
}

function showLoading(flag) {
const btnPayText = document.querySelector("#btn-pay-text");
const spinner = document.querySelector("#spinner");

if (flag) {
// Disable the button and show a spinner
spinner.classList.remove("hidden");
btnPayText.classList.add("hidden");
} else {
spinner.classList.add("hidden");
btnPayText.classList.remove("hidden");
}
}

async function initialize() {
const {clientSecret} = await fetch(
"/create_payment_intent.php",
{
method: "POST",
}
).then((r) => r.json());

elements = payrex.elements({
clientSecret
});

const paymentElementOptions = {
layout: "accordion",
};

const paymentElement = elements.create(
"payment",
paymentElementOptions
);

paymentElement.mount("#payment-element");
}

// Fetches the payment intent status after payment submission
async function checkPaymentIntentStatus() {
const clientSecret = new URLSearchParams(window.location.search).get(
"payment_intent_client_secret"
);

if (!clientSecret) {
return;
}

const paymentIntent = await payrex.getPaymentIntent(clientSecret);

switch (paymentIntent.status) {
case "succeeded":
window.alert("Payment succeeded.")
break;
case "processing":
window.alert("Payment is still being processed.")
break;
case "awaiting_payment_method":
window.alert("Payment was not successful. Try again..")

break;
default:
window.alert("Something went wrong")

break;
}
}

[OPTIONAL] Providing default values in billing information

Suppose you already have the customer's billing information in your system and want to speed up the payment process. In that case, you can add the' defaultValues' attribute to supply default values to the payment element.

checkout.js
  // redacted code

const paymentElementOptions = {
layout: "accordion",
defaultValues: {
billingDetails: {
name: "John Smith",
phone: "+639170000000",
email: "johnsmith@somedomain.com",
address: {
line1: "Address Line 1",
line2: "Address Line 2",
country: "PH",
city: "Address City",
state: "Address State",
postalCode: "1902",
},
},
},
};

// redacted code

3. Complete the payment on the client

For test cards, you can refer to this guide.

Handle the submit event of the pay button

Listen to your pay button's onClick event and attach a PaymentMethod resource to the PaymentIntent through the PayRex API. If you prefer to listen to a form-submit event, it could be your alternative approach.

checkout.js
// Add your PayRex Public API key.
const payrex = window.Payrex('');
let elements;

initialize();
checkPaymentIntentStatus();

async function payAction() {
showLoading(true)
await payrex.attachPaymentMethod({
elements,
options: {
// Return URL is where the customer will be redirected after completing a payment.
return_url: "http://localhost:4242/checkout.html",
},
});
showLoading(false)
}

function showLoading(flag) {
const btnPayText = document.querySelector("#btn-pay-text");
const spinner = document.querySelector("#spinner");

if (flag) {
// Disable the button and show a spinner
spinner.classList.remove("hidden");
btnPayText.classList.add("hidden");
} else {
spinner.classList.add("hidden");
btnPayText.classList.remove("hidden");
}
}

async function initialize() {
const {clientSecret} = await fetch(
"/create_payment_intent.php",
{
method: "POST",
}
).then((r) => r.json());

elements = payrex.elements({
clientSecret
});

const paymentElementOptions = {
layout: "accordion",
};

const paymentElement = elements.create(
"payment",
paymentElementOptions
);

paymentElement.mount("#payment-element");
}

// Fetches the payment intent status after payment submission
async function checkPaymentIntentStatus() {
const clientSecret = new URLSearchParams(window.location.search).get(
"payment_intent_client_secret"
);

if (!clientSecret) {
return;
}

const paymentIntent = await payrex.getPaymentIntent(clientSecret);

switch (paymentIntent.status) {
case "succeeded":
window.alert("Payment succeeded.")
break;
case "processing":
window.alert("Payment is still being processed.")
break;
case "awaiting_payment_method":
window.alert("Payment was not successful. Try again..")

break;
default:
window.alert("Something went wrong")

break;
}
}

Attach a PaymentMethod to the PaymentIntent

Call .attachPaymentMethod() from Payrex.js and pass along the Payment Element instance and a return_url to instruct PayRex to redirect your customer after they complete the payment.

For payment methods that require authentication, such as credit cards, PayRex will display a modal for authentication, e.g., 3DS for credit or debit cards, or redirect your customer to an authentication page, depending on the payment method. After your customer completes the authentication process, they will be redirected to your nominated return_url.

checkout.js
// Add your PayRex Public API key.
const payrex = window.Payrex('');
let elements;

initialize();
checkPaymentIntentStatus();

async function payAction() {
showLoading(true)
await payrex.attachPaymentMethod({
elements,
options: {
// Return URL is where the customer will be redirected after completing a payment.
return_url: "http://localhost:4242/checkout.html",
},
});
showLoading(false)
}

function showLoading(flag) {
const btnPayText = document.querySelector("#btn-pay-text");
const spinner = document.querySelector("#spinner");

if (flag) {
// Disable the button and show a spinner
spinner.classList.remove("hidden");
btnPayText.classList.add("hidden");
} else {
spinner.classList.add("hidden");
btnPayText.classList.remove("hidden");
}
}

async function initialize() {
const {clientSecret} = await fetch(
"/create_payment_intent.php",
{
method: "POST",
}
).then((r) => r.json());

elements = payrex.elements({
clientSecret
});

const paymentElementOptions = {
layout: "accordion",
};

const paymentElement = elements.create(
"payment",
paymentElementOptions
);

paymentElement.mount("#payment-element");
}

// Fetches the payment intent status after payment submission
async function checkPaymentIntentStatus() {
const clientSecret = new URLSearchParams(window.location.search).get(
"payment_intent_client_secret"
);

if (!clientSecret) {
return;
}

const paymentIntent = await payrex.getPaymentIntent(clientSecret);

switch (paymentIntent.status) {
case "succeeded":
window.alert("Payment succeeded.")
break;
case "processing":
window.alert("Payment is still being processed.")
break;
case "awaiting_payment_method":
window.alert("Payment was not successful. Try again..")

break;
default:
window.alert("Something went wrong")

break;
}
}

Show success/failed status message after redirection

Once PayRex redirects your customer to your nominated return_url, Payrex.js appends the payment_intent_client_secret query parameter, which is the PaymentIntent's client_secret. Use this parameter to retrieve the PaymentIntent to determine if the payment succeeds and show the relevant message to your customer.

checkout.js
// Add your PayRex Public API key.
const payrex = window.Payrex('');
let elements;

initialize();
checkPaymentIntentStatus();

async function payAction() {
showLoading(true)
await payrex.attachPaymentMethod({
elements,
options: {
// Return URL is where the customer will be redirected after completing a payment.
return_url: "http://localhost:4242/checkout.html",
},
});
showLoading(false)
}

function showLoading(flag) {
const btnPayText = document.querySelector("#btn-pay-text");
const spinner = document.querySelector("#spinner");

if (flag) {
// Disable the button and show a spinner
spinner.classList.remove("hidden");
btnPayText.classList.add("hidden");
} else {
spinner.classList.add("hidden");
btnPayText.classList.remove("hidden");
}
}

async function initialize() {
const {clientSecret} = await fetch(
"/create_payment_intent.php",
{
method: "POST",
}
).then((r) => r.json());

elements = payrex.elements({
clientSecret
});

const paymentElementOptions = {
layout: "accordion",
};

const paymentElement = elements.create(
"payment",
paymentElementOptions
);

paymentElement.mount("#payment-element");
}

// Fetches the payment intent status after payment submission
async function checkPaymentIntentStatus() {
const clientSecret = new URLSearchParams(window.location.search).get(
"payment_intent_client_secret"
);

if (!clientSecret) {
return;
}

const paymentIntent = await payrex.getPaymentIntent(clientSecret);

switch (paymentIntent.status) {
case "succeeded":
window.alert("Payment succeeded.")
break;
case "processing":
window.alert("Payment is still being processed.")
break;
case "awaiting_payment_method":
window.alert("Payment was not successful. Try again..")

break;
default:
window.alert("Something went wrong")

break;
}
}