Интеграция криптоплатёжного шлюза (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, но только в крипте.







