Вступление
Интегрировали криптоплатёжный шлюз, но вебхуки не проходят, статусы зависают, а клиенты жалуются на пропавшие платежи? Типичная причина — отсутствие проверки подписи уведомлений и неправильный маппинг статусов. Мы решаем это за 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%. Разница в 2 раза. При обороте 100 000 USD экономия составит 500 USD. Кроме того, 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 день | Код на боевом сервере, мониторинг |
Получите консультацию по интеграции криптоплатежей. Свяжитесь с нами — оценим ваш проект и предложим оптимальное решение. Закажите интеграцию уже сегодня.







