Управление API-ключами
Создавать, ограничивать, ставить на паузу и удалять API-ключи аккаунта через API — всё, что делает страница ключей в кабинете.
Методы
| Метод | Право | Что делает |
|---|---|---|
GET /keys | keys:read | Действующие ключи аккаунта |
POST /keys | keys:write | Создать ключ. Секрет — в ответе, один раз |
GET /keys/{id} | keys:read | Один ключ |
PATCH /keys/{id} | keys:write | Изменить переданные поля |
DELETE /keys/{id} | keys:write | Удалить ключ |
POST /keys/{id}/rotate | keys:write | Сбросить секрет. Новый — в ответе, один раз |
POST /keys/{id}/pause | keys:write | Поставить на паузу |
POST /keys/{id}/resume | keys:write | Возобновить |
POST /keys/{id}/duplicate | keys:write | Новый ключ с теми же настройками и своим секретом |
POST /keys/{id}/copy-settings | keys:write | Скопировать группы настроек на другие ключи |
GET /keys/my-ip | keys:read | Ваш IP, каким его видит список разрешённых адресов |
API-ключ эти методы не вызывает, даже для самого себя: свои настройки он читает через GET /aitunnel/key. Что значат бюджет, срок и списки, с примерами из кабинета, — в статье API-ключи.
Список ключей
curl https://api.aitunnel.ru/v1/aitunnel/keys \
-H "Authorization: Bearer sk-aitunnel-mgmt-xxx"{
"data": [
{
"id": 4217,
"name": "Прод-бот",
"hint": "sk-aitunnel-…x7Qp",
"paused_at": null,
"pause_reason": null,
"expires_at": "2027-01-01T00:00:00.000Z",
"budget": {
"limit": 500,
"spent": 120.4,
"remaining": 379.6,
"period": "monthly",
"resets_at": "2026-11-30T21:00:00.000Z",
"alert": true,
"alert_email": "ops@example.com"
},
"allowed_models": ["gpt-5.4-mini", "support-bot"],
"allowed_ips": ["203.0.113.10", "2001:db8::/32"],
"redaction": {
"mode": "mask",
"types": ["email", "phone"],
"dictionary": [
{ "word": "Проект Икс", "replacement": "проект" }
]
},
"log_days": 7,
"spent_total": 1840.25,
"last_used_at": "2026-11-14T08:12:44.000Z",
"secret_rotated_at": null,
"created_at": "2026-10-01T10:00:00.000Z",
"updated_at": "2026-11-02T15:20:11.000Z"
}
]
}Ключи идут от старых к новым. Удалённых в списке нет. GET /keys/{id} возвращает один такой объект.
| Поле | Смысл |
|---|---|
id | Номер ключа. Им ключ называется в путях и в параметре key_id расхода и запросов |
name | Имя ключа |
hint | Префикс и последние четыре символа секрета, чтобы различать ключи. Сам секрет не возвращается |
paused_at, pause_reason | Когда и почему ключ на паузе: owner — поставлен владельцем или через API, idle — 90 дней без запросов. null — ключ работает |
expires_at | Когда ключ перестанет работать. null — без срока |
budget | Бюджет ключа. null — бюджета нет |
allowed_models | Белый список моделей и пресетов. null — все |
allowed_ips | Разрешённые адреса и подсети. null — любые |
redaction | Защита данных: mode — mask, block или null (выключена); types — какие типы ловить, по умолчанию все; dictionary — свои замены, пары word и replacement |
log_days | Срок хранения запросов этого ключа, дней: 0, 1, 7, 30. null — как в аккаунте |
spent_total | Сколько ключ потратил за всё время, ₽ |
last_used_at | Последний запрос с ключом. null — запросов не было |
secret_rotated_at | Последний сброс секрета. null — не сбрасывался |
created_at, updated_at | Когда ключ создан и изменён |
Создать ключ
curl -X POST https://api.aitunnel.ru/v1/aitunnel/keys \
-H "Authorization: Bearer sk-aitunnel-mgmt-xxx" \
-H "Content-Type: application/json" \
-d '{
"name": "Прод-бот",
"budget": { "limit": 500, "period": "monthly", "alert": true },
"expires_at": "2027-01-01T00:00:00Z",
"allowed_models": ["gpt-5.4-mini", "support-bot"],
"allowed_ips": ["203.0.113.10"]
}'Ответ 201 — объект ключа и поле secret:
{
"id": 4217,
"name": "Прод-бот",
"hint": "sk-aitunnel-…x7Qp",
"paused_at": null,
"pause_reason": null,
"expires_at": "2027-01-01T00:00:00.000Z",
"budget": {
"limit": 500,
"spent": 0,
"remaining": 500,
"period": "monthly",
"resets_at": "2026-11-30T21:00:00.000Z",
"alert": true,
"alert_email": null
},
"allowed_models": ["gpt-5.4-mini", "support-bot"],
"allowed_ips": ["203.0.113.10"],
"redaction": {
"mode": null,
"types": ["email", "phone", "passport", "snils", "inn", "ogrn", "ogrnip", "credit_card", "jwt", "secret", "address", "person"],
"dictionary": []
},
"log_days": null,
"spent_total": 0,
"last_used_at": null,
"secret_rotated_at": null,
"created_at": "2026-11-14T13:16:00.000Z",
"updated_at": "2026-11-14T13:16:00.000Z",
"secret": "sk-aitunnel-EXAMPLEexampleEXAMPLEexamplex7Qp"
}| Поле запроса | Смысл |
|---|---|
name | Имя, до 64 символов, без < и >. При создании обязательно |
budget | Объект с limit (₽, обязателен для нового бюджета), period, alert, alert_email. null убирает бюджет |
expires_at | Время ISO 8601 с часовым поясом, от минуты до 5 лет вперёд. null — без срока |
allowed_models | До 500 имён моделей и пресетов, как в запросе. null или [] — все |
allowed_ips | До 500 адресов и подсетей CIDR. null или [] — любые |
redaction | Объект с mode, types, dictionary. types — из списка email, phone, passport, snils, inn, ogrn, ogrnip, credit_card, jwt, secret, address, person; null — все. dictionary — до 50 пар, слово от 3 символов |
log_days | 0, 1, 7, 30 или null |
- Обязательно только
name: получится ключ без бюджета, срока и ограничений. - Поле, которого метод не знает, — ошибка
400, а не пропуск: опечатка вbudgetне оставит ключ без бюджета. - Ключ можно создать при положительном балансе и подтверждённой почте.
- Число ключей ограничено: один ключ и ещё по одному за каждые полные 1 000 ₽ баланса. Сверх лимита —
409.
Изменить ключ
PATCH /keys/{id} принимает те же поля, что создание. Меняется только то, что передано; остальное остаётся. Ответ — объект ключа.
curl -X PATCH https://api.aitunnel.ru/v1/aitunnel/keys/4217 \
-H "Authorization: Bearer sk-aitunnel-mgmt-xxx" \
-H "Content-Type: application/json" \
-d '{
"budget": { "limit": 1000 },
"allowed_ips": null
}'nullили пустой список снимает ограничение:"allowed_ips": null— ключ работает с любого адреса.- Истёкший ключ продлевается новым
expires_at. Секрет и настройки прежние. - Новые правила действуют со следующего запроса с этим ключом.
Бюджет
Бюджет — сколько ключ может потратить за период. Исчерпан — запросы к моделям с этим ключом получают 402 с типом budget_exceeded.
| Поле | Смысл |
|---|---|
limit | Сколько ключ может потратить за период, ₽. Без периода — за всё время |
spent | Потрачено в текущем периоде, ₽. Может немного превысить лимит: последний запрос списывается целиком |
remaining | Остаток, ₽: limit − spent, не меньше 0 |
period | daily, weekly, monthly или null — бюджет не сбрасывается |
resets_at | Когда spent обнулится. null без периода |
alert | Слать письмо, когда от бюджета остаётся 20% и меньше |
alert_email | Куда слать. null — на адрес уведомлений аккаунта |
- Сброс привязан к календарю по московскому времени:
daily— в 00:00,weekly— в ночь на понедельник,monthly— в ночь на 1-е число. - Новый
limitсохраняет потраченное: подняли лимит с 500 до 1 000 ₽ при расходе 120 ₽ — осталось 880 ₽. - В
PATCHможно передатьbudget.remaining— сколько осталось в текущем периоде. Потраченное станетlimit − remaining. Остаток больше лимита —400. - Другой
periodпересчитываетresets_at; тот же период границу не сдвигает. "budget": nullубирает бюджет вместе с периодом и письмом.
Сбросить секрет
POST /keys/{id}/rotate выдаёт ключу новый секрет. Ответ — объект ключа и secret, как при создании. Старый секрет перестаёт работать сразу: запросы с ним получают 401. Имя, бюджет, расход, ограничения и пауза остаются.
curl -X POST https://api.aitunnel.ru/v1/aitunnel/keys/4217/rotate \
-H "Authorization: Bearer sk-aitunnel-mgmt-xxx"Пауза и возобновление
POST /keys/{id}/pause отключает ключ: запросы с ним получают 403 «Этот API-ключ приостановлен владельцем». Секрет, бюджет и настройки сохраняются. POST /keys/{id}/resume включает ключ обратно, в том числе поставленный на паузу автоматически после 90 дней без запросов. Оба метода без тела, ответ — объект ключа.
Дублировать
POST /keys/{id}/duplicate с телом { "name": "…" } создаёт новый ключ с настройками исходного. Ответ 201 — объект нового ключа и его secret.
- Копируются бюджет, модели, IP, защита данных и срок хранения логов.
- Расход не переносится: бюджет нового ключа полный.
- Срок переносится как длительность: ключ, созданный на 30 дней, даёт копию на 30 дней от текущего момента.
- Копия занимает место в лимите ключей, как обычный новый ключ.
Скопировать настройки
POST /keys/{id}/copy-settings переносит группы настроек ключа {id} на другие ключи аккаунта.
curl -X POST https://api.aitunnel.ru/v1/aitunnel/keys/4217/copy-settings \
-H "Authorization: Bearer sk-aitunnel-mgmt-xxx" \
-H "Content-Type: application/json" \
-d '{
"key_ids": [4218, 4219],
"groups": ["budget", "models"]
}'key_ids — до 500 номеров ключей, groups — какие группы копировать:
| Группа | Смысл |
|---|---|
budget | Лимит, период, письмо и его адрес |
models | Белый список моделей и пресетов |
ips | Разрешённые адреса |
redact | Защита данных: режим, типы, словарь |
- Ответ —
{ "data": [...] }с изменёнными ключами. - Всё или ничего: если хотя бы один номер не действующий ключ аккаунта, ответ
404и ни один ключ не меняется. - Имя, секрет, срок и пауза не копируются.
- Потраченное у каждого ключа своё: получив бюджет, ключ сохраняет свой расход за период, а если бюджета не было — начинает с нуля.
Удалить ключ
DELETE /keys/{id} отвечает 204 без тела. Ключ перестаёт работать со следующего запроса: 401 «Этот API-ключ удалён». Восстановить его нельзя; статистика и логи его запросов остаются.
Мой IP
GET /keys/my-ip отвечает { "ip": "203.0.113.10" } — адрес, с которого пришёл запрос, каким его сравнивает список allowed_ips. За зеркалом ru-api.aitunnel.ru это ваш адрес, а не адрес зеркала. null, если адрес определить не удалось.
Ошибки
| Статус | Смысл |
|---|---|
400 | invalid_request — неверное или неизвестное поле. В error.metadata.fields — каждое поле с объяснением |
401 | authentication_failed — ключа нет, он неверный, отозван или истёк |
402 | insufficient_balance — создать ключ можно только при положительном балансе. metadata.code — balance_required |
403 | permission_denied — у ключа нет нужного права, IP не в списке разрешённых или метод вызван API-ключом |
404 | not_found — «Ключ не найден»: такого номера нет, ключ удалён или принадлежит другому аккаунту |
409 | invalid_request — достигнут лимит ключей. metadata.code — keys_limit_reached, metadata.limit — сколько ключей можно держать |
503 | service_unavailable — перед изменением budget.limit, budget.remaining или копированием бюджета не удалось записать текущий расход. Ничего не изменено, повторите через Retry-After секунд |
{
"error": {
"code": 400,
"type": "invalid_request",
"message": "Поле «budget.remaining»: Остаток не может быть больше лимита",
"metadata": {
"fields": [
{
"field": "budget.remaining",
"message": "Остаток не может быть больше лимита"
}
]
},
"request_id": "req-0J9fQk2vXc8LrT1mNbZa4e"
}
}Каждое изменение, сделанное ключом управления, видно владельцу в журнале активности.