Amba

Event-triggered Currency Grants

Grant currency automatically when a user action fires — no admin keys exposed to the client.

Connect user behavior directly to your economy. When Amba.events.track() fires, the server checks for matching grant rules and credits the user's balance automatically — no admin credentials needed on the client side.

Quickstart

Step 1 — Create the currency (if you haven't already)

// Via MCP in your dev shell or agent
amba_currencies_create({
  project_id: 'proj_...',
  code: 'calm_points',
  name: 'Calm Points',
});

Step 2 — Provision a grant rule

// Grant 10 calm_points every time session.completed fires, up to 50 a day
amba_currency_grant_rules_create({
  project_id: 'proj_...',
  currency_key: 'calm_points',
  event_name: 'session.completed',
  grant_amount: 10,
  max_per_day: 50,
});

Every rule sets exactly one of max_per_day or uncapped: true. See Daily limits.

Step 3 — Track the event from your app

await Amba.events.track('session.completed', { minutes: 1 });
// → +10 calm_points granted automatically
// → balance updated on next Amba.currencies.getBalance() call

That's it. No server-side code needed.

Grant modes

Flat grant

Grant a fixed amount on every qualifying event.

amba_currency_grant_rules_create({
  currency_key: 'calm_points',
  event_name: 'session.completed',
  grant_amount: 10, // always +10
  max_per_day: 50,
});

Property-scaled grant

Scale the grant by a numeric property on the event. Useful for distance, duration, or score-based rewards.

amba_currency_grant_rules_create({
  currency_key: 'calm_points',
  event_name: 'session.completed',
  grant_property: 'minutes', // read from event properties
  grant_multiplier: 2, // 2 points per minute
  max_per_day: 120, // bounds what app-tracked events can grant per day
});
// 10-minute session → +20 calm_points
await Amba.events.track('session.completed', { minutes: 10 });

The result is floor(property_value × multiplier). If the property is absent or non-numeric, the grant is skipped silently.

The app supplies the property value on events it tracks with its client key, so a property-scaled rule applies to those events only when it sets max_per_day. A property-scaled rule with uncapped: true applies to events recorded by a server key, the admin events API, or the subscription cascade.

Daily limits

Every rule sets exactly one of these two. A create request with neither answers 400 DAILY_CAP_REQUIRED; one with both answers 400 INVALID_GRANT.

max_per_day

Caps the total the rule grants one user per UTC day. Use it for any event the app tracks itself, since an end user can repeat those.

amba_currency_grant_rules_create({
  currency_key: 'calm_points',
  event_name: 'session.completed',
  grant_amount: 10,
  max_per_day: 50, // cap at 50 points/day
});

Once a user reaches the daily cap, further events for that rule grant 0 points until UTC midnight resets the counter.

uncapped: true

Grants with no daily limit. A fixed-amount rule with uncapped: true grants on every matching event, including events an end user can send from the app as often as they like, so reserve it for events your server records or events that can't repeat. A property-scaled rule with uncapped: true grants only on events recorded by a server key, the admin events API, or the subscription cascade.

// Reward every new subscriber once per entitlement grant
amba_currency_grant_rules_create({
  currency_key: 'calm_points',
  event_name: 'entitlement.granted',
  grant_amount: 500,
  uncapped: true,
});

Rules created before daily limits were required

A fixed-amount rule created before this requirement, with no max_per_day, grants on events recorded by a server key, the admin events API, or the subscription cascade. Events the app tracks with its client key grant nothing from it. To restore its reach, delete it and create it again with max_per_day or uncapped: true.

Multiple rules

Multiple rules can target the same event. All matching enabled rules fire independently — their grants are summed.

// Both rules fire on "session.completed"
amba_currency_grant_rules_create({
  currency_key: 'calm_points',
  event_name: 'session.completed',
  grant_amount: 10,
  max_per_day: 50,
});
amba_currency_grant_rules_create({
  currency_key: 'streak_tokens',
  event_name: 'session.completed',
  grant_amount: 1,
  max_per_day: 1,
});

Managing rules

List rules

const rules = await amba_currency_grant_rules_list({ project_id: 'proj_...' });

Disable a rule (without deleting it)

Rules don't have an update endpoint yet — delete and re-create to change parameters. To pause a rule quickly, delete it; existing ledger history is preserved.

Delete a rule

await amba_currency_grant_rules_delete({
  project_id: 'proj_...',
  rule_id: 'rule_...',
});

Deleting a rule stops it from firing on future events. Historical grants in the transaction ledger are not affected.

Read the balance

After events fire, read the updated balance with the currencies SDK:

const balances = await Amba.currencies.getBalance();
const calmPoints = balances.find((b) => b.currency_code === 'calm_points');
console.log(calmPoints?.balance); // e.g. 50

How it works

  1. Amba.events.track(name, properties) sends the event to the API.
  2. The API writes the event to the database, then checks for enabled grant rules matching the event name.
  3. For each matching rule, the server runs a serialized transaction:
    • Reads the user's current balance with a row-level lock (prevents concurrent grant races).
    • Applies the daily cap if configured.
    • Credits the balance and writes an audit entry.
  4. The getBalances() call reflects the new balance immediately.

Grants are applied server-side — client code never touches admin credentials.


See Virtual Currencies for details on currency definitions, balance caps, and auto-recharge.

On this page