Skip to content

Reference

HTTP API reference

A readable map of the issuing service HTTP API, grouped by area — Runtime, Admin, Platform, Auth, Plans, Webhooks — with method, path, and how each is authenticated.

A readable map of the issuing service’s HTTP API, grouped by area. This page is for finding the right endpoint and knowing how it’s authenticated; the machine-readable OpenAPI spec ships with the service for full request/response schemas, field types, and examples.

$BASE is your issuing service URL (e.g. https://keyright.delta1labs.com).

Authentication at a glance

Every non-runtime endpoint is gated by one of these. All admin/platform auth uses the X-Admin-Token header (a session token from dashboard login is presented the same way).

AuthHeader(s)Who
none—end-customer runtime calls (activation, validate, trial)
tenant tokenX-Admin-Token: <team/session/env-admin token>a vendor managing their own tenant
platform tokenX-Admin-Token: <KEYRIGHT_PLATFORM_TOKEN> (+ X-Tenant for /admin/*)the platform operator
sessionX-Admin-Token: <session token from /auth/*>a signed-in dashboard user
HMACX-Keyright-Signaturepayment-provider webhooks
cron secretX-Cron-Secretthe external notification scheduler

Roles behind a tenant token are capability-gated (owner ⊃ admin ⊃ support/billing ⊃ viewer); an endpoint’s minimum role is noted below where it matters. See Admin dashboard for the role model.

Runtime (/v1/*) — no auth, called by your app / customer

MethodPathPurpose
POST/v1/activateActivate a key on a machine → consumes a seat, returns a signed lease. Body: { key, machineId, product }.
POST/v1/validateRe-validate / refresh a key+machine without consuming a new seat. Body: { key, machineId, product }.
POST/v1/free-seatRelease the seat this machine holds on a key. Body: { key, machineId, product }.
POST/v1/trialSelf-service trial: mint a trial key for a product and email it (idempotent per email — a re-request re-sends the existing key). Body { product, email, company }. The JSON response confirms { ok, trial, emailed, expiresUtc, days, created } and does not contain the key. CORS-open. See Self-service free trials.
POST/v1/coverageDoes this license cover a given build? Returns eligibility + status (Covered / NotCovered / NotConfigured) + newestCovered. Body { key, product, version, on, channel }. The signed coverage block normally rides on activate/validate; this is the explicit check. See Release coverage.

Admin (/admin/*) — tenant token

Manage one tenant’s products, licenses, and team. With the platform token these require an X-Tenant header naming the target tenant.

Products & tiers

MethodPathPurpose
GET/admin/productsList products (with tiers, license counts, trial settings).
POST/admin/productsCreate/update a product (name, slug, optional trialDays/trialTier/trialSeats).
POST/admin/products/{slug}/trialEnable/disable a product’s self-service trial. Body { days, tier, seats } (days <= 0 disables); the response echoes them as { trialDays, trialTier, trialSeats }.
POST/admin/products/{slug}/tiersCreate/update a per-product tier (seats + entitlement template).
POST/admin/products/{slug}/signing-keyGenerate (or, with {"rotate":true}, rotate) this product’s own signing key → returns signingPublicKey to embed in your app.
GET/admin/tiersList tenant-wide tier templates.
POST/admin/tiersCreate/update a tenant-wide tier template.

Licenses

MethodPathPurpose
POST/admin/licensesIssue a license (auto-generates a key unless you pass id).
GET/admin/licenses[?product=]List/filter licenses.
POST/admin/licenses/{id}/revokeRevoke a license (takes effect on the next online check).
POST/admin/licenses/{id}/renewExtend expiry / change seats, no new key.
POST/admin/licenses/{id}/transferTransfer ownership to a new licensee (audited history).
GET/admin/licenses/{id}/transfersThe license’s ownership chain.
POST/admin/licenses/{id}/deactivateRelease a specific machine’s seat.
POST/admin/licenses/{id}/offline-leaseSign an offline lease for an air-gapped machine id.
GET/admin/licenses/{id}/activationsMachines a license is active on (device metadata + geo).
POST/admin/licenses/bulk-revokeRevoke many by id, per-item results.
POST/admin/licenses/bulk-seatsChange seat counts in bulk, per-item results.
GET/admin/revocation-listBuild + sign a distributable offline revocation list.

Release coverage — which versions a license covers. See Release coverage for the full guide, field shapes and SDK side.

MethodPathPurpose
GET/admin/licenses/{id}/coverageA license’s coverage: configured flag, mode, grants, support-until.
POST/admin/licenses/{id}/coverage/grantsAppend a grant — a version range and/or a date window.
POST/admin/licenses/{id}/coverage/presetApply a preset (lifetime, updates-for-period, one-major, one-major + upgrade-protection, subscription, subscription-with-fallback) that expands into grants.
POST/admin/licenses/{id}/coverage/modeSet enforcement mode: enforced or unenforced.
POST/admin/licenses/{id}/coverage/revokeRevoke a grant.
GET/admin/licenses/{id}/coverage/check[?version=&on=&channel=]Evaluate a build against this license (Covered / NotCovered / NotConfigured, with reason).
GET/admin/licenses/{id}/coverage/blockThe signed coverage block for this license (for offline / air-gapped import).
GET/admin/products/{slug}/releasesList a product’s registered releases.
POST/admin/products/{slug}/releasesRegister a release (version, entitlement date, channel) — powers coverage previews and newest-covered.
GET/admin/products/{slug}/releases/previewCovered / not-covered / not-configured counts across the product’s licenses.
GET/admin/products/{slug}/coverage/readinessHow many licenses still lack coverage — the enablement gate before enforcing.
POST/admin/products/{slug}/coverage/backfillGive legacy licenses a legacy grant (lifetime, support-end, or CSV rows) so enforcing never locks them out.
POST/admin/products/{slug}/coverage/migrate[?dryRun=]Apply a grant across a product’s licenses; dryRun previews the gain.
GET/admin/products/{slug}/coverage/exportBulk-export each license’s signed coverage block for air-gapped delivery.

A customer can read their own coverage from the self-service portal: GET /portal/license/{id}/coverage (portal magic-link token) → the plain-language status sentence + support-until.

Team

MethodPathAuthPurpose
GET/POST/admin/teamownerList / invite team members (invite emails a one-time token).
POST/admin/team/{id}ownerEnable/disable a member.
POST/admin/team/{id}/set-passwordownerProvision a member’s dashboard password.

Workspace, reporting & integration

MethodPathPurpose
GET/admin/overviewHome dashboard: subscription summary, counts, per-product breakdown, trend, upcoming renewals.
GET/admin/accountTenant + plan + usage + the integration block (base URL, signing public key, webhook URL).
GET/admin/statsPer-product totals (licenses, active seats, expiring-soon, revoked).
GET/admin/usagePer-license allocated/used seats + totals (usage-based billing).
GET/admin/export[?product=]Full licenses + activations bundle.
GET/admin/auditAttributable audit log of mutating actions.
GET/admin/public-keyThe tenant signing public key. null until a tenant key exists — for a per-product key use POST /admin/products/{slug}/signing-key instead.
GET/admin/self-licenseSelf-hosted only: this instance’s own license status — status, edition, isTrial, phase (active/expiring/grace/gated), daysUntilExpiry, graceDaysLeft.
POST/admin/workspaceOwner: workspace name, logo, onboarding flag.
POST/admin/webhook-secret/rotateOwner: rotate this tenant’s fulfillment webhook secret.
POST/admin/billing/checkoutOwner: open a Lemon Squeezy checkout to upgrade the plan.
POST/GET/admin/resellers, /admin/resellers/{id}Manage resellers (capped, product-scoped issuers).

Platform (/platform/*) — platform token

The multi-tenant operator surface. Disabled (503) when KEYRIGHT_PLATFORM_TOKEN is unset (single-tenant self-host).

MethodPathPurpose
POST/platform/tenantsCreate a company/tenant → returns initial owner token, signing public key, webhook secret.
GET/platform/tenants[?slug=]List tenants.
POST/platform/tenants/{id}Enable/disable, set plan, subscription status.
POST/platform/tenants/{id}/signing-keyImport (Nebula’s PKCS#8) or generate a tenant signing key.
POST/platform/tenants/{id}/rotate-signing-keyRotate a tenant’s signing key.
POST/platform/tenants/{id}/rotate-webhook-secretRotate a tenant’s webhook secret.
GET/platform/plansFull plan catalog (incl. non-public plans).
POST/platform/plans/{key}Create/update a plan’s pricing, quotas, and features.

Auth (/auth/*) — dashboard sign-in → session token

These mint a session token you then present as X-Admin-Token to the /admin/* endpoints above. Login is per-tenant (pass X-Tenant; defaults to default).

MethodPathPurpose
POST/auth/loginEmail + password → an MFA challenge.
POST/auth/mfaEmail + password + TOTP code → session token.
POST/auth/ssoExchange a validated OIDC ID token for a session token.
POST/auth/sessionExchange a native / social sign-in access token for a session token.
GET/auth/oauth/{provider} → /auth/oauth/{provider}/callbackNative Google / GitHub OAuth on your own domain.

Plans (/plans) — public

MethodPathAuthPurpose
GET/plansnonePublic pricing catalog (plans marked public), for a pricing page or signup.

Webhooks (/webhooks/*) — HMAC

Fulfillment triggers: a payment provider (or a thin adapter) POSTs a normalized event, HMAC-signed over the raw body in X-Keyright-Signature. “Paid” mints a license (idempotent per order ref); “refund”/“cancel” revokes it. Payment processing itself is out of scope.

MethodPathPurpose
POST/webhooks/fulfill/{slug}Per-tenant webhook; tenant is taken from the route and verified by that tenant’s secret.
POST/webhooks/fulfillLegacy deployment-wide webhook (single-tenant, KEYRIGHT_WEBHOOK_SECRET).

Operational

MethodPathAuthPurpose
GET/healthnoneLiveness/version probe.
GET/brandingnoneWhite-label brand name/logo/color for any UI.
POST/internal/notifications/runcron secretRun the daily expiry/seat-limit scan (drive it from an external scheduler).
various/portal/*magic linkSelf-service customer portal (view licenses, re-download key/file, free seats).

The dashboard itself is served at /dashboard — see Admin dashboard.