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).
| Auth | Header(s) | Who |
|---|---|---|
| none | — | end-customer runtime calls (activation, validate, trial) |
| tenant token | X-Admin-Token: <team/session/env-admin token> | a vendor managing their own tenant |
| platform token | X-Admin-Token: <KEYRIGHT_PLATFORM_TOKEN> (+ X-Tenant for /admin/*) | the platform operator |
| session | X-Admin-Token: <session token from /auth/*> | a signed-in dashboard user |
| HMAC | X-Keyright-Signature | payment-provider webhooks |
| cron secret | X-Cron-Secret | the 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
| Method | Path | Purpose |
|---|---|---|
| POST | /v1/activate | Activate a key on a machine → consumes a seat, returns a signed lease. Body: { key, machineId, product }. |
| POST | /v1/validate | Re-validate / refresh a key+machine without consuming a new seat. Body: { key, machineId, product }. |
| POST | /v1/free-seat | Release the seat this machine holds on a key. Body: { key, machineId, product }. |
| POST | /v1/trial | Self-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/coverage | Does 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
| Method | Path | Purpose |
|---|---|---|
| GET | /admin/products | List products (with tiers, license counts, trial settings). |
| POST | /admin/products | Create/update a product (name, slug, optional trialDays/trialTier/trialSeats). |
| POST | /admin/products/{slug}/trial | Enable/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}/tiers | Create/update a per-product tier (seats + entitlement template). |
| POST | /admin/products/{slug}/signing-key | Generate (or, with {"rotate":true}, rotate) this product’s own signing key → returns signingPublicKey to embed in your app. |
| GET | /admin/tiers | List tenant-wide tier templates. |
| POST | /admin/tiers | Create/update a tenant-wide tier template. |
Licenses
| Method | Path | Purpose |
|---|---|---|
| POST | /admin/licenses | Issue a license (auto-generates a key unless you pass id). |
| GET | /admin/licenses[?product=] | List/filter licenses. |
| POST | /admin/licenses/{id}/revoke | Revoke a license (takes effect on the next online check). |
| POST | /admin/licenses/{id}/renew | Extend expiry / change seats, no new key. |
| POST | /admin/licenses/{id}/transfer | Transfer ownership to a new licensee (audited history). |
| GET | /admin/licenses/{id}/transfers | The license’s ownership chain. |
| POST | /admin/licenses/{id}/deactivate | Release a specific machine’s seat. |
| POST | /admin/licenses/{id}/offline-lease | Sign an offline lease for an air-gapped machine id. |
| GET | /admin/licenses/{id}/activations | Machines a license is active on (device metadata + geo). |
| POST | /admin/licenses/bulk-revoke | Revoke many by id, per-item results. |
| POST | /admin/licenses/bulk-seats | Change seat counts in bulk, per-item results. |
| GET | /admin/revocation-list | Build + 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.
| Method | Path | Purpose |
|---|---|---|
| GET | /admin/licenses/{id}/coverage | A license’s coverage: configured flag, mode, grants, support-until. |
| POST | /admin/licenses/{id}/coverage/grants | Append a grant — a version range and/or a date window. |
| POST | /admin/licenses/{id}/coverage/preset | Apply 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/mode | Set enforcement mode: enforced or unenforced. |
| POST | /admin/licenses/{id}/coverage/revoke | Revoke 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/block | The signed coverage block for this license (for offline / air-gapped import). |
| GET | /admin/products/{slug}/releases | List a product’s registered releases. |
| POST | /admin/products/{slug}/releases | Register a release (version, entitlement date, channel) — powers coverage previews and newest-covered. |
| GET | /admin/products/{slug}/releases/preview | Covered / not-covered / not-configured counts across the product’s licenses. |
| GET | /admin/products/{slug}/coverage/readiness | How many licenses still lack coverage — the enablement gate before enforcing. |
| POST | /admin/products/{slug}/coverage/backfill | Give 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/export | Bulk-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
| Method | Path | Auth | Purpose |
|---|---|---|---|
| GET/POST | /admin/team | owner | List / invite team members (invite emails a one-time token). |
| POST | /admin/team/{id} | owner | Enable/disable a member. |
| POST | /admin/team/{id}/set-password | owner | Provision a member’s dashboard password. |
Workspace, reporting & integration
| Method | Path | Purpose |
|---|---|---|
| GET | /admin/overview | Home dashboard: subscription summary, counts, per-product breakdown, trend, upcoming renewals. |
| GET | /admin/account | Tenant + plan + usage + the integration block (base URL, signing public key, webhook URL). |
| GET | /admin/stats | Per-product totals (licenses, active seats, expiring-soon, revoked). |
| GET | /admin/usage | Per-license allocated/used seats + totals (usage-based billing). |
| GET | /admin/export[?product=] | Full licenses + activations bundle. |
| GET | /admin/audit | Attributable audit log of mutating actions. |
| GET | /admin/public-key | The 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-license | Self-hosted only: this instance’s own license status — status, edition, isTrial, phase (active/expiring/grace/gated), daysUntilExpiry, graceDaysLeft. |
| POST | /admin/workspace | Owner: workspace name, logo, onboarding flag. |
| POST | /admin/webhook-secret/rotate | Owner: rotate this tenant’s fulfillment webhook secret. |
| POST | /admin/billing/checkout | Owner: 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).
| Method | Path | Purpose |
|---|---|---|
| POST | /platform/tenants | Create 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-key | Import (Nebula’s PKCS#8) or generate a tenant signing key. |
| POST | /platform/tenants/{id}/rotate-signing-key | Rotate a tenant’s signing key. |
| POST | /platform/tenants/{id}/rotate-webhook-secret | Rotate a tenant’s webhook secret. |
| GET | /platform/plans | Full 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).
| Method | Path | Purpose |
|---|---|---|
| POST | /auth/login | Email + password → an MFA challenge. |
| POST | /auth/mfa | Email + password + TOTP code → session token. |
| POST | /auth/sso | Exchange a validated OIDC ID token for a session token. |
| POST | /auth/session | Exchange a native / social sign-in access token for a session token. |
| GET | /auth/oauth/{provider} → /auth/oauth/{provider}/callback | Native Google / GitHub OAuth on your own domain. |
Plans (/plans) — public
| Method | Path | Auth | Purpose |
|---|---|---|---|
| GET | /plans | none | Public 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.
| Method | Path | Purpose |
|---|---|---|
| POST | /webhooks/fulfill/{slug} | Per-tenant webhook; tenant is taken from the route and verified by that tenant’s secret. |
| POST | /webhooks/fulfill | Legacy deployment-wide webhook (single-tenant, KEYRIGHT_WEBHOOK_SECRET). |
Operational
| Method | Path | Auth | Purpose |
|---|---|---|---|
| GET | /health | none | Liveness/version probe. |
| GET | /branding | none | White-label brand name/logo/color for any UI. |
| POST | /internal/notifications/run | cron secret | Run the daily expiry/seat-limit scan (drive it from an external scheduler). |
| various | /portal/* | magic link | Self-service customer portal (view licenses, re-download key/file, free seats). |
The dashboard itself is served at /dashboard — see Admin dashboard.