Check your balance from code with GET /v1/credits

· Hyperouter · 3 min read

Requests are paid from a prepaid balance, and a request the balance cannot cover is refused with 402 insufficient_credits. If you would rather hear about a low balance before that, ask for it: GET /v1/credits answers with your balance, authenticated with the same API key as every other call.

The call

curl https://api.hyperouter.app/v1/credits \
  -H "Authorization: Bearer $HYPEROUTER_API_KEY"

The answer has three fields, all decimal USD strings:

FieldMeaning
balance_usdYour balance.
held_usdWhat open requests hold.
available_usdWhat is left to spend.

Hyperouter holds the most a request can cost before it runs, then charges what was used and releases the rest (Billing & limits). That is why held_usd exists: while requests are in flight, part of your balance is not free to spend. available_usd is the balance less the holds, and it is the number to watch.

It is the account's balance

The balance belongs to the account, not to the key, so every key of the account sees the same numbers. A key with its own credit limit can still be refused at that limit with 402 insufficient_credits, even when available_usd is large.

The fields are strings, not floats. Hyperouter counts money exactly, and a string keeps it exact until you decide how to parse it. In Python, decimal.Decimal reads it directly. In TypeScript, compare after Number(...) if a few digits of precision do not matter to you, which for an alert threshold they do not.

Caching

The response carries Cache-Control: private, no-store, so a proxy or a client that honours the header will not keep it. Read it fresh each time.

One check a minute is plenty for an alert. A balance moves when requests settle and when staff credit a top-up, and neither needs a tighter loop.

A low-balance alert

A small script, run from cron or any scheduler you already have:

import os
import sys
from decimal import Decimal

import requests

THRESHOLD = Decimal("5.00")  # USD; pick your own

res = requests.get(
    "https://api.hyperouter.app/v1/credits",
    headers={"Authorization": f"Bearer {os.environ['HYPEROUTER_API_KEY']}"},
    timeout=10,
)
res.raise_for_status()
credits = res.json()

available = Decimal(credits["available_usd"])
if available < THRESHOLD:
    print(f"Hyperouter balance low: {available} USD available", file=sys.stderr)
    sys.exit(1)

A non-zero exit is something most schedulers can already turn into a message. The same check in TypeScript:

const res = await fetch("https://api.hyperouter.app/v1/credits", {
  headers: { Authorization: `Bearer ${process.env.HYPEROUTER_API_KEY}` },
});
if (!res.ok) throw new Error(`credits: HTTP ${res.status}`);

const { available_usd } = await res.json();
if (Number(available_usd) < 5) {
  console.error(`Hyperouter balance low: ${available_usd} USD available`);
  process.exitCode = 1;
}

If the call itself fails with 401, the key is missing, malformed, unknown or disabled; the authentication errors list each case.

Topping up

Top-ups are manual for now. Open a top-up request in the dashboard with the amount, the payment reference and a screenshot of the payment. Staff check the payment and credit your balance. Each top-up carries a fee of 5.5% of the amount paid, with a minimum of $0.80, so set your threshold high enough to leave time for a person to credit it.

What next