Skip to content

Python SDK

Open Markdown

Connect your Python app to customer licensing with ActivationClient. This guide takes you from SDK installation to customer approval and an actual permission check.

An activation request identifies the app installation to approve. The customer selects an owned license in the app-branded portal. The resulting activation response is signed and bound to that request and device. One license reserves one active registration.

Terminal window
python3 -m venv .venv
.venv/bin/python -m pip install signox-sdk==0.3.1

Use the package registry configured for your environment. Install the SDK as an application dependency; the sample ZIP contains source and is not the SDK installation method.

Runtime: Python 3.9+; pip installs the cryptography dependency.

Check the SDK installed in the virtual environment you just created. Version should be 0.3.1. Run the application with this same Python interpreter; another interpreter may have an older SDK installed.

Terminal window
.venv/bin/python -m pip show signox-sdk

Open the vendor dashboard, choose a product, and open its settings. Use the UUID in that product detail URL and download its public key. Create a policy with the demo_export boolean feature enabled, issue a test license, and register the key to a test customer in the customer portal.

InputWhere to get it and how it is used
SIGNOX_API_URLAPI address of the environment you are testing
SIGNOX_PRODUCT_IDUUID in the vendor product detail URL
SIGNOX_PUBLIC_KEY_FILEPath to the downloaded product SPKI PEM file
.signox-stateThe example creates this private directory; keep it across restarts

Set the three environment variables in the shell that runs the example. Use the pinned product public key from the trusted application distribution. Customer passwords belong only in the customer portal, and license keys are selected there rather than hard-coded in the app.

Save the complete code below in app.py and keep the same working directory for each command.

import json
import os
from pathlib import Path
import sys
from signox import ActivationClient
required = ('SIGNOX_API_URL', 'SIGNOX_PRODUCT_ID', 'SIGNOX_PUBLIC_KEY_FILE')
if not all(os.getenv(k) for k in required):
raise ValueError('Set SIGNOX_API_URL, SIGNOX_PRODUCT_ID and SIGNOX_PUBLIC_KEY_FILE')
client = ActivationClient(os.environ['SIGNOX_PRODUCT_ID'],
Path(os.environ['SIGNOX_PUBLIC_KEY_FILE']).read_text(),
base_url=os.environ['SIGNOX_API_URL'], state_dir='.signox-state')
command = sys.argv[1] if len(sys.argv) > 1 else 'start'
if command == 'start':
print(json.dumps(client.start()))
elif command == 'request':
print(client.create_request())
elif command == 'poll':
progress = client.poll()
print(progress['status'])
if progress.get('result') and not progress['result'].valid:
sys.exit(2)
else:
result = client.apply_response(Path(sys.argv[2]).read_text()) if command == 'apply' else client.validate()
allowed = result.valid and result.features.get('demo_export') is True
print(json.dumps(dict(valid=result.valid, code=str(result.code), exportAllowed=allowed)))
sys.exit(0 if result.valid else 2)

The example uses the same client for browser approval and file exchange. The SDK selects its device runtime; the app does not choose a device-provider type.

4. Approve this device in the customer portal

Section titled “4. Approve this device in the customer portal”
Terminal window
.venv/bin/python app.py start

Open the returned portalUrl in the system browser. Check the app name and device name, sign in with the customer account, select an owned license, and choose the activation button. If another device is registered, the portal offers a reasoned transfer request for vendor review.

Terminal window
.venv/bin/python app.py poll

Before approval, status is pending. Call again after approval; poll no faster than once every 3 seconds. A pending result means the request is still waiting, not that licensing succeeded.

5. Check the permission before running your feature

Section titled “5. Check the permission before running your feature”
Terminal window
.venv/bin/python app.py status

A successful check returns VALID or IN_GRACE_PERIOD. The example prints exportAllowed=true only when the license is valid and demo_export is true. A valid license without that feature must not write the CSV. Add this check inside your actual export operation, not only on the startup screen.

Run the sample that writes a CSV file

If the device cannot connect, export a request, import it at the customer portal /activate page on a connected computer, and bring activation.signox back to the original app. Pass the response text to applyResponse, not the path. The runnable example reads the file for you.

Terminal window
.venv/bin/python app.py request
.venv/bin/python app.py apply activation.signox

For a reliable request file, use the language sample activation-request request.signox command. Do not redirect Maven build logs into a request file.

Disconnected application requires a supported, trusted device key. A computer without it needs connectivity when applying the response. See the runtime and device requirements before distributing your app.

Check offline runtime requirements

NameTypeRequired / defaultDescription
product_idstrRequiredProduct UUID from the detail URL
product_public_keystrRequiredPinned SPKI PEM public key contents
state_dirstrRequiredPrivate persistent directory for this installation
base_urlstrhttps://api.signox.krAPI address for this environment
timeout_msint10000 msNetwork request timeout
ts_tolerance_secint300 secondsAllowed clock difference from the server
offline_grace_daysint365 daysLocal cap on server network grace; zero disables cache grace

The local grace cap cannot increase the signed server period. Expiry grace and network grace are different; neither allows an initial activation from an empty cache.

The default selects the OS module automatically. For a controlled device test or an application-owned runtime, use bridge_command: str, bridge_args: Sequence[str]. Only a runtime shipped by the trusted application or explicitly supplied by the test environment may be used. Never execute a path from customer JSON or an activation response. The samples accept SIGNOX_OFFLINE_RUNTIME and SIGNOX_OFFLINE_EXECUTABLE for the supplied test wrapper. An override does not bypass device trust or signature verification.

SignatureReturn typeBehavior
start(name=None)dictRegister a request and return the browser URL and requestId.
create_request(name=None, renew=False)strReturn public request JSON. name labels the device; renew replaces the request while retaining the installation credential.
poll()dictReturn pending before approval; after approval, apply the result and return its validation.
apply_response(content)LicenseResultRead response TEXT, verify request/device binding, and apply it.
validate()LicenseResultCheck license state and current feature permissions.
deactivate()LicenseResultRelease a connected registration; protected grants require reviewed transfer.

Node methods are asynchronous. Java, C# and Python methods are synchronous; run network and device work off the UI thread. A LicenseResult carries validity, code and features. Exceptions indicate request/state/import problems; do not turn them into successful permission checks.

Symptom / codeCauseAction and expected result
STATE_INVALIDSaved installation state is missing/corruptRestore its private state, or create a request in a new installation and request transfer.
DEVICE_TRUST_REQUIREDThe portal cannot issue to an unverified device keyThe operator must compare the key on the real device through a trusted channel, then enroll it.
TRANSFER_REQUIREDA different device is registered or secure return is unavailableRequest transfer from the destination device; the vendor reviews that exact request.
ACTIVATION_RESPONSE_INVALIDWrong file, signature, request or deviceUse the response issued for this request on the original device. Never edit its contents.
REQUEST_EXPIREDSeven-day request window endedCreate a renewed request and repeat customer approval.
NETWORK_ERRORA temporary connection/service failureRetry the connection; only a prior valid signed grant/cache can allow disconnected use.
REQUEST_ERRORInvalid URL, input or accessFix the request; do not retry a permanent HTTP error forever.

A signed suspension/revocation/expiry denial must stay denied after a later network failure. The old offline grant does not override it. Permanently disconnected grants cannot receive an immediate remote revocation. A format or file deletion is not proof that old backups stopped working.

Integration verification · Device recovery and transfer

If response delivery succeeds but local application validation fails, polling returns application_failed with its invalid result. Only applied plus a valid result confirms successful application.

Keep the runtime override identical between request creation and application. Browser/file transport does not select device protection; changing a request name also does not change its provider. OFFLINE_NOT_SUPPORTED after a verified response means the required local runtime cannot be used; restore that environment rather than request unrelated trust enrollment.