Інтеграція криптоплатіжного шлюзу (CoinGate/NOWPayments/BitPay) на сайт
Вступ
Інтегрували криптоплатіжний шлюз, але вебхуки не проходять, статуси зависають, а клієнти скаржаться на зниклі платежі? Типова причина — відсутність перевірки підпису сповіщень і неправильний маппінг статусів. Ми вирішуємо це за 1–3 дні: підключаємо CoinGate, NOWPayments або BitPay з повною обробкою вебхуків, часткових платежів і кастомними сторінками вибору монети. Використовуємо перевірені патерни: HMAC-верифікацію, черги для ретраїв, логування кожного IPN-запиту.
Які проблеми вирішуємо
- Верифікація вебхуків. Кожен провайдер використовує свій механізм підпису: HMAC-SHA512 (NOWPayments), токен (CoinGate), IPN-секрет (BitPay). Якщо пропустити перевірку — зловмисник може імітувати сповіщення та змінити статус замовлення. Ми завжди реалізуємо строгу перевірку підпису.
- Часткові платежі. NOWPayments вміє їх обробляти, але стандартних засобів доплати немає. Потрібно реалізувати логіку сповіщення та, за необхідності, повернення через API. На практиці 90% користувачів доплачують протягом години, якщо бачать зрозумілу інструкцію.
- Вибір монети. Покупець хоче платити своєю криптовалютою. Агрегатор пропонує сторінку вибору, але часто потрібна кастомна — вбудована в checkout сайту. Ми можемо створити таку сторінку з виведенням балансу та QR-коду.
Як ми це робимо
Використовуємо стек: PHP 8.3, Laravel 11, Guzzle. Клієнт для NOWPayments виглядає так:
use GuzzleHttp\Client; class NOWPaymentsClient { private Client $http; private string $apiKey; public function __construct(string $apiKey, bool $sandbox = false) { $this->apiKey = $apiKey; $baseUri = $sandbox ? 'https://api-sandbox.nowpayments.io/v1/' : 'https://api.nowpayments.io/v1/'; $this->http = new Client([ 'base_uri' => $baseUri, 'headers' => ['x-api-key' => $apiKey], ]); } public function createPayment(array $params): array { $response = $this->http->post('payment', ['json' => $params]); return json_decode($response->getBody()->getContents(), true); } public function getMinAmount(string $currency, string $fiatCurrency = 'usd'): float { $response = $this->http->get("min-amount?currency_from={$currency}¤cy_to={$fiatCurrency}"); return json_decode($response->getBody()->getContents(), true)['min_amount']; } } // Створення платежу $client = new NOWPaymentsClient(env('NOWPAYMENTS_API_KEY'), app()->isLocal()); $payment = $client->createPayment([ 'price_amount' => $order->total, 'price_currency' => 'usd', 'pay_currency' => 'btc', // або 'eth', 'usdttrc20', тощо. 'order_id' => (string) $order->id, 'order_description'=> 'Замовлення #' . $order->id, 'ipn_callback_url' => route('payments.nowpayments.webhook'), 'success_url' => route('orders.success', $order), 'cancel_url' => route('checkout'), ]); Редирект покупця на $payment['invoice_url']. NOWPayments показує сторінку вибору монети та QR-код з адресою для оплати.
CoinGate: API
$payment = $coingate->order->create([ 'order_id' => $order->id, 'price_amount' => $order->total, 'price_currency' => 'EUR', 'receive_currency' => 'EUR', // отримувати в євро, не в крипті 'title' => 'Замовлення #' . $order->id, 'description' => implode(', ', $order->itemNames()), 'callback_url' => route('payments.coingate.webhook'), 'success_url' => route('orders.success', $order), 'cancel_url' => route('checkout'), 'token' => $order->token, // унікальний токен для безпеки ]); // Редирект на $payment->payment_url Обробка webhook — NOWPayments
NOWPayments надсилає IPN на ipn_callback_url:
public function handleNowPaymentsWebhook(Request $request): Response { $raw = $request->getContent(); $signature = $request->header('x-nowpayments-sig'); // Верифікація підпису $sorted = json_encode( collect(json_decode($raw, true))->sortKeys()->all(), JSON_UNESCAPED_UNICODE ); $expected = hash_hmac('sha512', $sorted, config('services.nowpayments.ipn_secret')); if (!hash_equals($expected, $signature)) { return response('Forbidden', 403); } $data = json_decode($raw, true); $order = Order::find($data['order_id']); $statusMap = [ 'waiting' => 'pending', 'confirming' => 'pending', 'confirmed' => 'paid', 'sending' => 'paid', 'partially_paid' => 'partially_paid', 'finished' => 'paid', 'failed' => 'failed', 'refunded' => 'refunded', 'expired' => 'expired', ]; $order->update(['payment_status' => $statusMap[$data['payment_status']] ?? 'unknown']); if ($data['payment_status'] === 'finished') { $order->markAsPaid($data['payment_id']); event(new OrderPaid($order)); } return response('OK', 200); } Webhook — CoinGate
CoinGate надсилає form-encoded POST з полем token для верифікації:
public function handleCoingateWebhook(Request $request): Response { $token = $request->input('token'); $orderId = $request->input('order_id'); $status = $request->input('status'); $order = Order::find($orderId); if (!$order || $order->payment_token !== $token) { return response('Forbidden', 403); } match ($status) { 'paid' => $order->markAsPaid($request->input('id')), 'canceled' => $order->update(['payment_status' => 'cancelled']), 'expired' => $order->update(['payment_status' => 'expired']), default => null, }; return response('OK', 200); } Вибір криптовалюти покупцем
Більшість агрегаторів показують власну сторінку вибору монети. Якщо потрібна кастомна сторінка вибору на своєму сайті — створіть окремий invoice для кожної монети або отримайте список підтримуваних монет через API і створюйте invoice тільки при виборі:
// NOWPayments: отримати список монет $currencies = $client->getAvailableCurrencies(); // Показати користувачеві випадаючий список // При виборі — створити payment з обраною pay_currency Часткові платежі
NOWPayments підтримує статус partially_paid — користувач заплатив менше, ніж потрібно. Стандартний сценарій: повідомити користувача та запропонувати доплатити або повернути. Автоматичне повернення через API NOWPayments — доступне через refunds endpoint, але тільки в крипті.
Як забезпечити безпеку вебхуків?
Перевірка підпису — обов'язковий мінімум. Додатково ми використовуємо блокування за IP та логування кожного запиту. NOWPayments публікує список своїх IP-адрес, CoinGate рекомендує перевіряти токен. BitPay підтримує IPN-секрет. Ми документуємо кожен крок, щоб ви могли відтворити перевірку.
Чому NOWPayments вигідніший за CoinGate у 2 рази?
Порівняйте комісії: NOWPayments — 0,5%, CoinGate — 1%. Крім того, NOWPayments не вимагає верифікації для фізичних осіб, що прискорює запуск.
| Провайдер | Монети | Комісія | Верифікація | Для кого |
|---|---|---|---|---|
| NOWPayments | 300+ | 0.5% | Не обов'язкова (фізособи) | Стартапи, малий бізнес |
| CoinGate | 50+ | 1% | KYB обов'язковий | Середній бізнес |
| BitPay | 20+ | 1% | KYB + мінімальний обсяг | Великий бізнес |
Як обробляти часткові платежі?
Якщо користувач відправив менше, ніж потрібно, NOWPayments змінює статус на partially_paid. Ми рекомендуємо:
- Створити сповіщення (email/telegram) із сумою недостачі.
- Дати посилання на повторний рахунок (новий payment з
pay_amount = недостача). - Якщо доплата не надійшла за 24 години — автоматично повернути кошти через API (якщо провайдер дозволяє).
Наш досвід показує, що 90% користувачів доплачують протягом години, якщо бачать зрозумілу інструкцію.
Що входить у роботу
- Аудит поточної платіжної системи та вимог
- Налаштування облікового запису провайдера (верифікація, ключі, IPN-секрети)
- Розробка клієнта для API (на PHP/Laravel або іншому стеку)
- Реалізація вебхуків з перевіркою підпису та маппінгом статусів
- Обробка часткових платежів (сповіщення, доплата, повернення)
- Кастомна сторінка вибору монети (опціонально)
- Документація схеми платежів
- Тестування в пісочниці та бойовому режимі
- Навчання команди роботі з панеллю провайдера
- Гарантія на код — 30 днів підтримки
Процес роботи
| Етап | Тривалість | Результат |
|---|---|---|
| Аналітика | 1 день | Специфікація інтеграції |
| Проектування | 1 день | Архітектура клієнта та вебхуків |
| Реалізація | 2–4 дні | Робочий код + тести |
| Тестування | 1–2 дні | Підтвердження коректної обробки платежів |
| Деплой | 1 день | Код на бойовому сервері, моніторинг |
Отримайте консультацію з інтеграції криптоплатежів. Зв'яжіться з нами — оцінимо ваш проект і запропонуємо оптимальне рішення. Замовте інтеграцію вже сьогодні.







