DEVELOPER

Back to Developer Blog

technicalseries

Integrate Advanced Payment Functions in your Python Flask App

By Kevin Kimani and Laura Olson | November 5th, 2024

Payment processing refers to the handling of financial transactions between a customer and a business. It involves various steps, including authorizing the payment, verifying the transaction, and transferring the funds from the customer's account to the business's account. Payment processing is typically facilitated by payment processors, which are specialized companies that provide the infrastructure and technology to manage and secure online payments.

North's Custom Pay API connects to an in-house processor, EPX, making it easy to create a customized payment processing flow by providing several API endpoints to implement tasks such as authorizing and capturing a payment, making refunds, and retrieving past transactions.

In this article, you will learn how you can integrate North's Custom Pay API with your Python application. You will implement a Flask web application that prompts the user for payment details, use the Custom Pay API to process the payment, and display the payment results to the end user.

Checkout form made with North's Custom Pay API

Build this App

Clone this code repository to quickly create your own app today!

Benefits of the Custom Pay API

North's Custom Pay API lets you tailor your payment processing to your needs by accepting payments from various sources such as backend servers, a Point of Sale (POS) system, a website, or any other payment gateway that acts as a plugin or middleware. It is flexible enough to be used to accept payments online as well as through Semi-Integrated hardware. This makes the solution suitable for both card-present and card-not-present environments.

The API gives you access to a range of useful payment features, including the following:

  • Address verification system—a fraud-prevention measure that verifies a customer's billing address against the address on file with their credit card company to ensure that the transaction is legitimate.
  • Batch—to process multiple transactions at once, either closing all or partial transactions based on the ID provided. Batch transactions can also be used to retrieve batch totals and details.
  • Refund—to return funds to an account that was previously charged in a sale or captured transaction.
  • Reverse—to reverse the authorization of funds on a credit card, which releases the funds being held at the issuing bank. This feature is typically used when a customer cancels an order or returns a product.
  • Sale—to authorize and capture a transaction in one step, provided that the authorization portion is approved and able to settle.
  • Tip adjust—to allow the tip amount on a transaction to be adjusted after the payment has been processed.

Implementing the Custom Pay API

In this section, you will create a web application with Flask (a micro web framework written in Python) that prompts the user for payment details, use North's Custom Pay API to process the transaction, and display the transaction results.

You can find the code for this tutorial on GitHub.

Prerequisites

To follow along, you need to have the following:

  • Custom Pay API test credentials, which you get by contacting the integrations team
  • Python version 3+ installed on your development machine
  • A code editor—this article uses VS code

Get in Touch

Talk to us about adding payments to your Python application today.

Setting Up the Development Environment

Start by creating a project folder named 'python-custom-pay-api' and then create a Python virtual environment inside the folder by running this command in your terminal:

python3 -m venv env

If you're using a Linux-based operating system, run the command below to activate the virtual environment:

source env/bin/activate

If you're using a Windows operating system, use:

.\env\Scripts\activate

To create a Flask application, you need to install Flask in the virtual environment. You also need to install the Python requests module, which you will use to make API requests. To install these two modules, run the command:

pip install flask requests

Creating the Payment Solution

Now you're ready to create your solution.

In the project root folder, create a file named app.py and paste the code below into it:

from flask import Flask, render_template, request
import hmac
import hashlib
import requests
import json
import random

app = Flask(__name__)

@app.route('/', methods=['GET', 'POST'])
def payment():
   if request.method == 'POST':
       data = request.get_json()

       def send_payment_request(userData):
           payload = {
               'amount': userData['amount'],
               'account': userData['accountNumber'],
               'expirationDate': userData['expirationDate'],
               'capture': True,
               'cvv2': userData['cvv2'],
               'transaction': random.randint(100, 1000),
               'batchID': random.randint(100, 1000),
               'industryType': 'E',
               'cardEntryMethod': 'X'
           }

           concat_payload = '/sale' + json.dumps(payload)

            # generate the ePISignature following the instructions in the "How To Authenticate" section of the Custom Pay API Integration Guide


           headers={
               'Content-Type': 'application/json',
               'EPI-Id': b'<your-epi-id>',
               'EPI-Signature': epi_signature
           }

           response = requests.post('https://epi.epxuap.com/sale', data=json.dumps(payload), headers=headers)

           return response.json()
      
       payment_result = send_payment_request(data)

       payment_result_json = json.dumps(payment_result['data']['text'])
  
       return payment_result_json
   else:
       return render_template('index.html')

if __name__ == '__main__':
   app.run()

This code imports the required modules and defines an API route '/' that accepts GET and POST requests.

When a GET request is sent to this API route, it renders an index.html file that you will create later in the tutorial. When the route receives a POST request, it extracts the JSON data from the request body, and the send_payment_request method is used to send a payment request to the North EPX servers. It takes one argument—userData—which is the user’s payment details.

Generate the EPI-Signature following the instructions in the "How To Authenticate" section of the Custom Pay API Integration Guide. Note that you'll need to create a free North Developer account to view the Integration Guide. To get the JSON payload, the send_payment_request method creates a dictionary named payload that contains the fields required by the Custom Pay API in the request schema. To learn more about each of the fields, check out the official documentation.

The dictionary is then serialized using the json.dumps() method and concatenated with the string /sale, which is the endpoint. The result is stored in a variable called concat_payload.

A dictionary named headers is then created with all the parameters required by the /sale endpoint.

Finally, the requests.post() method is used to send a payment request to the North EPX servers. The data parameter contains the serialized payload while the headers parameter contains the headers dictionary. The response.json() method is used to parse the JSON response from the EPX servers and return it as a Python dictionary. The results of the transaction are then returned to the index.html template.

Remember to replace and with the credentials you received from the North Integrations team.

Next, create a folder named templates in the project root directory. Inside this folder, create a file named index.html and add the code below to it:

HTML
<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>North Developer</title>
   <style>
       body {
         display: flex;
         justify-content: center;
         align-items: center;
         height: 100vh;
         margin: 0;
         background-color: #f7f7f7;
         font-family: Arial, sans-serif;
       }
    
       .container {
         display: flex;
         align-items: center;
       }
    
       .product-container,
       form {
         flex: 1;
         padding: 20px;
         border: 1px solid #ccc;
         border-radius: 5px;
         background-color: #fff;
         box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
       }
    
       .product-container {
         margin-right: 20px;
       }
    
       .product-image img {
         max-width: 230px;
         height: auto;
         margin: 0 auto;
         margin-left: 1.3rem;
         border-radius: 5px;
       }
    
       .product-details {
         margin-left: 20px;
       }
    
       .product-title {
         font-size: 24px;
         font-weight: bold;
         margin: 0;
       }
    
       .product-description {
         margin-top: 10px;
         color: #555;
       }
    
       .product-price {
         margin-top: 10px;
         font-weight: bold;
       }
    
       .discount {
         color: #ff5722;
         font-weight: normal;
       }
    
       form {
         display: flex;
         flex-direction: column;
         align-items: flex-start;
       }
    
       label {
         display: block;
         font-weight: bold;
         margin-bottom: 5px;
       }
    
       input[type="number"],
       input[type="text"] {
         width: 100%;
         padding: 10px;
         margin-bottom: 10px;
         border: 1px solid #ccc;
         border-radius: 3px;
         box-sizing: border-box;
       }
    
       button[type="submit"] {
         padding: 10px 20px;
         background-color: #4caf50;
         color: #fff;
         border: none;
         border-radius: 3px;
         cursor: pointer;
         font-size: 16px;
       }
     </style>    
</head>
<body>
   <div class="container">
     <div class="product-container">
       <div class="product-image">
         <img src="https://i.dummyjson.com/data/products/1/thumbnail.webp" alt="Product Thumbnail">
       </div>
       <div class="product-details">
         <h2 class="product-title">iPhone 9</h2>
         <p class="product-description">A mobile phone</p>
         <p class="product-price">
           Price: $549
           <span class="discount">(-12.96%)</span>
         </p>
       </div>
     </div>
      <form>
       <div>
         <label for="account">Account Number:</label>
         <input type="text" name="account" id="account" value="4111111111111111" required>
       </div>
       <div>
         <label for="expirationDate">Expiration Date:</label>
         <input type="text" name="expirationDate" id="expirationDate" value="2504" required>
         <div>
           <label for="cvv2">CVV2:</label>
           <input type="text" name="cvv2" id="cvv2" value="123" required>
         </div>
         <button type="submit" id="buyNow">Buy Now</button>
       </form>
     </div>

     <script>
       document.addEventListener('DOMContentLoaded', () => {
         const form = document.querySelector('form');
         form.addEventListener('submit', async (event) => {
           event.preventDefault();
    
           const accountNumber = document.getElementById('account').value;
           const expirationDate = document.getElementById('expirationDate').value;
           const cvv2 = document.getElementById('cvv2').value;
    
           const payload = {
             accountNumber,
             expirationDate,
             cvv2,
             amount: 549.00
           };
    
           try {
             const response = await fetch('/', {
               method: 'POST',
               headers: {
                 'Content-Type': 'application/json'
               },
               body: JSON.stringify(payload)
             });
    
             const data = await response.json();
            
             if(data.includes('APPROVAL')){
               alert('Transaction processed successfully')
             } else {
               alert('An error occurred when processing your transaction')
             }
           } catch (error) {
             // An error occurred during the request
             console.log('An error occurred', error);
           }
         });
       });
     </script>     
   </body>
</html>

The code above renders a webpage with a product from the DummyJSON website and a form to collect the user details.

When the user clicks the Buy Now button, a POST request with the customer payment details and a hard-coded product price is made to the '/' endpoint. The code awaits the response from the API and extracts the JSON data from it using the response.json() method. It then checks if the data received includes the string "APPROVAL" and displays an appropriate alert message accordingly.

Demonstrating the Final Application

To test the application, run the command below in your terminal:

flask run

Navigate to http://localhost:5000 in your browser where you should see the payment form that has been prefilled with the test data provided by North. Click on the Buy Now button and you should see the payment result page.

The complete code for this article is available on GitHub .

How To Get Started

In this article, you learned how to integrate North's Custom Pay API into your Python Flask application to create a customized payment processing flow. As you could see, using the Custom Pay API is very easy. Even though this article only covered capturing a payment, you can do much more with this API. Contact us to learn more about how the Custom Pay API and other tools can meet your business needs.


Start your free Developer account and try it now.


©2025 North is a registered DBA of NorthAB, LLC. All rights reserved. North is a registered ISO of BMO Harris Bank N.A., Chicago, IL, Citizens Bank N.A., Providence, RI, The Bancorp Bank, Philadelphia, PA, FFB Bank, Fresno, CA, Wells Fargo Bank, N.A., Concord, CA, and PNC Bank, N.A.