Billing
All three endpoints below authenticate with your sk- API key — the same key you use for /v1/messages and /v1/chat/completions. The two /v1/dashboard/billing/* endpoints mirror OpenAI's legacy dashboard shape so existing balance-checker scripts and proxy UIs work unmodified; /api/usage/token/ is a BUZZ-native endpoint that breaks the quota down into remaining / used / granted.
| Endpoint | Auth | Returns |
|---|---|---|
GET /v1/dashboard/billing/subscription | sk- key | Remaining balance (credit limit) |
GET /v1/dashboard/billing/usage | sk- key | Cumulative amount used |
GET /api/usage/token/ | sk- key | Quota breakdown (available / used / granted) |
sk- API key, not an account access token. These three endpoints are the ones you can poll with the key you already hold. The separate GET /api/user/self endpoint reports balance too, but it authenticates with an account access token (generated under console settings) plus a Buzz-User header — an sk- key will be rejected there with "invalid access token". To check balance with an sk- key, use the endpoints on this page.
/v1/dashboard/billing/* responses mirror OpenAI's legacy dashboard billing endpoints, so OpenAI-style balance checkers and reverse-proxy UIs work without modification. The numeric meaning follows the site's quota-display setting — see QuotaDisplayType.
Authentication
Both endpoints require a user API token (an sk--prefixed key created from the BUZZ console). They run through the relay token-auth chain, the same one used by /v1/messages and /v1/chat/completions.
| Header | Notes |
|---|---|
Authorization: Bearer sk-<TOKEN> | The sk- prefix is automatically stripped server-side. The first hyphen-separated segment is treated as the lookup key. |
No Buzz-User header required — the token already encodes the owner.
QuotaDisplayType: how numbers are calculated
BUZZ stores everything as raw integer "quota units" internally and converts to a human-friendly number only when serving these endpoints. The conversion depends on the site's QuotaDisplayType operation setting:
| QuotaDisplayType | Conversion | What the response number means |
|---|---|---|
| USD (default) | amount = quota / QuotaPerUnit | US dollars. |
| CNY | amount = quota / QuotaPerUnit * USDExchangeRate | Local currency, applied via the site's exchange rate. |
| Tokens | amount = quota | Raw quota units; treat the number as token-equivalents, not currency. |
This means soft_limit_usd in the subscription response and total_usage in the usage response are not always USD. The field name is preserved for OpenAI compatibility, but the actual unit follows the site's display-type setting. Treat the unit as opaque and align it with whatever currency your site shows in the dashboard UI.
GET /v1/dashboard/billing/subscription
Returns the token's (or, when token-level stats are disabled, the user's) remaining-plus-used quota, formatted as if it were a "credit limit". This is what most balance-checker tools poll.
Source of numbers
- If the site has token-level stats enabled:
quota = token.RemainQuota + token.UsedQuota,access_until = token.ExpiredTime. - Otherwise:
quota = user.Quota + user.UsedQuota,access_until = 0. - If the token is unlimited, the response value is overridden to
100000000. - If the token has no expiry,
access_untilis forced to0.
Example request
curl -s 'https://buzzai.cc/v1/dashboard/billing/subscription' \
-H "Authorization: Bearer sk-$BUZZ_TOKEN"import os, requests
resp = requests.get(
"https://buzzai.cc/v1/dashboard/billing/subscription",
headers={"Authorization": f"Bearer sk-{os.environ['BUZZ_TOKEN']}"},
timeout=10,
)
data = resp.json()
print(data["soft_limit_usd"], data["access_until"])const resp = await fetch(
"https://buzzai.cc/v1/dashboard/billing/subscription",
{ headers: { Authorization: `Bearer sk-${process.env.BUZZ_TOKEN}` } },
);
const data = await resp.json();
console.log(data.soft_limit_usd, data.access_until);Live response
{
"object": "billing_subscription",
"has_payment_method": true,
"soft_limit_usd": 1,
"hard_limit_usd": 1,
"system_hard_limit_usd": 1,
"access_until": 0
}
Verified live on 2026-06-09 with a regular limited-quota token (USD display). The three limit fields share a single value; access_until = 0 because the site does not run token-level stats, so token expiry is not surfaced here.
Response fields
| Field | Type | Description |
|---|---|---|
| object | string | Always "billing_subscription". |
| has_payment_method | boolean | Hard-coded true for OpenAI-shape compatibility. Do not infer payment status from this field. |
| soft_limit_usd | number | Remain + used quota, converted via QuotaDisplayType (see above). Despite the name, the unit is not always USD. |
| hard_limit_usd | number | Same value as soft_limit_usd. |
| system_hard_limit_usd | number | Same value as soft_limit_usd. |
| access_until | integer | Token expiry as a Unix epoch (seconds). 0 if the token has no expiry. |
GET /v1/dashboard/billing/usage
Returns lifetime consumed quota for the calling token (or user). OpenAI's original endpoint is per-period; this BUZZ implementation returns a single cumulative number and ignores any date-range query parameters.
Source of numbers
- If the site has token-level stats enabled:
quota = token.UsedQuota. - Otherwise:
quota = GetUserUsedQuota(userId). - The same QuotaDisplayType conversion is applied to produce
amount. - Final result is multiplied by 100:
total_usage = amount * 100. The codebase comment calls this "unit: 0.01 dollar" — i.e. cents when display is USD. With CNY display the field iscents-of-CNY * exchange rate; with Tokens display it istokens * 100.
Example request
curl -s 'https://buzzai.cc/v1/dashboard/billing/usage' \
-H "Authorization: Bearer sk-$BUZZ_TOKEN"import os, requests
resp = requests.get(
"https://buzzai.cc/v1/dashboard/billing/usage",
headers={"Authorization": f"Bearer sk-{os.environ['BUZZ_TOKEN']}"},
timeout=10,
)
total_cents = resp.json()["total_usage"]
print(f"used: {total_cents / 100:.2f}") # divide by 100 to recover the display unitconst resp = await fetch(
"https://buzzai.cc/v1/dashboard/billing/usage",
{ headers: { Authorization: `Bearer sk-${process.env.BUZZ_TOKEN}` } },
);
const { total_usage } = await resp.json();
console.log(`used: ${(total_usage / 100).toFixed(2)}`);Live response
{
"object": "list",
"total_usage": 13.6228
}
Verified live on 2026-06-09 (same token as above). The number is "display-unit × 100" — divide by 100 to get the value you see in the dashboard (here ≈ $0.136 used).
Response fields
| Field | Type | Description |
|---|---|---|
| object | string | Always "list" (kept for OpenAI-shape compatibility, even though no items array is returned). |
| total_usage | number | Cumulative consumption × 100. Divide by 100 to recover the display unit. |
GET /api/usage/token/
A BUZZ-native endpoint that returns the calling token's quota broken into its three parts — what was granted, what has been used, and what remains — without any currency conversion. The numbers are raw quota units (the same integers stored internally; divide by QuotaPerUnit, default 500000, to get USD). This is the most direct way to read a single key's remaining balance.
/api/usage/token/ with a trailing slash. Requesting /api/usage/token (no slash) returns a redirect.
Source of numbers
total_granted = token.RemainQuota + token.UsedQuotatotal_used = token.UsedQuotatotal_available = token.RemainQuotaexpires_at = token.ExpiredTime, forced to0when the token never expires.- For an unlimited token,
unlimited_quotaistrueand the three quota numbers are0(there is no finite allowance to report).
Example request
curl -s 'https://buzzai.cc/api/usage/token/' \
-H "Authorization: Bearer sk-$BUZZ_TOKEN"import os, requests
resp = requests.get(
"https://buzzai.cc/api/usage/token/",
headers={"Authorization": f"Bearer sk-{os.environ['BUZZ_TOKEN']}"},
timeout=10,
)
d = resp.json()["data"]
print(d["total_available"] / 500000, "USD remaining") # divide by QuotaPerUnitconst resp = await fetch(
"https://buzzai.cc/api/usage/token/",
{ headers: { Authorization: `Bearer sk-${process.env.BUZZ_TOKEN}` } },
);
const { data } = await resp.json();
console.log(data.total_available / 500000, "USD remaining");Live response
{
"code": true,
"message": "ok",
"data": {
"object": "token_usage",
"name": "claude",
"total_granted": 500000,
"total_used": 68114,
"total_available": 431886,
"unlimited_quota": false,
"model_limits_enabled": false,
"model_limits": {},
"expires_at": 1781502010
}
}
Verified live on 2026-06-09. total_granted = total_used + total_available (500000 = 68114 + 431886). Divide any of them by QuotaPerUnit (500000) to convert to USD — here ≈ $0.864 remaining of a $1.00 grant.
Response fields
| Field | Type | Description |
|---|---|---|
| code | boolean | true on success. Note this endpoint uses code/message/data, not the relay error envelope. |
| message | string | "ok" on success. |
| data.object | string | Always "token_usage". |
| data.name | string | The token's display name. |
| data.total_granted | integer | Remaining + used, in raw quota units. |
| data.total_used | integer | Consumed quota, in raw units. |
| data.total_available | integer | Remaining quota, in raw units. Can go negative if the key overshot. |
| data.unlimited_quota | boolean | true if the token has no quota cap; the three quota numbers are then 0. |
| data.model_limits_enabled | boolean | Whether per-model limits are enforced for this token. |
| data.model_limits | object | The per-model limit map (empty when not enabled). |
| data.expires_at | integer | Token expiry as a Unix epoch (seconds). 0 if the token never expires. |
Errors
| HTTP | error.type | Cause |
|---|---|---|
| 401 | buzz_error | Missing or invalid sk- token. |
| 429 | buzz_error | Global API rate limit hit. |
| 500 | upstream_error (subscription) / buzz_error (usage) | Failed to load token or user state. The two endpoints differ here: subscription tags the type as upstream_error, usage tags it as buzz_error. |
See also
GET /api/user/self— full profile (also includes the rawquotainteger), but authenticates with an account access token +Buzz-Userheader, not ansk-keyGET /api/token/— managesk-tokens- Authentication guide — access tokens vs.
sk-API keys