Інтеграція криптоплатіжного шлюзу (CoinGate/NOWPayments/BitPay)
CoinGate, NOWPayments, BitPay — агрегатори криптоплатежів. Приймають 50–300 криптовалют, конвертують за поточним курсом та виплачують продавцю в фіаті або крипто за розписанням. Продавцю не потрібно мати справу з приватними ключами, чекати підтверджень блокчейну або стежити за курсом — агрегатор береже на себе.
Інтеграція займає 1–3 робочих дні.
Порівняння провайдерів
NOWPayments — найбільший список монет (300+), є sandbox, API добре задокументований. Комісія 0.5%. Працює з фізичними особами.
CoinGate — перевірений провайдер, працює з 2014 року, хороша репутація, суворо верифікація бізнесу. Комісія 1%.
BitPay — орієнтований на крупний бізнес, мінімальний обсяг для комерційного плану, високі вимоги до KYB.
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 (Instant Payment Notification) на 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, але тільки в крипто.







