What is a Subscription?
A subscription is the on-chain record linking a subscriber to a plan. It tracks billing state, lifecycle status, and timing. Each subscription is its own persistent ledger entry, enabling parallel processing across the network.State Machine
Every subscription moves through a defined set of states. Transitions are enforced by the contract - there is no way to skip a state or force an invalid transition.Paused is a recoverable state. If a subscriber tops up their wallet and calls
reactivate(), the subscription returns to Active and billing resumes. But if another full billing period passes while paused, the next charge() call will transition it to Cancelled permanently.There is no transition from Cancelled or Expired back to any other state. These are terminal. The subscriber must create a new subscription if they want to resume.
Creating a Subscription
When a subscriber callssubscribe(), several things happen in a single atomic transaction:
1
Subscriber authorization
The subscriber signs the transaction. Soroban’s auth tree means the subscriber signs once - this single signature covers both the
subscribe() contract call and the token.approve() call nested inside it. No separate approval transaction needed.2
Plan validation
The contract loads the plan and verifies:
- The plan exists
- The plan is
active == true - The subscriber is not the merchant (cannot subscribe to your own plan)
3
Allowance calculation
The contract calculates how much token allowance to request:Where
effective_periods is:max_periodsif the plan has a limit, or120if the plan is unlimited (max_periods == 0)
4
Token approval
The contract calls
token.approve(subscriber, contract_address, allowance, expiry_ledger). This grants the Vowena contract permission to pull up to allowance tokens from the subscriber over the approval period.5
Subscription stored
The contract increments
NextSubId, creates the Subscription struct with status: Active, and writes it to persistent storage. The subscription ID is appended to both SubscriberSubs(subscriber) and PlanSubs(plan_id) indexes.6
Event emitted
A
SubscriptionCreated event fires with the full subscription struct.Allowance Calculation Examples
- 12-month plan
- Unlimited plan
- Plan with trial
Plan: 10 USDC/month, ceiling 15 USDC, max 12 periodsThe subscriber’s wallet will show: “Approve 180 USDC for Vowena contract”.
Cancellation
Cancellation is always available to the subscriber and is immediate:Who can cancel?
Who can cancel?
Only the subscriber can cancel their own subscription. The contract calls
subscriber.require_auth(). Merchants cannot cancel on behalf of subscribers.What happens to the allowance?
What happens to the allowance?
The remaining token allowance stays until it expires naturally on the ledger. The contract will never use it after cancellation because the subscription status is
Cancelled and charge() checks status before attempting any transfer.Is it refundable?
Is it refundable?
Cancellation does not trigger an automatic refund. The current period is already paid. Merchants can issue voluntary refunds separately.
Reactivation
If a subscription is Paused (charge failed, grace expired), the subscriber can reactivate it:1
Top up wallet
The subscriber ensures they have sufficient token balance and that the contract’s allowance has not expired.
2
Call reactivate
The subscriber calls
reactivate(sub_id). The contract verifies the subscription is in Paused status and transitions it back to Active.3
Billing resumes
The
next_billing_time is reset so that the next charge() call can process immediately.What’s Next
Billing
The most important page - understand exactly what happens during a charge.
Migrations
How merchants move subscribers to new plans with explicit consent.