Wallet

Wallet

Four read-only endpoints, scoped to the key’s owner. A developer billing their own
customers needs the same figures the dashboard shows; reading them by hand does not scale
past a demo.

Every amount is reported twice, *_usd and *_micro_usd. Match on the micro integer when
reconciling.

Why negative is money out

Rows use one sign convention throughout, matching the wallet: a charge is negative, a grant
or top-up is positive. You never have to learn a per-type rule, and a sum across rows is
meaningful without filtering first.

Balance

GET /api/v1/balance
curl https://hisoka.ai/api/v1/balance -H "Authorization: Bearer $HISOKA_API_KEY"
{
  "object": "balance",
  "currency": "USD",
  "balance_usd": 4.819965,
  "balance_micro_usd": 4819965,
  "credits": "4819",
  "credit_value_usd": 0.001
}

credits and credit_value_usd are returned together so the two can be reconciled rather
than guessed at. New integrations should read balance_micro_usd.

Transactions

GET /api/v1/transactions
Query Notes
limit 1-100, default 25. Capped, not refused.
page default 1
type usage, grant, topup, adjustment, purchase. An unknown value is ignored rather than refused, so a stale client still gets data.
model exact model id
since / until ISO timestamps
curl "https://hisoka.ai/api/v1/transactions?limit=2&type=usage" \
  -H "Authorization: Bearer $HISOKA_API_KEY"
{
  "object": "list",
  "currency": "USD",
  "data": [
    {
      "id": "01M73N2HP4HDDZH803J1C120HT",
      "type": "usage",
      "product": "api",
      "amount_usd": -0.002759,
      "amount_micro_usd": -2759,
      "balance_after_usd": 4.819965,
      "balance_after_micro_usd": 4819965,
      "created_at": "2026-11-09T23:47:13+00:00",
      "model": "glm-5.3-flash",
      "provider": "Hisoka",
      "input_tokens": 55097,
      "output_tokens": 24,
      "cached_tokens": 0
    }
  ],
  "total": 1284,
  "page": 1,
  "limit": 2,
  "has_more": true
}

total counts rows matching the filter, not rows on the page. A page of 2 with
total: 1284 is the response working correctly, not a truncation.

provider is always our own brand. The upstream pool is operator information and is
scrubbed here the same way it is scrubbed in error messages.

One transaction

GET /api/v1/transactions/{publicId}

Accepts the public id or the numeric id. Scoped to your ledger: another account’s id
answers 404 transaction_not_found rather than 403, so the endpoint cannot be used to
probe for ids.

Usage summary

GET /api/v1/usage/summary?period=30d
period Window
24h, 7d, 30d, 90d that window
anything else all time, reported as "period": "all"
{
  "object": "usage_summary",
  "currency": "USD",
  "period": "30d",
  "requests": 1284,
  "tokens_in": 48210093,
  "tokens_out": 912342,
  "tokens": 49122435,
  "usd": 2.418,
  "micro_usd": 2418000,
  "usd_per_1k_tokens": 0.0000492,
  "models": [
    {
      "model": "glm-5.3-flash",
      "requests": 1102,
      "tokens_in": 44210000,
      "tokens_out": 812000,
      "usd": 1.994,
      "micro_usd": 1994000
    }
  ]
}

usd_per_1k_tokens is null when nothing was billed, because a rate over zero tokens is a
division by zero dressed up as a price.

models is sorted by spend, highest first, so the report leads with what actually costs
you money.

Errors

Code HTTP Means
invalid_api_key 401 missing, revoked or expired key
transaction_not_found 404 that id is not in your ledger