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 qrmax

Initialize 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....png

Async 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 "", 200

Error 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)