Платежі

Invoices і Payments

Telegram Bot API позволяет принимать платежи через sendInvoice — бот отправляет инвойс, пользователь оплачивает в клиенте Telegram, а ваш сервер получает подтверждение через pre_checkout_query и successful_payment.

Отправка инвойса

Метод sendInvoice требует токена провайдера (provider_token), полученного в BotFather при настройке платежей (Stripe, YooKassa, и др.). Минимальный набор параметров:

  • chat_id — целевой чат
  • title — название товара (до 32 символов)
  • description — описание (до 255 символов)
  • payload — ваша внутренняя строка (до 128 байт), вернётся в вебхуках
  • provider_token — токен платёжного провайдера
  • currency — трёхбуквенный код ISO 4217 (RUB, USD, EUR)
  • prices — массив LabeledPrice (label, amount в минимальных единицах валюты)
$payload = json_encode([
    'chat_id' => $chatId,
    'title' => 'Подписка Pro',
    'description' => 'Доступ к закрытым материалам на 30 дней',
    'payload' => 'sub_pro_30_' . $userId,
    'provider_token' => '398062629:TEST:999999999_F91D8F69C042267464B7',
    'currency' => 'RUB',
    'prices' => [[
        'label' => 'Подписка 30 дней',
        'amount' => 29900 // 299.00 RUB в копейках
    ]],
    'start_parameter' => 'sub_pro_30', // для deep-linking
]);
$ch = curl_init('https://api.telegram.org/bot' . $botToken . '/sendInvoice');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => $payload,
    CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 10,
]);
$res = curl_exec($ch);
if ($res === false) {
    throw new RuntimeException('cURL error: ' . curl_error($ch));
}
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$data = json_decode($res, true);
if (!$data['ok']) {
    throw new RuntimeException('API error: ' . ($data['description'] ?? 'unknown'));
}
// $data['result'] — Message с invoice

Подтверждение предоплаты (pre_checkout_query)

Когда пользователь нажимает «Оплатить», Telegram отправляет ваш боту pre_checkout_query. У вас есть 10 секунд, чтобы ответить answerPreCheckoutQuery с ok: true (всё готово) или ok: false + error_message (товар закончился, цена изменилась). Без ответа платёж отменится.

// В обработчике обновлений
if (isset($update['pre_checkout_query'])) {
    $query = $update['pre_checkout_query'];
    $payload = json_decode($query['invoice_payload'], true);
    // Проверяем, что товар актуален
    $ok = verifyProductAvailable($payload);
    
    $answer = [
        'pre_checkout_query_id' => $query['id'],
        'ok' => $ok,
    ];
    if (!$ok) {
        $answer['error_message'] = 'Товар временно недоступен, попробуйте позже.';
    }
    
    $ch = curl_init('https://api.telegram.org/bot' . $botToken . '/answerPreCheckoutQuery');
    curl_setopt_array($ch, [
        CURLOPT_POST => true,
        CURLOPT_POSTFIELDS => json_encode($answer),
        CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
        CURLOPT_RETURNTRANSFER => true,
    ]);
    curl_exec($ch);
    curl_close($ch);
    exit; // Важно: не обрабатывать дальше
}

Обработка успешной оплаты

После оплаты приходит Update с полем successful_payment. В нём: total_amount, currency, invoice_payload, telegram_payment_charge_id, provider_payment_charge_id. Сохраняйте эти данные для отчётности и выдачи товара.

if (isset($update['message']['successful_payment'])) {
    $pay = $update['message']['successful_payment'];
    $payload = json_decode($pay['invoice_payload'], true);
    
    // Выдача доступа
    grantAccess($payload['user_id'] ?? $update['message']['from']['id'], $payload);
    
    // Логирование
    logPayment([
        'tg_charge_id' => $pay['telegram_payment_charge_id'],
        'provider_charge_id' => $pay['provider_payment_charge_id'],
        'amount' => $pay['total_amount'],
        'currency' => $pay['currency'],
        'payload' => $payload,
    ]);
    
    // Ответ пользователю
    sendMessage($chatId, 'Оплата прошла успешно! Доступ открыт.');
}

Важные нюансы

  • payload — единственное поле, которое вы полностью контролируйте. Кладьте туда JSON с user_id, item_id, подписью HMAC для защиты от подделки.
  • Тестовые платежи: используйте тестовый токен провайдера и карту 4242 4242 4242 4242 (Stripe) или аналоги для других ПС. В тестовом режиме деньги не списываются.
  • Возврат: метод refundStarPayment работает только для Telegram Stars. Для обычных платежей возврат инициируется в панели провайдера (Stripe Dashboard, YooKassa и т.д.).
  • Чеки: если нужен фискальный чек (54-ФЗ в РФ), настройте отправку чеков на стороне провайдера (YooKassa, CloudPayments поддерживают это из коробки).

Платежи в Bot API — это мост между Telegram-клиентом и вашим платёжным шлюзом. Бот не видит реквизитов карты, только подтверждение. Дальше: Telegram Stars — встроенная валюта для цифровых товаров без внешних провайдеров.