Skip to main content

How to Integrate Stripe Checkout with Python-Generated PDF Invoices?


Stripe payment page

In the previous tutorial, we created a sales invoice using Python and ReportLab. The invoice included details such as customer information, line items, totals, and formatting. In this tutorial, we will enhance the invoice by adding a Stripe payment button directly inside the PDF. This functionality means that when a customer opens the invoice, they can click the "Pay Now" button, which redirects them to a Stripe checkout page to complete the payment.

Prerequisite:

This tutorial is part of the Automated Sales Invoice Series.

📚 View the Complete Automated Sales Invoice Series

⬅ Previous Part                                                                                                                     ➡ Next Part

Preliminary
Before I begin, please activate the virtual environment and install the required dependencies.

python -m venv venv
venv\Scripts\activate 
pip install reportlab
Then, we need to set up the file and folder structure, as below:

File and folder structure

Since this tutorial continues from the last tutorial, Part 2, all the files and folders remain the same, except I need to slightly amend 'pdf.py' and create a new file, 'payment.py' to add a button on the sales invoice, as shown in the diagram above.


Step 1: Log in to the Stripe platform and create a product
Go to the Stripe site and log in with my Google account. When I am at the dashboard page, from the left-side menu bar, I will click "Product Catalogue," and then a window will slide from the right. Next, I will click the purple button from the top right corner, "+ create product." 

Stripe platform

On the "Add a product" window, I input the product name and description, upload a simple image, select the payment type, preferred currency, and amount, and finally click the "Add product" button at the bottom. The details are shown in the diagram below.

Stripe product page


Step 2: Generate and copy a product link
I will create a product link once I've created the product. In the top right corner, there is a "+" button, and I click it, and a drop-down shows a list of options. I will click the "Payment Link." Then select the product category I created in step 1 above; a preview will appear in the right window. If I am satisfied with the layout, I can go ahead and click the "Create link" in the top right corner. Finally, I simply click the copy button when it has shown the payment link that I need.

Click "Create link" in the top-right
Create product link




Step 3: Create a button in the Sales Invoice PDF
Once I own the link, I will create the code below in the payment.py file. I need to create a red button at the centre bottom of the sales invoice with a clickable link. The copied URL link from the Stripe site will now be pasted into my code, and when the button is clicked, it will redirect me to the Stripe payment site. The following is my code in payment.py with a detailed explanation.
# Import module from the ReportLab
from reportlab.lib.units import inch
from reportlab.lib.colors import red

def stripe_payment(c):
    # Stripe Checkout payment link from step 2 above
    # This is the URL that customers will be redirected to when they click the button
    stripe_url = "https://buy.stripe.com/test_28EeVdecq3ME7n92OvgMw05"
    
    # ---------------------------------------------------------
    # Button Position and Size
    # ---------------------------------------------------------
    
    # the x, y coordination, width and height
    x = 2.8 * inch
    y = 0.5 * inch
    width = 2 * inch
    height = 0.5 * inch
    
    # ---------------------------------------------------------
    # Draw Button Background
    # ---------------------------------------------------------
    
    # Define the rectangle area of the button
    rect = (x, y, x + width, y + height)
    
    # Set the fill colour of the button
    c.setFillColor(red)
    
    # ---------------------------------------------------------
    # Add Button Text
    # ---------------------------------------------------------
    
    # Set the font style and size
    c.setFont("Roboto-Bold", 14)

    # Adjust text position slightly to centre it visually
    offset_x = -69   # negative = left
    offset_y = -76    # negative = down

    # Calculate text position based on button centre
    text_x = x + width/2 + offset_x
    text_y = y + height/2 + offset_y
    
    # Button label
    text = "Pay Now"
    
    # Draw the text centred at the calculated position
    c.drawCentredString(text_x, text_y, text)

    # ---------------------------------------------------------
    # Add Clickable Stripe Link
    # ---------------------------------------------------------
    
    # When the user clicks the rectangle area, it opens the Stripe payment page
    c.linkURL(
        stripe_url,
        rect,
        relative=0,
        thickness=2,
        color=red
    )
    
    # Return the updated canvas object
    return c
When it prompts a security warning, just click to allow the process to proceed.

Click the payment button

I made a button in payment.py, but it must be imported in pdf.py to work. Following is my code in pdf.py.
# import from the payment.py
from payment import stripe_payment 

# Set the output PDF file path
my_path = 'sales_invoice/my_invoice.pdf'

# Create a new PDF canvas object
c = canvas.Canvas(my_path, pagesize=letter)

# Stripe payment button at the bottom
c = stripe_payment(c)
When I run the app, it will generate a my_invoice.pdf file in the sales invoice folder. Then, I click PDF to open the file.


Step 4: Test the payment link

(A) Before payment

After I click the 'Pay Now' button, it will direct me to the Stripe payment link (the link in Step 2), as shown in the diagram below.

Payment page

Before I proceed, I need to fill out my email address and then complete the payment details.

The card number for testing purposes is as follows:
   (i) Visa - 4242424242424242, or
   (ii) Master - 5555555555554444

I used a Visa card for this tutorial; the card's expiration date is in the future, and the three-digit CVC is a random number, followed by my cardholder name and country, as diagrammed above.

(B) After payment

Once I have filled out the card details and clicked the subscribe button, the diagram below displays the payment status; the tick mark indicates the payment was successful. 

Thank you page

To confirm the payment was actually received, I need to return to the Stripe platform again. When I click the left sidebar menu on transactions to view the full list of transactions, I notice the successful payment details are shown in the table below.

Transaction view

Final wrap-up.
In this tutorial series, we created a sales invoice generator using Python and ReportLab and enhanced it by adding a clickable payment button directly inside the PDF. By combining a visual button with a payment link, customers can easily click “Pay Now” and complete their payment online. The link can point to any payment platform, such as Stripe, PayPal, or Razorpay, making the invoice flexible for different payment providers. This makes the invoice more interactive and convenient, turning the Python invoice system into a practical tool for generating invoices with built-in payment capabilities.

Published: Mar 2026
Last Updated: Mar 2026

About the Author

Kelvin Loh is a Python developer focused on Flask, desktop applications, and business automation solutions. He shares practical tutorials and real-world coding projects to help developers and small businesses build useful applications.

Comments

Popular Posts

How to Design a Location Tracking Module for Desktop Business Systems Using Python?

This tutorial will show you how to create an interactive map application that allows users to input geographic coordinates and visualize locations on an interactive map using Python's Tkinter GUI framework enhanced with TTKBootstrap styling and the TkinterMapView widget.  Prerequisite: This tutorial is part of the standalone tutorial. 📚 View the  standalone tutorial Preliminary   Before I begin, it is recommended to activate the virtual environment before installing the relevant dependencies. python -m venv venv venv\Scripts\activate pip install ttkbootstrap tkintermapview As usual, we need to import the relevant module and set the root values from tkinter import * import ttkbootstrap as tb import tkintermapview from ttkbootstrap.dialogs import Messagebox root = tb.Window(themename='darkly') root.title('Find My Map') root.geometry("1200x1200") I would like to divide it into three sections.  a) Input Panel Layout,  The headers are mainly a label...

How to Create Flask Forms with CKEditor and Flask-WTF?

In this tutorial, we will be integrating Flask-WTF and Flask-CKEditor into your Flask application! You'll learn how to set up the editor, securely handle formatted HTML content, and create a seamless user experience that enhances any project that requires user-generated content. Let's get started! Prerequisite: This tutorial is part of the Flask CKEditor Project Series. 📚 View the Complete Flask CKEditor Series                                                                                                                                                  ➡ Next Part Preliminary Before I begin, it is recommended to activate the v...

How to Store Application Data with SQLite in Python?

  In the previous tutorial, I used TinyDB as our storage solution to keep application data in a simple JSON-based format. While TinyDB is lightweight and easy to use, many web applications require a more structured and scalable database system. In this tutorial, we will switch to SQLite , a powerful relational database that integrates well with Python and web frameworks. By using SQLite, you will learn how to store, manage, and query data in a more structured way for real-world applications. Prerequisite: This tutorial is part of the Flask CKEditor Project Series. 📚 View the Complete Flask CKEditor Series ⬅ Previous Part                                                                                                         ...