SDK & APIReference
Complete reference for the Python SDK and all REST API endpoints. Every field documented from the source. All examples use real request and response shapes.
Authentication
The API uses three access levels. Pass your secret in the X-Admin-Secret header.
No authentication required. Called by your customers' running software via the SDK.
Pass MASTER_SECRET or PRODUCT_SECRET. Most license management operations.
Only MASTER_SECRET accepted. Product and plan management — destructive operations.
curl -s -X POST https://zlf.yourdomain.com/api/admin/licenses/issue \
-H "Content-Type: application/json" \
-H "X-Admin-Secret: your-master-secret" \
-d '{"email":"customer@example.com","product_id":"my-app","plan_id":"pro"}'Python SDK
Drop zlf_sdk.py into your product's root directory. No pip install — it's a single file dependency that ships with your product.
Setup
The SDK reads configuration from environment variables set by the installer in /opt/zlf/.env.
| Variable | Example | Description |
|---|---|---|
| ZLF_LICENSE_KEY | APP-XXXX-XXXX-XXXX-XXXX | Customer's license key. Set by the installer. |
| ZLF_WORKER_URL | https://zlf.yourdomain.com/api | Base URL of your ZLF API. No trailing slash. |
| ZLF_PLAN | pro | Plan ID. Set by installer, synced from API on heartbeat. |
import zlf_sdk
# Reads ZLF_LICENSE_KEY and ZLF_WORKER_URL from environment
zlf = zlf_sdk.from_env(
product_id = "my-app",
version = "1.0",
)
zlf.startup_validate()
zlf.start_heartbeat()Constructor. Reads ZLF_LICENSE_KEY and ZLF_WORKER_URL from the environment and returns a configured SDK instance.
- product_idYour product's ID. Must match what was registered in the portal.
- versionCurrent version string. Sent with heartbeats for checksum verification.
Call once at application startup. Validates the license key against the API, performs machine binding on first activation, and caches the plan limits locally. If validation fails, calls sys.exit(1) — the app will not start.
On first activation the machine ID is bound in the database and a confirmation email is sent to the license holder. Subsequent calls from the same machine re-sync limits without rebinding.
Starts a background daemon thread that calls POST /check/heartbeat every interval seconds (default 600 = 10 minutes). The heartbeat sends file checksums and re-syncs limits.
If the heartbeat returns "action": "lock" — due to a revoked license, machine mismatch, or tampered files — the SDK calls sys.exit(1).
- intervalSeconds between heartbeat calls. Default: 600. Minimum recommended: 60.
Fast local check using cached limits. No network call. Returns True if current_value is below the plan's limit for that dimension — meaning the action is allowed. Returns True if the dimension is not in the limits (i.e. unlimited).
- dimensionThe limit key to check. Must match the key in the plan's limits JSON exactly.
- current_valueThe current count to compare against the limit (e.g. current number of mailboxes).
if not zlf.check_limit("mailboxes", db.count_mailboxes()):
return jsonify({"error": "Mailbox limit reached"}), 403Returns the full limits dictionary cached from the last validate or heartbeat call. Use to show limit usage to your users. An empty dict {} means the plan is unlimited.
{"mailboxes": 10, "users": 3}Authoritative remote check. Calls POST /check/limits on the API with the current state. Use for high-stakes operations where you need a guaranteed fresh check rather than relying on cached limits.
- actionDescriptive string for the operation being attempted. Logged server-side.
- current_stateDict of dimension → current count. All dimensions you want checked.
{"allowed": bool, "violations": [...], "limits": {...}}result = zlf.check_limits_remote(
action = "add_mailbox",
current_state = {
"mailboxes": db.count_mailboxes(),
"concurrent_jobs": db.count_active_jobs(),
}
)
if not result.get("allowed"):
return jsonify({
"error": "Plan limit reached",
"violations": result["violations"]
}), 403Public API
Called by the SDK from your customers' machines. No authentication required. Base URL: https://zlf.yourdomain.com/api
Health check. Returns {"ok": true} when the API and database are reachable.
{ "ok": true, "service": "ZLF" }Validates a license key. On first call with a new machine ID, binds the key to that machine and sends an activation email. Subsequent calls from the same machine re-sync limits. Calls from a different machine return 403.
| Field | Type | Required | Description |
|---|---|---|---|
| key | string | Yes | The license key (e.g. APP-XXXX-XXXX-XXXX-XXXX). |
| product_id | string | Yes | Must match the product the key was issued against. |
| machine_id | string | Yes | Unique identifier for this machine/server. Derived from hardware by the SDK. |
| check_only | boolean | No | If true, validates without binding or logging. Default: false. |
{
"valid": true,
"email": "customer@example.com",
"product_id": "my-app",
"plan_id": "pro",
"limits": { "mailboxes": 25, "users": 5 },
"expires_at": null
}{ "valid": false, "message": "License is already activated on another machine. Contact support to transfer." }Periodic liveness check called by the SDK every 10 minutes. Verifies the license is still active, the machine ID matches, and optionally checks file integrity. Returns "action": "lock" to shut the app down.
| Field | Type | Required | Description |
|---|---|---|---|
| key | string | Yes | The license key. |
| product_id | string | Yes | Product ID. |
| machine_id | string | Yes | Must match the bound machine ID. |
| version | string | No | App version string. Required for checksum verification. |
| checksums | object | No | Map of filename → SHA-256 hash. Compared against registered checksums. |
{
"valid": true,
"plan_id": "pro",
"limits": { "mailboxes": 25 },
"expires_at": null,
"action": "continue"
}{
"valid": false,
"message": "File integrity check failed",
"tampered_files": ["api/api.py"],
"action": "lock"
}Authoritative remote limit check. Compares current_state against the license's active plan limits and returns violations. Used by zlf.check_limits_remote().
| Field | Type | Required | Description |
|---|---|---|---|
| key | string | Yes | The license key. |
| product_id | string | Yes | Product ID. |
| action | string | No | Descriptive name of the operation being checked. Returned in the response. |
| current_state | object | Yes | Map of dimension → current count. All dimensions to check. |
{ "allowed": true, "limits": { "mailboxes": 25 }, "action": "add_mailbox" }{
"allowed": false,
"message": "Plan limit reached",
"violations": [{ "dimension": "mailboxes", "current": 25, "limit": 25 }],
"limits": { "mailboxes": 25 }
}Standalone file integrity check. Used by the installer to verify the downloaded package before running setup. Compares submitted SHA-256 hashes against registered checksums for the given version.
| Field | Type | Required | Description |
|---|---|---|---|
| key | string | Yes | A valid license key for this product. |
| product_id | string | Yes | Product ID. |
| version | string | Yes | Version string matching registered checksums (e.g. "2.0"). |
| checksums | object | Yes | Map of filename → SHA-256 hash for every registered file. |
{ "valid": true, "unregistered": false }unregistered: true means no checksums are registered for this version yet. The check passes but you should run release.sh to register checksums before distributing.
Admin API — Licenses
License management endpoints. Accept MASTER_SECRET or PRODUCT_SECRET in X-Admin-Secret header.
Issues a new license key for a customer. Generates the key, stores it, and sends a license email to the customer via Resend (if configured).
| Field | Type | Required | Description |
|---|---|---|---|
| string | Yes | Customer email. License key is emailed here on issue and activation. | |
| product_id | string | Yes | The product to issue the key for. |
| plan_id | string | Yes | The plan the key is issued against. Determines limits. |
| expires_days | integer | No | Days until expiry. Omit or pass 0 for a perpetual license. |
| notes | string | No | Internal notes. Visible in the portal only. |
{
"key": "APP-GQE9-NSZM-YGCY-084Z",
"email": "customer@example.com",
"product_id": "my-app",
"plan_id": "pro",
"limits": { "mailboxes": 25 },
"expires_at": null
}Revokes a license key. The customer's app will receive "action": "lock" on its next heartbeat (within 10 minutes) and call sys.exit(1).
| Field | Type | Required | Description |
|---|---|---|---|
| key | string | Yes | The license key to revoke. |
{ "revoked": true, "key": "APP-XXXX-XXXX-XXXX-XXXX" }Re-activates a previously revoked license. Cannot reactivate an expired license — extend expiry first.
| Field | Type | Required | Description |
|---|---|---|---|
| key | string | Yes | The license key to reactivate. |
{ "reactivated": true, "key": "APP-XXXX-XXXX-XXXX-XXXX" }Clears the machine binding on a license key so it can be activated on a new server. The previous machine ID is logged to the machine_resets audit table.
| Field | Type | Required | Description |
|---|---|---|---|
| key | string | Yes | The license key to reset. |
| reset_by | string | No | Who performed the reset. Stored in audit log. Default: "admin". |
| reason | string | No | Reason for reset. Stored in audit log. |
{ "reset": true, "key": "APP-XXXX-XXXX-XXXX-XXXX" }Permanently deletes a license key and all associated validation log entries and machine reset records. Irreversible.
| Field | Type | Required | Description |
|---|---|---|---|
| key | string | Yes | The license key to permanently delete. |
{ "deleted": true, "key": "APP-XXXX-XXXX-XXXX-XXXX" }Returns a paginated list of licenses. Supports filtering by product and status.
| Param | Type | Required | Description |
|---|---|---|---|
| product_id | string | No | Filter to a specific product. |
| status | string | No | Filter by status: active, revoked, or expired. |
| limit | integer | No | Max results. Default: 100. Max: 500. |
| offset | integer | No | Pagination offset. Default: 0. |
Returns full details for a single license key including machine ID, activation timestamp, limits snapshot, and heartbeat time.
Admin API — Products
Product management. Requires MASTER_SECRET only — these are destructive operations.
Creates a new product. Product ID must be unique lowercase alphanumeric with hyphens only.
| Field | Type | Required | Description |
|---|---|---|---|
| id | string | Yes | Unique product ID. Lowercase, hyphens only. e.g. imapsync-gui. |
| name | string | Yes | Display name. Used in emails. e.g. "IMAPSync GUI". |
| worker_url | string | Yes | Your API base URL. e.g. https://zlf.yourdomain.com/api. |
| key_prefix | string | No | Prefix for generated keys. Default: LIC. e.g. "IMAP" → IMAP-XXXX-XXXX-XXXX-XXXX. |
| cdn_url | string | No | CDN download URL for the installer. |
| contact_email | string | No | Support email shown to customers. |
| product_secret | string | No | Secret for product-scoped admin API access. |
Returns all products ordered by creation date.
Updates product fields. Pass id plus any fields to update: name, worker_url, cdn_url, contact_email, product_secret, key_prefix.
Deletes a product. Blocked if active licenses exist unless force: true is passed.
| Field | Type | Required | Description |
|---|---|---|---|
| id | string | Yes | Product ID to delete. |
| force | boolean | No | Pass true to delete even if active licenses exist. |
Admin API — Plans
Plan management. Requires MASTER_SECRET. See the Plans & Limits guide for a complete walkthrough.
Creates a new plan for a product.
| Field | Type | Required | Description |
|---|---|---|---|
| id | string | Yes | Plan slug. Lowercase, hyphens only. e.g. pro. |
| product_id | string | Yes | The product this plan belongs to. |
| name | string | Yes | Display name. e.g. "Professional". |
| limits | object or string | No | Limits JSON. e.g. {"mailboxes":25}. Default: {} (unlimited). |
Lists all plans, optionally filtered by product_id.
Updates a plan's name or limits. Limit changes propagate to all active licenses on their next heartbeat — no customer action required.
| Field | Type | Required | Description |
|---|---|---|---|
| id | string | Yes | Plan ID to update. |
| name | string | No | New display name. |
| limits | object or string | No | New limits JSON. Replaces existing limits entirely. |
Deletes a plan. Blocked if active licenses are on this plan unless force: true is passed.
| Field | Type | Required | Description |
|---|---|---|---|
| id | string | Yes | Plan ID to delete. |
| force | boolean | No | Pass true to delete even if active licenses use this plan. |
Admin API — Checksums & Stats
Checksum registration is handled automatically by release.sh. These endpoints are documented for manual use or tooling.
Registers SHA-256 checksums for a product version. Uses upsert — safe to re-run. Called by release.sh after packaging.
| Field | Type | Required | Description |
|---|---|---|---|
| product_id | string | Yes | Product ID. |
| version | string | Yes | Version string matching the release. e.g. "2.0". |
| files | object | Yes | Map of filename → SHA-256 hex hash. |
{
"product_id": "my-app",
"version": "2.0",
"files": {
"api/api.py": "a3f2c1...",
"setup.sh": "b7e9d4..."
}
}Lists registered checksums. Filter with product_id and/or version query params.
Lists all registered versions and how many files are registered per version. Useful for confirming a release was registered correctly. Filter with product_id query param.
Returns aggregate counts across licenses, products, and plans. Filter to a single product with ?product_id=my-app.
{
"licenses": {
"total": 42,
"active": 38,
"revoked": 3,
"expired": 1,
"activated": 35, // keys that have been bound to a machine
"bound": 35 // keys with a machine_id set
},
"products": 3,
"plans": 9,
"product_filter": null
}