The official Python SDK is kdpika-licensing 1.1.5, published on PyPI. Its GitHub source is MIT-licensed. Import kdpika_licensing, not the distribution name.
What you will learn
- Install the published package and optional extras.
- Activate, validate, inspect verified features and release an installation.
- Preserve private state and migrate without creating another installation.
Prerequisites
Create a product and a disposable Sandbox license. Copy your Public App ID from Integration. A developer management API key never belongs in a desktop application.
Runtime and package
Python 3.11–3.14 is required. The dependency constraint is cryptography >=50.0.2,<51. Core release checks passed on Windows, Linux and Intel macOS across all four Python versions; a fresh PyPI installation and signed lifecycle also passed on Apple Silicon macOS. These checks do not certify every native GUI, keyring or packaged executable.
Apple Silicon macOS and supported 64-bit Windows/Linux normally use dependency wheels. Intel macOS may need Rust, Xcode command-line tools and OpenSSL 3 to build cryptography. See upstream installation requirements. A newer Python version outside the declared range is not supported by this release.
Install and use
Create a private virtual environment using a supported Python interpreter:
python -m venv .venv
source .venv/bin/activate
python -m pip install "kdpika-licensing==1.1.5"
python -m pip check
On Windows, create the environment with your supported Python launcher and activate it with .venv\\Scripts\\Activate.ps1 in PowerShell, or use .venv\\Scripts\\python.exe directly.
Optional extras are separate, not required for a core integration:
python -m pip install "kdpika-licensing[secure-storage]==1.1.5"
python -m pip install "kdpika-licensing[ui]==1.1.5"
secure-storage installs OS keyring support. ui installs PyQt6 for the optional activation UI. A usable native keyring still depends on the computer and OS configuration; do not describe private-file fallback as encryption.
Set KDP_APP_ID, KDP_STATE_DIR, KDP_LICENSE_KEY and optional KDP_CUSTOMER_EMAIL privately. The state directory must persist across restarts and upgrades.
import os
from pathlib import Path
from kdpika_licensing import LicenseClient
client = LicenseClient(
product=os.environ["KDP_APP_ID"],
environment="SANDBOX",
base_url="https://licensing.kdpika.com",
storage_dir=Path(os.environ["KDP_STATE_DIR"]),
)
result = client.check()
if result.error_code == "NOT_ACTIVATED":
result = client.activate(
os.environ["KDP_LICENSE_KEY"],
os.getenv("KDP_CUSTOMER_EMAIL") or None,
)
if result.valid and result.signature_valid and result.feature("pdf_export"):
print("PDF export is permitted.")
else:
print("This feature is not available. Check your license or connection.")
pdf_export is an example entitlement: define it in your product plan. When an email is supplied, the server requires it to match the license customer. Do not automatically reactivate after every validation failure.
Complete constructor configuration
| Option | Default | Purpose |
|---|---|---|
| product | required | Public App ID |
| environment | production, normalized to LIVE | Explicitly use SANDBOX for tests; TEST/PRODUCTION are aliases |
| base_url | https://licensing.kdpika.com | HTTPS origin; no path, query, credentials or fragment |
| application_name | Licensed Application | App label and default state path |
| application_version | empty string | Your app version, not the SDK version |
| verification_key | None | Optional trusted key_id/public_key pin |
| storage_dir | None | Private persistent root; SDK adds a product/environment namespace |
| timeout | 15.0 | Socket timeout above 0 and at most 120 seconds; not a total wall-time guarantee |
| prefer_keyring | True | Try the optional usable OS keyring |
| transport | None | Advanced trusted transport injection; preserve original JSON bytes |
| clock | None | Aware UTC clock; injection is for controlled tests |
| allow_loopback_http | False | Keyword-only local fixture opt-in; never use for remote HTTP |
Pins do not rotate silently. Fetch trusted keys only from the configured HTTPS origin or a controlled application update.
Public members and result contract
| Member | Use |
|---|---|
| client.activate(key, email=None) | Register the current installation online |
| client.check(force_online=False) | Check eligible signed cache or validate online |
| client.validate() | Request a fresh signed decision; bounded offline fallback only for eligible transport failure |
| client.deactivate() | Release the installation online |
| client.reset_local() | Clear local credentials/cache; does not release a server seat |
| client.activated | Local activation-state indicator, not an authorization decision |
| client.installation_id | Stable persisted random installation identity |
| client.storage_security | Actual storage mode; do not claim a vault without checking |
| client.feature(name, default=False) | Recheck current state before boolean feature use |
| client.feature_value(name, default=None) | Recheck state before typed feature access |
| result.valid / result.signature_valid | Explicit decision and signature gates |
| result.feature / result.feature_value | Fail-closed feature helpers; still use the explicit validity gate |
| result.status / license_id / expires_at / offline_grace_until | Verified result metadata; display only what is present |
| result.error_code / message / request_id | Safe failure handling and support correlation |
For exact signatures, fields and advanced storage/transport members, read the versioned client source, result source and SDK documentation. Do not treat writable payload data as an authorization grant.
Runnable member examples
The versioned examples directory contains basic.py, session.py, members.py and the optional PyQt6 example. Download the repository tag or source archive to get examples; a wheel installation is a library, not a promise that examples appear in your working directory.
Keep the adjacent _common.py helper when copying those examples. The persistent CLI supports status, activate, check, validate, deactivate and clear-local. Keep credentials in private environment variables rather than command-line arguments.
Errors and exceptions
License operations return LicenseResult for expected refusals. ConfigurationError, StorageError, SignatureVerificationError and NetworkError derive from LicenseSdkError and describe SDK failure categories. Catch only what your application can handle and deny protected access on failure. Do not log raw tokens, keys, signed customer payloads or private storage paths.
Storage and installation identity
Preserve the same product, environment, application name and private storage root. The SDK uses namespaced persistent random identity, atomic private files and bounded process/thread coordination. It does not derive identity from a MAC address or machine serial number. Local files are not protection from a computer owner or malware with equivalent access.
Offline and clock policy
An online activation is required first. Offline acceptance re-verifies cached signatures, binding, status and signed validation/grace/expiry deadlines. Authoritative server refusals do not authorize offline fallback. Clock rollback and corrupt/missing state fail closed. Do not delete state to work around those refusals.
Threading, asynchronous work and lifetime
AsyncLicenseClient wraps a configured LicenseClient and offloads its bounded synchronous operations. Await activate, check, validate and deactivate. Preserve the underlying client's private state. Follow the async source contract; a local thread lock is not a distributed lock.
Application and framework integration
Run licensing checks in the desktop application, CLI, service or authenticated web backend. Never expose developer API keys or turn these helpers into an unrestricted browser management endpoint. Keep blocking calls off a GUI event loop.
Packaging and distribution
Bundle only the dependencies your application needs. PyQt6 and native keyring backends require target-OS acceptance. Test your actual packaged app, state persistence, missing-vault behavior and offline/refusal paths. The SDK's MIT license does not license the KDPika SaaS backend or grant a platform subscription.
Upgrade and uninstall
Follow the migration checklist. The old license_sdk import is deprecated but remains a compatibility shim. Remove an installed studio-soline-license-sdk distribution before installing the new one so two distributions do not own that namespace. Preserve private identity/state. Deactivate online before intentionally releasing a seat; uninstalling a package alone does not release it.
Expected result
The package imports from your virtual environment and your application grants features only after an accepted signed decision.
Common mistakes
- Installing a different similarly named package or using an unsupported Python version.
- Shipping developer API keys, hard-coded customer keys or synthetic example App IDs.
- Deleting identity/state during an upgrade or assuming token presence means paid access.
Security notes
Keep HTTPS, signature verification, product/environment/installation binding and deadline checks enabled. Never bypass a failed signature to make an example pass. Pin the package version for reproducible application releases and review changes before upgrading.
Troubleshooting
| Symptom | Safe next step |
|---|---|
| No matching distribution | Check Python 3.11–3.14 and the exact kdpika-licensing package name |
| Import fails | Use the same virtualenv interpreter for pip and your application; import kdpika_licensing |
| Intel macOS dependency build fails | Follow cryptography's Rust/OpenSSL/Xcode build requirements |
| NOT_ACTIVATED | Perform an explicit online activation with the correct App ID and environment |
| Signature or clock failure | Deny access; inspect trusted configuration and contact the publisher |
| Storage unavailable | Use the intended writable private directory; do not silently create another identity |
Next steps
Run the quickstart, inspect API activation, and test offline behavior.