Python SDK
Drop-in source files for Python — copy them into your project. Nothing to install from a package registry.
Download
Two files, copy what you need:
| File | Runs on | Needs |
|---|---|---|
license_client.py | your customers' machines - checks a license | pip install cryptography |
automation_client.py | your server only - creates and manages keys with an API token | nothing (standard library) |
License client
from license_client import LicenseClient
client = LicenseClient(
base_url="https://license.foliox.sbs",
product="YOUR_PRODUCT_ID", # shown on the product's page in your dashboard
public_key_b64="PASTE_PUBLIC_KEY_FROM_THE_DOCS", # public - not a secret
)
result = client.check(license_key) # activates on first run, verifies afterwards
if result.valid:
print("licensed, status:", result.status, "expires:", result.expires_at)
else:
print("not licensed:", result.reason)
See example.py for a runnable script. Useful extras: client.require(key) (raises LicenseInvalid), client.clear_cache(), is_valid_key_format(key), compute_hwid().
What it does for you
- HTTPS only (plain
http://is refused except for localhost while developing); certificates always verified, TLS 1.2+, redirects never followed. - Nothing is believed before its Ed25519 signature is checked, then the product it names and its age (
max response age, default 15 minutes) so an old captured answer can't be replayed. - Safe retries: network errors, timeouts, HTTP 429 and 5xx are retried with exponential backoff + jitter inside a hard deadline (default 20 s). A definite answer (revoked, expired, wrong device) is never retried or softened.
- Offline grace from the last valid signed answer (72 h, never past the key's own expiry), bound to this device, product and key; the raw key is never stored; a definite "no" deletes it; a clock set back is detected.
check()never raises/panics for runtime conditions - it returns a result. Bad configuration is reported when the client is created.
Offline grace is a resilience feature, not a security boundary. See the SDKs & API wrapper page in your server's docs for the full list, what no client library can do, and upgrade notes from v1.
Automation client (server side)
import os
from automation_client import AutomationClient
api = AutomationClient("https://license.foliox.sbs", token=os.environ["LICENSE_API_TOKEN"])
[key] = api.create_keys("YOUR_PRODUCT_ID", duration_days=365, customer_email="[email protected]")
print(key["key"])
api.revoke_key(key["key"])
# a public key: no device binding, so any number of people can use the same key at once
[shared] = api.create_keys("YOUR_PRODUCT_ID", key_type="public")
key_type is "device" (the default: each key locks to the first device that activates it) or "public". The license client above works with both types unchanged.
The token can mint keys: keep it in an environment variable or secret manager on a server you control, never in software your customers run. Every failure is a typed exception (NotFoundError, PlanLimitError, RateLimitedError, ...). Creating keys is not retried after an ambiguous failure, so it can't create duplicates.