Runtime Verification
Use this page to verify signed runtime responses correctly before you ship an application-side integration.
Who This Is For
- developers integrating runtime validation into an app
- security-conscious teams that need tamper-evident runtime responses
- AI agents implementing activation, validation, metering, offline, or floating flows
When To Use This
Read this page whenever you call a runtime endpoint under /api/v1/license/....
Runtime verification is not optional. The runtime success envelope is only trustworthy after you verify the signature over the data payload.
How It Works
Signed runtime surface
Runtime success responses use:
json
{
"data": { "...": "..." },
"signature": { "...": "..." },
"meta": { "...": "..." }
}The signature covers the JSON bytes of data.
This applies to runtime responses such as:
- activation
- validation
- check
- consume
- deactivate
- floating checkout
- floating heartbeat
- floating checkin
Offline issuance is slightly different:
POST /api/v1/license/offlinereturns an encrypted envelope- after decryption, the inner payload is signed and must still be verified
Public keys
Fetch verification keys from:
text
GET /api/v1/system/public-keysKey rotation matters:
- new responses use the active signing key
- retired public keys stay published so older signed payloads can still be verified
- clients should match by
kidand not assume one permanent key
Verification flow
- call the runtime endpoint with
Authorization: License <license-key> - read
data,signature, andsignature.kid - fetch or load public keys from the system endpoint
- verify the signature against the exact
datapayload bytes - only then trust
status,features,expires_at, orversion_eligibility
Example
TypeScript verification with the first-party SDK:
ts
import {
PublicKeyStore,
RuntimeClient,
SystemClient,
verifyRuntimeResult
} from "@licensekit/sdk";
const baseUrl = "https://api.licensekit.dev";
const runtime = new RuntimeClient({
baseUrl,
licenseKey: process.env.LICENSE_KEY!
});
const system = new SystemClient({ baseUrl });
const result = await runtime.validateLicense({
body: {
fingerprint: "workstation-01",
app_version: "1.2.0"
}
});
const publicKeys = await system.listPublicKeys();
const verification = await verifyRuntimeResult(
result,
new PublicKeyStore(publicKeys.data)
);
if (!verification.ok) {
throw new Error(`verification failed for key ${result.signature.kid}`);
}
if (result.data.status !== "active") {
throw new Error(`license is not active: ${result.data.status}`);
}For offline usage, decrypt the offline envelope first, then apply the same verification rule to the inner signed payload.
Common Mistakes
- trusting
databefore checking the signature - verifying the whole envelope instead of the
datapayload - dropping retired public keys and breaking verification after rotation
- treating offline envelopes as already verified after decryption
- assuming
/healthor/readyzhas anything to do with runtime signature trust