Amba

Virtual Currencies

Soft and premium currencies with auto-recharge, balance caps, and transaction history.

Define virtual currencies for your app. Currencies can be soft (earned through gameplay) or premium (purchased with real money), with optional auto-recharge for time-gated mechanics.

SDK usage

Get balances

const balances = await client.currencies.getBalances();
// Returns:
// [
//   { currency_code: "gold", name: "Gold Coins", balance: 500, is_premium: false },
//   { currency_code: "gems", name: "Gems", balance: 10, is_premium: true }
// ]

Get transactions

const { data, total } = await client.currencies.getTransactions({
  currency_code: 'gold',
  limit: 20,
});

Client API reference

MethodPathDescription
GET/client/currenciesGet all currency balances
GET/client/currencies/transactionsGet transaction history

MCP tools

ToolDescription
amba_currencies_createCreate a currency (soft/premium, auto-recharge, caps)
amba_currencies_listList all currencies
amba_currencies_grantGrant currency to a user (admin). Accepts idempotency_key for exactly-once grants.
amba_currencies_spendDebit currency from a user (admin). Atomic; rejects on insufficient funds. Accepts idempotency_key.

Example: Hearts system

Agent: "Create a hearts currency that recharges 1 heart every 30 minutes, max 5"

amba_currencies_create({
  project_id: "proj_xxx",
  code: "hearts",
  name: "Hearts",
  description: "Lives for gameplay",
  is_premium: false,
  initial_balance: 5,
  max_balance: 5,
  auto_recharge_amount: 1,
  auto_recharge_interval_hours: 0.5
})

Currency options

FieldTypeDescription
codestringUnique code (e.g., "gold", "gems")
namestringDisplay name
is_premiumbooleanPremium (real money) currency
initial_balancenumberSpendable starting balance for new users (default 0) — see below
max_balancenumberBalance cap (null for unlimited)
auto_recharge_amountnumberAmount to auto-recharge
auto_recharge_interval_hoursnumberHours between recharges

Spendable starting balances

When a currency sets initial_balance > 0, that starting amount is real, spendable currency — not just a number the balance read displays. The first time a user is granted or spends the currency, Amba lazily credits the starting balance into the user's transaction history as a system transaction, then applies the grant or spend on top. From that point on, the balance read and the transaction history always agree: summing a user's transactions reconstructs their current balance.

This means a user can spend their starting balance immediately, even before their first grant. Currencies with initial_balance of 0 are unaffected — nothing is credited and the user starts empty.

Idempotent grants and spends

Both grants and spends accept an optional idempotency_key (string, ≤255 characters). It makes the operation exactly-once: if you replay a request with the same key for the same user and currency, Amba returns the original transaction with idempotent_replay: true and does not apply the balance change again.

The key is permanent — it's anchored to the ledger row it created, so there's no expiry window to manage. You control the dedup window entirely through what you encode into the key. Want to cap a reward at "one grant per share, per day"? Encode the day into the key:

// Grant 10 gold for sharing — but at most once per user per day.
await client.currencies.grant({
  app_user_id: user.id,
  currency_code: 'gold',
  amount: 10,
  idempotency_key: `share:${user.id}:${todayYmd}`, // e.g. "share:u_123:2026-05-29"
});

The first call that day credits the balance and returns idempotent_replay: false. Every later call with the same key that day is a no-op replay that returns the original transaction — no double-grants, and no guard collection of your own to maintain. The next day's key is different, so the grant lands again.

One exception worth knowing: a spend that fails with insufficient funds stores no key (no ledger row was created), so retrying the same key after the user tops up is allowed and will go through.

Event-triggered grants

Grant currency automatically when a user action fires — no admin credentials needed on the client.

See Event-triggered Currency Grants for setup, grant modes, daily caps, and how it works.

On this page