Manifests and signing
Delivery manifests are signed, versioned, tenant-scoped, and served from Cloudflare KV.
A manifest is the delivery artifact consumed by SDKs. It contains the experiments, variants, audience rules, and execution metadata needed for assignment.
Signing
Manifests are signed with tenant-scoped Ed25519 keys. Public keys are exposed through JWKS:
GET /.well-known/jwks/{orgId}The Cloudflare manifest worker can proxy JWKS to the API and cache it at the edge.
An unknown organization can return an empty {"keys":[]} set. That response
does not establish trust: SDK verification fails closed unless a matching active
key validates the manifest or preview token.
The browser and server SDK fetch paths verify all of the following before a manifest can influence assignment:
- strict delivery schema and supported schema version,
- tenant, experiment, and variant identifier integrity,
- unique identifiers, valid references, and weight totals,
- SHA-256 content hash over the canonical payload,
- Ed25519 signature against the tenant JWKS,
- active key status and optional maximum manifest age.
Fetched manifests are verified by default. requireSignedManifest: false is a
test-only escape hatch. Direct createClient(manifest, ...) and
NodeClient.setManifest() calls are trusted injection boundaries; verify any
network-delivered value before using those APIs.
Publishing
The API publishes signed manifests to Cloudflare via:
POST /admin/publishIn staging/production this path is HMAC-protected with timestamp and nonce headers to reduce replay risk. Customer tenants publish with a tenant-specific HMAC provisioned during provider onboarding. A registered tenant cannot fall back to the provider-global HMAC, so a customer release never needs or receives the provider credential.
Revocation
Revoked manifest versions are served from:
GET /.well-known/revocations/{orgId}The record is JSON with a unique non-negative integer list:
{ "versions": [41, 42] }Both fetched-manifest SDK paths consult this record on initial load and every
refresh, and reject a listed manifestVersion. The edge response uses a
15-second cache TTL with mandatory revalidation, so emergency revocations stop
new SDK refreshes within that cache interval. A static origin that returns 404
is treated as having no revocation service; governed deployments should expose
the endpoint or pass an explicit manifestRevocationsUrl.