February 04, 2022 âą 1936 Views âą 29 min read
Tetiana Stoyko
CTO & Co-Founder
Online payment gateways have never been easier to use. These apps enable users to pay on e-commerce platforms and perform internet shopping. Itâs a virtual version of the actual point of sale seen in many retail stores. Retailers should be able to take digital payments swiftly, transparently, and simply via a payment gateway. The fundamental goal of any secure payment gateway is to handle transactions in such a way that your customersâ money and their personal data are kept safe.
A bespoke payment gateway generally necessitates a higher time and financial commitment; nevertheless, a custom payment gateway solution will significantly assist your organization in growing and prospering. By API integration of a secure payment gateway, you can earn your clientsâ awareness and encourage them to deal with your application. That is why it is better to consider implementing Payment API that is well-known throughout the world and which drawbacks wouldnât appear as a surprise.
In this article, we put together three prominent Payment gateway API Integration tools, such as Stripe, Apple Wallet, and ApplePay (PayFort API). Since we have experience in integrating every mentioned payment API, we are sharing code fillets to help you go through the deployment process simpler.
Stripe is one of the most popular payment systems. You can easily integrate it into your project: while building your unique checkout UI, you can establish a complete API integration or just use the javascript library to classify your clientsâ payment information. Stripe enables processing API integration tools for creating payment getaway for your web application, iOS, or Android app.
First, you need to create an account on the Stripe website. To obtain keys for this Payment API you should navigate to the Developers page and then choose the API keys tab:
On frontend you need to include Stripe.js on your checkout page:
import { loadStripe } from '@stripe/stripe-js';
const stripe = await loadStripe('pk_test_*************************');
Then you need to create a form where the user can enter payment data. Stripe provides elements that can be used to build the form.
For example, if you use React you can use the âreact-stripe-elementsâ module. First, you need to wrap your application into StripeProvider:
import { StripeProvider } from 'react-stripe-elements'
import { AppContainer } from 'react-hot-loader'
render(
<StripeProvider apiKey={process.env.STRIPE_PUBLIC_KEY}>
<AppContainer>
/* ... */
</AppContainer>
</StripeProvider>,
document.getElementById('root')
)
Your form should be wrapped into the Elements component:
import React from 'react'
import { Elements } from 'react-stripe-elements'
import CreditCardForm from './CreditCardForm'
class CheckoutPage extends React.Component {
render() {
return (
<Elements>
<CreditCardForm />
</Elements>
);
}
}
module.exports = CheckoutPage;
Then you should use HOC injectStripe to build your payment form.
Please note: injectStripe should be used on the child of Elements component.
import React from 'react'
import {
CardNumberElement,
CardExpiryElement,
CardCVCElement,
injectStripe
} from 'react-stripe-elements'
import RaisedButton from 'material-ui/RaisedButton'
class CreditCardForm extends React.Component {
state = {
error: null,
cardholderName: '',
}
handleChangeCardholderName = e => this.setState({
cardholderName: e.target.value
})
handleSubmit = (e) => {
const { cardholderName } = this.state
const { stripe, onSubmit } = this.props
e.preventDefault()
this.setState({
error: null,
})
stripe.createToken({ name: cardholderName })
.then(payload => {
if (!payload.error) {
onSubmit(payload.token)
} else {
this.setState({
error: payload.error.message,
})
}
})
}
render() {
const { error, cardholderName} = this.state
const { onCancel } = this.props
return (
<div>
<form onSubmit={this.handleSubmit}>
<div className="credit-card-wrapper">
<div className="card-general card-row">
<div className="card-number card-input-group">
<div className="card-input-label">Card Number</div>
<CardNumberElement />
</div>
</div>
<div className="card-additional card-row mb-0">
<div className="card-expire card-input-group">
<div className="card-input-label">Expires</div>
<CardExpiryElement />
</div>
<div className="card-cvc card-input-group">
<div className="card-input-label">CVC</div>
<CardCVCElement />
</div>
</div>
<div className="card-row">
<div className="card-input-group">
<div className="card-input-label">Cardholder Name</div>
<div className="StripeElement">
<input
name="cardholder"
placeholder="John Doe"
type="text"
value={cardholderName}
onChange={this.handleChangeCardholderName} />
</div>
</div>
</div>
</div>
<FlatButton primary onClick={onCancel} />
<RaisedButton type="submit" label="Submit" />
{
error && <p className="form-error">{error}</p>
}
</form>
</div>
)
}
}
module.exports = injectStripe(CreditCardForm);
The onSubmit method should pass the Stripe token to the backend and the payment will be executed there.
On the backend, you should use a secret key to execute payment or perform any other action. You can use Stripe SDK for NodeJS:
import config from 'config';
import Stripe from 'stripe';
const stripe = new Stripe(config.get('stripe.secret_key'));
First you should exchange token you received on frontend to customer id:
function createCustomer(email, token, metadata) {
return stripe.customers.create({ email, source: token, metadata });
}
With a customer id, you will be able to perform different actions. For example, CRUD operations with customers:
function getCustomer(customerId) {
return stripe.customers.retrieve(customerId);
}
function deleteCustomer(customerId) {
return stripe.customers.del(customerId);
}
function updateCustomerMetadata(customerId, metadata) {
return stripe.customers.update(customerId, { metadata });
}
function updateCustomerEmail(customerId, email) {
return stripe.customers.update(customerId, { email });
}
function getCustomerCards(customerId) {
return stripe.customers.listCards(customerId);
}
function createCustomerCard(customerId, cardToken) {
return stripe.customers.createSource(customerId, { source: cardToken });
}
function deleteCustomerCard(customerId, cardId) {
return stripe.customers.deleteCard(customerId, cardId);
}
Also, you will be able to create a charge or subscription for a customer:
function charge(stripeCustomerId, amount, metadata) {
return stripe.charges.create({
customer: stripeCustomerId,
amount,
currency: 'usd',
description,
metadata,
});
}
function subscribe(stripePlanId, stripeCustomerId, quantity, metadata)
return stripe.subscriptions.create({
customer: stripeCustomerId,
items: [
{
plan: stripePlanId,
quantity,
},
],
metadata,
});
}
function unsubscribe(subscriptionId) {
return stripe.subscriptions.del(subscriptionId);
}
There is also a possibility to make a subscription to some events on Stripe using webhooks. To create a webhook you should just add an endpoint and select events that will trigger it:
Here is an endpoint example for webhooks:
const config = require('config');
const stripe = require('stripe')(config.get('stripe.secret_key'));
const apiResponse = require('helpers/apiResponse');
const { STRIPE_EVENTS } = require('./constants');
const endpointSecret = config.get('stripe.endpoint_secret');
/**
* Stripe web-hook endpoint.
*
* @param req
* @param res
* @returns {Promise<void>}
*/
async function webhooks(req, res) {
const { type, data: { object } } = req.body;
// validate stripe signature
const sig = req.get('stripe-signature');
stripe.webhooks.constructEvent(req.rawBody, sig, endpointSecret);
// filter undesired events to be processed
const allowedEvents = [
...Object.values(STRIPE_EVENTS.CHARGE),
];
// Ok response to all event types which we will not handle
if (!allowedEvents.includes(type)) {
return apiResponse.success(res, {}, 200);
}
// ...
return apiResponse.success(res, {}, 200);
}
module.exports = {
webhooks,
};
Apple Wallet allows customers to manage and utilize boarding passes and tickets, as well as other items like gift cards all in one tool. Its API integration will give key data when consumers need it and provide passes depending on location using Apple Wallet on iPhone, iPod touch, and Apple Watch. Passes may be programmed to appear on the userâs device at the right time, such as when the user arrives at the airport or walks into a shop because Wallet is time and location oriented.
You need to create your Apple Developer account and get a Pass Type ID Certificate.
So, you will get a .cer file but you need to extract .p12 from it. You can do it using Keychain. This certificate has an expiration date, so, donât forget to renew it and the other keys (mentioned below) regularly.
To generate an Apple Wallet pass we need four keys. First is the .p12 file we get on the previous step. Second, you need to download Appleâs World Wide Developer Relations (WWDR) certificate. The other 2 keys can be generated using the passbook module. You should put .p12 and Apple WWDR into one directory and then run this command:
./node_modules/passbook/bin/node-passbook prepare-keys -p <path-to-directory-with-.p12-and-wwdr>
You will be asked for the Import Password. If you leave it empty you will get the keys, but then you will have issues with Apple Wallet pass generating. So, use a secure password here.
wwdr.pem and Certificates.pem will be generated. You should rename Certificates.pem to your Pass Type ID. You can find it in the Certificates.pem file. You should find there CN=Pass Type ID: pass.<pass-type-id>. So, new name for your Certificates.pem should looks like <pass-type-id>.pem.
Currently, you should have a directory with keys:
Once you get all the required keys you can generate a pass. It can be done using the passbook module in this way:
const passbook = require('passbook');
const { pkpassConfig } = require('../../constants');
/**
* Generates .pkpass for apple wallet
*
* @returns {Promise<void>}
*/
async function generatePkpass(passData, isDev = false) {
let template = passbook(pkpassConfig.PASS_TYPES.GENERIC, {
passTypeIdentifier: pkpassConfig.PASS_TYPE_INDERTIFIER,
teamIdentifier: pkpassConfig.TEAM_IDENTIFIER,
organizationName: pkpassConfig.ORGANIZATION_NAME,
description: pkpassConfig.DESCRIPTION,
});
template.loadImagesFrom(pkpassConfig.IMAGES_DIRECTORY);
template.fields.barcode = pkpassConfig.BARCODE(passData);
template.fields.foregroundColor = pkpassConfig.FOREGROUND_COLOR;
template.fields.backgroundColor = pkpassConfig.BACKGROUND_COLOR;
template.fields.stripColor = pkpassConfig.FOREGROUND_COLOR;
template.fields.labelColor = pkpassConfig.LABEL_COLOR;
template.fields.generic = pkpassConfig.GENERIC(passData);
template.fields.serialNumber = passData.accountNumber.toString();
template.keys(pkpassConfig.KEYS_DIRECTORY, pkpassConfig.KEYS_PASSWORD);
return template.createPass();
}
module.exports = {
generatePkpass,
};
There are 5 templates for Apple Wallet Pass: boardingPass, coupon, eventTicket, generic, storeCard. Pass Type Identifier, Team Identifier, Organization Name are the values from Certificates.pem (renamed previously) CN=Pass Type ID: <Pass-Type-Identifier>, OU=<Team-Identifier>, O=<OrganizationName>.
A barcode should be an object with the following structure:
{
format: 'PKBarcodeFormatQR',
message: 'Some message',
messageEncoding: 'utf-8',
}
The colors should be in RGB format, for example, rgb(0, 0, 0).
Keys password is the password you entered in the previous step. A generic field should have the following structure:
{
headerFields: [{
key: 'someKey',
label: 'someLabel',
value: 'someValue',
}],
primaryFields: [{
key: 'someKey',
label: 'someLabel',
value: 'someValue',
}],
secondaryFields: [{
key: 'someKey',
label: 'someLabel',
value: 'someValue',
}],
backFields: [{
key: 'someKey',
label: 'someLabel',
value: 'someValue',
}],
}
PayFort solution is based in the United Arab Emirates, that provides payment API to customers across the Middle East through its payment gateway. Many countries of the Middle East donât support popular and well-known payment systems, such as Stripe, Braintree, etc. So, when you work with clients from those countries, there is a big chance that you will face with PayFort.
Integrating PayFort into your project, you will notice that the lack of an online terminal reduces the capacity to conduct invoices through the Checkfront Booking Manager.
PayFort supports in-app refunds, which means that a Checkfront compensation will instantly appear in this payment API and reimburse the consumer. This makes these API integration tools more convenient for users and increases the benefit of implementing ApplePay into your app.
Generate Payment Processing and Merchant identity certificates in the ApplePay developer account.
In your PayFort account, go to the âApplePay Settingsâ page and upload the Payment Processing certificate you obtained from Apple. The certificate should be placed into a .p12 file together with a private key and encrypted with a password(this password you should provide in ApplePay settings). You can do it in the âKeychain Accessâ tool if you are using Mac or OpenSSL on Windows.
Add apple developer merchant id domain association file on your server. Set up Merchant Identifier, Access Code, SHA Type, and SHA Request Phrase in your Payfort account:
We finished with preparations, letâs write some code. At first, we should validate the merchant session. [Docs are here]
NodeJS code example:
import * as fs from 'file-system';
import * as request from 'request';
public validateSession(validationURL: string, res: Response) {
const options = {
url: validationURL,
method: 'POST',
cert: fs.readFileSync(path.join(__dirname, '../../../identityCert.pem'), 'binary'),
key: fs.readFileSync(path.join(__dirname, '../../../key.pem'), 'binary'),
body: {
merchantIdentifier: 'merchant.com.example.mystore',
displayName: 'MyStore',
initiative: 'web',
initiativeContext: 'mystore.example.com'
},
json: true,
};
request(options, (err, response, body) => {
if (err) {
return res.status(400).send(body);
}
return res.send(body);
});
}
âkeyâ property â a private key generated with your certificate in Apple developer account
Response from Apple should look like this:
{
...
"token": {
"paymentData": {
"data": "...",
"signature": "...",
"header": {
"publicKeyHash": "...",
"ephemeralPublicKey": "...",
"transactionId": ".."
},
"version": "EC_v1"
},
"paymentMethod": {
"displayName": "...",
"network": "...",
"type": "..."
},
"transactionIdentifier": "..."
}
...
}
This data will be used on the next step â The PayFort payment request. Letâs prepare data for this request [Docs are here]. Now create payment body.
NodeJS code example:
const paymentBody = {
digital_wallet: 'APPLE_PAY',
command: 'PURCHASE',
access_code: PAYFORT_CONFIG.APPLE_PAY_ACCESS_CODE,
merchant_identifier: PAYFORT_CONFIG.APPLE_PAY_MERCHANT_ID,
merchant_reference: orderId,
amount: price * 100,
currency: 'SAR',
language: data.language,
customer_email: data.customerEmail,
apple_data: data.token.paymentData.data,
apple_signature: data.token.paymentData.signature,
apple_header: {
apple_transactionId: data.token.paymentData.header.transactionId,
apple_ephemeralPublicKey: data.token.paymentData.header.ephemeralPublicKey,
apple_publicKeyHash: data.token.paymentData.header.publicKeyHash,
},
apple_paymentMethod: {
apple_displayName: data.token.paymentMethod.displayName,
apple_network: data.token.paymentMethod.network,
apple_type: data.token.paymentMethod.type,
},
customer_name: data.customerName,
};
Signature for request should be generated and encoder with SHA Type which set up in your Payfort account (default SHA 256):
Decoded signature (JavaScript example):
const decodedSignature = `${PAYFORT_CONFIG.APPLE_PAY_REQ_PASSPHRASE}access_code=${paymentBody.access_code}` +
`amount=${paymentBody.amount}` +
`apple_data=${paymentBody.apple_data}` +
`apple_header={apple_transactionId=${paymentBody.apple_header.apple_transactionId}` +
`, apple_ephemeralPublicKey=${paymentBody.apple_header.apple_ephemeralPublicKey}` +
`, apple_publicKeyHash=${paymentBody.apple_header.apple_publicKeyHash}}` +
`apple_paymentMethod={apple_displayName=${paymentBody.apple_paymentMethod.apple_displayName}` +
`, apple_network=${paymentBody.apple_paymentMethod.apple_network}` +
`, apple_type=${paymentBody.apple_paymentMethod.apple_type}}` +
`apple_signature=${paymentBody.apple_signature}` +
`command=${paymentBody.command}` +
`currency=${paymentBody.currency}` +
`customer_email=${paymentBody.customer_email}` +
`customer_name=${paymentBody.customer_name}` +
`digital_wallet=${paymentBody.digital_wallet}` +
`language=${paymentBody.language}` +
`merchant_identifier=${paymentBody.merchant_identifier}` +
`merchant_reference=${paymentBody.merchant_reference}${PAYFORT_CONFIG.APPLE_PAY_REQ_PASSPHRASE}`;
Please notice: Each character is important. Any typo will cause a âSignature mismatchâ error.
Letâs encrypt the signature:
const hash = crypto
.createHash('sha256')
.update(decodedSignature, 'utf8')
.digest('hex');
Attach signature to payment body and make a payment request:
paymentBody.signature = hash;
const options = {
url: 'https://paymentservices.payfort.com/FortAPI/paymentApi',
method: 'POST',
body: paymentBody,
json: true,
};
const paymentRequestResult = await request(options);
The response should contain status 14 meaning that the transaction was successful.
Create index.html, style.css, and script.js files and place them as static ones on your server.
Set up ApplePay button [Docs for CSS are here] [Docs for JavaScript are here]. Write a function that will check if ApplePay is available in the script.js file:
const init = () => {
const isApplePayAvailable = window.ApplePaySession;
if(isApplePayAvailable) {
// Show button
...
// Add "click" event listener on the button which will trigger start apple pay session
setButtonClickListener();
} else {
// Error: Apple Pay is unavailable
}
}
Add ApplePay button listener which starts the session with payment detail:
const setButtonClickListener = () => {
document
.getElementById("appleButton")
.addEventListener("click", function () {
startApplePaySession({
currencyCode: "SAR",
countryCode: "SA",
merchantCapabilities: [
"supports3DS",
"supportsCredit",
"supportsDebit",
],
supportedNetworks: config.payments.acceptedCardSchemes,
shippingType: "shipping",
total: {
label: config.shop.shop_name,
amount: config.shop.product_price,
type: "final",
},
});
});
};
Letâs add the âstart ApplePay Sessionâ method implementation. It is responsible for starting sessions with provided payment details and tracking events.
const startApplePaySession = (config) => {
const applePaySession = new ApplePaySession(6, config);
handleApplePayEvents(applePaySession);
applePaySession.begin();
};
âHandle ApplePay Eventsâ method:
const handleApplePayEvents = (appleSession) => {
// This is the first event that Apple triggers. Here you need to validate the
// Apple Pay Session from your Back-End
appleSession.onvalidatemerchant = function (event) {
validateApplePaySession(event.validationURL, function (merchantSession) {
appleSession.completeMerchantValidation(merchantSession);
});
};
appleSession.onpaymentauthorized = function (event) {
performTransaction(event.payment, appleSession, function (outcome) {
if (outcome) {
appleSession.completePayment(ApplePaySession.STATUS_SUCCESS);
} else {
appleSession.completePayment(ApplePaySession.STATUS_FAILURE);
}
});
};
};
To validate merchant events should request validation on our Backend and complete merchant validation with the response. The âvalidateApplePaySessionâ is responsible for sending requests:
const validateApplePaySession = (appleUrl, callback) => {
axios
.post('url of the backend API that triggers validateSession method which we implemented', {
url: appleUrl + "",
})
.then(function (response) {
callback(response.data);
})
.catch((err) => {
alert(err, "ApplePaySession");
});
};
After validation succeeds, on payment authorized event will be triggered. The handler should make a transaction:
const performTransaction = (details, appleSession, callback) => {
const payload = {
token: details,
customerEmail: 'email@emample.com',
orderId: 'HERE IS ORDER ID',
language: 'AR',
customerName: "customerName",
};
axios
.post(`Backend API url to Payfort payment request route`, payload)
.then(function (response) {
callback(response.data);
})
.catch((e) => {
appleSession.completePayment(ApplePaySession.STATUS_FAILURE);
});
};
Thatâs it! Now, go to your static index.html file. If your device supports ApplePay, the payment button should appear and you are ready to test your payment API!
Whether your application is connected to E-Commerce and Online Shopping or not, Payment Gateway is a necessary solution for each software that offers purchases of goods or services. API integration of such solutions may expand the functionality of your platform and create a better user experience.
At Incora we know what it takes to integrate a payment API into an app, therefore we attempted to make this process as simple as possible for you. But, whether youâre still in the planning phase of your app or need to finish your current project, weâre ready to help you out by deploying payment gateways. Just fill in the contact form and weâll be in touch right away.
Share this post
Tags
Love it!
Valuable
Exciting
Unsatisfied
YOU MAY ALSO LIKE
Letâs talk!
This site uses cookies to improve your user experience.Read our Privacy Policy
Accept