FA

وب‌هوک‌های پرداخت کریپتو: بررسی امضا، تکرارها و تحویل‌های تکراری

وب‌هوک‌های SnapEX Pay

وب‌هوک راهی است که فروشگاه، پنل بیلینگ یا ربات شما از پرداخت مشتری باخبر می‌شود. SnapEX Pay برای هر رویداد فاکتور، پرداخت و برداشت یک درخواست HTTP POST به URL شما می‌فرستد. اگر درست پیاده شود، سریع‌ترین و مطمئن‌ترین سیگنالی است که دارید. اگر بی‌دقت پیاده شود، راهی است برای پرداخت‌شده علامت‌زدن سفارش‌هایی که هرگز پرداخت نشده‌اند. این راهنما بخش‌های مهم را پوشش می‌دهد.

تنظیم

در پنل فروشنده به Invoices → کارت Webhook بروید، URL خود را وارد کنید و Save را بزنید. یک URL برای هر حساب همه انواع رویداد را دریافت می‌کند. در اولین ذخیره، پنل رمز امضای whsec_… را فقط یک بار نشان می‌دهد: آن را فقط روی سرور خود نگه دارید.

URL باید یک آدرس مطلق https:// با میزبان عمومی باشد: بدون login:password، بدون localhost و میزبان نباید به IP خصوصی یا رزروشده اشاره کند. ریدایرکت‌ها دنبال نمی‌شوند، پس URL نهایی را بدهید.

چه چیزی می‌رسد

هر درخواست چهار هدر دارد:

هدر معنی
Webhook-Id شناسه یکتای رویداد. در تکرارها یا ارسال دستی دوباره تغییر نمی‌کند.
Webhook-Timestamp زمان یونیکس (ثانیه) ارسال این تلاش. هر تکرار مقدار تازه‌ای دارد.
Webhook-Signature v1= و HMAC-SHA256 هگز با حروف کوچک از {Webhook-Timestamp}.{raw body}.
Content-Type همیشه application/json.

بدنه شامل id (همان Webhook-Id)، type، created_at و data است. برای رویدادهای invoice.*، data همان فاکتور با ساختار GET /invoices/{id} است، از جمله environment، amount_usd، status و external_id شما.

رویدادهای فاکتور:

رویداد چه زمانی
invoice.created فاکتور ساخته شد، هنوز روش پرداختی انتخاب نشده.
invoice.awaiting روش پرداخت انتخاب و آدرس صادر شد.
invoice.underpaid بخشی از مبلغ رسید؛ همان آدرس منتظر باقی‌مانده است.
invoice.paid کل مبلغ پرداخت و واریز شد. تنها سیگنال برای ارسال سفارش.
invoice.partially_paid فقط بخشی پرداخت شد، مهلت تکمیل تمام شد و بخش دریافت‌شده به شما واریز شد.
invoice.expired مهلت فاکتور بدون پرداخت تمام شد.
invoice.extra_payment انتقال دیگری پس از پرداخت فاکتور رسید؛ جداگانه واریز می‌شود.

بررسی امضا

  1. بدنه خام درخواست را به‌صورت بایت، پیش از هر پردازش JSON، بخوانید. JSONی که دوباره سریال‌سازی شده مطابقت نخواهد داشت.
  2. HMAC-SHA256 را روی {Webhook-Timestamp}.{raw body} با کل رمز به‌عنوان کلید (همراه با پیشوند whsec_) محاسبه و به هگز تبدیل کنید.
  3. v1= + هگز را با هدر Webhook-Signature با یک تابع زمان‌ثابت مقایسه کنید.
  4. Webhook-Timestampی را که بیش از ۵ دقیقه با ساعت شما اختلاف دارد رد کنید. تکرارها زمان تازه دارند، پس این کار آن‌ها را خراب نمی‌کند.

PHP:

$secret = getenv('SNAPEX_WEBHOOK_SECRET');          // whsec_… from the cabinet
$body   = file_get_contents('php://input');           // raw body, before json_decode
$ts     = $_SERVER['HTTP_WEBHOOK_TIMESTAMP'] ?? '';
$sig    = $_SERVER['HTTP_WEBHOOK_SIGNATURE'] ?? '';

$expected = 'v1=' . hash_hmac('sha256', $ts . '.' . $body, $secret);
if (!hash_equals($expected, $sig) || abs(time() - (int) $ts) > 300) {
    http_response_code(400);
    exit;
}

$event = json_decode($body, true);
// skip if $event['id'] was already processed; do the heavy work in a queue
http_response_code(200);

Node.js (Express):

const crypto = require('crypto');

app.post('/hooks/snapex', express.raw({ type: 'application/json' }), (req, res) => {
  const ts = req.get('Webhook-Timestamp') || '';
  const sig = Buffer.from(req.get('Webhook-Signature') || '');
  const expected = Buffer.from('v1=' + crypto
    .createHmac('sha256', process.env.SNAPEX_WEBHOOK_SECRET)
    .update(ts + '.' + req.body)
    .digest('hex'));

  const fresh = Math.abs(Date.now() / 1000 - Number(ts)) <= 300;
  if (!fresh || sig.length !== expected.length || !crypto.timingSafeEqual(sig, expected)) {
    return res.sendStatus(400);
  }

  const event = JSON.parse(req.body);
  // skip if event.id was already processed; queue the heavy work
  res.sendStatus(200);
});

تکرارها، تحویل‌های تکراری و ترتیب

  • موفقیت یعنی هر پاسخ 2xx. هر کد دیگر، تایم‌اوت یا خطای شبکه شکست است. تایم‌اوت‌ها ۵ ثانیه برای اتصال و ۱۵ ثانیه برای کل درخواست هستند، پس سریع پاسخ دهید و کار سنگین را ناهمگام انجام دهید.
  • تکرارها. تا ۵ تلاش برای هر رویداد: تلاش اول، سپس حدود ۱۰ ثانیه، ۱ دقیقه، ۵ دقیقه و ۱۵ دقیقه پس از هر شکست. پس از پنجمین شکست، ارسال خودکار متوقف می‌شود؛ پنل تحویل‌های اخیر را فهرست می‌کند و دکمه Retry دارد که رویداد را با همان Webhook-Id دوباره می‌فرستد.
  • تحویل‌های تکراری. تحویل at-least-once است: یک رویداد ممکن است بیش از یک بار برسد. مقادیر Webhook-Id پردازش‌شده را ذخیره کنید و تکرارها را نادیده بگیرید.
  • ترتیب. رویدادها ممکن است نامرتب برسند: یک رویداد قدیمی تکرارشده می‌تواند پس از رویداد جدیدتر برسد. به ترتیب تکیه نکنید؛ وضعیت داخل رویداد را با آنچه از قبل دارید مقایسه کنید.
  • در صورت تمایل دوباره بررسی کنید. پس از وب‌هوک می‌توانید شیء را دوباره از API بخوانید: GET /invoices/{id}.

تست بدون پول واقعی

یک فاکتور تست ("environment": "test") بسازید، آن را در صفحه پرداخت بپردازید و ببینید وب‌هوک‌ها با data.environment = "test" می‌رسند. جزئیات: چگونه پرداخت کریپتو را بدون پول واقعی تست کنیم.

ماژول‌های آماده برای WHMCS، BILLmanager، WooCommerce و پلتفرم‌های دیگر از قبل امضا را بررسی می‌کنند و هرگز یک پرداخت را دو بار واریز نمی‌کنند؛ pay.snapex.pro را ببینید. مرجع کامل: مستندات API SnapEX Pay.

راهنماهای بیشتر

مشتری کمتر از مبلغ فاکتور فرستاد: کم‌پرداخت در کریپتو چگونه کار می‌کند صرافی‌ها اغلب کارمزد برداشت را از مبلغ کم می‌کنند و فاکتور کریپتو ناقص می‌رسد. SnapEX Pay با کم‌پرداخت چه می‌کند، چه وب‌هوک‌هایی دریافت می‌کنید و با سفارش چه کنید. کارمزد فاکتور کریپتو را چه کسی می‌پردازد: شما یا مشتری در SnapEX Pay برای هر فاکتور انتخاب می‌کنید که کارمزد سرویس و هزینه شبکه را چه کسی بپردازد. fee_on چه می‌کند و چگونه مبلغ پرداختی مشتری و مبلغ دریافتی شما را تغییر می‌دهد. مقایسه SnapEX Pay با NOWPayments، Cryptomus و CoinGate: کارمزد و ماژول‌های آماده مقایسه SnapEX Pay با NOWPayments، Cryptomus و CoinGate از نظر کارمزد اعلام‌شده، هزینه ماهانه و ماژول‌های آماده برای بیلینگ هاستینگ، پنل‌های VPN و فروشگاه‌ها. داده‌های رقبا از سایت‌های خودشان، ۱۱ اکتبر ۲۰۲۶. چگونه پرداخت کریپتو را بدون پول واقعی تست کنیم فاکتورهای تست در SnapEX Pay همان وضعیت‌ها و همان وب‌هوک‌های فاکتورهای واقعی را دارند، اما خودبه‌خود تأیید می‌شوند و به موجودی شما دست نمی‌زنند. روش استفاده از آن‌ها در این راهنما.

آماده دریافت کریپتو هستید؟

حساب فروشنده بسازید و کلید API بگیرید. 1٪ برای هر پرداخت، بدون هزینه ماهانه.