Мониторинг расходов
Программный учёт трат через GET /v1/usage — отслеживание расхода по ключу, бюджет-алёрты, отчёты.
Hubris отдаёт расход по API-ключу через GET /v1/usage — отдельные запросы и агрегированные суммы. Используется для автоматического мониторинга: алёрты по порогам, отчёты, экспорт в свою аналитику.
Endpoint-референс — на GET /v1/usage. Этот гид — про практические паттерны.
Базовый запрос
curl -s -H "Authorization: Bearer $HUBRIS_API_KEY" \
https://api.hubris.pw/v1/usageПо умолчанию — расход за последние 24 часа по тому ключу, которым сделан запрос. Ответ:
{
"object": "usage",
"period": { "from": "2026-05-21T00:00Z", "to": "2026-05-22T00:00Z" },
"scope": { "key_id": "...", "key_prefix": "sk-gw-758f...d4e3" },
"totals": {
"requests": 142,
"prompt_tokens": 18500,
"completion_tokens": 3200,
"total_tokens": 21700,
"cost_rub": 187.45,
"cost_kopecks": "18745"
},
"granularity": null,
"buckets": null
}Важно: виден расход только этого ключа, а не всего аккаунта. Это намеренно — скомпрометированный ключ не должен раскрывать общий бюджет.
Паттерн 1: ежедневный отчёт
Cron-задача, которая раз в день берёт суммарный расход за вчера и шлёт письмо/слак/телеграм:
import os
import requests
from datetime import datetime, timedelta, timezone
key = os.environ["HUBRIS_API_KEY"]
yesterday = datetime.now(timezone.utc) - timedelta(days=1)
day_start = yesterday.replace(hour=0, minute=0, second=0, microsecond=0)
day_end = day_start + timedelta(days=1)
resp = requests.get(
"https://api.hubris.pw/v1/usage",
params={"from": day_start.isoformat(), "to": day_end.isoformat()},
headers={"Authorization": f"Bearer {key}"},
).json()
totals = resp["totals"]
print(f"Вчера: {totals['requests']} запросов, {totals['cost_rub']} ₽")
# Отправить в Slack, если расход за день выше нормы:
if float(totals["cost_rub"]) > 500:
notify_slack(f"⚠️ Вчера ушло {totals['cost_rub']} ₽")Паттерн 2: бюджет-алёрт после каждого запроса
Если у вас агент, который может за сессию «уйти в космос» — проверяйте расход после каждого запроса и останавливайтесь при превышении лимита:
DAILY_BUDGET_RUB = 1000
def check_budget():
resp = requests.get(
"https://api.hubris.pw/v1/usage",
params={"period": "today"},
headers={"Authorization": f"Bearer {key}"},
).json()
return float(resp["totals"]["cost_rub"])
# В цикле агента
while task_not_done:
if check_budget() > DAILY_BUDGET_RUB:
raise BudgetExceeded(f"Превышен дневной лимит {DAILY_BUDGET_RUB} ₽")
response = run_step()
process(response)В большинстве сценариев лучше использовать встроенный дневной лимит ключа (см. /keys) — он гарантированно прерывает на стороне сервера и возвращает 429 daily_limit_exceeded. Бюджет в коде — мягкая защита поверх него, для случаев когда нужен ранний алёрт «потратили 80% бюджета — переключаемся на дешёвую модель».
Паттерн 3: график по дням
Для дашборда — берите данные с почасовой/посуточной разбивкой:
curl -s -H "Authorization: Bearer $HUBRIS_API_KEY" \
"https://api.hubris.pw/v1/usage?period=30d&granularity=day"В ответе появится массив buckets:
{
"totals": { "cost_rub": 5432.10, ... },
"granularity": "day",
"buckets": [
{ "bucket": "2026-04-22T00:00:00Z", "cost_rub": 180.30, "requests": 142 },
{ "bucket": "2026-04-23T00:00:00Z", "cost_rub": 213.45, "requests": 167 },
{ "bucket": "2026-04-24T00:00:00Z", "cost_rub": 0, "requests": 0 }
]
}Дни без запросов всё равно присутствуют (с cost_rub: 0) — удобно для линейного графика без пропусков.
Паттерн 4: разделение по проектам
Один аккаунт — несколько ключей под разные проекты. Дашборд /usage агрегирует общий расход; API даёт расход только запрашиваемого ключа.
Чтобы получить разбивку по проектам — храните ключи (или их key_id) на стороне ваших систем и запрашивайте /v1/usage каждым ключом отдельно:
PROJECT_KEYS = {
"production": os.environ["HUBRIS_KEY_PROD"],
"staging": os.environ["HUBRIS_KEY_STG"],
"research": os.environ["HUBRIS_KEY_RES"],
}
for project, key in PROJECT_KEYS.items():
resp = requests.get(
"https://api.hubris.pw/v1/usage",
params={"period": "7d"},
headers={"Authorization": f"Bearer {key}"},
).json()
print(f"{project}: {resp['totals']['cost_rub']} ₽ / {resp['totals']['requests']} req")TypeScript
type UsageResp = {
totals: {
requests: number;
prompt_tokens: number;
completion_tokens: number;
cost_rub: number;
cost_kopecks: string;
};
buckets: Array<{
bucket: string;
cost_rub: number;
cost_kopecks: string;
requests: number;
}> | null;
};
async function fetchUsage(period = '7d', granularity?: 'hour' | 'day') {
const url = new URL('https://api.hubris.pw/v1/usage');
url.searchParams.set('period', period);
if (granularity) url.searchParams.set('granularity', granularity);
const resp = await fetch(url, {
headers: { Authorization: `Bearer ${process.env.HUBRIS_API_KEY}` },
});
return (await resp.json()) as UsageResp;
}
const week = await fetchUsage('7d', 'day');
console.log(`За 7 дней: ${week.totals.cost_rub} ₽`);
for (const day of week.buckets ?? []) {
console.log(` ${day.bucket}: ${day.cost_rub} ₽`);
}Точность сумм при больших расходах
cost_kopecks приходит как строка — чтобы при сериализации в JavaScript не терялась точность на больших суммах. Если вам важна копейка-в-копейку точность (бухучёт, биллинг клиентов поверх Hubris) — парсите cost_kopecks через BigInt, не через Number:
const kopecks = BigInt(resp.totals.cost_kopecks);
const rubFormatted = (Number(kopecks) / 100).toFixed(2);Поле cost_rub — это уже cost_kopecks / 100, удобно для отображения, но не для арифметики.
Часовые пояса
Время в API — UTC. Если нужно «расход за сегодня по Москве» — конвертируйте границы суток у себя и передавайте явные from / to (ISO 8601 UTC):
from datetime import datetime, timezone, timedelta
MSK = timezone(timedelta(hours=3))
now_msk = datetime.now(MSK)
day_start_msk = now_msk.replace(hour=0, minute=0, second=0, microsecond=0)
day_end_msk = day_start_msk + timedelta(days=1)
resp = requests.get(
"https://api.hubris.pw/v1/usage",
params={
"from": day_start_msk.astimezone(timezone.utc).isoformat(),
"to": day_end_msk.astimezone(timezone.utc).isoformat(),
},
headers={"Authorization": f"Bearer {key}"},
).json()Дашбордная альтернатива
Если ручной мониторинг — overkill, на странице /usage дашборда есть готовые фильтры по модели, ключу и статусу, графики по дням и CSV-экспорт. Многие сценарии решаются прямо в UI без написания кода.
Что важно знать
- Кешируйте. Не дёргайте
/v1/usageчаще, чем раз в минуту — для большинства сценариев достаточно раз в 5–10 минут. Избыточные запросы влияют только на ваш rate-budget. - Расход обновляется в течение нескольких секунд после успешного списания. Свежий запрос → пара секунд → его стоимость в
/v1/usage. - Запросы на free-модели добавляются к
requests, но не кcost_rub. Если у вас активны бесплатные модели, число запросов в дашборде будет выше, чем «сколько денег ушло». - Только успешные запросы входят в totals. Запросы с ошибками (4xx/5xx) не списываются и не попадают в счётчик расхода.
Что дальше
- GET /v1/usage — полная схема параметров и ответа.
- Управление ключами — настроить дневной лимит на уровне ключа.
- Биллинг — как формируется стоимость токенов.
- /usage — дашборд расходов с фильтрами и CSV-экспортом.
Обновлено: