TipBitapi

API для разработчиков

Принимайте оплату в крипте из любого своего проекта: сайта, магазина, Telegram-бота, бота для стримеров. Вы создаёте платёж одним запросом, отдаёте клиенту ссылку на готовую страницу оплаты, а TipBit сам следит за сетью, подтверждает транзакцию и присылает webhook. Деньги зачисляются на ваш баланс в кабинете — их можно вывести на карту или в крипте.

REST · JSON X-Api-Key webhook версия API — загрузка описания…

Аутентификация

Каждый запрос к API подписывается ключом в заголовке X-Api-Key. Ключ создаётся в кабинете, в разделе «Для разработчиков»: там же его можно отозвать.

  • Полный ключ показывается один раз — сразу после создания. В списке остаётся только префикс.
  • Держите ключ в переменных окружения проекта или в секретах хостинга. В браузере и в Git его быть не должно.
  • Один ключ — один проект: так проще отозвать доступ, если ключ утёк.
  • Отзыв действует сразу: запросы с отозванным ключом получают 401.
GET https://tipbit.click/api/v1/me
X-Api-Key: tb_live_xxxxxxxxxxxxxxxxxxxxxxxx
Accept: application/json
Запрос проверки ключа: возвращает ваш аккаунт и лимиты.

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

Платёж — это один POST. В ответ приходят ссылка на оплату, адрес, QR и срок действия.

curl -X POST https://tipbit.click/api/v1/payments \
  -H "X-Api-Key: $TIPBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 500,
    "currency": "RUB",
    "description": "Подписка на месяц",
    "externalId": "order-1042",
    "callbackUrl": "https://example.com/tipbit/webhook"
  }'
// Node.js 22+ — fetch встроен, зависимости не нужны
const API = 'https://tipbit.click/api/v1/payments';

export async function createPayment(order) {
  const res = await fetch(API, {
    method: 'POST',
    headers: {
      'X-Api-Key': process.env.TIPBIT_API_KEY,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      amount: order.amount,
      currency: order.currency || 'RUB',
      description: order.title,
      externalId: order.id,
      callbackUrl: 'https://example.com/tipbit/webhook',
    }),
  });
  if (!res.ok) throw new Error('TipBit: ' + res.status + ' ' + await res.text());
  return res.json(); // { id, status, payUrl, address, qrSvg, expiresAt, ... }
}

Как проходит платёж

  1. Создание. Вы вызываете POST /api/v1/payments и получаете payUrl — готовую страницу оплаты, где клиент выбирает сеть и видит QR.
  2. Оплата. Клиент платит по адресу из ответа. Для TON и других сетей с меткой memo платформа подставляет её сама — в QR и на странице оплаты.
  3. Подтверждение. Индексер видит транзакцию в сети, ждёт подтверждений и переводит платёж в paid.
  4. Webhook. На ваш callbackUrl приходит событие с итоговым статусом и подписью. Ответ 2xx считается доставкой; иначе платформа повторяет попытку.
  5. Зачисление. Сумма (за вычетом комиссии платформы) попадает на ваш баланс в кабинете.
СтатусЧто значитЧто делать
pendingПлатёж создан, оплаты ещё нетПоказать клиенту payUrl и QR
processingТранзакция в сети, ждём подтвержденийНичего, дождаться webhook
paidОплата подтверждена и зачисленаВыдать заказ, закрыть заявку
expiredСрок действия истёк, оплаты не былоСоздать новый платёж
cancelledПлатёж отменён вамиСоздать новый, если заказ ещё нужен
Статус можно перепроверить в любой момент: GET /api/v1/payments/<id>.

Справочник эндпоинтов

Базовый адрес: https://tipbit.click

Загрузка списка эндпоинтов…

Готовая страница оплаты

Не нужно рисовать QR и объяснять клиенту, куда переводить: в ответе на создание платежа есть payUrl — это страница TipBit с суммой, адресом, QR-кодом, таймером и выбором сети. Её содержимое отдаёт публичная ручка GET /api/public/pay/<id>: статус, сумма, актив, сеть, адрес, метка, QR (SVG), срок действия и имя получателя.

  • Ссылку можно открыть на телефоне, встроить в Telegram-бот или показать в приложении.
  • Страница сама обновляет статус: клиенту не нужно перезагружать её после оплаты.
  • Если платёж отменён или просрочен — на странице это видно, повторной оплаты по старому адресу не будет.

Webhook: событие об оплате

Укажите callbackUrl при создании платежа — платформа отправит POST с JSON, когда статус изменится. Отвечайте 2xx; иначе попытка повторится. Всегда перепроверяйте подпись: тело запроса можно подделать.

{
  "event": "payment.paid",
  "id": "pay_8f3a1c9e",
  "externalId": "order-1042",
  "status": "paid",
  "amount": 500,
  "currency": "RUB",
  "asset": "USDT-TRC20",
  "network": "tron",
  "amountFiat": 500,
  "txid": "0x…",
  "paidAt": 1731065400000
}

Проверка подписи — Node.js

import crypto from 'node:crypto';

// Секрет webhook — из кабинета (раздел «Для разработчиков»)
const SECRET = process.env.TIPBIT_WEBHOOK_SECRET;
const HEADER = 'x-tipbit-signature';

export function verifyTipBit(rawBody, headers) {
  const got = String(headers[HEADER] || '').trim();
  if (!got || !SECRET) return false;
  const expected = crypto.createHmac('sha256', SECRET).update(rawBody).digest('hex');
  // Сравнение постоянного времени: обычное === утекает по таймингу
  const a = Buffer.from(got);
  const b = Buffer.from(expected);
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}

Проверка подписи — Python

import hmac, hashlib, os

SECRET = os.environ["TIPBIT_WEBHOOK_SECRET"].encode()
HEADER = "x-tipbit-signature"

def verify_tipbit(raw_body: bytes, headers: dict) -> bool:
    got = (headers.get(HEADER) or "").strip()
    if not got:
        return False
    expected = hmac.new(SECRET, raw_body, hashlib.sha256).hexdigest()
    # compare_digest — сравнение постоянного времени
    return hmac.compare_digest(got, expected)
Точное имя заголовка и алгоритм подписи сервер отдаёт в ответе /api/public/api-docs (поле webhook) — если оно отличается от примера, доверяйте ответу сервера: пример выше показывает схему проверки, а не заменяет контракт.

Пример: Telegram-бот принимает оплату

Бот на Node.js без зависимостей: команда /buy создаёт платёж и присылает клиенту ссылку на оплату. Оплата засчитывается по webhook — бот не должен доверять сообщениям пользователя о том, что он «уже заплатил».

// Node.js 22+, без npm-зависимостей
const TG = 'https://api.telegram.org/bot' + process.env.TG_TOKEN;
const API = 'https://tipbit.click/api/v1/payments';

async function onMessage(msg) {
  if (msg.text !== '/buy') return;
  const res = await fetch(API, {
    method: 'POST',
    headers: { 'X-Api-Key': process.env.TIPBIT_API_KEY, 'Content-Type': 'application/json' },
    body: JSON.stringify({
      amount: 500,
      currency: 'RUB',
      description: 'Подписка на месяц',
      externalId: 'tg-' + msg.from.id + '-' + Date.now(),
      callbackUrl: 'https://example.com/tipbit/webhook',
    }),
  });
  const pay = await res.json();
  await fetch(TG + '/sendMessage', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      chat_id: msg.chat.id,
      text: 'Оплата 500 ₽: ' + pay.payUrl,
      disable_web_page_preview: false,
    }),
  });
}

// long polling: getUpdates → onMessage (полный цикл — 10 строк)
let offset = 0;
for (;;) {
  const r = await fetch(TG + '/getUpdates?timeout=30&offset=' + offset).then((x) => x.json());
  for (const u of r.result || []) {
    offset = u.update_id + 1;
    if (u.message) await onMessage(u.message);
  }
}

Ошибки

Ошибка всегда приходит JSON-ом: { "error": "текст", "code": "машинный_код" }. Ориентируйтесь на HTTP-статус и поле code, а не на текст.

HTTPcodeЧто значитЧто делать
400invalid_requestНет поля, неверная сумма или валютаПроверить тело запроса по справочнику
401unauthorizedКлюч не передан, отозван или неверныйПроверить X-Api-Key и не отозван ли ключ
403forbiddenКлюч без нужных прав или аккаунт заблокированСоздать ключ заново / связаться с поддержкой
404not_foundПлатёж с таким id не найденПроверить id из ответа на создание
409conflictПлатёж уже оплачен или отменёнНе менять финальный статус, создать новый
429rate_limitedСлишком много запросовПодождать и повторить с задержкой
500server_errorВнутренняя ошибка (в ответе есть ref)Повторить позже; ref подскажет поддержке, где искать

Комиссии и лимиты

  • Комиссия платформы удерживается при зачислении платежа. Ставка задаётся администратором по каждому активу, поэтому точное значение — в кабинете и в ответах API, а не в этой странице.
  • Минимальная сумма зависит от сети: у разных активов она разная (нужна, чтобы комиссия сети не съела платёж). Запрос с суммой ниже минимума вернёт 400.
  • Срок действия платежа задаётся параметром expiresInMin при создании; после истечения платёж переходит в expired.
  • Лимит запросов считается по ключу: при превышении вернётся 429.
  • Вывод средств — отдельный сценарий кабинета (карта, PayPal/Wise или крипта) с 2FA и подтверждением администратора. API создаёт платежи на приём, а не выводит деньги.
🔑 Готовы попробовать?

Создайте ключ в кабинете — он показывается один раз, поэтому держите его под рукой.