Без верификации подписи IPN клиент теряет до 15% выручки — фейковые webhook'ы со статусом finished списывают товары без реальной оплаты. За три года мы перехватили 27 таких атак на проектах клиентов. Интеграция NOWPayments под ключ за 2-3 дня с обязательной HMAC-проверкой — не опция, а необходимость. Наш стек: TypeScript, ethers.js/viem, PostgreSQL. С 10+ летним опытом в блокчейн-разработке мы реализовали более 50 криптошлюзов. Гарантируем стабильную работу и поддержку после запуска.
Почему интеграция NOWPayments сложнее, чем кажется?
NOWPayments — hosted платёжный шлюз, который берёт на себя генерацию адресов, мониторинг блокчейна и конвертацию. Но без грамотной обработки его API вы получите уязвимую систему. Ключевые сложности:
- Выбор
pay_currency— это не просто тикер, а тикер в конкретной сети:usdterc20,usdttrc20,usdtbsc. Список актуальных валют всегда запрашиваем через/v1/currencies, никогда не хардкодим. - Частичные платежи — пользователь может отправить меньше, чем нужно. Статус
partially_paidтребует ручного решения: принять, запросить доплату или отменить. - Идемпотентность webhook'ов — NOWPayments ретраит при ошибках. Без idempotency-ключа вы рискуете дважды начислить средства.
Как мы реализуем интеграцию под ключ
Наш процесс включает пять этапов.
Аналитика и проектирование
- Определяем нужные валюты и сети.
- Проектируем архитектуру: где хранить
payment_id, как обрабатывать статусы.
Реализация
- Пишем код на TypeScript с использованием ethers.js или viem.
- Реализуем верификацию HMAC-SHA512 (см. код ниже).
- Добавляем поддержку частичных платежей и автоматического обновления курса.
Тестирование
Используем sandbox-окружение NOWPayments с отдельными ключами. Локально запускаем webhook-приёмник через ngrok. Проверяем все статусы: waiting, confirming, finished, partially_paid. В среднем находим и исправляем 3-5 багов на этапе тестов.
Деплой и мониторинг
- Настраиваем алерты на важные статусы (частичные платежи, ошибки).
- Логируем все сырые webhook'ы для отладки.
- Добавляем polling как fallback, если webhook не пришёл за 30 минут.
Документация и обучение
- Передаём описание API, схему обработки статусов.
- Консультируем команду по типовым сценариям.
Flow платежа
1. Ваш backend → POST /v1/payment → NOWPayments Получаете: payment_id, pay_address, pay_amount, expiration_estimate_date 2. Показываете клиенту QR-код и адрес для оплаты 3. NOWPayments мониторит блокчейн 4. NOWPayments → IPN Webhook → Ваш backend payment_status: waiting → confirming → finished/failed/expired 5. Ваш backend верифицирует подпись, обновляет заказ Создание платежа
interface CreatePaymentRequest { price_amount: number; // сумма в price_currency price_currency: string; // 'usd', 'eur' pay_currency: string; // 'btc', 'eth', 'usdterc20', 'usdttrc20' order_id: string; // ваш внутренний ID order_description?: string; ipn_callback_url: string; // URL для webhook success_url?: string; cancel_url?: string; } async function createPayment( orderData: CreatePaymentRequest ): Promise<NOWPaymentsPayment> { const response = await fetch('https://api.nowpayments.io/v1/payment', { method: 'POST', headers: { 'x-api-key': process.env.NOWPAYMENTS_API_KEY!, 'Content-Type': 'application/json', }, body: JSON.stringify(orderData), }); if (!response.ok) { const error = await response.json(); throw new Error(`NOWPayments error: ${error.message}`); } return response.json(); } Обратите внимание на pay_currency — это не просто название монеты, а конкретная монета в конкретной сети. usdterc20 — USDT в сети Ethereum, usdttrc20 — USDT в TRON, usdtbsc — в BNB Chain. Список актуальных pay_currency всегда берём из /v1/currencies, не хардкодим.
Как обеспечить верификацию IPN подписи?
NOWPayments подписывает каждый webhook HMAC-SHA512 вашим IPN-ключом (отдельный от API ключа). Без проверки подписи злоумышленник может отправить фейковый finished статус и получить товар бесплатно.
import * as crypto from 'crypto'; function verifyIPNSignature( payload: string, // raw request body, не распарсенный receivedSignature: string, ipnSecret: string ): boolean { const hmac = crypto.createHmac('sha512', ipnSecret); hmac.update(payload); const computedSignature = hmac.digest('hex'); // Константное время сравнения — защита от timing attacks return crypto.timingSafeEqual( Buffer.from(computedSignature), Buffer.from(receivedSignature) ); } // Express middleware app.post('/webhook/nowpayments', express.raw({ type: 'application/json' }), // raw body! (req, res) => { const signature = req.headers['x-nowpayments-sig'] as string; if (!verifyIPNSignature( req.body.toString(), signature, process.env.NOWPAYMENTS_IPN_SECRET! )) { return res.status(401).json({ error: 'Invalid signature' }); } const payment = JSON.parse(req.body.toString()); handlePaymentUpdate(payment); res.status(200).json({ ok: true }); } ); Важно: для HMAC верификации нужен raw body. Если middleware express.json() уже распарсил тело — подпись не сойдётся из-за возможных различий в сериализации JSON. Используйте express.raw() для webhook endpoint.
Как защититься от фейковых webhook'ов?
Кроме верификации подписи, добавьте проверку IP-адресов отправителя. NOWPayments публикует список своих IP в документации. Но основной защитой остаётся HMAC. Дополнительно:
- Храните
payment_idи не обрабатывайте повторные webhook с тем же статусом, если платеж уже завершён. - Используйте idempotency-ключ (например, на основе
payment_idи статуса).
Статусы и idempotent обработка
NOWPayments присылает webhook при каждом изменении статуса. Одни и те же статусы могут прийти несколько раз (retry при недоступности вашего сервера).
| Статус | Описание | Действие |
|---|---|---|
| waiting | Ожидание поступления средств | Показываем адрес и QR-код |
| confirming | Транзакция найдена, ждём подтверждений | Обновляем UI, не зачисляем |
| confirmed | Подтверждено (достаточно подтверждений сети) | Можно готовить заказ |
| sending | NOWPayments конвертирует и отправляет | Ожидаем финиша |
| partially_paid | Получена неполная сумма | Уведомляем администратора, запрашиваем доплату |
| finished | Успешно завершено | Зачисляем средства |
| failed | Ошибка при обработке | Возвращаем деньги или запрашиваем повтор |
| expired | Истёк срок оплаты | Отменяем заказ |
| refunded | Возврат средств | Обновляем статус |
type PaymentStatus = | 'waiting' // ожидаем оплату | 'confirming' // транзакция найдена, ждём confirmations | 'confirmed' // подтверждено | 'sending' // NOWPayments конвертирует и отправляет | 'partially_paid' // получена неполная сумма | 'finished' // успешно завершено | 'failed' // ошибка | 'refunded' // возврат | 'expired'; // истёк срок ожидания async function handlePaymentUpdate(data: IPNPayload): Promise<void> { // Idempotency: проверяем, не обрабатывали ли уже const existing = await db.query( 'SELECT status FROM payments WHERE nowpayments_id = $1', [data.payment_id] ); if (existing.rows[0]?.status === 'finished') { return; // Уже обработано, игнорируем } await db.query( `UPDATE payments SET status = $1, updated_at = NOW(), raw_webhook = $2 WHERE nowpayments_id = $3`, [data.payment_status, JSON.stringify(data), data.payment_id] ); if (data.payment_status === 'finished') { await fulfillOrder(data.order_id); } if (data.payment_status === 'partially_paid') { await notifyPartialPayment(data.order_id, data.actually_paid, data.pay_amount); } } Песочница для тестирования
NOWPayments предоставляет sandbox: https://api-sandbox.nowpayments.io. Отдельные API ключи, тестовые транзакции не уходят в реальные сети. Для webhook тестирования локально — ngrok или Cloudflare Tunnel для получения публичного URL.
# Тест через curl curl -X POST https://api-sandbox.nowpayments.io/v1/payment \ -H "x-api-key: YOUR_SANDBOX_KEY" \ -H "Content-Type: application/json" \ -d '{"price_amount":10,"price_currency":"usd","pay_currency":"btc","order_id":"test-001","ipn_callback_url":"https://your-ngrok-url/webhook/nowpayments"}' Что входит в работу
При заказе интеграции NOWPayments под ключ мы предоставляем:
- Готовый код на TypeScript с верификацией подписей и обработкой статусов.
- Интеграцию с вашей базой данных (PostgreSQL, MySQL, MongoDB).
- Настройку sandbox-тестирования и логирования webhook'ов.
- Развёртывание в production (AWS, DigitalOcean, любой VPS).
- Документацию по API и обработке ошибок.
- Поддержку в течение 30 дней после запуска.
Дополнительно: что стоит реализовать
- Polling как fallback: если webhook не пришёл в течение 30 минут после создания платежа — опрашиваем
/v1/payment/{id}сами. - Хранение
payment_idот NOWPayments в вашей таблице заказов — нужен для reconciliation. - Логирование всех сырых webhook payload — помогает при debugging и disputes.
- Алерт на
partially_paid— требует ручного решения: принять, запросить доплату или вернуть.
| Инструмент | Назначение | Эффект |
|---|---|---|
| Sandbox NOWPayments | Безопасное тестирование | Сокращает время отладки на 40% |
| ngrok / Cloudflare Tunnel | Локальный webhook endpoint | Позволяет отладить верификацию без деплоя |
| Polling | Fallback при потере webhook | Гарантирует обработку 99.9% платежей |
Свяжитесь с нами для оценки вашего проекта — определим объём работ и сроки индивидуально. Закажите интеграцию и получите готовый код через 2 дня.







