# Launch Purchase Duration and Account SDK Boundaries

This change is only for local development and validation; Launch has not been deployed, and the SDK package has not been released. The current source code depends on Licentivo's account authorization agreement and the accompanying official SDK updates, and cannot be used interchangeably with the old server that only supports long-term license keys.

## Responsibilities

| Capabilities | Responsible Parties |
| --- | --- |
| Registration, login, account security, products, orders, payments, refunds | Launch |
| Renewal/upgrade quotations, purchase cycle, and absolute start and end time calculations | Launch |
| Mapping execution and policy verification for package-referenced authorized products/policies | Licentivo; Launch provide selection and registration entry points |
| Licenses, feature permissions, device quotas, authorized sessions, offline licenses | Licentivo and official SDK |
| Device list and remote unbinding | Licentivo; Launch proxies requests from the current account and displays results |
| Saving login credentials, account recovery, and logout entry point | Launch SDK |

Launch's orders, purchase duration, and sync completion flags do not allow access to protected features. Clients must execute protected operations through running interfaces such as `RunFeature` provided by the official SDK.

Each Launch product maintains a stable public Licentivo product route. Different plans for the same product can choose different strategies, but you can’t switch to another remote product; mapping is checked serially through database row locks of the common product. Customer identity, plan release, and SDK access configurations read the same binding, and drafts cannot change the product context for purchased customers. This only checks the consistency of access configurations and doesn’t determine features or device authorization. When the old database lacks stable fields, priority is given to purchase and release history, and if uniqueness can’t be confirmed, `PRODUCT_MAPPING_CONFLICT` is returned. See details in [Mapping Concurrency Fix ](/en/launch-documents/product-mapping-fix-2026-10-24/).

## Purchase period synchronization

Reuse existing interfaces; no new payment facts, refund facts, or quotation services:

- `POST /api/v1/launch/connections`, `PUT /connections/{id}`: Register identity signature public key, connecting separately to production and test environments.
- `PUT /api/v1/launch/connections/{id}/plans/{plan}`: Register non-repeatable Launch plan version references as well as remote product and strategy versions.
- `POST /api/v1/launch/connections/{id}/events`: Submit a full versioned purchase snapshot.
- `GET /api/v1/launch/connections/{id}/events/{event}`: Confirm the processing result.
- `POST /api/v1/launch/connections/{id}/events/{event}/retry`: Verify and retry the original event.

Snapshots only include event ID, environment, event type, purchase reference, anonymous account reference, Launch product, plan version reference, incremental version, and absolute `valid_from` / `valid_until`; attach old license ID during migration. Payment keys, prices, customer emails, or long-term license keys are not sent. Permanent purchases of `valid_until` are `null`, checked by Licentivo to see if they match the strategy.

Launch confirms payment, records immutable purchase coverage periods, and saves sync tasks within the same database transaction. Deadlines are calculated according to daily/monthly/yearly calendar cycles; renewals use the original purchase anchor, and if payment is made after expiration, it starts from the actual payment date. Upgrade quotations and periods are still calculated in Launch.

Each change sends the full absolute value. Retry using the same event ID and the same content; do not send "add N more days." Task persistence requests, remote connections, and processing progress; lost responses, process restarts, and concurrent workers will not stack the deadlines.

HTTP 202 only means Licentivo has been received. Only when `applied` is received is synchronization marked complete; `pending` continues querying, `manual_review` and unconfirmed `stale` remain in a pending verification state. Network errors should retry with backoff; after consecutive failures reach the limit, it goes to manual verification.

Refunds only remove the coverage period for the corresponding order: refunding an upgrade order restores the base package; refunding a renewal order removes the extended portion; if there are still unrefunded purchases, the sync recalculates the result but does not revoke all purchases. Once all purchases are refunded, `entitlement.refunded` is sent. Future repurchases use a new purchase reference to avoid reviving revoked remote licenses.

Channel-confirmed lost disputes or chargebacks also only remove coverage for the corresponding order; the order shows `reversed`, but actual entitlement changes are still processed after applying the purchase snapshot with Licentivo. Pending disputes do not change the purchase record. Historical pending chargeback notices can be re-verified and resent through the original channel to restore.

Unknown refunds entering manual verification can be restored by an administrator using `POST /api/v1/admin/refunds/{id}/reconcile`. Receipts must match the original transaction, currency, and amount; the original operation number and approval time cannot be changed. After exceeding the safe retry window, do not blindly resubmit fund requests.

## Accounts and clients

1. Clients use `POST /api/v1/auth/login` to establish a real desktop login session.
2. Launch SDK requests `POST /api/v1/software/products/{id}/identity`, specifying `sandbox` or `live`.
3. Launch issues an identity assertion valid for up to 120 seconds, specifying the recipient and product/purchase context, including real login `sid` and login expiry. The assertion does not include functionality, device quota, or offline permissions.
4. The Launch SDK only passes `identity_token`, `launch_connection_id`, and `environment` to the official SDK in memory, while `license_key` is empty.
5. The official SDK calls Licentivo with `/api/v1/launch/exchange`, and Licentivo determines authorization and issues device credentials and signing licenses.

Launch normal account records use v2, only saving account sessions and public routing info, not saving assertions, license keys, or authorization permissions. When explicitly logging out, it switches to a private v3 task just for revocation, which can't be restored to login; delete it only after confirming the Launch session has been revoked. Old `/credential` APIs return HTTP 410. Public keys and product IDs can be distributed with the app, while management keys remain on the server.

## Logout, shutdown, remote unbinding

| Operation | Action |
| --- | --- |
| Ordinary Close / Dispose / Drop | Keep purchases, device bindings, and actively remembered accounts when stopping |
| Logout / ReleaseDevice compatible entry | Mark local account as logged out and call the official SDK to log out, then revoke the session in Launch; unconfirmed account logouts retain a security task |
| When unable to access the device, manage it in Launch | Proxy the device list, unbinding requests, and handling results for Licentivo |

Logging out from the official SDK immediately stops the process from using the license, clears running credentials, and revokes remote bindings using a dedicated revocation ticket. If the network fails, the SDK's `.logout.json` must be retained, showing that remote revocation is pending and not indicating unbinding success. Launch SDK does not delete, traverse, clean, or modify the official SDK cache directory; pending revocation tickets are restored and processed once the official SDK reinitializes the corresponding cache.

Launch accounts have their own independent pending states when logging out: in case of network failure, cancellation, or lost responses, security records needed for retry aren't deleted; logging in again, restoring, or logging out only resubmits the original session revocation, and the pending tasks can't be used to restore login. They are deleted once the session is successfully terminated or confirmed invalid via HTTP 401. Cross-process recovery requires a persistent security store, as MemoryStore is only valid within the current process. For details, see [Logout Retry Fix and Integration ](/en/launch-documents/logout-retry-fix-2026-10-24/).

Remote unbinding requests carry `activation_id` and `expected_generation` returned from the original list, and retries reuse `operation_id`. Launch doesn’t count unbinding attempts, nor does it approve or execute the unbinding queue by itself, and it doesn’t automatically retry old operations after generation updates. Remaining attempts, release permissions, audits, and final results all come from Licentivo.

Account recovery via `Restore` requires online verification of the account and obtaining a new identity assertion; Launch won’t choose offline release on its own if the account service fails. Apps that need offline startup should integrate according to the official SDK’s recovery contract; signing, offline validity, and clock checks are still handled by the official SDK.

## Server-side identity revocation

Interface for connecting Licentivo V39, no need for commercial facts or quote interfaces:

- `POST /api/v1/launch/connections/{id}/session-revocations`: revokes old logins for the specified `sid` or account, and returns a receipt for the synchronized submission.
- `GET /api/v1/launch/connections/{id}/session-revocations/{event_id}`: retrieves the submitted result of the original event and recovers requests with lost responses.

Regular desktop logout or forcibly logging out a specific session uses `scope=session`; changing password, resetting password, changing email, deactivating accounts, or website personnel role changes that invalidate all sessions use `scope=account`. Normal website session logout doesn’t affect client software. Launch only notifies that the identity is invalid; remote authorized sessions, running credentials, and device release are handled by Licentivo, without modifying purchase periods or consuming the unbinding quota maintained by Launch.

Local session invalidation and notification queuing are completed within the same transaction. Queues freeze existing connections and environments at that time, using the same event ID, account anonymous identifier, and retrying the original request; later created connections do not receive historical account revocations. First, check the original receipt, and only resubmit if it does not exist; each environment persists results separately, and completion is only shown when all matching success receipts are received. Automatic retry occurs after network disconnection, and credential/contract conflicts require manual verification. Admins can view notifications and retry on the sync task page; retries do not generate new revocation events.

Account-wide revocations use Licentivo and the first received `revoked_before` as boundary. While notifications are pending, new desktop logins and identity assertions are paused; after completion, the actual login `auth_time` must strictly occur after the deadline second in all environment receipts. Same-second logins can reauthenticate later; refreshing `iat` or identity assertions cannot extend the old login. Website logins can still be used for recovery operations. After re-enabling the account, logging in is required again; old sessions are not restored.

## Legacy data migration

For purchases already confirmed with old license binding using `entitlement.migrated`, only submit the old license ID without reading or issuing old keys. After Licentivo confirms migration, a separate new-version snapshot synchronizes the current commercial term and status. Unconfirmed old issuance results and incompatible authorizations need manual verification; old management commands are not automatically replayed.

Regular SDK logout, remote device unbinding, and server-side identity revocation all integrate with existing interfaces. Remote deactivation is still subject to the officially issued offline license period by the SDK; Launch does not guarantee immediate revocation for offline devices.

<!-- account-store-ownership-2026-10-24 -->

Account logout uses separate secure todo items, local session logout summary, and cross-process coordination; old instances only handle their own logins. After storage failures, recovery first resubmits account revocations without acquiring identity or starting authorization; features, offline licenses, device generations, and unbinding limits continue to be determined by Licentivo. See [Fix and dual-end coordination record ](/en/launch-documents/account-store-fix-2026-10-24/).
