SagaPay Python SDK
Python SDK for SagaPay - the world's first free, non-custodial blockchain payment gateway service provider. This SDK enables Python developers to seamlessly integrate cryptocurrency payments without holding customer funds. With enterprise-grade security and zero transaction fees, SagaPay empowers merchants to accept crypto payments across multiple blockchains while maintaining full control of their digital assets.
Installation
pip install sagapay-sdk
Quick Start
from sagapay import Client, NetworkType
# Initialize the SagaPay client
client = Client(
api_key="your-api-key",
api_secret="your-api-secret"
)
# Create a deposit address
deposit = client.create_deposit({
"network_type": NetworkType.BEP20,
"contract_address": "0", # Use '0' for native tokens (BNB)
"amount": "1.5",
"ipn_url": "https://yourwebsite.com/webhook",
"udf": "order-123",
"type": "TEMPORARY"
})
print(f"Deposit address created: {deposit.address}")
print(f"Expires at: {deposit.expires_at}")
Features
- Deposit address generation
- Withdrawal processing
- Transaction status checking
- Wallet balance fetching
- Multi-chain support (ERC20, BEP20, TRC20, POLYGON, SOLANA)
- Webhook notifications (IPN)
- Custom UDF field support
- Non-custodial architecture
- Comprehensive error handling
- Pydantic models for type safety
API Reference
Create Deposit
deposit = client.create_deposit({
"network_type": NetworkType.BEP20, # Required: Blockchain network type
"contract_address": "0", # Required: Contract address or '0' for native coins
"amount": "1.5", # Required: Expected deposit amount
"ipn_url": "https://example.com/webhook", # Required: URL for notifications
"udf": "order-123", # Optional: User-defined field
"type": "TEMPORARY", # Optional: TEMPORARY or PERMANENT
"transfer_balance": True # Optional: Auto-transfer received funds (default: true)
})
Create Withdrawal
withdrawal = client.create_withdrawal({
"network_type": NetworkType.ERC20,
"contract_address": "0xdAC17F958D2ee523a2206206994597C13D831ec7", # USDT on Ethereum
"address": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
"amount": "10.5",
"ipn_url": "https://example.com/webhook",
"udf": "withdrawal-456"
})
Check Transaction Status
# By address
status = client.check_transaction_status(
transaction_type=TransactionType.DEPOSIT,
address="0x742d35Cc6634C0532925a3b844Bc454e4438f44e"
)
# By transaction ID
status = client.check_transaction_status(
transaction_type=TransactionType.DEPOSIT,
id="deposit-uuid"
)
Fetch Wallet Balance
balance = client.fetch_wallet_balance(
address="0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
network_type=NetworkType.ERC20,
contract_address="0xdAC17F958D2ee523a2206206994597C13D831ec7" # USDT on Ethereum
)
Verify IPN
verify_ipn() confirms directly with SagaPay that an IPN notification is genuine. It is the primary way to authenticate webhook notifications. Your API credentials are sent in the request body for this endpoint (no authentication headers are used).
from sagapay import IpnType
result = client.verify_ipn(
txn_hash="0xabc123...", # txHash from the webhook payload
type=IpnType.DEPOSIT, # or "DEPOSIT" / "WITHDRAWAL"
amount="10.5",
address="0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
)
if result.verified:
print("Notification is genuine")
Handling Webhooks (IPN)
SagaPay sends webhook notifications to your specified ipn_url when a transaction completes. Delivery is at-least-once, so the same notification may be delivered more than once — make your handling idempotent (e.g. skip transaction IDs you have already processed).
The primary way to confirm a notification is genuine is client.verify_ipn(), which checks the transaction directly with SagaPay.
In addition, each webhook request carries an X-Sagapay-Signature: sha256=<hex digest> header — an HMAC-SHA256 of the exact raw request body, keyed with a platform-issued IPN secret (this is NOT your API secret). If SagaPay has issued you an IPN secret, pass it to WebhookHandler to verify the header; if you have none, leave it unset and signature verification is skipped.
from flask import Flask, request, jsonify
from sagapay import Client, IpnType, TransactionStatus, WebhookHandler
app = Flask(__name__)
client = Client(api_key="your-api-key", api_secret="your-api-secret")
# ipn_secret is the OPTIONAL platform-issued IPN secret (NOT your API secret).
# Leave it unset (None) if you have none -- signature verification is skipped.
webhook_handler = WebhookHandler(ipn_secret="your-ipn-secret")
@app.route("/webhook", methods=["POST"])
def handle_webhook():
# Get the signature from the headers, e.g. "sha256=<hex digest>"
signature = request.headers.get("X-Sagapay-Signature")
# Get the exact raw request body (required for signature verification)
payload = request.get_data()
try:
# Parse the payload (the signature is verified only when an
# ipn_secret is configured)
webhook = webhook_handler.process_webhook(payload, signature)
# Primary check: confirm the notification with SagaPay
verification = client.verify_ipn(
txn_hash=webhook.tx_hash,
type=webhook.type,
amount=webhook.amount,
address=webhook.address,
)
if not verification.verified:
return jsonify({"received": False, "error": "IPN not verified"}), 200
# Handle the transaction (delivery is at-least-once -- be idempotent)
if webhook.status == TransactionStatus.COMPLETED:
if webhook.type == IpnType.DEPOSIT:
# Handle successful deposit
update_order_status(webhook.udf, "paid")
else:
# Handle successful withdrawal
update_withdrawal_status(webhook.udf, "completed")
# Return a success response
return jsonify({"received": True}), 200
except Exception as e:
# Log the error and return a response
# Still return 200 to prevent retries
return jsonify({"received": False, "error": str(e)}), 200
Webhook Payload Format
When SagaPay sends a webhook to your endpoint, it will include the following payload:
{
"id": "transaction-uuid",
"type": "DEPOSIT|WITHDRAWAL",
"status": "COMPLETED",
"address": "0x123abc...",
"networkType": "ERC20|BEP20|TRC20|POLYGON|SOLANA",
"amount": "10.5",
"udf": "your-optional-user-defined-field",
"txHash": "0xabc123...",
"timestamp": "2025-03-16T14:30:00Z"
}
Notes:
typeis uppercase (DEPOSITorWITHDRAWAL) and parses toIpnType.statusis currently alwaysCOMPLETED— notifications are only sent when a transaction completes.udfandtxHashmay benull.
Error Handling
The SDK includes comprehensive error handling with specific exception types. API errors are returned as {"error": "<human-readable message>"} — the message is surfaced in the exception, and the full body is available on e.response:
from sagapay import Client
from sagapay.exceptions import APIError, ValidationError, WebhookError, NetworkError
try:
client = Client(api_key="your-api-key", api_secret="your-api-secret")
deposit = client.create_deposit(params)
except ValidationError as e:
print(f"Validation error: {e}")
except APIError as e:
print(f"API error ({e.status_code}): {e.message}")
except NetworkError as e:
print(f"Network error: {e}")
License
This SDK is released under the MIT License.
Support
For questions or support, please contact support@sagapay.net or visit https://sagapay.net.
Release files for sagapay-sdk 0.4.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| sagapay_sdk-0.4.0.tar.gz | 16.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| sagapay_sdk-0.4.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 29.4 kB
Release files / sagapay_sdk-0.4.0.tar.gz
| Download URL | sagapay_sdk-0.4.0.tar.gz |
|---|---|
| Size | 16.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f165f5e35a1a0f613b51f58e1da15612105aa2f648327de70cb6b389b1d1f1b2
|
|
BLAKE2b-256 checksum How to use checksums |
08cd9a50cb5c73d2d5688211dc2b3caff36d828ba59dfa802427e42e9782d97c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.7
|
Release files / sagapay_sdk-0.4.0-py3-none-any.whl
| Download URL | sagapay_sdk-0.4.0-py3-none-any.whl |
|---|---|
| Size | 12.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
d3cd3db482738ddd3b61a3244de581ce4d2e9c3c06d83da1e34a37f7c5f86b50
|
|
BLAKE2b-256 checksum How to use checksums |
b5aa514872768b613338f1a41b1f8b752ae6054587a9f52e4fa9cc295bdb01f6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.7
|