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.
Installation
Section titled “Installation”pip install sanwopip install "sanwo[django]"pip install "sanwo[flask]"pip install "sanwo[fastapi]"Standalone usage
Section titled “Standalone usage”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 buttonbutton_html = sanwo.render_checkout( amount=500000, email="customer@example.com", button_text="Pay ₦5,000",)
# Render a custom amount widgetcustom_html = sanwo.render_custom_amount( email="donor@example.com", button_text="Donate", placeholder="Enter amount",)Django
Section titled “Django”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 = FalseAdd the script
Section titled “Add the script”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.
Checkout button
Section titled “Checkout button”{% load sanwo_tags %}
{% sanwo_checkout amount=500000 email="customer@example.com" button_text="Pay ₦5,000" %}Available parameters
Section titled “Available parameters”| 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 |
Examples
Section titled “Examples”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" %}Custom amount form
Section titled “Custom amount form”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?" %}Handling results
Section titled “Handling results”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 Flaskfrom 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 appTemplates
Section titled “Templates”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>Custom amount
Section titled “Custom amount”{{ sanwo_custom_amount(email="donor@example.com", button_text="Donate", placeholder="Enter amount") }}Handling results
Section titled “Handling results”<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") }}FastAPI
Section titled “FastAPI”from fastapi import FastAPI, Requestfrom fastapi.responses import HTMLResponsefrom starlette.templating import Jinja2Templatesfrom 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)Templates
Section titled “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>Custom amount
Section titled “Custom amount”{{ sanwo_custom_amount(email="donor@example.com", button_text="Donate", placeholder="Enter amount") }}Handling results
Section titled “Handling results”<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") }}Providers
Section titled “Providers”All five providers are available as constants:
from sanwo import providers
providers.PAYSTACKproviders.FLUTTERWAVEproviders.RAZORPAYproviders.MONNIFYproviders.INTERSWITCHYou can also pass provider IDs as strings:
sanwo = Sanwo(provider="paystack", public_key="pk_test_xxxxx")Custom provider templates
Section titled “Custom provider templates”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).
Standalone
Section titled “Standalone”from sanwo import Sanwo
# Inline templatesanwo = Sanwo( provider="custom", public_key="your_key", template='<div id="payment-form">...</div>',)
# Or load from a URLsanwo = 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")Django
Section titled “Django”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.
FastAPI
Section titled “FastAPI”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.
Source code
Section titled “Source code”Sanwohq/python on GitHub.