Official Python SDK for NordPay API — crypto payment processing
Project description
NordPay Python SDK
Official Python SDK for the NordPay API — accept crypto payments with a few lines of code.
Features
- Sync & Async —
NordPay(sync) andAsyncNordPay(async) with identical API - Full type hints — autocomplete everywhere,
py.typed(PEP 561) - Pydantic v2 models — validated responses,
Decimalprecision for money - Typed exceptions — specific error class for every HTTP status
- Automatic retries — exponential backoff on 429/5xx (configurable)
- Webhook verification — validate postback signatures with constant-time comparison
- Zero config — just pass your API key
Installation
pip install nordpay
Quick Start
from nordpay import NordPay
with NordPay("your-api-key") as client:
# Create a $100 invoice
invoice = client.invoices.create(
amount="100 USD",
label="Order #123",
expires_time=60, # minutes
allowed_currencies=["BTC", "USDTERC20", "USDTTRC20"],
)
print(f"Payment link: {invoice.url}")
print(f"Status: {invoice.status}")
Async
import asyncio
from nordpay import AsyncNordPay
async def main():
async with AsyncNordPay("your-api-key") as client:
invoice = await client.invoices.create(
amount="50 USD",
label="Subscription",
expires_time=30,
allowed_currencies=["BTC", "USDTERC20", "USDTTRC20"],
)
print(invoice.url)
asyncio.run(main())
API Reference
Currencies (public, no auth)
client = NordPay() # no API key needed
currencies = client.currencies.list() # each Currency carries its own `.rate`
rates = client.currencies.rates() # convenience view derived from list()
fiats = client.fiat_currencies.list()
fiat_rates = client.fiat_currencies.rates()
Invoices
# Create
invoice = client.invoices.create(
amount="100 USD", # or "0.5 BTC"
label="Order #123",
expires_time=60, # minutes (30-1440)
currency="USDTERC20", # lock to specific crypto (or use allowed_currencies)
postback_url="https://...", # optional: webhook URL
success_url="https://...", # optional: redirect on success
fail_url="https://...", # optional: redirect on failure
allowed_currencies=["BTC", "USDTERC20", "USDTTRC20"], # min 2 currencies
)
# List / Get
invoices = client.invoices.list() # paginates over all invoices
inv = client.invoices.get("uuid-or-id")
print(inv.status, inv.tx_hash, inv.explorer_url) # tx_hash / explorer_url populate once paid
# Paginated list with filters
page = client.invoices.list_paginated(
status="paid", currency=["BTC", "USDTBEP20"],
sort="created_at:desc", limit=50,
)
# Auto-paginate (iterate all pages automatically)
for inv in client.invoices.auto_paginate(status="paid"):
print(inv.uuid, inv.amount_usd)
# Summary statistics
summary = client.invoices.summary()
print(
f"Total: {summary.total_count}, Paid: {summary.paid_count}, "
f"Pending: {summary.pending_count}, Cancelled: {summary.cancelled_count}, "
f"Partially paid: {summary.partially_paid_count}"
)
# Transactions
txs = client.invoices.transactions() # all invoices
txs = client.invoices.transactions("uuid-or-id") # specific
# Postback logs & retry
logs = client.invoices.postback_logs(invoice_id=131)
client.invoices.retry_postback(invoice_id=131, log_id=1)
Wallets
wallet = client.wallets.create(currency="BTC", label="Store Wallet")
wallets = client.wallets.list()
wallet = client.wallets.get(wallet_id=42)
qr = client.wallets.qrcode(wallet_id=42) # base64
txs = client.wallets.transactions(wallet_id=42)
# Paginated list
page = client.wallets.list_paginated(currency="USDTBEP20", status="active")
# Wallet creation limits
limits = client.wallets.limits()
print(f"Available: {limits.available}/{limits.total}")
# Postback logs
logs = client.wallets.postback_logs(wallet_id=42)
Balance
balances = client.balance.get()
for b in balances:
if float(b.amount) > 0:
print(f"{b.currency}: {b.amount}")
# Withdrawal history (paginated)
history = client.balance.withdraw_history(currency="USDTBEP20", limit=50)
for w in client.balance.auto_paginate_withdraws():
print(f"{w.currency}: {w.amount} — {w.status}")
# Per-currency withdrawal limits
for lim in client.balance.withdraw_limits():
print(f"{lim.currency}: min={lim.min_amount}, max={lim.max_amount}, fee={lim.fee_percent}%")
Withdrawals
from decimal import Decimal
# Step 1: Request
req = client.withdrawals.request(
currency="USDTERC20",
address="0x742d35Cc6634C0532925a3b844Bc9e7595f2bD18",
amount=Decimal("100.50"),
)
print(f"Fee: {req.service_fee} | Expires: {req.expires_at}")
# Step 2: Confirm
result = client.withdrawals.confirm(req.identifier)
# Batch withdrawal
batch = client.withdrawals.request_multiple(
currency="USDTTRC20",
recipients=[
("TAddress1...", Decimal("50.00")),
("TAddress2...", Decimal("75.00")),
],
)
result = client.withdrawals.confirm_multiple(batch.identifier)
Webhook Verification
NordPay sends a postback_secret in webhook payloads. Verify it:
from nordpay import verify_postback, WebhookVerificationError
# FastAPI
@app.post("/webhook")
async def handle(request: Request):
body = await request.json()
try:
event = verify_postback(body, secret="your-postback-secret")
except WebhookVerificationError:
raise HTTPException(403)
if event.postback_type == "transaction":
print(f"Tx {event.tx_hash}: {event.amount} {event.currency}")
return {"ok": True}
Or just a boolean check:
from nordpay import is_valid_postback
if is_valid_postback(payload, secret="your-secret"):
# process
...
Error Handling
from nordpay import NordPay, BadRequestError, AuthenticationError, RateLimitError
try:
invoice = client.invoices.create(amount="100 USD", label="Test", expires_time=60)
except AuthenticationError:
print("Invalid API key")
except BadRequestError as e:
print(f"Bad request: {e.detail}")
print(f"Response: {e.response_body}") # full error body
except RateLimitError as e:
print(f"Rate limited, retry after {e.retry_after}s")
Exception Hierarchy
NordPayError # base
├── AuthenticationError # 401
├── ForbiddenError # 403
├── BadRequestError # 400
├── NotFoundError # 404
├── RateLimitError # 429 (+ retry_after)
├── ServerError # 5xx
└── WebhookVerificationError # invalid postback
Configuration
client = NordPay(
api_key="your-key",
base_url="https://api.nord-pay.com", # default
timeout=30.0, # seconds
max_retries=3, # retry on 429/5xx (0 to disable)
)
Logging
import logging
logging.basicConfig(level=logging.DEBUG)
logging.getLogger("nordpay").setLevel(logging.DEBUG)
# Now you'll see all HTTP requests and retries
Requirements
- Python 3.10+
- httpx >= 0.25
- pydantic >= 2.0
License
MIT
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
nordpay-1.3.0.tar.gz
(14.2 kB
view details)
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
nordpay-1.3.0-py3-none-any.whl
(16.7 kB
view details)
File details
Details for the file nordpay-1.3.0.tar.gz.
File metadata
- Download URL: nordpay-1.3.0.tar.gz
- Upload date:
- Size: 14.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.8 {"installer":{"name":"uv","version":"0.11.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
02627916145ffbb4e5c7d69f18a5a82000ee2f4d10f1efc21c93272bafc54136
|
|
| MD5 |
0bf842ef17022e2df83da78a0a46b29e
|
|
| BLAKE2b-256 |
90fd1ef4f4aca3a71bc45025b7a1f540c1318ecb1dfab31397412b8411d3a6f7
|
File details
Details for the file nordpay-1.3.0-py3-none-any.whl.
File metadata
- Download URL: nordpay-1.3.0-py3-none-any.whl
- Upload date:
- Size: 16.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.8 {"installer":{"name":"uv","version":"0.11.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
afcd23e8c805dba5d8f8b26e067476bfb2d4d64996012195ea5fe38d3445008c
|
|
| MD5 |
d02a7052fb50033f493672fbb6077fb6
|
|
| BLAKE2b-256 |
9015e54875bf91a82602abd95a072f4251644088b771fb78aee24ddf683f642e
|