How to Add License Key Validation to Your Python Application
Whether you're building a CLI tool, a Django web app, or a desktop application with PyQt, adding license key validation protects your revenue. This tutorial walks you through the complete implementation using Python.
Prerequisites
- Python 3.8+
- A Traffic Orchestrator account (sign up free)
- An API key from your dashboard
Validate your first license key in under 5 minutes — free plan, no credit card required.
Installation
pip install traffic-orchestrator
The traffic-orchestrator package is published on PyPI and supports Python 3.8+.
Basic License Validation
The simplest integration is a single validation call:
from traffic_orchestrator import TrafficOrchestrator
Initialize with your API key client = TrafficOrchestrator(api_key="to_live_xxxxxxxxxxxx")
Validate a license key result = client.licenses.validate( key="LIC-XXXX-XXXX-XXXX", domain="app.example.com" # Optional: for domain-bound licenses )
if result.valid: print(f"License active — Plan: {result.plan}") print(f"Expires: {result.expires_at}") else: print(f"License invalid: {result.error}") ```
That's the entire integration. Three lines of real code.
Handling Edge Cases
Production code needs to handle more than the happy path:
import sys
from traffic_orchestrator import TrafficOrchestrator
from traffic_orchestrator.exceptions import (
NetworkError,
RateLimitError,
InvalidKeyError
)
client = TrafficOrchestrator(api_key="to_live_xxxxxxxxxxxx")
def check_license(license_key: str) -> bool: """Validate license with graceful error handling.""" try: result = client.licenses.validate(license_key) if not result.valid: print(f"License expired or revoked: {result.error}") return False # Check if approaching expiration if result.days_remaining and result.days_remaining < 14: print(f"Warning: License expires in {result.days_remaining} days") return True except NetworkError: # Network is down — fall back to cached validation # or allow a grace period print("Network unavailable — using cached validation") return check_cached_license(license_key) except RateLimitError: # Too many validation requests print("Rate limited — using cached result") return check_cached_license(license_key) except InvalidKeyError: # Key format is wrong print("Invalid license key format") return False
def check_cached_license(key: str) -> bool: """Check locally cached validation result.""" import json from pathlib import Path from datetime import datetime, timedelta cache_file = Path.home() / ".myapp" / "license_cache.json" if not cache_file.exists(): return False cache = json.loads(cache_file.read_text()) if cache.get("key") != key: return False # Allow 7-day offline grace period cached_at = datetime.fromisoformat(cache["validated_at"]) if datetime.now() - cached_at > timedelta(days=7): return False return cache.get("valid", False) ```
Django Integration
For Django applications, create a middleware that checks the license on startup:
# myapp/middleware.py
from traffic_orchestrator import TrafficOrchestrator
from django.conf import settings
from django.http import HttpResponse
client = TrafficOrchestrator(api_key=settings.TO_API_KEY) _license_valid = None # Cache the result
class LicenseMiddleware: def __init__(self, get_response): self.get_response = get_response self._check_license() def _check_license(self): global _license_valid try: result = client.licenses.validate( key=settings.LICENSE_KEY, domain=settings.ALLOWED_HOSTS[0] ) _license_valid = result.valid except Exception: # On error, use previous cached state if _license_valid is None: _license_valid = False def __call__(self, request): if not _license_valid: return HttpResponse( "License validation failed. Please check your license key.", status=403 ) return self.get_response(request) ```
# settings.py
MIDDLEWARE = [
'myapp.middleware.LicenseMiddleware',
# ... other middleware
]
TO_API_KEY = os.environ.get('TRAFFIC_ORCHESTRATOR_API_KEY') LICENSE_KEY = os.environ.get('APP_LICENSE_KEY') ```
Flask Integration
For Flask, use a before_request hook:
from flask import Flask, abort
from traffic_orchestrator import TrafficOrchestrator
app = Flask(__name__) client = TrafficOrchestrator(api_key=app.config['TO_API_KEY'])
@app.before_first_request def validate_license(): result = client.licenses.validate(app.config['LICENSE_KEY']) if not result.valid: raise RuntimeError(f"Invalid license: {result.error}")
@app.route('/') def index(): return "Application running with valid license" ```
CLI Tool Protection
For command-line tools distributed via PyPI:
# cli.py
import click
from traffic_orchestrator import TrafficOrchestrator
client = TrafficOrchestrator(api_key="to_live_xxxxxxxxxxxx")
@click.group() def cli(): """My awesome CLI tool.""" pass
@cli.command() @click.argument('license_key') def activate(license_key: str): """Activate your license.""" result = client.licenses.validate(license_key) if result.valid: # Store the key locally config_dir = Path.home() / ".mytool" config_dir.mkdir(exist_ok=True) (config_dir / "license").write_text(license_key) click.echo("License activated successfully!") else: click.echo(f"Invalid license: {result.error}", err=True) sys.exit(1)
@cli.command() def run(): """Run the tool (requires valid license).""" license_file = Path.home() / ".mytool" / "license" if not license_file.exists(): click.echo("No license found. Run: mytool activate YOUR-KEY", err=True) sys.exit(1) key = license_file.read_text().strip() result = client.licenses.validate(key) if not result.valid: click.echo(f"License invalid: {result.error}", err=True) sys.exit(1) # Your actual tool logic here click.echo("Running with valid license...") ```
Best Practices
- Cache validation results — Don't validate on every function call. Cache for 1-24 hours.
- Handle offline gracefully — Allow a grace period (7-30 days) using cached results.
- Don't block the UI — Validate in a background thread for desktop apps.
- Store keys securely — Use the OS keyring, not plain text files, for production.
- Log validation failures — But never log the full license key itself.
Next Steps
- Sign up for free — Builder plan includes 5 licenses
- API Documentation — Full endpoint reference
- Node.js Tutorial — If you also need Node.js integration
Published by Traffic Orchestrator Team
Related Articles
- How to Add License Key Validation to Your Rust Application
- How to Build a Secure License Key Generator
- Looking for a Keygen Alternative?
Ship licensing in your next release
5 licenses, 500 validations/month, full API access. Set up in under 5 minutes — no credit card required.