Skip to main content

Client SDK for Licers — verify software license keys with tamper-proof, signed responses.

Project description

pylicensify

Client SDK for Licers — verify software license keys with tamper-proof, signed responses. A cracked "fake server" can't grant access, because every response is verified against your public key.

pip install pylicensify

Brand vs. endpoint: Licers lives at licers.com (dashboard, docs, account). The SDK talks to the validation API at https://license.pyobfuscate.com by default — a stable, long-lived host your shipped apps rely on. Override it only for self-hosting (see below).

Quick start

Get your public key from the Licers dashboardIntegration page (safe to embed in your distributed app; the private key never leaves the server).

from pylicensify import LicenseClient

client = LicenseClient(public_key="YOUR_PUBLIC_KEY")

result = client.validate("PY-XXXXXXXXXXXXXXXX")
if result:
    print("Licensed. Entitlements:", result.features)
    if result.feature("pro"):
        enable_pro_features()
else:
    print("Not licensed:", result.error)
    raise SystemExit(1)

validate() sends a nonce, verifies the Ed25519 signature, and rejects stale / replayed responses automatically. It raises SignatureError on tampering and NetworkError if the server is unreachable.

Feature gating

result = client.validate(key)
seats = result.feature("seats", 1)
if result.feature("pro"):
    ...

Offline license files (air-gapped)

Issue a signed .lic file from a license row in the dashboard, ship it with the app, and verify it locally with zero network calls:

from pylicensify import verify_offline_license

data = verify_offline_license("YOUR_PUBLIC_KEY", "license.lic")
print("Valid for:", data.get("customer"), data.get("features"))

Checks signature, expiry, device binding, and OS lock.

Floating / concurrent licenses

For keys with a concurrent-session limit — the SDK checks out a seat, heartbeats in the background, and releases on exit:

from pylicensify import LicenseClient, SeatUnavailable

client = LicenseClient(public_key="YOUR_PUBLIC_KEY")
try:
    with client.session("PY-XXXX...") as sess:
        print("Seat acquired:", sess.seats)   # {'used': 1, 'max': 5}
        run_app()                              # released automatically on exit
except SeatUnavailable:
    print("All seats are in use — try again later.")

Update checks

info = client.check_update("PY-XXXX...", current_version="1.0.0")
if info["update_available"]:
    print("New version:", info["version"], info["notes"])
    # info["download_url"] is a license-gated download link

Self-hosted / custom domain

By default the SDK calls the managed cloud API at https://license.pyobfuscate.com (your account and dashboard live at licers.com). To target a self-hosted deployment, pass api_url:

client = LicenseClient(public_key="...", api_url="https://license.yourdomain.com")

Hardware ID

By default the SDK uses a stable per-installation device id: the machine's MAC address where one is readable, otherwise a random id persisted to disk and reused on every run. This keeps the same device identity across runs on all platforms — including Android/Pydroid, VMs, and containers, where the MAC is not reliable and a naive uuid.getnode() changes on every run (which would trip the max-device limit).

The persisted id lives under a per-user data dir (%LOCALAPPDATA%\pylicensify on Windows, ~/.local/share/pylicensify elsewhere); override the location with the PYLICENSIFY_HWID_DIR environment variable. Pass your own for a stronger/OS-specific fingerprint:

client.validate(key, hwid=my_custom_fingerprint())

Errors

Exception Meaning
InvalidLicense Server rejected the key (invalid/expired/revoked/blocked)
SignatureError Signature/nonce/timestamp failed — forged or replayed
NetworkError Couldn't reach the license server
SeatUnavailable Floating license has no free seats

All inherit from LicenseError.

Hardening

Obfuscate your client so the check itself can't be trivially patched out — e.g. with PyObfuscate.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pylicensify-1.0.2.tar.gz (10.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pylicensify-1.0.2-py3-none-any.whl (9.8 kB view details)

Uploaded Python 3

File details

Details for the file pylicensify-1.0.2.tar.gz.

File metadata

  • Download URL: pylicensify-1.0.2.tar.gz
  • Upload date:
  • Size: 10.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.2

File hashes

Hashes for pylicensify-1.0.2.tar.gz
Algorithm Hash digest
SHA256 1fe4b06a9b7d179ca21c855d82782aac0423c8f0fa929960d25396ca792837ad
MD5 3f99c092be52ba45f216a29a42c1c303
BLAKE2b-256 54d0554718c88108ce83eb883ca7df4f64621183c0a318c03d58bbb643fee3de

See more details on using hashes here.

File details

Details for the file pylicensify-1.0.2-py3-none-any.whl.

File metadata

  • Download URL: pylicensify-1.0.2-py3-none-any.whl
  • Upload date:
  • Size: 9.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.2

File hashes

Hashes for pylicensify-1.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 e23b48e85024967793e3ad72bbc99ee48b7f4cb62719bf9e20f6e7ce9594c060
MD5 5fd53f51d7644ff85f67fb4ce600b17a
BLAKE2b-256 29776f0bc61a63834eefc45e0d8d45a5fc0d05dd56bdb97a03deb3a037324204

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page