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