Subscriptions System & Service Registry
The Shamwari Subscriptions System (nxt.subscriptions.SubscriptionsHome) provides a protocol-native, decentralized recurring revenue infrastructure built directly into the core Shamwari ledger runtime.
By executing subscription management natively within nxt.subscriptions—rather than relying on third-party smart contracts or centralized billing aggregators—Shamwari eliminates payment processor fees, chargeback vulnerabilities, card-token storage risks, and virtual machine execution overhead. The system enables providers to establish flexible multi-tier subscription plans, receive recurring payments in any native holding asset (fiat stablecoin, platform coin, or custom totem asset), and grant tamper-proof, block-height-verified access entitlements to subscriber accounts across BetaChains.
Core Capabilities & Architecture
- Protocol-Native Recurring Revenue: Managed directly by
nxt.subscriptions, bypassing VM smart contract execution to eliminate reentrancy risks and gas friction. - Multi-Holding Asset Settlement: Supports payments denominated in any
HoldingType—includingCURRENCY(ShamwariPay fiat/stablecoins),COIN(BetaChain native coins), orTOTEM(custom digital assets/tokens). - JSON-Serialized Multi-Tier Plans: Providers can define unlimited billing tiers (e.g., daily, monthly, annual, or custom block spans) within a single service registration using JSON-serialized
SubscriptionPlanarrays. - Strict Payload Validation: Enforces a hard ceiling (
MAX_PLANS_BYTE_SIZE) on serialized plan specifications viaSubscriptionPlanValidatorto protect ledger state. - Block-Height Entitlement Engine: Entitlements are tracked on-chain in
AccountSubscriptionrecords, evaluating subscription validity directly against blockchain block height (). - Non-Loss Auto-Renewal Logic: Renewal transactions extend active subscriptions seamlessly from their existing expiry height () rather than resetting from the transaction block height, ensuring early renewals lose zero paid access time.
- Integrated Fiscal Tax Withholding: Payment execution automatically calculates and credits protocol taxes via
CurrencyTaxRecordforCURRENCYholding payments before disbursing net revenue to provider accounts. - Full-Text Searchable Service Registry: Services are indexed in
public.subscription_serviceusing full-text search capabilities (ft.score), enabling native service discovery by keywords and provider IDs. - Immutable Payment Audit Trail: Every subscription settlement generates an append-only, versioned record in
public.subscription_paymentfor compliance and financial auditing.
Data Model & Relational Schema
The Subscriptions System maintains two primary versioned entity tables per BetaChain schema, indexed by transaction IDs, provider IDs, subscriber IDs, block height, and timestamp.
1. Primary Subscription Entities
| Table | Primary Key / Index | Entity Class | Description |
|---|---|---|---|
public.subscription_service | id, height | SubscriptionService | Master registry table tracking service definitions, provider accounts, holding parameters, JSON plans, and active status. |
public.subscription_payment | id, height | SubscriptionPayment | Append-only transaction audit log recording subscriber payments, selected plans, amounts, and tax deductions. |
2. Service Definition Record (public.subscription_service)
| Field | Type | Description |
|---|---|---|
id | long | Transaction ID of the initial service registration (globally unique handle). |
full_hash | byte[] | Full 32-byte cryptographic hash of the registration transaction. |
provider_id | long | Account ID of the service provider receiving recurring payments. |
name | String | Human-readable name of the subscription service (full-text indexed). |
description | String | Detailed service description and capabilities (full-text indexed). |
holding_id | long | Specific ID of the currency or totem asset accepted for payment ( for native chain coin). |
holding_type | byte | Enum code for accepted payment asset: CURRENCY (), COIN (), or TOTEM (). |
plans | VARCHAR (JSON) | Serialized JSON array of available SubscriptionPlan tiers. |
timestamp | int | Blockchain timestamp (seconds since epoch) when the service was registered. |
is_deleted | boolean | Flag set to true if the provider decommissions/discontinues the service. |
height | int | Block height of the latest entity modification. |
latest | boolean | Versioning flag denoting the current active record state. |
3. Payment Settlement Record (public.subscription_payment)
| Field | Type | Description |
|---|---|---|
id | long | Transaction ID of the payment transaction. |
subscriber_id | long | Account ID of the subscriber making the payment. |
service_id | long | Target SubscriptionService ID being purchased/renewed. |
provider_id | long | Receiving provider account ID. |
holding_id | long | Asset ID utilized for payment settlement. |
holding_type | byte | Asset type code (CURRENCY, COIN, or TOTEM). |
plan | String | Specific name of the plan tier selected by the subscriber. |
amount | long | Total price paid in quantum units (). |
tax | long | Tax amount () withheld and credited to the BetaChain tax collector. |
timestamp | int | Timestamp of payment execution. |
height | int | Block height at which payment was confirmed and entitlement extended. |
4. Subscription Plan Object Structure (SubscriptionPlan)
Each billing tier within a service is represented by an immutable SubscriptionPlan object and serialized into JSON for database storage:
| Field | Data Type | Description |
|---|---|---|
name | String | Unique tier identifier (e.g., "Monthly-Pro", "Annual-Enterprise"). |
description | String | Feature summary or SLA description for the tier. |
duration | int | Service duration in blockchain blocks (). |
amountQNT | long | Required payment amount in atomic units () of the specified holding. |
metadata | Map<String, String> | Custom key-value pairs for domain-specific parameters (e.g., claim limits, API quotas). |
Subscription Lifecycle & State Machine
A subscription service transitions through operational states managed by provider transactions and subscriber interactions:
┌───────────────────────────────────────────────┐
│ addSubscriptionService() / Registration │
└───────────────────────┬─── ────────────────────┘
│
▼
┌───────────────────────────────────────┐
│ ACTIVE SERVICE │
│ (is_deleted == false) │
└───────┬───────────────┬───────┬───────┘
│ │ │
updateServicePlans() │ │ │ discontinueService()
(Modifies JSON Array) │ │ │ (Decommissions Service)
▼ │ ▼
┌───────────────┐ │ ┌───────────────────────┐
│ Updated Tiers │ │ │ DISCONTINUED SERVICE │
└───────────────┘ │ │ (is_deleted == true) │
│ └───────────────────────┘
│ ▲
│ No Payments │
│ Allowed │
▼ │
┌───────────────────────────────────────┴┐
│ addSubscriptionPayment() │
│ (Subscriber Debited / Provider Paid) │
└───────────────────────┬────────────────┘
│
▼
┌────────────────────────────────────────┐
│ AccountSubscription Entitlement │
│ expirationHeight = max(current, old) │
│ + plan.duration │
└────────────────────────────────────────┘
Validation Rules & Payload Limits (SubscriptionPlanValidator)
To maintain chain efficiency and protect nodes against memory exhaustion or storage inflation, all plan structures undergo byte-level validation during transaction submission and verification:
1. Payload Size Constraint
The total serialized byte size of a service's SubscriptionPlan[] array must not exceed the system threshold:
If a provider attempts to register or update a service exceeding , SubscriptionPlanValidator.validatePlansByteSize() throws a NxtException.NotValidException.
2. Binary Serialization Calculation Formula
The byte calculation executed by SubscriptionPlanValidator.calculatePlansByteSize() measures the precise wire length of the plan array:
Where:
- prefix for array length .
- For each plan :
- name length indicator (UTF-8 bytes).
- description length indicator (UTF-8 bytes).
- for
duration(32-bit integer). - for
amountQNT(64-bit long integer). - metadata entry count .
- For each metadata entry : key length value length .
Mathematical Formulas & Entitlement Calculations
1. Access Entitlement Expiration Formula
When a subscriber purchases or renews a subscription tier, Account.addOrRenewSubscription() computes the new access expiration height ():
- Expired/New Subscriptions: If , access begins at and extends by .
- Active Renewals: If , access is added directly to , ensuring subscribers retain of pre-paid access time.
2. Entitlement Status Evaluation
An application verifies a subscriber's access entitlement by querying their AccountSubscription record for a given serviceId:
3. Net Revenue & Fiscal Tax Deduction
When processing a CURRENCY subscription payment, protocol taxes are computed via TaxCalculator and processed prior to provider crediting:
The net funds are credited to the provider's balance, and a record is logged in public.currency_tax_record.
Detailed Operational Workflows
1. Registering a Subscription Service
A service provider invokes addSubscriptionService() via a SUBSCRIPTION_SERVICE transaction attachment:
- Validates that plan byte size satisfies .
- Sets
is_deleted = falseand records creation timestamp. - Serializes plan objects into JSON and inserts a row into
public.subscription_service. - Emits
SubscriptionsHome.Event.NEW_SUBSCRIPTION_SERVICE.
2. Updating Service Tier Plans
A provider can modify billing tiers via updateServicePlans():
- Fetches active service record by
serviceId. - Validates that
is_deleted == false(discontinued services cannot update plans). - Validates new plan array byte size using
SubscriptionPlanValidator. - Replaces the
plansJSON representation and inserts a new versioned row intopublic.subscription_service. - Emits
SubscriptionsHome.Event.SUBSCRIPTION_PLAN_UPDATE.
3. Subscribing and Paying (addSubscriptionPayment)
A subscriber submits a SUBSCRIPTION_PAYMENT transaction specifying serviceId and target plan:
- System validates that the service exists and
is_deleted == false. - Locates the requested plan name within the service's
plansarray. - Debits from the subscriber's holding balance.
- Credits to the provider's account.
- Invokes
Account.addOrRenewSubscription()to calculate and store the updatedexpirationHeight. - Inserts a row into
public.subscription_payment. - Emits
SubscriptionsHome.Event.SUBSCRIPTION_PAYMENT.
4. Discontinuing a Service
A provider can decommission an active offering via discontinueService():
- Queries the service entity by
serviceId. - Sets
is_deleted = true. - Inserts updated state into
public.subscription_service. - Emits
SubscriptionsHome.Event.SUBSCRIPTION_SERVICE_ENDED. - Note: Existing subscribers retain access until their
expirationHeightpasses, but no new subscriptions or renewals can be processed.
Event Listener Matrix
The Subscriptions System exposes strongly-typed cross-chain listeners via SubscriptionsHome:
| Event Enum | Class Target | Trigger Condition |
|---|---|---|
NEW_SUBSCRIPTION_SERVICE | SubscriptionService | New service successfully validated and indexed in registry. |
SUBSCRIPTION_PLAN_UPDATE | SubscriptionService | Service provider updated plan tiers, pricing, or metadata JSON. |
SUBSCRIPTION_SERVICE_ENDED | SubscriptionService | Provider decommissioned service (is_deleted set to true). |
SUBSCRIPTION_PAYMENT | SubscriptionPayment | Subscriber payment processed, revenue disbursed, and entitlement extended. |
// Registering a global subscription payment listener
SubscriptionsHome.addSubscriptionPaymentListener(payment -> {
System.out.println("Payment received for Service: " + payment.getServiceId()
+ " by Subscriber: " + payment.getSubscriberId()
+ " Amount: " + payment.getAmountQNT());
}, SubscriptionsHome.Event.SUBSCRIPTION_PAYMENT);
Related APIs
| API | Description |
|---|---|
| CreateSubscriptionService | Create subscription service |
| UpdateSubscriptionPlans | Update service plans |
| GetSubscriptionService | Get specific service |
| GetSubscriptionServices | List all services |
| SearchSubscriptionServices | Search services |
| GetSubscriptionServicesCount | Get services count |
| DiscontinueSubscriptionService | Discontinue service |
| SubscriptionPayment | Make subscription payment |
| GetSubscriptionPayment | Get payment |
| GetSubscriptionPayments | List payments |
| GetSubscriptionPaymentsCount | Get payments count |
| GetAccountSubscriptions | Get account subscriptions |
Primary Institutional Use Cases
- SaaS & API Access Control: Software providers gate feature access and API rate limits behind block-height subscription tiers. Applications verify entitlement directly on-chain without maintaining external user databases.
- Media, Streaming & Digital Content: Content creators, news agencies, and streaming platforms issue tiered subscriptions, maintaining immutable records of subscriber access rights.
- Professional Associations & Licensing: Industry bodies and chambers of commerce track annual membership dues on-chain with auto-expiring block-height certificates.
- Automated Insurance Premium Collection: Seamlessly integrates with the Shamwari Insurance Subsystem (
nxt.insurance) to automate recurring policy premium collections (monthly, quarterly, annual). - Tokenized Loyalty & Membership Badges: Service providers accept custom
TOTEMdigital assets or native loyalty tokens as subscription fees, enabling staking-based and token-gated access tiers.