No matching topic
Try an application name, feature, endpoint, or error code.
Overview
One control plane, four trust boundaries
Konvoa is the current server-side authority for a desktop application's accounts, licenses, devices, sessions, subscriptions, and release metadata. A shipped client proves possession of an installation key and verifies the server's signed response. It never decides its own entitlement.
- Workspace
- The owner account, plan, teammates, reseller relationships, and applications.
- Application
- The isolation boundary for customer identities, policies, versions, files, and access records.
- Desktop session
- A short-lived, application-bound authorization context tied to a device key.
- External artifact
- Owner-hosted bytes identified by a Konvoa file ID and verified SHA-256.
Quick start
From an empty workspace to a verified login
- 1
Create the application
Open the console, create an application, and keep HWID Lock enabled unless multi-device access is intentional. Copy the public
app_…identifier. - 2
Define the entitlement
Create at least one subscription tier, then issue a test license with an explicit duration. A customer consumes that license during registration.
- 3
Integrate a client
Use the maintained C++ SDK or download a reference client for C#, Python, Node.js, Go, Rust, or PHP. Keep its persistent device key and response-key pins intact.
- 4
Publish the exact build
Register a strict SemVer version and the SHA-256 of the artifact you ship. When its file is eligible, the console selects minimum-version enforcement by default; clear that choice only when a staged rollout is intentional.
- 5
Test failures before release
Exercise a revoked license, changed device, expired session, replayed nonce, wrong response pin, outdated version, disabled app, and mismatched artifact digest.
Core model
IDs are stable; authorization is scoped
Use opaque IDs exactly as returned. Do not infer ownership, creation time, or permissions from an identifier. Customer usernames are unique inside an application, while the underlying identity remains isolated from users with the same display name in another app.
| Resource | Identifier | Scope | Keep secret? |
|---|---|---|---|
| Application | app_… | Workspace | No |
| License record | Opaque key ID | Application | No |
| Raw license | Configured key format | Customer activation | Yes |
| User and session | Opaque user ID / SID | Application | Tokens are secret |
| File | file_ plus 32 lowercase hexadecimal characters | Application | No |
| Device key ID | Ed25519 public-key thumbprint | Installation | Private key is secret |
Applications
The application is the operating boundary
Create a separate application for each independently shipped product or environment. Its users, licenses, subscriptions, variables, files, versions, sessions, reseller access, and security policy stay scoped together.
- Status
- Active accepts eligible logins. Disabled blocks new authorization and should be used for an immediate product-wide stop.
- Public ID
- Compile this identifier into the client. It selects an app but grants no authority by itself.
- Session lifetime
- Set the duration deliberately. Shorter sessions reduce stale access; refresh rotation keeps active customers signed in.
- Archival
- Removing an application is a high-impact operation. Export required operational records and confirm the selected app before proceeding.
Licenses
Issue access, then manage the record
A license starts unused, is consumed by registration, and then remains connected to the resulting user and subscription. The console masks raw keys at rest in the interface, permits a rate-limited reveal only when authorized, and supports selection-based management.
- Create
- Choose a subscription, quantity, and duration unit. Use a custom expiration date when access must end at local end-of-day on a specific date.
- Extend
- Add time to the active entitlement without issuing a replacement identity.
- Revoke
- Stops authorization and closes dependent sessions. Treat revocation as an access-control event, not a visual status change.
- Device reset
- Clears the active binding so the legitimate customer can establish a new one on the next authenticated flow.
Management operations that support Idempotency-Key should receive a unique value for the business action and reuse that same value only when retrying that action.
Users and sessions
Customer state and live access stay connected
Use the Users view for durable account state and the Sessions view for currently authorized clients. Extending or subtracting expiration updates entitlement time. Disabling or deleting a user can also revoke its license when that explicit option is selected.
Subscriptions and variables
Model what a customer receives
Subscriptions are application-scoped entitlement tiers. Licenses select a tier, users inherit the resulting access, and files can be restricted to selected tiers. Use a clear default tier for the common case and reserve additional tiers for meaningful product differences.
Variables expose small owner-managed values to signed clients. They are suitable for configuration flags and public runtime settings, not for private service credentials. Any value returned to a customer-controlled process must be treated as observable.
Access controls
Policies are evaluated on the server
Application status
Disable the app to stop eligible users from creating new authorized sessions. Restore it only after the incident or maintenance window is resolved.
Immediate product-wide controlHWID Lock
Enabled by default. The service binds a user to its installation identity and requires an owner reset when a different device attempts to replace it.
Server-side device bindingVPN policy
Off skips the provider decision, Monitor records a result without blocking, and Enforce rejects a provider-classified VPN. Enforcement is unavailable until the configured intelligence provider is healthy.
Provider-backed network policyHash Check
Monitor compares the signed client-reported build digest with the published artifact. Enforce can reject a mismatch. This is tamper telemetry, not hardware attestation.
Release-integrity signalVersions and files
Publish metadata; keep release bytes on your host
A version records strict SemVer, channel, lifecycle status, release notes, and an optional file. An application can hold multiple files, each with its own stable ID, editable direct HTTPS URL, expected SHA-256, content metadata, status, and subscription mapping.
The Files inventory supports row selection, select-all up to the 100-record bulk limit, label and link editing, digest and metadata editing, subscription access changes, individual deletion, and atomic bulk deletion. Deletion permanently removes an unreferenced file record, cancels its pending download tickets, and releases plan capacity. A file referenced by any draft, published, or archived version must first be removed from that version; published artifact history remains immutable.
- 1
Create a file record
Provide a label, direct HTTPS URL, complete lowercase SHA-256, and optional tier mappings. Konvoa stores metadata only.
- 2
Publish a version
Attach the exact file and digest for the build. For a published version whose file is active, has a valid SHA-256, and is available across subscriptions, “Enforce this as the minimum version” is selected by default.
- 3
Confirm the policy
The console publishes an eligible version and applies Enforce in the same server transaction. Draft, unavailable, invalid, or tier-restricted artifacts do not auto-enforce, and the server validates every policy change. Monitor reports adoption without blocking; Off removes the minimum decision.
- 4
Recover an outdated client
The authenticated client retrieves signed minimum-version metadata and then downloads from the owner's host with a fresh credential-free request.
Konvoa does not accept upload bytes, fetch the publisher URL, proxy content, or forward credentials to the external host. The client must reject redirects, require HTTP 200, bound the transfer, and verify the complete SHA-256 before use.
SDKs and examples
Start from code that already verifies the protocol
The maintained C++ SDK includes the full native client, self-contained Visual Studio x64 solution, bundled libsodium headers and static libraries, response pins, one-click build script, and beginner starter. Reference clients demonstrate the signed login exchange in six additional languages.
C++ beginner build
1. Extract the complete ZIP without moving individual folders.
2. Edit starter/app_config.hpp and replace PASTE_APP_ID_HERE.
3. Set kApplicationVersion to this build's strict SemVer.
4. Double-click BUILD-WINDOWS.cmd.
5. Run out\Release\x64\konvoa-starter.exe.
The ordinary Visual Studio build needs no vcpkg install, SODIUM_DIR, DLL copy, or manual include and library paths. Verify every archive against SHA256SUMS before extracting it.
Desktop API
Signed client operations
The desktop base path is /api/v2/desktop. Every operation uses the signed-request protocol. “Session” below means an access token bound to the application, user, device ID, and device-key thumbprint.
| Method | Path | Authorization | Purpose |
|---|---|---|---|
| POST | /auth/bootstrap | Device proof | Register the installation's public device key through the bootstrap flow. |
| POST | /simple/register | Device proof | Consume a license and create an application-scoped customer. |
| POST | /simple/login | Device proof | Authenticate and issue the bound access and refresh session. |
| POST | /auth/refresh | Refresh proof | Rotate the refresh credential and receive a new access context. |
| GET | /license/check | Session | Recheck current license, identity, scope, product, and risk state. |
| POST | /simple/subscription/check | Session | Resolve active entitlement for a product subscription. |
| GET | /simple/var/{name} | Session | Read an application-scoped client variable. |
| GET | /simple/version-policy | Session | Read the signed minimum-version decision, including during update recovery. |
| GET | /simple/version-update | Session | Resolve the minimum version's authorized external artifact metadata. |
| GET | /simple/download-link/{file_id} | Session | Resolve an entitled external file URL and its optional SHA-256 integrity pin. |
| POST | /simple/self-ban | Session | Disable the current authenticated context for an application-defined critical response. |
Use the SDK for request construction and response verification. The route list does not replace canonical signing, replay protection, response pins, bounded parsing, or secure credential storage.
Signed protocol
Sign the exact bytes that cross the boundary
Canonical request v2 binds the key ID, application ID, strict application version, optional executable digest, uppercase method, exact origin-form path and query, lowercase host, UUID request ID, Unix timestamp, random nonce, bearer-token digest, and exact body digest. Konvoa verifies freshness and one-time replay state before protected mutation.
The response signature binds its response-key ID, method, unchanged path and query, HTTP status, original request ID, server timestamp, and exact response-body digest. Verify that signature against a release-authenticated pin before parsing protected JSON or trusting an error's recovery metadata.
Errors and recovery
Branch on verified codes, not message text
| Status | Meaning | Client response |
|---|---|---|
400 | Malformed or inconsistent signed input | Stop and correct the integration. Do not retry unchanged. |
401 | Invalid credentials, token, session, or proof | Clear terminal credentials when required, then perform a clean sign-in. |
403 | Current policy denied the operation | Show an appropriate access message without exposing policy internals. |
404 | Resource is absent or intentionally hidden by scope | Do not use the difference to infer another application's resources. |
409 | State conflict or replay-sensitive operation | Fetch current state and decide whether a new business action is valid. |
410 | A retired compatibility flow was requested | Move to the documented replacement rather than retrying. |
426 | AUTH_UPDATE_REQUIRED | Verify the response, pause ordinary work, then use the signed version recovery flow. |
429 | Network or subject rate limit | Apply bounded backoff and avoid parallel refresh or login storms. |
503 | Maintenance or a required policy provider is unavailable | Fail closed and retry later with a bounded schedule. |
AUTH_OWNER_RESET_REQUIRED means a locked user's device can only be cleared by an authorized application operator. Never work around it by silently replacing local identity material.
Teams
Delegate work without transferring ownership
Invite teammates into the workspace and assign the smallest role that covers their job. Application-scoped access limits which products a member can inspect or change. Workspace-wide permissions are reserved for duties such as team membership, billing, and reseller administration.
- Invitation
- Send to the intended account email, review the role and application scope, and revoke unused invitations.
- Role change
- Takes effect against current server authorization. Review active sessions after a material reduction in access.
- Application scope
- Select only the apps the member operates. Empty or broad scope must never be treated as implicit authorization.
- Removal
- Ends workspace membership without deleting the underlying account or the owner's application data.
Resellers
Separate delegated sales from workspace administration
An owner grants a reseller access to selected applications and selected actions. Per-application balances represent the units available for issuance. The reseller portal exposes only records inside that grant and keeps its inventory and customer operations separate from platform administration.
Reseller automation
Automated delivery without pre-stocking keys
An application owner can opt a reseller into on-demand license delivery for one selected application. The API issues a fresh key during each delivery instead of forcing the reseller to pre-generate or stock keys. Credentials are separate from browser sessions and desktop-user tokens.
Owner credential management
| Method | Path | Purpose |
|---|---|---|
| GET | /api/v2/console/resellers/{reseller_id}/api-credentials | List credential metadata. Secrets and secret hashes are never returned. |
| POST | /api/v2/console/resellers/{reseller_id}/api-credentials | Create a scoped credential. The complete secret is returned once. |
| POST | /api/v2/console/resellers/{reseller_id}/api-credentials/{credential_id}/revoke | Reversibly stop a credential so future deliveries fail. |
| POST | /api/v2/console/resellers/{reseller_id}/api-credentials/{credential_id}/reactivate | Reactivate an unexpired credential after its live application grants are revalidated. |
| DELETE | /api/v2/console/resellers/{reseller_id}/api-credentials/{credential_id} | Delete the credential from management while retaining immutable delivery evidence. |
POST /api/v2/console/resellers/{reseller_id}/api-credentials
Content-Type: application/json
X-CSRF-Token: <workspace-session-csrf-token>
{
"name": "Store delivery",
"application_id": "app_0123456789abcdef0123",
"subscription_ids": ["sub_standard"],
"scopes": ["licenses:deliver"],
"expires_at": 1798761600
}
The signed-in actor must be the workspace owner or a full-workspace administrator with reseller-management permission. Credential creation does not ask for a password again, but it still requires a valid session with at least five minutes remaining, a same-origin JSON request, the session's CSRF token, and the credential-creation rate limit. Every lifecycle change is audited. Choose between 1 and 25 subscriptions, or omit subscription_ids to bind every subscription the reseller can currently issue for the application. Expiration defaults to 90 days, must be at least five minutes away, and cannot exceed 365 days. A reseller can hold at most 10 active automation credentials.
The HTTP 201 response wraps credential, secret, and secret_available_once: true inside data. Store the returned kvo_rs_v1.… secret in a server-side secret manager; subsequent lifecycle responses expose only its masked preview and never the secret or its hash. Reactivation uses the original secret and is rejected when the credential expired, the reseller is suspended, an application grant changed, or the active-credential limit is full.
Credential metadata contains credential_id, reseller and application IDs, name, secret_preview, scopes, subscription IDs, stored status, effective status, expiry, last-use time, creation and update times, and revocation time. Listing returns non-deleted records in data.items. Deletion is an auditable tombstone, not a physical row removal, because delivery and idempotency journals retain restrictive references to the credential.
Create a delivery
POST /api/v2/reseller-api/v1/deliveries
Authorization: Bearer kvo_rs_v1.<credential_id>.<secret>
Idempotency-Key: ord_7Jf3Qz9mP2vK8sRc4nTx6w
Content-Type: application/json
{
"subscription_id": "sub_standard",
"customer_reference": "ord_7Jf3Qz9mP2vK8sRc4nTx6w",
"duration_unit": "month",
"duration_count": 1
}
| Field | Requirement |
|---|---|
subscription_id | Must be included in the credential and remain issuable under the reseller's live application grant. |
customer_reference | 1 to 160 safe characters. Use a high-entropy opaque order ID; Konvoa persists only a domain-separated keyed digest. |
duration_unit | day, week, month, year, or lifetime. Custom dates and expires_at are not accepted by this API. |
duration_count | Must be 1. Each delivery consumes one allocated key from the selected duration bucket and issues one license with that preset. |
mask | Optional key template, at most 64 characters, using X, A, 9, and hyphens with at least 64 bits of randomness. |
Idempotency-Key is required, 16 to 128 characters, and accepts ASCII letters, numbers, periods, underscores, colons, and hyphens. Use one stable value per customer order. Its namespace belongs to the reseller and application, so retrying the same order after replacing or revoking an API credential returns the original delivery without consuming a second balance unit. Changing the normalized request under that key returns HTTP 409. After the customer redeems the license, a replay does not expose it again and never creates a duplicate.
A new delivery returns HTTP 201. An eligible idempotent replay returns HTTP 200. The response includes data.delivery_id, replayed, the application and subscription IDs, the customer reference, and license. Read the raw key from license.key only when license.key_available is true, then deliver it through your own protected order flow.
- Authorization
- Konvoa rechecks the credential, reseller status, application grant,
licenses:deliverscope, subscription allowlist, and current permissions on every call. Available balance is checked for every new delivery; an eligible idempotent replay neither consumes nor requires another balance unit. - Atomic delivery
- Balance consumption, license creation, the immutable delivery journal, and its reseller/application idempotency alias commit in one transaction.
- Errors
- Invalid, expired, and revoked credentials share a generic HTTP 401 response. Disallowed scope or subscription uses a generic HTTP 403 response.
- Transport
- Responses use private no-store caching. Limits are 120 requests per minute per IP and 60 per minute per credential, with rate-limit and retry headers.
Create and securely install the replacement credential, switch the reseller service, retry any queued customer orders with their original idempotency keys, then revoke the old credential. Those retries remain bound to the original deliveries across credential rotation. Use a new idempotency key only for a genuinely new customer order. Never embed a reseller secret in a desktop app, browser bundle, webhook payload, log, or customer email.
Account and billing
Manage identity, active sessions, and plan limits together
Account settings include profile details, password rotation, and a list of browser sessions with device, approximate network, creation, activity, and expiry context. An active console session renews near its rolling expiry only after its signed cookie and persistent session record both validate, while an absolute lifetime cap still requires a fresh sign-in. Renewal preserves the session nonce so the current page's CSRF binding remains valid. Revoke a selected session or all other sessions when access may have been exposed. Changing the password requires reauthentication.
Free, Starter, and Pro differ by resource limits. Paid checkout, invoices, plan changes, and cancellation use the billing portal when the payment provider is configured. A plan status must remain eligible for paid limits; an old plan name alone is not an entitlement.
Billing webhooks
Provider events update billing state, not client authority directly
The billing endpoint is service infrastructure, not a customer integration endpoint. It verifies the payment provider's signature against the exact raw request body, binds events to known checkout and subscription records, and processes repeated deliveries idempotently. Never expose the webhook secret to a browser, desktop client, reseller, or customer.
Configure the production signing secret, use the exact public HTTPS endpoint registered with the provider, monitor rejected events, and reconcile subscription state before relying on paid limits.
Platform administration
Operator controls are distinct from customer workspaces
/admin is the platform operator surface for commercial accounts, sales and billing visibility, manual plan grants, platform event review, and service-wide management. /legacy/admin remains the isolated legacy-auth operator surface during migration. Neither surface is a public API or a substitute for owner and reseller scoping.
Operator actions should use named administrator identities, short sessions, strong authentication, audit review, and the smallest necessary access. Manual plan grants need an owner, reason, duration, and revocation path.
Production security
Ship only after the external controls match the code
Use end-to-end verified TLS, including Full (strict) between the edge and origin. Client signatures complement TLS; they do not replace it.
Keep database, signing, payment, provider, and session secrets outside source and release archives. Rotate them with a tested overlap or invalidation plan.
Pin response keys, sign the executable with the platform mechanism, compute the shipped artifact digest, and verify external updates before staging.
Keep same-origin and CSRF checks, secure cookies, bounded inputs, private cache headers, and crawler exclusion on authenticated pages.
Monitor authentication failures, policy denials, reseller issuance, plan changes, key reveals, revocation, and provider health without logging credentials.
Test encrypted backups, database integrity, rollback, response-key rotation, provider outage behavior, and forced session revocation.
LICENSE_KEY_ENCRYPTION_SECRET protects unused license ciphertext and is also the root for separate keyed customer-reference and idempotency digests. Konvoa pins a non-secret fingerprint of that root and fails reseller delivery closed if it changes. Rotate it only through a coordinated maintenance migration that re-encrypts ciphertext, migrates blind indexes, and updates the pinned fingerprint; changing it in place makes existing unused ciphertext and historical reseller idempotency lookups unavailable.
Read the security architecture for the threat boundary and the developer guide before changing any canonical request, token, response, or download-verification behavior.