Shiba Bank API v1.0

Начисляйте звёзды со своего кошелька в @barboskich_stars_bot на кошельки людей прямо из своего сервиса: награды за действия, призы, выплаты модераторам. Звёзды не покидают бот — они переходят из кошелька в кошелёк, как по команде +send.

Базовый адрес: https://shiba-bank.com/api/v1

Быстрый старт

  1. Откройте @barboskich_stars_bot, отправьте /api и нажмите «🔑 Создать ключ». Ключ покажется один раз — сохраните его в переменную окружения SHIBA_API_KEY на своём сервере.
  2. Пополните кошелёк бота: переводы идут только из вашего баланса.
  3. Проверьте ключ и баланс:
    curl https://shiba-bank.com/api/v1/balance -H "Authorization: Bearer $SHIBA_API_KEY"
  4. Переведите звёзды:
    curl -X POST https://shiba-bank.com/api/v1/transfers \
      -H "Authorization: Bearer $SHIBA_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{"telegram_id": 123456789, "amount": 5, "comment": "за модерацию никнейма", "notify": true, "idempotency_key": "moderation-8841"}'
    Ответ:
    {
      "success": true,
      "end_balance": 307,
      "replayed": false,
      "transfer": {
        "id": "tr_5f0c2a9e41b7d3c8a6e1f024",
        "status": "completed",
        "telegram_id": 123456789,
        "amount": 5,
        "comment": "за модерацию никнейма",
        "notify": true,
        "idempotency_key": "moderation-8841",
        "error": null,
        "end_balance": 307,
        "created_at": "2026-09-23T14:13:05.120931Z"
      }
    }

Получателю бот сам пришлёт сообщение с суммой, отправителем и вашим комментарием, если notify не false.

Основы

ЗаголовокКогдаЗначение
AuthorizationвсегдаBearer sbk_…
Content-TypePOSTapplication/json
Idempotency-KeyPOST /transfers, по желанию вместо полятот же, что idempotency_key

Ключ и авторизация

Каждый запрос, кроме /status, несёт ключ в заголовке:

Authorization: Bearer sbk_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Можно и X-Api-Key: sbk_…. Ключ в адресе (?key=) отвергается и считается раскрытым.

Безопасность

Что ключ может: читать ваш баланс, лимиты и свои переводы; проверять, может ли человек получить звёзды; переводить звёзды с вашего кошелька на кошельки людей в боте.

Чего ключ не может никогда: выводить звёзды из бота, продавать их, покупать, списывать с чужих кошельков, менять свои лимиты и адреса, видеть чужие данные. Настройки меняются только в самом боте.

Как защитить ключ

Что делает сервер

Лимиты

ЧтоСколькоГде меняется
Один переводпо умолчанию 500 ⭐ максимум 100 000 ⭐/api → 📏
Сутки (UTC)по умолчанию 2000 ⭐ максимум 1 000 000 ⭐/api → 📅
Запросы на ключ10 в секунду, всплеск до 30—
Переводы на ключ3 в секунду, всплеск до 10; одновременно — один—
Запросы с одного IP10 в секунду, всплеск до 40 (сверх — HTTP 429 от веб-сервера)—
Тело запроса4096 байт—
Разрешённые адресадо 10 IP или подсетей/api → 🌐

Суточный лимит считается по суткам UTC (обнуляется в 00:00 UTC = 03:00 МСК) и включает все переводы ключа, выполненные и начатые. Текущие цифры — в GET /me.

При 429 и 503 смотрите заголовок Retry-After — через столько секунд можно повторить.

Идемпотентность и повторы

Сеть рвётся. Если ответ на перевод не дошёл, вы не знаете, списались ли звёзды. Поэтому у каждого перевода есть ваш ключ идемпотентности — постоянное имя операции: moderation-8841, order-1234-reward, daily-2026-09-23-user-42. Повторяйте запрос с тем же ключом сколько угодно — звёзды спишутся один раз.

СитуацияЧто ответит API
Новый ключВыполнит перевод.
Тот же ключ и те же поля, перевод выполненТот же ответ, replayed: true, ничего не списано повторно.
Тот же ключ и те же поля, перевод «pending»Доведёт тот же перевод до конца.
Тот же ключ, другие поля409 idempotency_conflict.
Тот же ключ после отказа (не хватило звёзд, лимит, заморозка)Пробует заново: отказ ничего не списал и ключ не занял.

Правило простое: ключ — из ваших данных, а не случайный на каждую попытку. Случайный ключ на каждую попытку отключает защиту от двойных выплат.

Повторять безопасно: сетевую ошибку, таймаут, HTTP 429, 500, 503. Не повторять без изменений: остальные 4xx — они не изменятся от повторения.

СтатусЧто значит
completedЗвёзды у получателя. Окончательно.
pendingПеревод начат, итог ещё не записан (обрыв связи или перезапуск). Повторите тот же запрос с тем же ключом — он доведёт перевод.
refusedОтказ, ничего не списано. Код — в error.

POST /transfers — перевод звёзд

Списывает звёзды с вашего кошелька и зачисляет на кошелёк получателя в боте.

ПолеТипОбязательноОписание
telegram_idintegerдаTelegram id получателя. Он должен хотя бы раз запустить @barboskich_stars_bot.
amountintegerдаСколько звёзд перевести: целое от 1 до 100 000 и не выше лимита ключа.
commentstringнетНазначение платежа, до 255 символов. Одна строка: переносы и повторные пробелы склеиваются. Без ссылок, доменов, @упоминаний и хештегов.
notifybooleanнет, trueПрислать ли получателю сообщение от бота о зачислении.
idempotency_keystringда*Ваш уникальный ключ операции, 1–64 символа A–Z a–z 0–9 _ - . :. Можно передать заголовком Idempotency-Key. *Не нужен при dry_run.
dry_runbooleanнет, falseПроверить всё (ключ, получателя, лимиты, баланс) и ничего не переводить.

Запрос

curl -X POST https://shiba-bank.com/api/v1/transfers \
  -H "Authorization: Bearer $SHIBA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"telegram_id": 123456789, "amount": 5, "comment": "за модерацию никнейма", "notify": true, "idempotency_key": "moderation-8841"}'

Успешный ответ — 200

{
  "success": true,
  "end_balance": 307,
  "replayed": false,
  "transfer": {
    "id": "tr_5f0c2a9e41b7d3c8a6e1f024",
    "status": "completed",
    "telegram_id": 123456789,
    "amount": 5,
    "comment": "за модерацию никнейма",
    "notify": true,
    "idempotency_key": "moderation-8841",
    "error": null,
    "end_balance": 307,
    "created_at": "2026-09-23T14:13:05.120931Z"
  }
}
ПолеОписание
successtrue — звёзды зачислены.
end_balanceОстаток на вашем кошельке сразу после этого перевода.
replayedtrue, если это повтор уже выполненного перевода: новых списаний не было.
transfer.idНаш номер перевода, tr_….
transfer.statuscompleted, pending или refused.
transfer.errorКод отказа у refused, иначе null.

Проверка без перевода — dry_run

{
  "telegram_id": 123456789,
  "amount": 5,
  "dry_run": true
}
{
  "success": true,
  "dry_run": true,
  "end_balance": 307,
  "balance": 312
}

Ошибка — 422

{
  "success": false,
  "error": {
    "code": "insufficient_balance",
    "message": "Not enough Stars in the wallet.",
    "balance": 3,
    "required": 5
  },
  "request_id": "req_9b1e04c27d5a6f33"
}

GET /transfers/{id} — один перевод

Состояние перевода по нашему id (tr_…). Видны только переводы вашего аккаунта.

curl https://shiba-bank.com/api/v1/transfers/tr_5f0c2a9e41b7d3c8a6e1f024 -H "Authorization: Bearer $SHIBA_API_KEY"
{
  "success": true,
  "transfer": {
    "id": "tr_5f0c2a9e41b7d3c8a6e1f024",
    "status": "completed",
    "telegram_id": 123456789,
    "amount": 5,
    "comment": "за модерацию никнейма",
    "notify": true,
    "idempotency_key": "moderation-8841",
    "error": null,
    "end_balance": 307,
    "created_at": "2026-09-23T14:13:05.120931Z"
  }
}

GET /transfers — история переводов

Переводы через API вашего аккаунта, новые первыми.

ПараметрОписание
limit1–100, по умолчанию 20.
cursornext_cursor из прошлого ответа — следующая страница.
statuspending | completed | refused
idempotency_keyНайти перевод по своему ключу — удобно, если ответ потерялся.
telegram_idТолько переводы этому получателю.
curl "https://shiba-bank.com/api/v1/transfers?limit=50&status=completed" -H "Authorization: Bearer $SHIBA_API_KEY"
{
  "success": true,
  "transfers": [
    {
      "id": "tr_5f0c2a9e41b7d3c8a6e1f024",
      "status": "completed",
      "telegram_id": 123456789,
      "amount": 5,
      "comment": "за модерацию никнейма",
      "notify": true,
      "idempotency_key": "moderation-8841",
      "error": null,
      "end_balance": 307,
      "created_at": "2026-09-23T14:13:05.120931Z"
    }
  ],
  "next_cursor": "tr_5f0c2a9e41b7d3c8a6e1f024"
}

next_cursor равен null на последней странице.

GET /balance — баланс

Сколько звёзд на вашем кошельке доступно прямо сейчас.

curl https://shiba-bank.com/api/v1/balance -H "Authorization: Bearer $SHIBA_API_KEY"
{
  "success": true,
  "telegram_id": 555000111,
  "balance": 312
}

GET /me — ключ, лимиты, баланс

Всё о ключе одним запросом: чей он, лимиты, сколько потрачено сегодня, разрешённые адреса.

{
  "success": true,
  "telegram_id": 555000111,
  "username": "my_service_owner",
  "balance": 312,
  "key": {
    "prefix": "sbk_Q2x9aZ1p…",
    "created_at": "2026-09-23T10:00:00Z",
    "last_used_at": "2026-09-23T14:12:44Z"
  },
  "limits": {
    "per_transfer": 500,
    "daily": 2000,
    "used_today": 120,
    "remaining_today": 1880,
    "resets_at": "2026-09-24T00:00:00Z",
    "allowed_ips": [
      "203.0.113.7"
    ]
  },
  "api_version": "1.0"
}

GET /recipients/{telegram_id} — можно ли перевести

Проверка до обещания награды: can_receive — true, если человек запускал @barboskich_stars_bot и его кошелёк доступен. Имени и других данных API не раскрывает.

{
  "success": true,
  "telegram_id": 123456789,
  "can_receive": true
}

Если false — попросите человека открыть @barboskich_stars_bot и нажать «Старт»: звёзды на аккаунт, который бот не знает, не переводятся, иначе они бы потерялись.

GET /status — жив ли API

Без ключа. Для мониторинга.

{
  "success": true,
  "api_version": "1.0",
  "time": "2026-09-23T14:13:05Z",
  "docs": "/api/docs"
}

Описание OpenAPI 3.1 для Postman, Swagger и генераторов кода: /api/v1/openapi.json

Уведомление и комментарий

При notify: true получатель получает от бота сообщение на своём языке:

⭐ Вам зачислено 5 ⭐
От: @my_service_owner

💬 «за модерацию никнейма»
👛 Кошелёк · 312 Stars

Правила комментария

Ошибки

{
  "success": false,
  "error": {
    "code": "insufficient_balance",
    "message": "Not enough Stars in the wallet.",
    "balance": 3,
    "required": 5
  },
  "request_id": "req_9b1e04c27d5a6f33"
}
КодHTTPЧто значит и что делать
invalid_json400Тело не JSON-объект в UTF-8 или поле повторено дважды.
invalid_request400Поле отсутствует, не того типа или вне диапазона — какое, скажет field.
unknown_field400Поле, которого API не знает (часто опечатка: ammount).
invalid_comment400comment не строка.
comment_too_long400Комментарий длиннее 255 символов.
comment_not_allowed400В комментарии ссылка, домен, @упоминание или хештег.
idempotency_key_required400Перевод без ключа идемпотентности.
invalid_idempotency_key400Ключ не по формату или в заголовке и в теле разные ключи.
key_in_url400Ключ API передан в адресе. Считайте его раскрытым и выпустите новый.
unauthorized401Ключа нет, он неверный или отозван.
key_blocked403Доступ к API у аккаунта заблокирован администрацией.
account_restricted403Аккаунт владельца ключа ограничен в боте.
ip_not_allowed403Адрес запроса не в списке разрешённых. Поле ip — какой адрес видит сервер.
not_found404Нет такого перевода (или он чужой).
recipient_not_found404Получатель ни разу не запускал бота или его кошелёк недоступен.
idempotency_conflict409Ключ уже занят другим переводом (другие получатель, сумма, комментарий или notify).
payload_too_large413Тело больше 4096 байт.
unsupported_media_type415Нет заголовка Content-Type: application/json.
recipient_is_self422Перевод самому себе.
per_transfer_limit_exceeded422Сумма выше лимита на один перевод (limit).
daily_limit_exceeded422Перевод превысит суточный лимит: limit, used_today, remaining.
insufficient_balance422Не хватает звёзд: balance и required. Ничего не списано, тот же ключ можно повторить после пополнения.
wallet_frozen422Кошелёк отправителя или получателя заморожен или на проверке. Ничего не списано.
transfer_refused422Кошелёк отказал в переводе. Ничего не списано.
account_too_new422Аккаунт пока не может передавать звёзды (hours_left).
rate_limited429Слишком часто. Подождите Retry-After секунд.
too_many_failed_attempts429С вашего адреса много запросов с неверным ключом. Проверьте ключ и подождите.
internal_error500Ошибка у нас. Напишите в поддержку с request_id.
api_disabled503API временно выключен.
busy503Очередь переводов занята. Повторите тот же запрос через Retry-After.
outcome_unknown503Итог пока неизвестен. Повторите тот же запрос с тем же ключом — двойного списания не будет.

Любой ответ 4xx означает: этим запросом ничего не списано. При 5xx итог может быть неизвестен — повторите тот же запрос с тем же ключом.

Примеры кода

Python (requests)

import os
import time

import requests

API = "https://shiba-bank.com/api/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['SHIBA_API_KEY']}"}


class ShibaApiError(Exception):
    def __init__(self, code: str, message: str, details: dict):
        super().__init__(f"{code}: {message}")
        self.code, self.details = code, details


def give_stars(telegram_id: int, amount: int, comment: str, key: str, notify: bool = True) -> int:
    """Credit Stars and return the balance left. Safe to call again with the same key."""
    payload = {
        "telegram_id": telegram_id,
        "amount": amount,
        "comment": comment,
        "notify": notify,
        "idempotency_key": key,
    }
    for attempt in range(6):
        try:
            response = requests.post(f"{API}/transfers", headers=HEADERS, json=payload, timeout=40)
        except requests.RequestException:
            time.sleep(2 ** attempt)  # the network failed: the same key is safe to repeat
            continue
        if response.status_code in (429, 503) or response.status_code >= 500:
            time.sleep(int(response.headers.get("Retry-After", 2 ** attempt)))
            continue
        data = response.json()
        if data["success"]:
            return data["end_balance"]
        error = data["error"]
        raise ShibaApiError(error["code"], error["message"], error)
    raise RuntimeError("the API did not answer; repeat later with the same key")


balance = give_stars(123456789, 5, "за модерацию никнейма", key="moderation-8841")
print("left:", balance)

Node.js

// Node.js 18+ (global fetch)
const API = "https://shiba-bank.com/api/v1";

async function giveStars(telegramId, amount, comment, key, notify = true) {
  const body = JSON.stringify({
    telegram_id: telegramId, amount, comment, notify, idempotency_key: key,
  });
  for (let attempt = 0; attempt < 6; attempt++) {
    let res;
    try {
      res = await fetch(`${API}/transfers`, {
        method: "POST",
        headers: {
          "Authorization": `Bearer ${process.env.SHIBA_API_KEY}`,
          "Content-Type": "application/json",
        },
        body,
      });
    } catch (e) {
      await new Promise(r => setTimeout(r, 1000 * 2 ** attempt));
      continue;
    }
    if (res.status === 429 || res.status >= 500) {
      const wait = Number(res.headers.get("Retry-After") || 2 ** attempt);
      await new Promise(r => setTimeout(r, 1000 * wait));
      continue;
    }
    const data = await res.json();
    if (data.success) return data.end_balance;
    const err = new Error(`${data.error.code}: ${data.error.message}`);
    err.details = data.error;
    throw err;
  }
  throw new Error("the API did not answer; repeat later with the same key");
}

giveStars(123456789, 5, "за модерацию никнейма", "moderation-8841").then(console.log);

PHP

<?php
function give_stars(int $telegramId, int $amount, string $comment, string $key, bool $notify = true): int {
    $ch = curl_init("https://shiba-bank.com/api/v1/transfers");
    curl_setopt_array($ch, [
        CURLOPT_POST => true,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT => 40,
        CURLOPT_HTTPHEADER => [
            "Authorization: Bearer " . getenv("SHIBA_API_KEY"),
            "Content-Type: application/json",
        ],
        CURLOPT_POSTFIELDS => json_encode([
            "telegram_id" => $telegramId,
            "amount" => $amount,
            "comment" => $comment,
            "notify" => $notify,
            "idempotency_key" => $key,
        ], JSON_UNESCAPED_UNICODE),
    ]);
    $raw = curl_exec($ch);
    curl_close($ch);
    if ($raw === false) {
        throw new RuntimeException("network error: repeat with the same key");
    }
    $data = json_decode($raw, true);
    if (!$data["success"]) {
        throw new RuntimeException($data["error"]["code"] . ": " . $data["error"]["message"]);
    }
    return $data["end_balance"];
}

Массовая выплата

Отдельного пакетного метода нет: отправляйте переводы по одному, каждый со своим ключом (например, payout-2026-09-23-<telegram_id>). Если скрипт упал на середине — запустите его заново целиком: уже выполненные переводы вернутся с replayed: true и не спишутся второй раз.

for user_id, stars in winners:
    give_stars(user_id, stars, "приз недели", key=f"weekly-2026-39-{user_id}")

FAQ

Откуда берутся звёзды для переводов?
Только с вашего кошелька в @barboskich_stars_bot. Пополнить — в боте: «👛 Кошелёк» → «Пополнить».
Что может получатель со звёздами?
Всё, что с любыми звёздами кошелька: вывести на аккаунт Telegram, продать, раздать в чате, отправить чеком.
Можно ли отменить перевод?
Нет. Выполненный перевод окончателен, как +send. Для проверки используйте dry_run.
Как узнать Telegram id человека?
Его присылает Telegram в каждом апдейте вашего бота: message.from.id. По @username API не переводит — username меняется, id нет.
Сколько стоит API?
Бесплатно. Переводы между кошельками без комиссии.
Мне пришёл 503 outcome_unknown — звёзды ушли?
Повторите тот же запрос с тем же ключом: придёт окончательный ответ, двойного списания не будет. Или посмотрите GET /transfers?idempotency_key=….
Нужен вебхук о входящих переводах или приём оплаты звёздами?
Напишите в поддержку бота, что именно нужно: так мы решим, что добавить в следующих версиях.

История версий

1.0 — 23.09.2026. Переводы, баланс, лимиты, история, проверка получателя, OpenAPI.