Skip to main content

What is a Keeper?

A keeper is an automated script that calls charge() on the Vowena contract for subscriptions that are due. Because charge() is permissionless, anyone can trigger it - the contract validates all conditions on-chain. The keeper simply pays the tiny transaction fee (~$0.00001 in XLM), while the subscription payment flows directly from the subscriber to the merchant.
You don’t need to run your own keeper. The Vowena Dashboard provides a managed keeper service. This page is for developers who want to self-host or customize their keeper.

How It Works

  1. The keeper polls for subscription IDs that may be due for charging
  2. For each subscription, it builds a charge() transaction using the SDK
  3. It signs the transaction with its own keypair (the keeper wallet)
  4. It submits the transaction to the network
  5. If the charge succeeds, USDC transfers from subscriber to merchant. If it fails (not yet due, insufficient balance, etc.), the contract rejects it harmlessly.
The keeper’s wallet only needs a small XLM balance for transaction fees. It never handles or holds USDC - payments go directly between subscriber and merchant.

Setup

The standalone keeper bot lives at sdk/keeper/src/index.ts in the Vowena repository.
1

Fund a Keeper Wallet

Create a new Stellar keypair and fund it with a small amount of XLM for transaction fees.
A few XLM is sufficient for thousands of charge transactions.
2

Configure Environment Variables

The keeper bot reads its configuration from environment variables:
Your KEEPER_SECRET is a private key that can sign transactions. Never commit it to source control, share it in logs, or expose it in client-side code. Use a secrets manager or environment variable injection in production.
3

Run the Keeper

Or with all options:
The keeper will start polling and log each charge attempt:
4

Verify It's Working

Use the SDK to check that subscriptions are being charged:

How charge() Is Permissionless

When a subscriber signs the subscribe() transaction, they authorize a SEP-41 token allowance to the Vowena contract. From that point on, the contract itself can pull funds via transfer_from() - it does not matter who initiates the charge() call. The contract enforces all rules:
  • The billing period must have elapsed
  • The subscription must be active
  • The subscriber must have sufficient balance and allowance
  • Trial periods must be complete
  • The max period limit must not be exceeded
The caller (keeper) only pays the transaction fee. The USDC payment goes directly from subscriber to merchant - never through the keeper’s wallet.

Production Considerations

The basic keeper iterates subscription IDs sequentially, which works for small-scale testing. For production, use the dashboard’s event indexer (or build your own) to maintain a database of active subscriptions and their next charge dates. This way you only attempt charges for subscriptions that are actually due, saving RPC calls and transaction fees.
Public Soroban RPC endpoints have rate limits. For production keepers, use a dedicated RPC provider or self-host a Stellar node to avoid throttling during high-traffic periods.
Set up monitoring for your keeper process. Track metrics like successful charges, failed charges, and RPC errors. Alert on prolonged failures so you can intervene before subscriptions start pausing due to missed charges.
If you run multiple keeper instances, they may attempt to charge the same subscription simultaneously. The contract handles this safely - only the first charge succeeds, and subsequent attempts fail harmlessly. However, you will pay unnecessary transaction fees. Use a coordination layer or partition subscription IDs across keepers.
For most merchants, the managed keeper in the Vowena Dashboard is the simplest option. Self-hosting a keeper is recommended only if you need custom logic, want full control over infrastructure, or are operating at scale.