XKOVA Docs

Plan and Add-on Entitlements

Not every feature is on for every tenant. Core value movement (stablecoin payments, escrow, wallets) is always available, but capabilities like treasury, full compliance screening, and the tokenization module are add-ons that a tenant unlocks. A tenant's effective feature set is the union of what its plan includes and any overlay grants layered on top. When a request hits a feature it does not have, the API returns a single, predictable error so your integration can react. This page covers how entitlements resolve, how to read them, how to redeem an activation code, and the feature_not_enabled contract.

How Entitlements Resolve

A tenant's effective feature set is a union of two sources. There is no precedence to reason about: a feature is active if either source grants it.

SourceWhat it isHow it changes
Plan baselineThe features included in the tenant's assigned plan. Changes when the tenant's plan changes.
Overlay grantsPer-tenant add-on grants layered on top of the plan, from a redeemed activation code or a direct grant by XKOVA staff. Changes when a code is redeemed, or a grant is added or revoked.

An overlay grant that duplicates a plan feature is a no-op: the plan already grants it. Revoking an overlay grant only drops the add-on, not a feature the plan itself includes. To drop a plan feature, change the plan.

The Feature Catalog

Feature gating is binary and module-level. There is one feature key per top-level capability, not a read/write split. Either the tenant has the key, or it does not. The add-on keys are:

Feature keyGates
treasuryThe treasury surface: multi-signature wallets, signers, and N-of-M approved transfers. See Treasury.
revenue_controlsRevenue and fee controls, including the revenue treasury link and fee schedules. See Fee Schedules.
screening_fullThe upper-tier compliance screening provider used during the pre-sign pipeline. See Screening and Sanctions.
byo_oidcBring-your-own OIDC identity provider configuration for member sign-in.
production_workspaceThe operator-approval leg of live production access. The grant alone does not mint or enable live keys (see the note below).
rwa_tokenizationThe ERC-721 and ERC-1155 tokenization module and the entire real-world-asset metadata surface. See Real-World Assets.
Stablecoin tokens (ERC-20) are the base product and are never gated by an entitlement. Only the NFT and real-world-asset surface sits behind rwa_tokenization.
The production_workspace feature is one leg of live production access, not the whole gate. Enabling live keys additionally requires an active commercial billing subscription and an approved production-access review. Redeeming a code that grants production_workspace clears the operator approval lever only; the other legs are checked at the point a live key is issued.

Reading Effective Entitlements

Fetch the caller-tenant's plan and full feature catalog with a single read. The call is tenant-scoped: it reports the plan and, for every feature in the catalog, whether it is active for this tenant and how it became active. The inactive features are returned too, so a settings surface can show the add-ons a tenant has not unlocked.

The response carries a plan object (key and name) and a features array. Each feature row reports its key, name, description, category, an active boolean, a granted_via provenance value, and a granted_at timestamp.

granted_viaMeaninggranted_at
planActive because the tenant's plan includes it. null (plan grants are implicit, with no per-tenant timestamp).
activation_codeAn overlay grant from a redeemed activation code. ISO-8601 grant time.
admin_grantAn overlay grant set directly by XKOVA staff. ISO-8601 grant time.
nullThe feature is not active for this tenant. null.

This read is what the console uses to drive sidebar gating and the Plan and Add-ons settings section. See Settings and Branding for the operator view.

Redeeming an Activation Code

An add-on is unlocked by redeeming an activation code. Redemption is an admin staff action: it requires the entitlement.redeem permission, a step-up MFA session (AAL2), and it is audited. The request body carries only the plaintext code. XKOVA hashes the code before lookup and never logs the plaintext.

A code references a named grant template, a fixed bundle of feature keys it unlocks. The templates are:

TemplateUnlocks
all_addonsEvery add-on feature.
treasury_onlytreasury.
rwa_onlyrwa_tokenization.
prod_unlockproduction_workspace.

The response reports what changed. granted_features lists the keys this redemption newly activated, already_active lists keys the tenant already held (nothing to do), and redemption_id is the audit row id to quote in a support ticket.

Two idempotency properties matter here, and they are different:

  • The redemption is idempotent at the feature-set layer. Re-granting a feature the tenant already has is a no-op, reported in already_active rather than raising an error.
  • The code itself is one-time-use across all tenants. Once a code has been redeemed, a second redemption of that same code fails with activation_code_already_redeemed. To grant the same features again, issue a fresh code.

Codes may be scoped to a single tenant. A scoped code presented by a different tenant is rejected with activation_code_tenant_mismatch, kept distinct from the not-recognized case so support can tell a mistyped code from one issued to someone else. Codes issued via the redeem endpoint cannot be created there; code issuance is an operator function, not a public API surface.

The feature_not_enabled Contract

When a request reaches a surface gated by an add-on the tenant does not have, the API returns 403 feature_not_enabled. The check runs after authentication and before the handler, so the request never touches the gated resource. The error body's details.feature carries the exact feature key that was missing, so your integration (or the console) can render a targeted "redeem a code to unlock X" prompt rather than a generic denial.

feature_not_enabled is not retryable. Retrying the same call changes nothing; the tenant must first gain the feature (redeem a code, or have staff grant it). This is distinct from an authorization role gap: a role failure is role_denied (you are not allowed to perform the action), while feature_not_enabled means the capability is not turned on for the tenant at all.

The codes you may see across the read, redeem, and gated-call paths:

CodeStatusWhen
feature_not_enabled403The tenant lacks the entitlement a gated surface requires. details.feature names the key.
activation_code_invalid422The code did not match any known row (a hash lookup miss), or it references a grant template that no longer exists.
activation_code_expired422The code carries an expiry in the past.
activation_code_already_redeemed409The code was already redeemed; codes are one-time-use.
activation_code_tenant_mismatch403The code was issued for a different tenant.
role_denied403The caller is not an admin staff member, so cannot redeem.
step_up_required403The admin caller does not hold a step-up MFA (AAL2) session.

See the error catalog for the full envelope shape and correlation IDs.

Related

For the exact request and response shapes, see the operations list or try the calls live in the interactive reference.