Python SDK
Installation (Coming Soon)
pip install xqr-pythonRequires Python 3.10+.
Quick Start
import asynciofrom xqr import AsyncXQR
async def main(): xqr = AsyncXQR(api_key="xqr_pk_...")
link = await xqr.links.create( url="https://example.com", custom_slug="my-link", labels=["campaign"], ) print(link.short_url) # https://xqr.co/my-link
asyncio.run(main())from xqr import XQR
xqr = XQR(api_key="xqr_pk_...")
link = xqr.links.create( url="https://example.com", custom_slug="my-link",)print(link.short_url)Links
# Create with routing ruleslink = await xqr.links.create( url="https://example.com/default", custom_slug="global-promo", labels=["promo", "q1"], routing_rules=[ { "destination": "https://example.de/promo", "priority": 1, "conditions": { "countries": ["DE", "AT", "CH"], "country_mode": "include", }, } ], expires_at="2026-09-30T23:59:59Z",)
# List with auto-paginationasync for link in xqr.links.list(label="campaign"): print(f"{link.short_code}: {link.scan_count} scans")
# Updateawait xqr.links.update(link.id, url="https://example.com/updated")
# Deleteawait xqr.links.delete(link.id)
# Bulk createresult = await xqr.links.bulk_create([ {"url": "https://example.com/page-1"}, {"url": "https://example.com/page-2", "custom_slug": "page-2"},])print(f"Created: {len(result.created)}, Errors: {len(result.errors)}")QR Codes
# Generate a QR codeqr_bytes = await xqr.qr.generate( content="https://example.com", format="png", size=20, error_correction="H", foreground="#8B5CF6",)
with open("qr.png", "wb") as f: f.write(qr_bytes)
# Create a templatetemplate = await xqr.qr.templates.create( name="Brand Primary", design={ "foreground": "#8B5CF6", "background": "#FFFFFF", "error_correction": "H", "logo_url": "https://cdn.xqr.co/logo.png", "dot_style": "rounded", },)
# Render with templatebranded = await xqr.qr.templates.render( template.id, content="https://example.com/campaign", size=30,)Analytics
# Workspace summarysummary = await xqr.analytics.summary(period="30d")print(f"Total scans: {summary.total_scans}")print(f"Growth: {summary.scans_change_pct}%")
# Timeseriestimeseries = await xqr.analytics.timeseries(period="7d", granularity="hour")for point in timeseries: print(f"{point.timestamp}: {point.scans}")
# Geographygeo = await xqr.analytics.geography(period="30d")for g in geo: print(f"{g.country}: {g.percentage}%")
# Link-specific statsstats = await xqr.analytics.link_stats(link.id, period="90d")print(f"{stats.total_scans} scans, {stats.unique_visitors} unique")
# Top linkstop = await xqr.analytics.top_links(period="30d", limit=5)Link-in-Bio
# Create a pagepage = await xqr.bio.create( title="Jane Doe", slug="janedoe", bio="Designer & Developer", links=[ {"title": "Portfolio", "url": "https://janedoe.com"}, {"title": "GitHub", "url": "https://github.com/janedoe", "icon": "github"}, ],)
# Publishawait xqr.bio.publish(page.id)
# Updateawait xqr.bio.update(page.id, bio="Senior Designer & Developer")
# Get statsstats = await xqr.bio.stats(page.id)print(f"Page views: {stats.page_views}")Assets
# Upload a fileasset = await xqr.assets.upload("./logo.png")
# Publish to CDNpublished = await xqr.assets.publish(asset.id)print(published.public_url)
# List assetsasync for asset in xqr.assets.list(): print(f"{asset.filename} ({asset.status})")Error Handling
from xqr import AsyncXQR, XQRError, RateLimitError, ValidationError
try: link = await xqr.links.create(url="invalid")except ValidationError as e: print(f"Bad input: {e.message}")except RateLimitError as e: print(f"Rate limited. Retry after {e.retry_after}s")except XQRError as e: print(f"API error {e.code}: {e.message}") print(f"Request ID: {e.request_id}")Configuration
xqr = AsyncXQR( api_key="xqr_pk_...",
# Optional base_url="https://xqr.co/api/v1", timeout=30.0, max_retries=3, debug=False,)
# Or from environment variableimport osxqr = AsyncXQR(api_key=os.environ["XQR_API_KEY"])Pydantic Models
All response objects are Pydantic models with full type annotations:
from xqr.models import Link, QRTemplate, BioPage
link: Link = await xqr.links.get("link-id")print(link.model_dump_json(indent=2))
# Type-safe accessprint(link.short_url) # strprint(link.scan_count) # intprint(link.labels) # list[str]print(link.created_at) # datetimeStay Updated
Watch the GitHub repository for the SDK release announcement, or subscribe to the changelog RSS feed.
Was this page helpful?
Thanks for your feedback!