Skip to content

Python SDK ​

Official server-side SDK for integrating ZevPay Checkout in Python applications. Provides full REST API coverage with httpx HTTP client.

Installation ​

bash
pip install zevpay

Requires Python 3.8 or later.

Quick start ​

python
from zevpay import ZevPay

client = ZevPay("sk_test_your_secret_key")

# Initialize a checkout session
session = client.checkout.initialize(
    amount=500000,  # ₦5,000 in kobo
    email="customer@example.com",
    reference="ORDER-123",
    callback_url="https://yoursite.com/callback",
)

print(session["checkout_url"])

Configuration ​

python
client = ZevPay(
    "sk_live_xxx",
    base_url="https://api.zevpaycheckout.com",  # default
    timeout=30,      # 30s request timeout (default)
    max_retries=2,   # retries on 5xx errors (default)
)
OptionTypeDefaultDescription
base_urlstrhttps://api.zevpaycheckout.comAPI base URL
timeoutint30Request timeout in seconds
max_retriesint2Max retries on server errors

Secret keys only

The SDK only accepts secret keys (sk_live_* or sk_test_*). Public keys cannot be used server-side.

Checkout sessions ​

Initialize a session ​

python
session = client.checkout.initialize(
    amount=500000,
    email="customer@example.com",
    currency="NGN",
    reference="ORDER-123",
    callback_url="https://yoursite.com/callback",
    metadata={"order_id": "123"},
    payment_methods=["bank_transfer", "payid"],
)

# Redirect your customer to:
print(session["checkout_url"])

Verify a payment ​

python
result = client.checkout.verify(session["session_id"])

if result["status"] == "completed":
    print(f"Payment confirmed at: {result['paid_at']}")

Get session details ​

python
details = client.checkout.get("ses_abc123")

Transfers ​

Bank transfer ​

python
transfer = client.transfers.create(
    type="bank_transfer",
    amount=1000000,  # ₦10,000
    account_number="0123456789",
    bank_code="044",
    account_name="John Doe",
    narration="Payout",
    reference="TXN-123",
)

PayID transfer ​

python
transfer = client.transfers.create(
    type="payid",
    amount=500000,
    pay_id="johndoe",
    narration="Payment",
)

List, verify, resolve ​

python
# List transfers
transfers = client.transfers.list(
    page=1,
    page_size=20,
    status="completed",
)

# Verify a transfer
result = client.transfers.verify("TXN-123")

# List banks
banks = client.transfers.list_banks()

# Resolve bank account
account = client.transfers.resolve_account(
    account_number="0123456789",
    bank_code="044",
)
print(account["account_name"])  # 'JOHN DOE'

# Calculate fees
charges = client.transfers.calculate_charges(amount=1000000)

# Get wallet balance
balance = client.transfers.get_balance()

Invoices ​

python
# Create
invoice = client.invoices.create(
    customer_name="Jane Doe",
    customer_email="jane@example.com",
    due_date="2026-04-01",
    line_items=[
        {"description": "Web Design", "quantity": 1, "unit_price": 5000000},
        {"description": "Hosting (1yr)", "quantity": 1, "unit_price": 1200000},
    ],
    tax_rate=7.5,
)

# Send (draft → sent)
client.invoices.send(invoice["public_id"])

# List
invoices = client.invoices.list(status="sent")

# Cancel
client.invoices.cancel(invoice["public_id"])

Static PayIDs ​

python
# Create
payid = client.static_payid.create(
    pay_id="mystore",
    name="My Store",
    description="Accept payments to my store",
)

# Deactivate / Reactivate
client.static_payid.deactivate(payid["id"])
client.static_payid.reactivate(payid["id"])

Dynamic PayIDs ​

python
# Create a time-limited payment link
dpayid = client.dynamic_payid.create(
    amount=1000000,
    name="Donation Drive",
    expires_in_minutes=60,
)

print(dpayid["full_pay_id"])  # e.g. 'donation-drive-xyz.dpay'

# Deactivate
client.dynamic_payid.deactivate(dpayid["id"])

Virtual accounts ​

python
# Create
va = client.virtual_accounts.create(
    amount=1000000,
    validity_minutes=60,
)

print(va["account_number"])  # Customer pays to this account

# List
accounts = client.virtual_accounts.list(status="pending")

Wallet ​

python
# Get wallet details
wallet = client.wallet.get()

# List members
members = client.wallet.list_members()

# Add / remove members
client.wallet.add_member(pay_id="johndoe")
client.wallet.remove_member("johndoe")

Webhook verification ​

Verify incoming webhook signatures using your webhook secret:

python
import os
from zevpay import Webhook, ZevPayError

# In your webhook handler (e.g. Flask, Django, FastAPI)
payload = request.get_data(as_text=True)
signature = request.headers.get("x-zevpay-signature", "")
secret = os.environ["ZEVPAY_WEBHOOK_SECRET"]

try:
    event = Webhook.construct_event(payload, signature, secret)

    if event["event"] == "charge.success":
        # Handle successful checkout payment
        pass
    elif event["event"] == "transfer.success":
        # Handle successful transfer
        pass
    elif event["event"] == "transfer.failed":
        # Handle failed transfer
        pass
    elif event["event"] == "invoice.paid":
        # Handle paid invoice
        pass

    return "OK", 200
except ZevPayError:
    return "Invalid signature", 400

Always verify

Never process webhook events without verifying the signature. See Verifying Signatures for details.

Error handling ​

All API errors raise typed exceptions:

python
from zevpay import (
    ZevPay,
    ValidationError,
    AuthenticationError,
    NotFoundError,
    ConflictError,
    RateLimitError,
    ApiError,
)

client = ZevPay("sk_test_your_secret_key")

try:
    client.transfers.create(type="bank_transfer", amount=1000000)
except ValidationError as e:
    # 400 — invalid parameters
    print(e.code)     # e.g. 'VALIDATION_ERROR'
    print(e.message)  # Human-readable message
except AuthenticationError:
    # 401 — invalid API key
    pass
except NotFoundError:
    # 404 — resource not found
    pass
except ConflictError:
    # 409 — duplicate transaction
    pass
except RateLimitError:
    # 429 — rate limit exceeded
    pass
except ApiError:
    # 500+ — server error
    pass
Exception classStatusWhen
ValidationError400Invalid request parameters
AuthenticationError401Invalid or missing API key
ForbiddenError403Insufficient permissions
NotFoundError404Resource not found
ConflictError409Duplicate resource
RateLimitError429Too many requests
ApiError500+Server error

Context manager ​

The client can be used as a context manager to ensure the HTTP connection is properly closed:

python
with ZevPay("sk_test_your_secret_key") as client:
    session = client.checkout.initialize(
        amount=500000,
        email="customer@example.com",
    )

Full example: FastAPI ​

python
import os
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse, RedirectResponse
from zevpay import ZevPay, Webhook, ZevPayError

app = FastAPI()
zevpay = ZevPay(os.environ["ZEVPAY_SECRET_KEY"])


@app.post("/api/pay")
async def create_payment(request: Request):
    body = await request.json()

    session = zevpay.checkout.initialize(
        amount=body["amount"],
        email=body["email"],
        reference=f"ORDER-{body['order_id']}",
        callback_url=str(request.url_for("payment_callback")),
    )

    return {"checkout_url": session["checkout_url"]}


@app.get("/api/callback")
async def payment_callback(session_id: str):
    result = zevpay.checkout.verify(session_id)

    if result["status"] == "completed":
        return {"message": "Payment successful!"}

    return {"message": "Payment not completed yet."}


@app.post("/webhooks/zevpay")
async def webhook_handler(request: Request):
    payload = (await request.body()).decode()
    signature = request.headers.get("x-zevpay-signature", "")

    try:
        event = Webhook.construct_event(
            payload, signature, os.environ["ZEVPAY_WEBHOOK_SECRET"]
        )
        print(f"Webhook received: {event['event']}")
        return {"status": "ok"}
    except ZevPayError:
        return JSONResponse({"error": "Invalid signature"}, status_code=400)

Resources ​

ZevPay Checkout Developer Documentation