Python SDK

Official ZynPay SDK for Python applications. Perfect for FastAPI backends with MetaMask frontend integration.

v0.2.0TestnetPython ≥3.8

Key Features

  • 💳 Accept USDC payments with MetaMask integration
  • 🔁 Refunds: Full and partial refunds, enforced by smart contract
  • 📊 Payment logs: Fetch on-chain payment history for dashboards & analytics
  • 🔒 Non-custodial: Payments go directly to your wallet
  • ⚡ Zero backend complexity: No API keys or servers required

Installation

pip install zynpay

Quick Start

Backend (FastAPI)

from fastapi import FastAPI
from zynpay import ZynPayClient, Environment

app = FastAPI()

client = ZynPayClient(
    merchant_wallet="0xYourBusinessWallet",
    environment=Environment.TESTNET
)

@app.post("/api/payment/create")
async def create_payment(amount: float):
    payment = client.payments.create(amount=amount, chain="base")
    return {
        'payment_id': payment.id,
        'amount': payment.amount,
        'router_address': payment.router_address
    }

API Reference

ZynPayClient(config)
Initialize the SDK client
client = ZynPayClient(
    merchant_wallet="0x...",
    environment=Environment.TESTNET,
    default_chain="base"
)
client.payments.create()
Create a new payment request
payment = client.payments.create(
    amount=49.99,
    chain="base",
    metadata={"order_id": "123"}
)
client.payments.verify()
Verify payment on blockchain
verified = client.payments.verify(payment, tx_hash="0x...")
client.payments.list_payments() – Payment log (on-chain history)
Fetch an on-chain payment log for a merchant

Under the hood, this reads

PaymentSplit
events from the router contract using
getLogs
.

# Basic: all payments for the configured merchant wallet
payments = client.payments.list_payments()

# Or for another merchant wallet:
payments = client.payments.list_payments(
    merchant_address="0xMerchantAddress..."
)

# With filters:
payments = client.payments.list_payments(
    merchant_address="0xMerchantAddress...",
    network="base-sepolia",
    from_block="34000000",
    to_block="latest",
)

for p in payments:
    amount = float(p["amountTotal"]) / 1e6
    merchant_amount = float(p["amountToMerchant"]) / 1e6
    fee = float(p["amountToPlatform"]) / 1e6

    print("Payment: $" + format(amount, ".2f") + " USDC")
    print("  You receive: $" + format(merchant_amount, ".2f") + " USDC")
    print("  Platform fee: $" + format(fee, ".2f") + " USDC")
    print("  TX: " + p['txHash'])
    print("  Payer: " + p['payer'])
    if p.get("metadata"):
        print("  Metadata: " + str(p['metadata']))

Use cases:

  • Build a merchant dashboard (revenue, average order value, etc.)
  • Export payments to your own database / BI tool
  • Reconcile off-chain orders with on-chain payments using metadata (e.g. order_id)
client.payments.refund() – Refund a payment
Refunds are initiated by the merchant wallet that originally received the funds

Use this when you need to refund a customer (full or partial). Refunds are merchant-driven and on-chain.

from zynpay import ZynPayClient, Environment

client = ZynPayClient(
    merchant_wallet="0xYourMerchantWallet",
    environment=Environment.TESTNET,
)

# Example: refund 5.00 USDC from a previous payment
refund_tx = client.payments.refund(
    payment_id="PAYMENT_REQUEST_ID_FROM_BACKEND",
    amount=5.00,
    chain="base",           # optional if default_chain is set
)

print(f"✅ Refund sent! TX: {refund_tx.hash}")

How refunds work:

  • Refunds are merchant-driven: Only the merchant (the wallet that received the payment) can initiate a refund.
  • Refunds are on-chain: The merchant sends USDC back to the payer via the router contract.
  • Supports: ✅ Full refunds (up to 100% of the original amount) ✅ Multiple partial refunds
  • The smart contract guarantees: You can never refund more than the original amount (cumulative limit). Platform fee is not automatically refunded – if you refund 100%, that extra few % comes from your balance.

🔐 The SDK handles the on-chain call for you. You just decide which payment and how much to refund.

client.web3.get_balance()
Check USDC and native token balance
balance = client.web3.get_balance(wallet="0x...", chain="base")
client.web3.estimate_gas()
Estimate gas cost for payment
estimate = client.web3.estimate_gas(amount=10.0, chain="base")
client.testnet.get_faucet_url()
Get testnet faucet URL (testnet only)
url = client.testnet.get_faucet_url("base")

Environment Management

from zynpay import Environment

# Testnet
client = ZynPayClient(
    merchant_wallet="0x...",
    environment=Environment.TESTNET
)

# Mainnet (coming soon)
client = ZynPayClient(
    merchant_wallet="0x...",
    environment=Environment.MAINNET
)

Error Handling

from zynpay import (
    InsufficientFundsException,
    PaymentFailedException
)

try:
    payment = client.payments.create(amount=5.00)
except InsufficientFundsException as e:
    print(f"Not enough funds: {e.required} USDC required")
except PaymentFailedException as e:
    print(f"Payment failed: {e.reason}")

Supported Networks

Base Sepolia (Recommended)
Arc Testnet

chain="arc"

Get free USDC

Why No API Keys?

ZynPay works directly with the blockchain - no servers, no accounts, no authentication needed. The 3% fee is enforced by smart contracts, making it truly decentralized and permissionless.