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 API Integration 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 gateways for your web application, iOS, or Android app. Getting started First, you need to create an account on the . To obtain keys for this Payment API you should navigate to the Developers page and then choose the API keys tab: Stripe website Frontend 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 . First, you need to wrap your application into StripeProvider: ‘react-stripe-elements’ module 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. Backend 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); } Webhooks 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 your endpoint: 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 API Integration 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. Getting started 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 from it. You can do it . This certificate has an expiration date, so, don’t forget to renew it and the other keys (mentioned below) regularly. .p12 using Keychain Prepare keys To generate an Apple Wallet pass we need four keys. First is the we get on the previous step. Second, you need to download . The other 2 keys can be generated using the . You should put and into one directory and then run this command: .p12 file Apple’s World Wide Developer Relations (WWDR) certificate passbook module .p12 Apple WWDR ./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. and will be generated. You should rename to your . You can find it in the . You should find there . So, new name for your Certificates.pem should looks like wwdr.pem Certificates.pem Certificates.pem Pass Type ID Certificates.pem file CN=Pass Type ID: pass.<pass-type-id> <pass-type-id>.pem Generate the Pass for Apple Wallet 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: . Pass Type Identifier, Team Identifier, Organization Name are the values from Certificates.pem (renamed previously) CN=Pass Type ID: boardingPass, coupon, eventTicket, generic, storeCard <Pass-Type-Identifier>, OU=<Team-Identifier>, O=<OrganizationName>. In the image directory you should have these files: 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, . Keys password is the password you entered in the previous step. A generic field should have the following structure: rgb(0, 0, 0) { 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', }], } ApplePay integration using PayFort API 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. Getting Started Backend 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. 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 . Now create payment body. [Docs are here] 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}`; Be careful, 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. Frontend Create index.html, style.css, and script.js files and place them as static ones on your server. Set up ApplePay button . Write a function that will check if ApplePay is available in the script.js file: [Docs for CSS are here] [Docs for JavaScript are here] 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 . If your device supports ApplePay, the payment button should appear and you are ready to test your payment API! static index.html file Summary 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. Also posted on Incora blog: https://incorainc.com/how-to-deploy-a-payment-gateway-payment-api-practical-use/