Інтеграція криптоплатіжного шлюзу (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 день | Код на бойовому сервері, моніторинг |
Отримайте консультацію з інтеграції криптоплатежів. Зв'яжіться з нами — оцінимо ваш проект і запропонуємо оптимальне рішення. Замовте інтеграцію вже сьогодні.







