Skip to main content
The Vowena contract emits events for every significant state change - plan creation, charges, cancellations, migrations, and more. The SDK provides two ways to consume these events.

getEvents

Fetches events from the Soroban RPC in a single request. Useful for one-off queries or building your own polling loop.
import { getEvents } from "vowena";

const { events, latestLedger } = await getEvents(
  "https://soroban-testnet.stellar.org",
  "CABC...CONTRACT",
  12345678,  // startLedger
  100        // limit (optional)
);

for (const event of events) {
  console.log(event.type, event.ledger, event.data);
}
Signature:
function getEvents(
  rpcUrl: string,
  contractId: string,
  startLedger: number,
  limit?: number
): Promise<{ events: VowenaEvent[]; latestLedger: number }>;
ParameterTypeRequiredDescription
rpcUrlstringYesSoroban RPC endpoint URL
contractIdstringYesVowena contract address
startLedgernumberYesLedger sequence to start fetching from
limitnumberNoMaximum number of events to return
Returns: Promise<{ events: VowenaEvent[], latestLedger: number }>

VowenaEvent

Every event returned by getEvents or the poller follows this shape:
interface VowenaEvent {
  type: string;        // Event type identifier (e.g., "charge_ok", "sub_created")
  ledger: number;      // Ledger sequence where the event was emitted
  timestamp: number;   // Unix timestamp of the ledger
  contractId: string;  // Contract that emitted the event
  topics: unknown[];   // Raw event topics
  data: unknown;       // Parsed event data
}

VowenaEventPoller

For continuous monitoring, use VowenaEventPoller. It polls the RPC at a configurable interval and invokes your callback for each new event.
import { VowenaEventPoller } from "vowena";

const poller = new VowenaEventPoller({
  contractId: "C...",
  rpcUrl: "https://soroban-testnet.stellar.org",
  onEvent: (event) => console.log(event.type, event.data),
  intervalMs: 5000,
});

await poller.start();

// Later, when you want to stop:
poller.stop();
Constructor options:
interface EventPollerOptions {
  contractId: string;
  rpcUrl: string;
  onEvent: (event: VowenaEvent) => void;
  intervalMs?: number;    // Polling interval in ms (default: 5000)
  startLedger?: number;   // Ledger to start from (default: latest)
}
OptionTypeRequiredDescription
contractIdstringYesVowena contract address
rpcUrlstringYesSoroban RPC endpoint URL
onEvent(event: VowenaEvent) => voidYesCallback invoked for each event
intervalMsnumberNoPolling interval in milliseconds (default: 5000)
startLedgernumberNoLedger to begin polling from (default: latest ledger at start)
Methods:
MethodDescription
await poller.start()Begin polling. Resolves once the first poll completes.
poller.stop()Stop polling. Safe to call multiple times.

Event Types

The Vowena contract emits the following event types:
Event TypeEmitted When
plan_createdA new subscription plan is created
plan_updatedA plan’s amount is updated
sub_createdA subscriber subscribes to a plan
charge_okA charge succeeds and USDC is transferred
charge_failA charge attempt fails (e.g., insufficient balance)
sub_cancelA subscription is cancelled
sub_pausedA subscription is paused due to failed charges exceeding the grace period
sub_expiredA subscription reaches its maximum period limit
sub_reactA paused subscription is reactivated
refundA merchant issues a refund
mig_reqA merchant requests plan migration
mig_acceptA subscriber accepts a migration
mig_rejectA subscriber rejects a migration

Example: Logging All Charges

import { VowenaEventPoller, NETWORKS } from "vowena";

const poller = new VowenaEventPoller({
  contractId: NETWORKS.testnet.contractId,
  rpcUrl: NETWORKS.testnet.rpcUrl,
  onEvent: (event) => {
    if (event.type === "charge_ok") {
      console.log(`Charge succeeded at ledger ${event.ledger}`, event.data);
    }
    if (event.type === "charge_fail") {
      console.warn(`Charge failed at ledger ${event.ledger}`, event.data);
    }
  },
  intervalMs: 10_000,
});

await poller.start();
Soroban RPC retains events for a limited window (typically the last ~24 hours of ledgers). For production use, persist events to your own database and use the startLedger option to resume from where you left off. The Vowena Dashboard includes a built-in event indexer that handles this automatically.