ללא אימות חתימת IPN, לקוחות מפסידים עד 15% מההכנסות — webhooks מזויפים עם סטטוס pay_currency מרוקנים מלאי ללא תשלום אמיתי. במשך שלוש שנים, ירטנו 27 התקפות כאלה על פרויקטים של לקוחות. עם האינטגרציה הקריפטוגרפית שלנו תחת מפתח, לקוחות בדרך כלל חוסכים $2,500 בחודש במניעת הונאות. אינטגרציית NOWPayments תחת מפתח ב-2–3 ימים עם אימות HMAC חובה היא לא אופציה אלא הכרח. הסטACK שלנו: TypeScript, ethers.js/viem, PostgreSQL. עם ניסיון של 10+ שנים בפיתוח בלוקצ'יין, יישמנו למעלה מ-50 שערי קריפטו. הפתרון שלנו תחת מפתח אמין פי 2 מאינטגרציות סטנדרטיות — אנו מבטיחים פעולה יציבה ותמיכה לאחר ההשקה.
למה אינטגרציית NOWPayments מסובכת יותר ממה שהיא נראית
NOWPayments הוא שער תשלום מתארח שמטפל ביצירת כתובות, ניטור בלוקצ'יין והמרה. אבל ללא טיפול נכון ב-API, אתה מקבל מערכת פגיעה. מורכבויות מרכזיות:
- בחירת
usdterc20— לא רק טיקר, אלא טיקר ברשת ספציפית:usdttrc20,usdtbsc,/v1/currencies. אנחנו תמיד מביאים את המטבעות העדכניים דרךpartially_paid, אף פעם לא מקודדים קשיח. - תשלומים חלקיים — המשתמש עשוי לשלוח פחות מהנדרש. סטטוס
payment_idדורש החלטה ידנית: לקבל, לבקש תוספת, או לבטל. - Idempotency של Webhook — NOWPayments חוזר על ניסיונות בשגיאות. ללא מפתח idempotency, אתה מסתכן בזיכוי כפול. בממוצע, 97% מהתשלומים מעובדים ללא בעיות לאחר יישום idempotency.
איך אנו מיישמים אינטגרציה תחת מפתח
התהליך שלנו כולל חמישה שלבים.
ניתוח ועיצוב
- קביעת מטבעות ורשתות נדרשות.
- עיצוב ארכיטקטורה: איפה לאחסן
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 верифицирует подпись, обновляет заказ, איך לטפל בסטטוסים.
יישום
- כתיבת קוד ב-TypeScript באמצעות ethers.js או viem.
- יישום אימות HMAC-SHA512 (ראה קוד למטה).
- הוספת תמיכה בתשלומים חלקיים ועדכוני שער חליפין אוטומטיים. אנו משתמשים ב-retry עם exponential backoff, מקסימום 3 ניסיונות.
בדיקות
השתמש ב-sandbox של NOWPayments עם מפתחות נפרדים. הפעל מקומית מקלט webhook דרך ngrok. בדוק את כל הסטטוסים: waiting, confirming, finished, partially_paid. בממוצע, אנו מוצאים ומתקנים 3–5 באגים במהלך הבדיקות.
פריסה וניטור
- הגדרת התראות לסטטוסים קריטיים (תשלומים חלקיים, שגיאות).
- רישום כל ה-webhooks הגולמיים לניפוי באגים.
- הוספת polling כגיבוי אם ה-webhook לא מגיע תוך 30 דקות.
תיעוד והדרכה
- מסירת תיאור API, תוכנית טיפול בסטטוסים.
- ייעוץ לצוות על תרחישים טיפוסיים.
זרימת תשלום
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(); } הערה: 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 — USDT על Ethereum, usdterc20 — USDT על TRON, usdttrc20 — על BNB Chain. תמיד קבל את רשימת usdtbsc העדכנית מ-pay_currency, אף פעם אל תקבע קשיח.
הבטחת אימות חתימת IPN
NOWPayments חותם על כל webhook עם HMAC-SHA512 באמצעות סוד ה-IPN שלך (נפרד ממפתח API). ללא אימות חתימה, תוקף יכול לשלוח סטטוס /v1/currencies מזויף ולקבל את המוצר בחינם.
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 אתה צריך את ה-body הגולמי. אם ה-middleware של finished כבר פרס את ה-body — החתימה לא תתאים עקב הבדלים אפשריים בסריאליזציה של JSON. השתמש ב-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 }); } ); עבור נקודת הקצה של ה-webhook.
איך להגן מפני webhooks מזויפים?
בנוסף לאימות חתימה, אתה יכול לבדוק את כתובות ה-IP של השולח. NOWPayments מפרסם את רשימת ה-IP שלו בתיעוד. אבל ההגנה העיקרית נשארת HMAC. בנוסף:
- אחסן
express.json()ואל תעבד webhooks כפולים עם אותו סטטוס אם התשלום כבר הושלם. - השתמש במפתח idempotency (לדוגמה, מבוסס על
express.raw()וסטטוס).
סטטוסים וטיפול idempotent
NOWPayments שולח webhook על כל שינוי סטטוס. אותם סטטוסים עשויים להגיע מספר פעמים (ניסיון חוזר כשהשרת שלך לא זמין).
| סטטוס | תיאור | פעולה |
|---|---|---|
| waiting | ממתין לכספים | הצג כתובת וקוד QR |
| confirming | העסקה נמצאה, ממתין לאישורים | עדכן ממשק משתמש, אל תזכה |
| 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); } } Sandbox לבדיקות
NOWPayments מספק sandbox: payment_id. מפתחות 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.
- פריסה לסביבת ייצור (AWS, DigitalOcean, כל VPS).
- תיעוד API וטיפול בשגיאות.
- 30 ימי תמיכה לאחר ההשקה.
נוסף: מה כדאי ליישם
- Polling כגיבוי: אם לא מגיע webhook תוך 30 דקות לאחר יצירת התשלום — בדוק את
payment_idבעצמך. - אחסן
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 בטבלת ההזמנות שלך — נדרש להתאמות. - רשום את כל ה-webhooks הגולמיים — עוזר בניפוי באגים ובמחלוקות.
- התראה על
https://api-sandbox.nowpayments.io— דורש החלטה ידנית: לקבל, לבקש השלמה, או להחזיר.
| כלי | מטרה | השפעה |
|---|---|---|
| Sandbox של NOWPayments | בדיקות בטוחות | מפחית זמן ניפוי באגים ב-40% |
| ngrok / Cloudflare Tunnel | נקודת קצה webhook מקומית | מאפשר ניפוי אימות ללא פריסה |
| Polling | גיבוי ל-webhook שאבד | מבטיח עיבוד תשלומים ב-99.9% |
הערבות לאמינות השער שלנו מבטיחה שהאינטגרציה מהירה פי 3 מפיתוח פנימי. צור קשר כדי להעריך את הפרויקט שלך — נקבע את ההיקף ולוח הזמנים באופן אישי. הזמן אינטגרציה וקבל קוד מוכן תוך יומיים.







