# Complete Integration Guide — Python

Sandbox learning route. Review the Stage 14 launch gate before production.

# Stage 1: Understand the idea

A [license key](/docs/v1/start/glossary#license-key) is like a ticket. Your software checks the ticket before allowing a protected [feature](/docs/v1/start/glossary#feature).
## What you will do
Understand the four actions without writing code.
An API is the HTTPS interface your program calls. An SDK is a ready-made client library that makes those calls and checks responses. A signed response includes proof that the server's access decision was not changed.
Customer buys → gets a license key → your app activates → your app checks access.
1. Your [customer](/docs/v1/start/glossary#customer) receives a key, manually or after a verified purchase.
2. **Activate** connects that key to one installation: one installed copy of your app.
3. **Validate** asks whether that installation still has access.
4. **Deactivate** releases its [device](/docs/v1/start/glossary#device) seat when moving to another computer.
A device seat is one allowed installation. An entitlement is a feature or limit, such as PDF export or two devices.
## Expected result
You can explain why receiving a key is not the same as permission to unlock a feature.
## If it does not work
If you only want to send keys, skip coding and use the non-programmer route in [Stage 12](/docs/v1/integration-guide/deliver).
## Stage checklist
- I know the difference between a key, an installation and a signed access decision.

## Next steps
[Continue to Stage 2: Set up your Sandbox](/docs/v1/integration-guide/sandbox)

# Stage 2: Set up your Sandbox

## What you will do
Create a verified evaluation workspace, without real [customer](/docs/v1/start/glossary#customer) payments.
1. Open [registration](/register) and select Free for [Sandbox](/docs/v1/start/glossary#sandbox) evaluation.
2. Enter an email you control and verify the code or single-use link from the message.
3. Complete your name, workspace name, password and terms acknowledgement.
4. In the workspace header, select **Sandbox**.
A workspace is the private area that contains your [products](/docs/v1/start/glossary#product) and [licenses](/docs/v1/start/glossary#license). Sandbox means test records, separate from [Live](/docs/v1/start/glossary#live). A paid platform selection can require checkout; it is not a customer license purchase.
## Expected result
You can open the dashboard and the environment reads Sandbox.
## If it does not work
Check spam and wait for the resend control's cooldown. Do not repeatedly submit new registrations. If email proof fails, contact support. A Live record will not appear in Sandbox.
## Stage checklist
- My inbox is verified and I can sign in.
- Sandbox is selected.

## Next steps
[Continue to Stage 3: Create your product and plan](/docs/v1/integration-guide/model)

# Stage 3: Create your product and plan

## What you will do
Create one software [product](/docs/v1/start/glossary#product) and a worked example plan. If you already sell in WooCommerce, Stage 12 offers a combined import instead; the manual example below is still useful for learning.
1. Open **Products → New product** (or **Create product** on an empty page).
2. Enter **Product name** Quickstart App, **Slug** quickstart-app, **Platform** Desktop, and **[License](/docs/v1/start/glossary#license) prefix** QUICK. Choose **Create product**.
3. Saving opens the first-plan form in **Plans & [features](/docs/v1/start/glossary#feature)**. If it is closed, choose **New plan**.
4. Select Quickstart App. Enter **Plan name** Quickstart plan and **Slug** quickstart-plan.
5. Choose **Currency** EUR, **Price** 19.50, **Billing type** Monthly, **Duration days** 30, **Max [devices](/docs/v1/start/glossary#device)** 2 and **Feature keys** pdf_export.
6. Choose **Create plan**. Return to Products and copy the product's public **App ID**.
A product represents your software. Its App ID is the application identifier; there is no separate Application record to create. A plan describes access for that product. These plan prices are reference metadata, not a payment or recurring charge.
The sample price and name are test data. Python SDK 1.1.5 fixes the earlier Python canonicalization defects; legacy JavaScript/C# limitations remain documented. Test your real payloads and never weaken verification. A production assessment is required at Stage 14.
For the general model, Pro / two devices / one year means the same product with a plan whose duration is 365 days. Duration is not a payment instruction; your sales system handles payments.
## Expected result
The product card has an App ID and an active plan.
## If it does not work
A duplicate slug needs a new unique slug. A grey WooCommerce product needs an active plan or the combined product/plan import. Free limits are enforced; do not create more test products than your evaluation allows.
## Stage checklist
- I copied my [public App ID](/docs/v1/start/glossary#public-app-id).
- My plan enables pdf_export and two devices.

## Next steps
[Continue to Stage 4: Create a test license](/docs/v1/integration-guide/license-and-credentials)

# Stage 4: Create a test license

## What you will do
Issue a [customer](/docs/v1/start/glossary#customer) key and distinguish public identifiers from secrets.
1. Open **[Licenses](/docs/v1/start/glossary#license)** while the header still says **[Sandbox](/docs/v1/start/glossary#sandbox)**.
2. Choose **New license** or **Create first license**.
3. Select Quickstart App / Quickstart plan in **[Product](/docs/v1/start/glossary#product) and plan**.
4. Enter your test **Customer email** and a simple **Customer name**, such as Quickstart Tester. Company and External customer ID are optional.
5. Choose **Create license**. Copy **Your new [license key](/docs/v1/start/glossary#license-key)**, shown once, into your private test configuration.
The dashboard creates or reuses the customer for this email. A new license has no activated [devices](/docs/v1/start/glossary#device) yet.
The [public App ID](/docs/v1/start/glossary#public-app-id) identifies the software. A customer license key activates one purchase. The SDK receives a private [activation token](/docs/v1/start/glossary#activation-token) and stores an installation identity. A [developer API key](/docs/v1/start/glossary#developer-api-key) can manage licenses: create one under **API keys** only for a trusted sales backend, never for this client. If you supply an email during [activation](/docs/v1/start/glossary#activation), it must match the license.
## Expected result
The new Sandbox license is active and has zero [active devices](/docs/v1/start/glossary#active-devices).
## If it does not work
If the key was lost, masked listings cannot reveal it. Issue a replacement using your normal support procedure, without sharing customer keys in feedback.
## Stage checklist
- I stored the full key privately.
- I have not put a developer API key in my app.

## Next steps
[Continue to Stage 5: Choose your language and app type](/docs/v1/integration-guide/choose)

# Stage 5: Choose your language and app type

## What you will do
Choose one programming language and one place where access is enforced.
Choose Desktop app, Web / SaaS backend, CLI tool, Plugin / extension, or manual issuance. Select your language at [Choose your path](/docs/v1/start/choose-your-path). The guide supports four official SDKs and ten REST client routes.
| App type | Where the check belongs |
|---|---|
| Desktop | Inside the app; valuable online operations also need server authorization. |
| Web / SaaS backend | On your authenticated server, before protected work. |
| CLI / [developer](/docs/v1/start/glossary#developer) tool | In the tool process, with private per-user state. |
| Plugin / extension | In its trusted process; a browser extension needs a backend for valuable server actions. |
| Just issue keys | Use manual issuance or a verified store route in Stage 12; no SDK is required to send a key. |
Four [official SDKs](/docs/v1/start/glossary#official-sdk) are distinct from ten REST projects. JavaScript here means Node.js or Electron main, not a browser SDK. Unlisted languages use HTTPS/JSON and a conforming signature verifier.
## Expected result
Your chosen language follows you through code examples and links.
## If it does not work
Language and app-type choices organize examples; they do not create unsupported framework integrations. No browser-only check protects a SaaS backend.
## Stage checklist
- I know where my protected action runs.
- I chose an official SDK or accepted the extra REST verification work.

## Next steps
[Continue to Stage 6: Install and configure](/docs/v1/integration-guide/install)

# Stage 6: Install and configure

## What you will do
Install exactly the published source archive, then configure a private [Sandbox](/docs/v1/start/glossary#sandbox) example.
### Python setup
Use Python 3.11–3.14 and a working HTTPS certificate store. The official package is published on [PyPI](https://pypi.org/project/kdpika-licensing/) with [GitHub source](https://github.com/kdpika/kdpika-licensing). Create a virtual environment, then install:
```bash
python3 -m venv .venv
.venv/bin/python -m pip install "kdpika-licensing==1.1.5"
.venv/bin/python -m pip check
```
On native Windows use py -m venv .venv, then .venv\\Scripts\\python.exe for both pip commands and the example. Import kdpika_licensing. Use the same virtualenv interpreter for pip and your example.

## Configure this terminal
Set these variables in your terminal. App ID is public; your [customer](/docs/v1/start/glossary#customer)'s key and state directory are private. Do not use a [developer API key](/docs/v1/start/glossary#developer-api-key) in this client.
```bash
export KDP_APP_ID="YOUR_PUBLIC_APP_ID"
export KDP_CUSTOMER_EMAIL="YOUR_TEST_CUSTOMER_EMAIL"
export KDP_STATE_DIR="$HOME/.kdpika-guide-sandbox"
read -r -s -p "Sandbox license key: " KDP_LICENSE_KEY
printf '\n'
export KDP_LICENSE_KEY
```
For a different [device](/docs/v1/start/glossary#device) test, use a new private state directory, not a different email.
```powershell
$env:KDP_APP_ID = "YOUR_PUBLIC_APP_ID"
$env:KDP_CUSTOMER_EMAIL = "YOUR_TEST_CUSTOMER_EMAIL"
$env:KDP_STATE_DIR = Join-Path $env:LOCALAPPDATA "KDPikaGuideSandbox"
$secureKey = Read-Host "Sandbox license key" -AsSecureString
$env:KDP_LICENSE_KEY = [System.Net.NetworkCredential]::new("", $secureKey).Password
```
The variable is plaintext in this process; do not print it or leave it in a shared terminal. Close the terminal after testing. Windows Python uses .venv\\Scripts\\python.exe; Node/PHP/.NET commands are the same if their runtimes are installed.
Expected result: the variables are available only to this terminal and its child processes. Use a user-owned directory, outside a web root or shared repository. The sample uses Sandbox explicitly.
## Expected result
Your chosen runtime can load the SDK and write private installation state. Python uses its verified PyPI release; other SDKs retain their documented source-install requirements.
## If it does not work
If extraction creates another directory level, point the install command at the folder containing pyproject.toml, package.json, composer.json or KDPika.LicenseSdk.csproj. PHP needs 8.2+ despite older metadata.
## Stage checklist
- I installed my chosen SDK from its source ZIP.
- I configured App ID, test email, Sandbox key and private state path.

## Next steps
[Continue to Stage 7: Activate your first license](/docs/v1/integration-guide/activate)

# Stage 7: Activate your first license

## What you will do
Save one complete file and run it. It also supports later validate, check and deactivate actions. Keep this file through Stages 8–13.
Save **license-check.py** in your example folder.
```python
"""Sandbox learning example; use private state, never a developer API key."""
import os
import sys
from pathlib import Path
from kdpika_licensing import LicenseClient

try:
    action = sys.argv[1] if len(sys.argv) == 2 else "activate"
    if action not in ("activate", "validate", "check", "deactivate"):
        raise ValueError("Choose an action")
    client = LicenseClient(
        product=os.environ["KDP_APP_ID"], environment="SANDBOX",
        base_url=os.getenv("KDP_BASE_URL", "https://licensing.kdpika.com"),
        storage_dir=Path(os.environ["KDP_STATE_DIR"]), prefer_keyring=False)
    result = client.activate(os.environ["KDP_LICENSE_KEY"],
        os.getenv("KDP_CUSTOMER_EMAIL") or None) if action == "activate" else getattr(client, action)()
    released = action == "deactivate" and result.valid
    allowed = action != "deactivate" and result.valid and result.signature_valid
    print("Device released." if released else "Sandbox license verified." if allowed
          else "License could not be confirmed. Check your key or contact support.")
    sys.exit(0 if released or allowed else 1)
except Exception:
    print("License check unavailable. Check configuration and connection.", file=sys.stderr)
    sys.exit(2)
```
Run:
```bash
.venv/bin/python license-check.py activate
```
## Expected result
For a valid fresh activation, standard output is exactly:
```text
Sandbox license verified.
```
The program exits with code 0. In the dashboard, open **[Devices](/docs/v1/start/glossary#device)** or the [license](/docs/v1/start/glossary#license)'s **Devices** count: one installation is active. The sample never prints a token or full key.
## If it does not work
| What you see | What to do |
|---|---|
| INVALID_LICENSE | Check the full key, [public App ID](/docs/v1/start/glossary#public-app-id), [Sandbox](/docs/v1/start/glossary#sandbox) selection and matching [customer](/docs/v1/start/glossary#customer) email. |
| MAX_DEVICES_REACHED | Deactivate an old installation or inspect Devices. Do not make random identities. |
| SIGNATURE_INVALID / cached signature error | Keep access locked. Check the runtime, clock and SDK compatibility notes; do not disable verification. |
| NOT_ACTIVATED | Run activate in the same private state directory first. |
| NETWORK_ERROR / no connection | Reconnect. A first activation needs internet; no cached response means no offline grant. |
| LICENSE_EXPIRED / LICENSE_REVOKED / LICENSE_SUSPENDED | Explain the state to the customer and provide support; never silently convert it to valid. |
## Stage checklist
- My chosen sample ran against Sandbox.
- I checked the active device in the dashboard.
- I did not unlock [features](/docs/v1/start/glossary#feature) on an unverified answer.

## Next steps
[Continue to Stage 8: Validate when your app starts](/docs/v1/integration-guide/validate)

# Stage 8: Validate when your app starts

## What you will do
Check access before protected work, including on every app launch. Keep one stable client identity.
Request a fresh check (the SDK may use signed [offline grace](/docs/v1/start/glossary#offline-grace) after a network failure) with the same state directory:
```bash
.venv/bin/python license-check.py validate
```
For normal launch policy, use:
```bash
.venv/bin/python license-check.py check
```
The same file checks both validity and signature before reporting success.

| Result | Your app does |
|---|---|
| Valid, signature verified, required [feature](/docs/v1/start/glossary#feature) enabled | Allow only that feature. |
| Expired, revoked, suspended or cancelled | Deny protected work; explain how to contact the publisher. |
| Invalid signature or inconsistent binding | Deny access; collect a safe [request ID](/docs/v1/start/glossary#request-id) for support. |
| Network failure | Follow the verified, unexpired cache policy in Stage 10; never invent permission. |
The sample prints an access decision. Replace that print with your protected action only after adding the feature check described on the SDK page. A valid [license](/docs/v1/start/glossary#license) does not imply every feature is included.
## Expected result
validate prints [Sandbox](/docs/v1/start/glossary#sandbox) license verified. while the license is valid. Deactivation is a release acknowledgement, never a grant.
## If it does not work
Reusing a different state directory makes a different installation. Check the chosen [product](/docs/v1/start/glossary#product), environment, clock and current license status before asking the [customer](/docs/v1/start/glossary#customer) to reinstall.
## Stage checklist
- Every protected entry point checks access.
- Required feature checks follow verified validity.

## Next steps
[Continue to Stage 9: Check the signed decision](/docs/v1/integration-guide/signatures)

# Stage 9: Check the signed decision

## What you will do
Ensure a fake “licensed” response cannot unlock your app.
A signature is the server's proof that a decision has not been changed. The [public verification key](/docs/v1/start/glossary#public-verification-key) is not a [developer API key](/docs/v1/start/glossary#developer-api-key).
The four [official SDKs](/docs/v1/start/glossary#official-sdk) fetch the public key, verify Ed25519 and check the signed decision against the application, environment, installation and time. The Stage 7 sample also requires the SDK's signature-valid flag. Do not replace this with a success field from raw JSON.
Confirm result.valid and result.signature_valid before result.[feature](/docs/v1/start/glossary#feature)("pdf_export"). The sample already requires the first two flags.

Use the selected language SDK or REST client from [SDKs and languages](/docs/v1/sdks/python), its [signature verifier](/docs/v1/security/verify-ed25519/python), and the supported [webhook verifier](/docs/v1/guides/verify-webhook-signatures/python).
## Expected result
A modified payload/signature fails closed. The selected SDK/client's negative signature tests must pass for the payload shapes your [product](/docs/v1/start/glossary#product) uses.
## If it does not work
Known Python separator/exponent cases, JavaScript integral-float cases and C# Unicode cache cases are documented in [Current integration limitations](/docs/v1/integration-notes). A narrow successful example does not remove these defects. Do not ship affected cases or bypass verification; seek a compatible release/assessed verifier before [Live](/docs/v1/start/glossary#live).
## Stage checklist
- Tampering is denied.
- Public-key retrieval and rotation policy are understood.
- My production payloads pass the compatibility/test-vector gate.

## Next steps
[Continue to Stage 10: Handle errors and offline use](/docs/v1/integration-guide/real-world)

# Stage 10: Handle errors and offline use

## What you will do
Handle failures without trapping the [customer](/docs/v1/start/glossary#customer) or weakening access checks.
| What you see | What to do |
|---|---|
| INVALID_LICENSE | Check the full key, [public App ID](/docs/v1/start/glossary#public-app-id), [Sandbox](/docs/v1/start/glossary#sandbox) selection and matching customer email. |
| MAX_DEVICES_REACHED | Deactivate an old installation or inspect [Devices](/docs/v1/start/glossary#device). Do not make random identities. |
| SIGNATURE_INVALID / cached signature error | Keep access locked. Check the runtime, clock and SDK compatibility notes; do not disable verification. |
| NOT_ACTIVATED | Run activate in the same private state directory first. |
| NETWORK_ERROR / no connection | Reconnect. A first [activation](/docs/v1/start/glossary#activation) needs internet; no cached response means no offline grant. |
| LICENSE_EXPIRED / LICENSE_REVOKED / LICENSE_SUSPENDED | Explain the state to the customer and provide support; never silently convert it to valid. |
For normal launches, check can reuse a verified cache before its signed next_validation_at. After a network failure, any offline decision must still verify its signature, bindings, clock and offline_grace_until. Grace is based on signed server time, not “another N days after failure”.
1. Keep first activation online.
2. Use the same sample's check command to exercise the SDK's real cache policy.
3. Treat missing, corrupted, stale or clock-rollback cache as a denial requiring reconnection.
4. To move computers, run deactivate on the old installation while online, then activate on the new one.
Release this installation:
```bash
.venv/bin/python license-check.py deactivate
```
Expected output: Device released. This action does not grant access. Use activate on the replacement installation.

Do not erase local files as a substitute for server deactivation; that can abandon a device seat. Reset devices in the dashboard only after an authenticated support decision.
## Expected result
Customers get a clear message: “We could not check your [license](/docs/v1/start/glossary#license). Reconnect or contact support.” They never see raw keys, tokens or stack traces.
## If it does not work
An offline denial can be a correct security outcome. The current C# Unicode cache issue needs explicit testing; permission-protected files are not an OS vault.
## Stage checklist
- I tested a disconnected launch and an expired cache.
- I tested a full device limit and a successful release.
- I keep unknown or unverified states locked.

## Next steps
[Continue to Stage 11: Protect tokens and identity](/docs/v1/integration-guide/storage)

# Stage 11: Protect tokens and identity

## What you will do
Keep one stable installation identity and protect its token/cache.
The example intentionally uses a private state directory. It demonstrates the SDK's file behavior, not complete production vault integration.
| Platform | Simplest correct starting point |
|---|---|
| Windows | A per-user LocalAppData directory with user-only ACLs; assess DPAPI or Credential Manager through an appropriate adapter. |
| macOS | A user-owned application-support directory; assess Keychain for the private token. |
| Linux | A user-owned application-data directory with restrictive permissions; assess Secret Service availability. |
| Shared backend | A private path outside the web root, isolated per application tenant/installation. |
Do not invent an adapter constructor option. The Python SDK can use its existing keyring support; the other current SDKs' file implementations require assessment before claiming a vault. No vault is installed by the sample.
1. Preserve the SDK-created installation identity through restarts.
2. Keep App ID/environment/state namespaces separate.
3. Never sync [activation tokens](/docs/v1/start/glossary#activation-token) through a public repository or distribute your activated test directory.
4. Serialize identity, [activation](/docs/v1/start/glossary#activation) and deactivation writes for the same installation.
Use the selected language SDK or REST client from [SDKs and languages](/docs/v1/sdks/python), its [signature verifier](/docs/v1/security/verify-ed25519/python), and the supported [webhook verifier](/docs/v1/guides/verify-webhook-signatures/python).
## Expected result
A restarted app validates the same installation without consuming another seat. Another OS user cannot read its private files.
## If it does not work
Deleting identity state is not a [license](/docs/v1/start/glossary#license) reset. A customer-controlled desktop cannot be made tamper-proof; enforce valuable online operations on your authenticated backend too.
## Stage checklist
- I checked file permissions on every supported OS.
- My app does not ship a private activation token or [developer API key](/docs/v1/start/glossary#developer-api-key).
- Unsupported storage/runtime assumptions are resolved before [Live](/docs/v1/start/glossary#live).

## Next steps
[Continue to Stage 12: Deliver licenses to customers](/docs/v1/integration-guide/deliver)

# Stage 12: Deliver licenses to customers

## What you will do
Choose one [delivery](/docs/v1/start/glossary#delivery) route. Sending a key and protecting the software are separate tasks.
### No-code manual route
1. Open [Sandbox](/docs/v1/start/glossary#sandbox) **[Licenses](/docs/v1/start/glossary#license) → New license**.
2. Choose the [customer](/docs/v1/start/glossary#customer)'s [product](/docs/v1/start/glossary#product) and plan, enter their email and create the key.
3. Deliver it through your private customer channel. The full key is shown once.
4. Inspect [Devices](/docs/v1/start/glossary#device) and the license status for support, never request a password.
### WooCommerce
1. Install the official connector and connect your workspace.
2. Use **Import store products → Complete setup & enable sync** to prepare App IDs, plans and mappings together. Existing IDs are reused.
3. Review the shared device/access defaults once. Official subscription metadata comes from WooCommerce; inferred name-based periods need review.
4. Test a confirmed store order and verify the key in the order and My Account.
5. Keep Test/[Live](/docs/v1/start/glossary#live) payment evidence, quotas and product permissions enforced.
The native connector is different from the advanced standalone store-service reference.
### Another store or backend
Choose the matching [sales-platform guide](/docs/v1/sell). A [webhook](/docs/v1/start/glossary#webhook) is a server notification, not payment proof by itself.
1. Verify the provider notification's signature using original raw bytes.
2. Retrieve/confirm the current purchase with the provider and match product/customer/amount/state.
3. Issue or update through a scoped management API key on your trusted backend.
4. Save a durable purchase-to-license mapping and deduplicate retries.
5. Handle cancellations, paid-through access, refunds and disputes without blind reissuance.
No-code automation still needs a trusted verification/fulfillment step; do not paste a [developer](/docs/v1/start/glossary#developer) key into public browser code.
## Expected result
One eligible purchase produces the intended license, and repeated notifications do not duplicate it.
## If it does not work
Customer software license sales are separate from Stripe/Mollie billing for your KDPika [platform subscription](/docs/v1/start/glossary#platform-subscription). Delayed notifications and an unconfirmed payment must not unlock customer access.
## Stage checklist
- I chose one delivery route.
- Confirmed purchase and license ownership match.
- I tested duplicate delivery, cancellation and refund handling.

## Next steps
[Continue to Stage 13: Test the complete lifecycle](/docs/v1/integration-guide/test)

# Stage 13: Test the complete lifecycle

## What you will do
Exercise negative cases before [customers](/docs/v1/start/glossary#customer) rely on your integration.
Use [Sandbox](/docs/v1/start/glossary#sandbox) only. This is a checklist for your implementation, not permission to test attacks on other systems.
1. Run the Stage 7 file with activate. Confirm one active [device](/docs/v1/start/glossary#device).
2. Run validate, then check after restarting the process. Confirm the same identity/seat.
3. Activate on a second private state directory. With Max devices 2, a third installation must return MAX_DEVICES_REACHED.
4. Run deactivate on one installation. A replacement [activation](/docs/v1/start/glossary#activation) should now fit.
5. In **[Licenses](/docs/v1/start/glossary#license) → Manage**, choose Suspend. A forced online validate must deny. Restore allows a new activation; it does not revive the old revoked token. Run activate again before expecting validation to succeed.
6. Create a separate test license, choose Revoke and verify denial. Revocation is not a temporary support toggle.
7. Test a short-duration/expired license. Do not alter the server clock or production database to fake this result.
8. Test supported renewal through the documented backend/store workflow, with a confirmed paid period; it must not duplicate the license. Renew extends the license, not the token's original lifetime. Validate online to obtain the updated signed decision; activate again if the existing token has expired or was revoked.
9. Disconnect the network; test valid, missing, corrupted and expired cache states.
10. Modify a signed payload in an isolated verifier test. The verifier must deny it.
11. Test wrong email, App ID and environment. Cross-environment access must fail.
12. Follow your selected store's duplicate, failure, cancellation and refund checklist.
Use the exact same file and state directory for a lifecycle:
```bash
.venv/bin/python license-check.py activate
.venv/bin/python license-check.py validate
.venv/bin/python license-check.py check
.venv/bin/python license-check.py deactivate
```
Activation/validation success prints Sandbox license verified.; deactivation prints Device released. A failure exits nonzero and must not unlock your software.

## Expected result
Your test notes show both successful access and deliberate denials, without real charges or leaked tokens.
## If it does not work
Stop at the first unsafe result. Keep the application locked, record a safe [request ID](/docs/v1/start/glossary#request-id) and contact support. Do not “fix” a negative test by removing its signature or entitlement guard.
## Stage checklist
- All lifecycle, device, state, network and signature cases pass for my runtime.
- I tested the non-programmer [delivery](/docs/v1/start/glossary#delivery) route if I use one.

## Next steps
[Continue to Stage 14: Go live safely](/docs/v1/integration-guide/go-live)

# Stage 14: Go live safely

## What you will do
Make a deliberate production decision, not just change a label.
1. Resolve the runtime, canonicalization and storage limits relevant to your payloads. The current SDK known defects can block a general production sign-off; a passing demonstration is not universal certification.
2. Use a platform entitlement that permits **[Live](/docs/v1/start/glossary#live)**. Free [Sandbox](/docs/v1/start/glossary#sandbox) is evaluation only.
3. Create or select separate Live [product](/docs/v1/start/glossary#product)/plan/[license](/docs/v1/start/glossary#license) records and correctly scoped backend credentials. Test keys do not become Live keys.
4. Keep the [public App ID](/docs/v1/start/glossary#public-app-id), environment and installation binding correct. Change the example's explicit SANDBOX setting only in your assessed production configuration.
5. Store backend secrets outside the client and web root; rotate exposed credentials.
6. Deploy HTTPS, verified signatures, required-feature gates, trusted payment verification and private state with tested permissions.
7. Add health/status monitoring, safe logs, support instructions and a rollback plan.
8. Run a final controlled Live smoke test only with your authorized payment/license workflow; do not treat a return URL as confirmation.
## Launch checklist
```text
[ ] Supported runtime and actual production payloads verified
[ ] Known SDK compatibility/storage blockers resolved
[ ] Live entitlement and separate Live records confirmed
[ ] No management secrets in customer apps
[ ] Signature, binding, time and feature gates fail closed
[ ] Payment, cancellation, refund and duplicate delivery tested
[ ] Private installation/token storage tested on supported OSs
[ ] Monitoring, support, credential rotation and rollback ready
```
Use Copy on this block, Download Markdown, or the roadmap's selected-language full-guide export.
## Expected result
You have an evidence-backed launch checklist. If a compatibility blocker remains, your integration stays in Sandbox until it is resolved.
## If it does not work
Ask support for help with the specific blocker. Do not claim an SDK is safe for all payloads or all operating systems on the basis of the narrow quickstart.
## Stage checklist
- Every launch item is checked or explicitly blocks release.
- My support and rollback path are ready.

## Next steps
[Review your go-live checklist](/docs/v1/start/go-live-checklist)
