Back to docs
SDK
Python
The official qrmax Python SDK — typed with Pydantic v2, both sync and async clients, Python 3.9+.
Pydantic v2Sync + AsyncPython 3.9+Type-stubbed
Install
pip install qrmaxInitialize the client
Both sync and async clients share the same interface.
Python
from qrmax import QRMax
qrmax = QRMax(api_key="qrmx_live_sk_...")
# or async
from qrmax import AsyncQRMax
async_client = AsyncQRMax(api_key="qrmx_live_sk_...")Create a dynamic QR code
Sync usage — returns a fully typed QR code object.
Python
qr = qrmax.qr_codes.create(
type="url",
target="https://example.com/spring-sale",
dynamic=True,
design={
"foreground_color": "#4f46e5",
"logo_url": "https://example.com/logo.png",
"corner_style": "rounded",
},
)
print(qr.short_url) # https://qrx.io/a3b9c2
print(qr.image_url) # https://cdn.qrmax.io/qr/qr_01HNP....pngAsync usage
For FastAPI, Starlette, or any asyncio-based server.
Python
import asyncio
from qrmax import AsyncQRMax
async def main():
async with AsyncQRMax(api_key="...") as qrmax:
qr = await qrmax.qr_codes.create(
type="url",
target="https://example.com",
dynamic=True,
)
print(qr.short_url)
asyncio.run(main())Re-target a dynamic QR
The printed pattern never changes — only the redirect does.
Python
qrmax.qr_codes.update(qr.id, target="https://example.com/summer-sale")Fetch scan analytics
Pass dates as strings or datetime objects.
Python
from datetime import date
analytics = qrmax.qr_codes.analytics(
qr.id,
from_=date(2026, 4, 1),
to=date(2026, 4, 19),
)
print(analytics.total_scans) # 1247
print(analytics.unique_scanners) # 892
for c in analytics.top_countries:
print(c.code, c.scans)List and iterate
Auto-pagination across pages.
Python
for qr in qrmax.qr_codes.list(type="url"):
print(qr.id, qr.short_url)Verify a webhook (Flask)
Validate HMAC signature before trusting webhook payloads.
Python
from flask import Flask, request, abort
from qrmax import verify_webhook
app = Flask(__name__)
@app.post("/webhooks/qrmax")
def qrmax_webhook():
signature = request.headers.get("X-QRMax-Signature")
body = request.get_data() # raw bytes
try:
event = verify_webhook(
body=body,
signature=signature,
secret=os.environ["QRMAX_WEBHOOK_SECRET"],
)
except ValueError:
abort(400, "invalid signature")
print(event["event"], event["data"])
return "", 200Error handling
Typed exceptions for different failure modes.
Python
from qrmax import QRMaxError, RateLimitError, ValidationError
try:
qrmax.qr_codes.create(type="url", target="")
except ValidationError as err:
print("validation failed:", err.details)
except RateLimitError as err:
print(f"retry after {err.retry_after_ms}ms")
except QRMaxError as err:
print(err.status, err.code, err.message)