VendoVendo Docs
GuidesRecipes

Poll Credit Balance

Read the tenant's prepaid credit balance, gate expensive operations, and handle OSS mode gracefully.

vendo.billing.balance() returns the tenant's current prepaid credit balance. Use it to gate expensive operations, render a balance display, or trigger a low-balance warning.

Vendo mode only. Raises VendoOnlyFeature in OSS mode — there is no billing backend when running outside Vendo.

Balances are reported in micros (1 USD = 1,000,000 micros). Divide by 1_000_000 to render dollars.


Read the balance

from vendo import Vendo
from vendo.errors import VendoOnlyFeature

client = Vendo()

def get_balance():
    try:
        balance = client.billing.balance()
        return {
            "credits_remaining_usd": balance.credits_remaining_micros / 1_000_000,
            "currency": balance.currency,
            "top_up_url": balance.top_up_url,
        }
    except VendoOnlyFeature:
        return {"credits_remaining_usd": None, "message": "billing not available in OSS mode"}

vendo.billing is also exposed as a lazy module-level singleton — vendo.billing.balance() works once VENDO_API_KEY is set — but the explicit Vendo() client makes the dependency obvious and is what every other recipe on this page uses.

import { Vendo, VendoOnlyFeature } from "@vendodev/sdk";

const vendo = new Vendo();

async function getBalance() {
  try {
    const balance = await vendo.billing.balance();
    return {
      creditsRemainingUsd: balance.creditsRemainingMicros / 1_000_000,
      currency: balance.currency,
      topUpUrl: balance.topUpUrl,
    };
  } catch (e) {
    if (e instanceof VendoOnlyFeature) {
      return { creditsRemainingUsd: null, message: "billing not available in OSS mode" };
    }
    throw e;
  }
}

Gate a feature on available balance

MIN_BALANCE_MICROS = 500_000  # $0.50

def run_expensive_action(client: Vendo):
    try:
        balance = client.billing.balance()
    except VendoOnlyFeature:
        balance = None

    if balance is not None and balance.credits_remaining_micros < MIN_BALANCE_MICROS:
        return {"error": "insufficient_balance", "credits_remaining_micros": balance.credits_remaining_micros}

    return client.data.execute("SOME_EXPENSIVE_ACTION", {})
const MIN_BALANCE_MICROS = 500_000; // $0.50

async function runExpensiveAction() {
  let balance: Awaited<ReturnType<typeof vendo.billing.balance>> | null = null;
  try {
    balance = await vendo.billing.balance();
  } catch (e) {
    if (!(e instanceof VendoOnlyFeature)) throw e;
  }

  if (balance !== null && balance.creditsRemainingMicros < MIN_BALANCE_MICROS) {
    return {
      error: "insufficient_balance",
      creditsRemainingMicros: balance.creditsRemainingMicros,
    };
  }

  return vendo.data.execute("SOME_EXPENSIVE_ACTION", {});
}

Notes

  • balance() is a live read — it reflects credits after pending charges are applied. Cache it for no longer than 30 seconds if you are polling it in a dashboard.
  • BalanceExhausted is raised automatically by the proxy when a metered operation would push the balance below zero. You do not need to check the balance before every data.execute call — the proxy enforces it.
  • SpendCaps can also block operations before the balance hits zero. Read spend caps with vendo.billing.spend_caps().
  • The billing period is calendar-month UTC. billing.usage(period="month") returns the breakdown for the current month.

On this page