Comments
Sign in to join the conversation
While Stripe is a developer favorite, PayPal remains a dominant force in global payments. Many users prefer PayPal for its trusted brand and ease of use (no credit card entry required if they have an account).
In this article, we'll explore how to add a "Pay with PayPal" button to your React app and handle the transaction verification on your Django backend.
The flow for PayPal is slightly different from Stripe's custom elements:
onApprove callback triggers.@paypal/react-paypal-jsPayPal provides an official React wrapper which makes integration smooth.
npm install @paypal/react-paypal-js
Refrain from using the raw script tag; use the PayPalScriptProvider.
import { PayPalScriptProvider, PayPalButtons } from "@paypal/react-paypal-js";
import { useState } from "react";
export default function PayPalCheckout() {
const [success, setSuccess] = useState(false);
const [errorMessage, setErrorMessage] = useState("");
// Create the order on the client or call your backend to create it
const createOrder = (data, actions) => {
return actions.order.create({
purchase_units: [
{
amount: {
value: "10.00",
},
},
],
});
};
// Handle the payment approval
const onApprove = async (data, actions) => {
// Capture the funds from the transaction
const details = await actions.order.capture();
// Show a success message to the buyer
const name = details.payer.name.given_name;
alert(`Transaction completed by ${name}`);
// OPTIONAL: Call your backend to save the transaction
verifyTransaction(data.orderID);
};
const verifyTransaction = async (orderID) => {
try {
const response = await fetch('/api/verify-paypal-transaction/', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ orderID }),
});
const result = await response.json();
if (result.success) {
setSuccess(true);
}
} catch (err) {
setErrorMessage("Payment verification failed on server.");
}
};
return (
<PayPalScriptProvider options={{ "client-id": "test" }}>
<PayPalButtons
createOrder={createOrder}
onApprove={onApprove}
onError={(err) => setErrorMessage(err.toString())}
/>
{success && <div>Order verified and saved!</div>}
{errorMessage && <div className="text-red-500">{errorMessage}</div>}
</PayPalScriptProvider>
);
}
Although actions.order.capture() on the client captures the money, you should verify this on the server to prevent spoofing.
PayPal has a REST API. You can use requests to verify the token.
pip install requests
import requests
from rest_framework.views import APIView
from rest_framework.response import Response
from django.conf import settings
class VerifyPayPalTransaction(APIView):
def post(self, request):
order_id = request.data.get('orderID')
# Get an access token first
client_id = settings.PAYPAL_CLIENT_ID
secret = settings.PAYPAL_SECRET
auth_response = requests.post(
'https://api-m.sandbox.paypal.com/v1/oauth2/token',
auth=(client_id, secret),
data={'grant_type':
| Feature | Stripe | PayPal |
|---|---|---|
| Customization | High (Custom Elements) | Medium (Smart Buttons) |
| Global Reach | Excellent | Ubiquitous |
| Fees | Standard (~2.9% + 30¢) | Standard (varies by region) |
| DX | Excellent | Good |
Adding PayPal gives your users more choice, often leading to higher conversion rates. With the react-paypal-js library, the integration is cleaner than ever.