وبلاگ سایاپی · امنیت و پیگیری پرداخت

چرا بازگشت از درگاه پرداخت، تأیید پرداخت موفق نیست؟

برای فروشگاه، مهم فقط دیدن صفحهٔ موفقیت نیست؛ باید نتیجهٔ معتبر به همان سفارش برسد و سفارش هم فقط یک بار تکمیل شود.

آیا بازگشت از درگاه یعنی پرداخت موفق است؟

خیر. برگشتن مرورگر به فروشگاه یا دیدن عبارتی مثل «موفق» در نشانی صفحه، به‌تنهایی اثبات پرداخت نیست. تصمیم دربارهٔ تکمیل سفارش باید سمت سرور، با نتیجهٔ معتبر و تطبیق اطلاعات همان سفارش گرفته شود.

عکس این موضوع هم مهم است: نرسیدن مشتری به صفحهٔ بازگشت، به‌تنهایی شکست پرداخت را ثابت نمی‌کند. اتصال اینترنت یا مرورگر ممکن است در مسیر برگشت قطع شود. در راهنمای رسمی Stripe دربارهٔ تکمیل سفارش هم تأکید شده که تکمیل سفارش نباید فقط به بازدید صفحهٔ موفقیت وابسته باشد. این یک اصل طراحی است، نه معرفی Stripe به‌عنوان اتصال سایاپی.

بازگشت مرورگر، پیام سروری و تأیید: سه مفهوم متفاوت

نام callback در سرویس‌های مختلف یکسان استفاده نمی‌شود. پیش از پیاده‌سازی، مشخص کنید پیام از مرورگر می‌آید یا از سرور ارائه‌دهنده و برای معتبرکردن آن چه قراردادی وجود دارد.

در موبایل، جدول را افقی جابه‌جا کنید تا ستون «محدودیت» هم دیده شود.

چه چیزی را می‌بینیم و چه تصمیمی می‌توانیم بگیریم؟
پیامنقشمحدودیت
بازگشت مرورگرنمایش صفحهٔ پیگیری به مشتریپارامتر نشانی قابل تغییر است؛ مجوز تحویل سفارش نیست.
وب‌هوک یا اعلان سروریخبررسانی مستقل از حضور مشتریاصالت پیام و نتیجه طبق قرارداد ارائه‌دهنده بررسی می‌شود؛ دریافت هر پیام یعنی موفقیت نیست.
تأیید سروریبررسی نتیجهٔ معتبر برای پرداخت ذخیره‌شدهعلاوه بر وضعیت، شناسه، مبلغ و ارز باید با سفارش تطبیق داشته باشند.

راهنمای امنیت اتصال درگاه OWASP، اعتماد به پارامترهای بازگشت را خطا می‌داند و تأیید سروری و تطبیق اطلاعات سفارش را توصیه می‌کند. جزئیات امضا و تأیید را از مستندات همان ارائه‌دهنده بخوانید؛ یک الگوریتم مشترک برای همه وجود ندارد.

مسیر درست از سفارش تا تحویل

  1. مبلغ نهایی و واحد آن را روی سرور از سفارش معتبر محاسبه و همراه شناسهٔ سفارش ذخیره کنید.
  2. پس از ساخت درخواست، شناسهٔ پرداخت را به همان سفارش متصل کنید؛ شمارهٔ دریافت‌شده از مرورگر نباید به‌تنهایی سفارش مقصد را تعیین کند.
  3. با کلید خصوصی اتصال، نتیجه را از مسیر سروری مجاز بررسی کنید. اطلاعات پرداخت را با سفارش ذخیره‌شده تطبیق دهید.
  4. فقط در نتیجهٔ معتبرِ موفق و تطبیق کامل، سفارش را یک بار تکمیل کنید. اجرای هم‌زمان یا تکراری این مرحله نباید تحویل یا اعتبار دوباره ایجاد کند.

تکرار درخواست API و تکرار تحویل سفارش دو مسئلهٔ جدا هستند. جلوگیری از درخواست تکراری در ارائه‌دهنده، جای کنترل تکمیل یک‌باره در فروشگاه را نمی‌گیرد. مستندات Adyen دربارهٔ idempotency مثال‌ای از قرارداد جلوگیری از اجرای دوبارهٔ درخواست است؛ قواعد هر API را باید جداگانه رعایت کرد.

مثال: سفارش ۱۲٬۰۰۰ تومانی با پیام بازگشت «موفق»

دادهٔ ساختگی برای توضیح؛ رسید بانکی نیست
سفارش ذخیره‌شده
order-1042
مبلغ مورد انتظار
۱۲۰٬۰۰۰ ریال؛ ارز IRR
پیام مرورگر
status=success؛ ورودی غیرقابل اتکا
تصمیم فروشگاه
ابتدا بررسی سروریِ پرداخت متصل به سفارش؛ سپس تطبیق و تکمیل یک‌باره

اگر پاسخ معتبر مربوط به سفارش دیگری باشد یا مبلغ ۱۲٬۰۰۰ ریال باشد، سفارش ۱۲۰٬۰۰۰ ریالی را تکمیل نکنید؛ حتی اگر وضعیت پاسخ موفق است. اگر تأیید هنوز قطعی نیست، سفارش را در انتظار بررسی نگه دارید. جزئیات تبدیل واحد را در راهنمای ریال و تومان در API بخوانید.

در محیط آموزشی سایاپی چه چیزی تأیید می‌شود؟

مسیر sandbox برای آموزش فنی و جدا از دریافت بانکی حساب کسب‌وکار است. verify در این نسخه، رسید امضاشدهٔ ارائه‌دهندهٔ شبیه‌سازی‌شده را بررسی می‌کند؛ استعلام بانکی یا اتصال فعال ارائه‌دهندهٔ پرداخت نیست. نتیجهٔ آموزشی را رسید پرداخت واقعی معرفی نکنید.

طبق قرارداد API آموزشی سایاپی، مسیرهای زیر از سرور فروشگاه و با کلید آموزشیِ همان پذیرنده فراخوانی می‌شوند. PAYMENT_ID و sp_test_YOUR_KEY جای‌نگهدارند؛ کلید واقعی اتصال را در مرورگر، نشانی بازگشت یا مقاله ننویسید.

GET /api/v1/payments/PAYMENT_ID
Authorization: Bearer sp_test_YOUR_KEY

POST /api/v1/payments/PAYMENT_ID/verify
Authorization: Bearer sp_test_YOUR_KEY
Content-Type: application/json

{}

وضعیت paid در این محیط یعنی نتیجهٔ موفق آموزشی. تا رسید معتبرِ قطعی موجود نباشد، verify می‌تواند خطای verification_pending با HTTP 409 بدهد؛ این پاسخ مجوز تکمیل سفارش نیست. وضعیت ناموفق و زمان انقضای لینک نیز جداگانه بررسی می‌شوند؛ انقضای لینک به‌تنهایی نتیجهٔ یک رسید ثبت‌شده را باطل نمی‌کند.

در پاسخ پرداخت، شناسهٔ پرداخت، order_id، amount، currency و محیط آموزشی را با دادهٔ ذخیره‌شدهٔ فروشگاه مقایسه کنید. مقدار ارسالی مشتری جای دادهٔ سفارش سمت سرور را نمی‌گیرد. استرداد کامل یا جزئی را هم جدا بررسی کنید؛ صرف دیدن paid برای تحویل کامل سفارش کافی نیست.

اگر پاسخ نرسید یا نتیجه مشخص نبود، چه کنیم؟

قطع ارتباط فقط می‌گوید پاسخ کامل در اختیار شما نیست. به مشتری پیام روشن «نتیجه در حال بررسی است» نشان دهید و شناسهٔ پیگیری نگه دارید؛ نه تأیید قطعی و نه درخواست فوری پرداخت دوباره. در مثال ما، «نامشخص» توضیح وضعیت بررسی در فروشگاه است و نام یک status جدید در API سایاپی نیست.

استعلام مجدد و اعلان‌های معتبر را طبق قرارداد ارائه‌دهنده پیگیری کنید. برای تکرار درخواستِ قابل تکرار، همان کلید جلوگیری از تکرار و همان داده را حفظ کنید؛ تغییر کلید می‌تواند درخواست جدید بسازد. راهنمای Adyen رفتار تکرار پس از timeout را برای API خودش توضیح می‌دهد؛ آن را بدون بررسی قرارداد به سرویس دیگری تعمیم ندهید.

اگر مشتری صفحه را ببندد، سفارش گم می‌شود؟

پیگیری نباید فقط به آن تب مرورگر وابسته باشد. فروشگاه به مسیر سروری مستقل برای دریافت یا بازیابی نتیجه نیاز دارد. در سایاپی آموزشی می‌توانید پرداخت ذخیره‌شده را از API و پنل پیگیری کنید؛ وجود این مسیر به معنی تکمیل خودکار فروشگاه شما نیست.

اگر callback دو بار برسد، چه می‌شود؟

اتصال فروشگاه باید هر دو اجرا را به همان سفارش برساند و تحویل را فقط یک بار ثبت کند. این کنترل را در دیتابیس و تراکنش فروشگاه پیاده کنید؛ صرفاً مخفی‌کردن دکمه یا متغیر داخل مرورگر کافی نیست.

چک‌لیست آزمون پیش از اتصال واقعی

این موارد سناریوی پیشنهادی برای فروشگاه شما هستند، نه ادعای تأیید اتصال بانکی:

  • بازکردن دستی نشانی بازگشت با پارامتر «موفق» نباید سفارش را تکمیل کند.
  • شناسهٔ پرداخت متعلق به سفارش یا پذیرندهٔ دیگر نباید پذیرفته شود.
  • نتیجهٔ معتبر با مبلغ یا ارز متفاوت نباید به تحویل منجر شود.
  • پاسخ در انتظار تأیید یا ناموفق نباید مثل موفق پردازش شود؛ برای لینک منقضی، رسید ثبت‌شده را پیش از ساخت تلاش تازه بررسی کنید.
  • تکرار و اجرای هم‌زمان تأیید نباید تحویل، ایمیل یا اعتبار دوباره ایجاد کند.
  • بستن مرورگر و قطع پاسخ باید مسیر پیگیری داشته باشد؛ نتیجه حدس زده نشود.

تست‌ها را با سفارش ساختگی و کلید آموزشی انجام دهید. لاگ پیگیری را به شناسه‌ها، وضعیت و خطای لازم محدود کنید؛ رمز، کلید API و اطلاعات حساس مشتری را در آن ذخیره نکنید.

منابع و حدود این راهنما

اصول عمومی با منابع اصلی OWASP، Stripe و Adyen که کنار موضوع مربوط آمده‌اند تطبیق داده شده‌اند. رفتارهای سایاپی با قرارداد و آزمون‌های نسخهٔ آموزشی بررسی شده‌اند. این سرویس‌های خارجی، اتصال‌های فعال سایاپی یا پیشنهاد استفاده برای کاربران ایران نیستند.

این مقاله با کمک هوش مصنوعی تدوین شده است و جایگزین مستندات ارائه‌دهندهٔ پرداخت، قرارداد بانکی یا بازبینی امنیت اتصال نیست. خطای محتوا را از تماس با سایاپی گزارش کنید.