Skip to content

Python

The sanwo package provides Django template tags, a Flask extension, and a FastAPI integration that render Sanwo checkout buttons and custom amount forms. Configure once, use anywhere in your templates.

Terminal window
pip install sanwo

Use the Sanwo client directly in any Python application:

from sanwo import Sanwo, providers
sanwo = Sanwo(
provider=providers.PAYSTACK,
public_key="pk_test_xxxxx",
currency="NGN",
)
# Render the CDN script tag (once per page)
script_tag = sanwo.render_script()
# Render a checkout button
button_html = sanwo.render_checkout(
amount=500000,
email="customer@example.com",
button_text="Pay ₦5,000",
)
# Render a custom amount widget
custom_html = sanwo.render_custom_amount(
email="donor@example.com",
button_text="Donate",
placeholder="Enter amount",
)

Add sanwo.django to your installed apps and configure in settings.py:

INSTALLED_APPS = [
# ...
"sanwo.django",
]
SANWO_PROVIDER = "paystack"
SANWO_PUBLIC_KEY = "pk_test_xxxxx"
SANWO_CURRENCY = "NGN"
SANWO_DEBUG = False

Add the script tag to your base template, before </body>:

{% load sanwo_tags %}
{% sanwo_scripts %}

This renders the CDN script tag. Only needed once per page.

{% load sanwo_tags %}
{% sanwo_checkout amount=500000 email="customer@example.com" button_text="Pay ₦5,000" %}
Parameter Type Required Default Description
amount int Yes Amount in minor units (kobo, cents)
email str Yes Customer email
button_text str No "Pay Now" Button label
button_class str No "sanwo-button" CSS class
provider str No Settings value Provider name
public_key str No Settings value Public key
currency str No Settings value Currency code
description str No Payment description
reference str No Auto-generated Transaction reference
first_name str No Customer first name
last_name str No Customer last name
phone str No Customer phone
callback str No JS callback function name

Basic:

{% sanwo_checkout amount=500000 email="user@example.com" %}

With dynamic data:

{% sanwo_checkout amount=order.total_in_kobo email=user.email first_name=user.first_name button_text="Complete Purchase" %}

Override provider per button:

{% sanwo_checkout amount=500000 email="user@example.com" provider="flutterwave" public_key="FLWPUBK_TEST-xxxxx" %}

Let customers enter their own amount — for donations, tips, or pay-what-you-want:

{% sanwo_custom_amount email="donor@example.com" button_text="Donate" placeholder="How much would you like to give?" %}

JavaScript callback:

<script>
function onPaid(result) {
if (result.status === 'successful') {
fetch('/payments/verify/', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': '{{ csrf_token }}'
},
body: JSON.stringify({ reference: result.reference })
});
}
}
</script>
{% sanwo_checkout amount=500000 email="user@example.com" callback="onPaid" %}

DOM events:

<script>
document.addEventListener('sanwo:complete', function(e) {
if (e.detail.status === 'successful') {
window.location.href = '/thank-you/?ref=' + e.detail.reference;
}
});
</script>
from flask import Flask
from sanwo.flask import SanwoFlask
app = Flask(__name__)
app.config["SANWO_PROVIDER"] = "paystack"
app.config["SANWO_PUBLIC_KEY"] = "pk_test_xxxxx"
app.config["SANWO_CURRENCY"] = "NGN"
app.config["SANWO_DEBUG"] = False
sanwo = SanwoFlask(app)

Or with the application factory pattern:

sanwo = SanwoFlask()
def create_app():
app = Flask(__name__)
app.config["SANWO_PROVIDER"] = "paystack"
app.config["SANWO_PUBLIC_KEY"] = "pk_test_xxxxx"
sanwo.init_app(app)
return app

The extension registers Jinja2 globals automatically:

<!DOCTYPE html>
<html>
<body>
<h1>Checkout</h1>
{{ sanwo_scripts() }}
{{ sanwo_checkout(amount=500000, email="customer@example.com", button_text="Pay ₦5,000") }}
</body>
</html>
{{ sanwo_custom_amount(email="donor@example.com", button_text="Donate", placeholder="Enter amount") }}
<script>
function onPaid(result) {
if (result.status === 'successful') {
window.location.href = '/thank-you?ref=' + result.reference;
}
}
</script>
{{ sanwo_checkout(amount=500000, email="user@example.com", callback="onPaid") }}
from fastapi import FastAPI, Request
from fastapi.responses import HTMLResponse
from starlette.templating import Jinja2Templates
from sanwo.fastapi import SanwoFastAPI
app = FastAPI()
sanwo = SanwoFastAPI(
app,
provider="paystack",
public_key="pk_test_xxxxx",
currency="NGN",
debug=False,
)
templates = Jinja2Templates(directory="templates")
sanwo.init_templates(templates)

Or deferred:

sanwo = SanwoFastAPI(provider="paystack", public_key="pk_test_xxxxx")
app = FastAPI()
sanwo.init_app(app)
templates = Jinja2Templates(directory="templates")
sanwo.init_templates(templates)

The same Jinja2 globals are available as in Flask:

<!DOCTYPE html>
<html>
<body>
<h1>Checkout</h1>
{{ sanwo_scripts() }}
{{ sanwo_checkout(amount=500000, email="customer@example.com", button_text="Pay ₦5,000") }}
</body>
</html>
{{ sanwo_custom_amount(email="donor@example.com", button_text="Donate", placeholder="Enter amount") }}
<script>
function onPaid(result) {
if (result.status === 'successful') {
window.location.href = '/thank-you?ref=' + result.reference;
}
}
</script>
{{ sanwo_checkout(amount=500000, email="user@example.com", callback="onPaid") }}

All five providers are available as constants:

from sanwo import providers
providers.PAYSTACK
providers.FLUTTERWAVE
providers.RAZORPAY
providers.MONNIFY
providers.INTERSWITCH

You can also pass provider IDs as strings:

sanwo = Sanwo(provider="paystack", public_key="pk_test_xxxxx")

Use a custom provider template to integrate any payment gateway not built in. Set provider="custom" and supply either a template (inline HTML string) or a template_url (URL that returns the template HTML).

from sanwo import Sanwo
# Inline template
sanwo = Sanwo(
provider="custom",
public_key="your_key",
template='<div id="payment-form">...</div>',
)
# Or load from a URL
sanwo = Sanwo(
provider="custom",
public_key="your_key",
template_url="https://example.com/my-provider-template.html",
)
html = sanwo.render_checkout(amount=500000, email="user@example.com")
settings.py
SANWO_PROVIDER = "custom"
SANWO_PUBLIC_KEY = "your_key"
SANWO_TEMPLATE_URL = "https://example.com/my-provider-template.html"
# or: SANWO_TEMPLATE = '<div id="payment-form">...</div>'

Then use {% sanwo_checkout %} as normal — the custom template is applied automatically.

app.config["SANWO_PROVIDER"] = "custom"
app.config["SANWO_PUBLIC_KEY"] = "your_key"
app.config["SANWO_TEMPLATE_URL"] = "https://example.com/my-provider-template.html"
# or: app.config["SANWO_TEMPLATE"] = '<div id="payment-form">...</div>'

Then use {{ sanwo_checkout(...) }} as normal.

sanwo = SanwoFastAPI(
app,
provider="custom",
public_key="your_key",
template_url="https://example.com/my-provider-template.html",
# or: template='<div id="payment-form">...</div>',
)

Then use {{ sanwo_checkout(...) }} as normal.

Sanwohq/python on GitHub.