آماده انتشار
مراقبت از کلیدها، الزام https، مدیریت مبالغ، و فهرستی که پیش از گرفتن یک پرداخت واقعی باید طی کنید
کوینلند پی از همان فراخوانی اول پول واقعی جابهجا میکند. نه کلید آزمایشی وجود دارد و نه حالت تست: جلسهای که میسازید جلسهای است که یک مشتری میتواند پرداختش کند، پس راه تمرین این است که با حساب خودتان و مبلغی کوچک از ارزی که دارید امتحان کنید.
همین باعث میشود فهرست پایین ارزش داشته باشد که واقعاً طی شود، نه اینکه از رویش رد شوید.
مراقبت از کلیدها
کلید API شما یک اطلاعات محرمانه از نوع bearer است. هر کسی آن را داشته باشد میتواند به نام شما جلسه پرداخت بسازد، هر پرداختی که تا امروز گرفتهاید را بخواند، و شناسه سفارشهای مشتریانتان را ببیند.
دو کلاس کلید وجود دارد و دو اعتبارنامه جدا هستند: clpay_live_ برای پرداختگیری و clpay_payout_ برای
پرداخت به مشتری و بازپرداخت. هر چه پایین میآید برای هر دو صدق میکند، و این جدایی یک چیز
ارزشمند به شما میدهد — کلیدی که در بیشترین جاها کپی میشود نمیتواند از کیفپول شما پول بیرون بفرستد.
- فقط سمت سرور. هرگز در باندل مرورگر، فایل اجرایی اپلیکیشن موبایل، مخزن عمومی، لاگ CI یا تیکت پشتیبانی. اگر کلیدی حتی یک بار در هر یک از اینها بوده، لو رفته است، مستقل از آنچه بعد از آن رخ داده.
- فقط یک بار نمایش داده میشود. کوینلند هش را ذخیره میکند نه مقدار را، پس کلید گمشده قابل بازیابی نیست. فقط پیشوند نگه داشته میشود تا در کنسول کلیدها را از هم تشخیص دهید.
- چرخاندن با همپوشانی. کلید تازه را بسازید، منتشر کنید، مطمئن شوید ترافیک روی آن جاری است، و بعد کلید قدیمی را باطل کنید. باطل کردن اول یعنی یک قطعی بین دو انتشار.
- یک کلید برای هر محیط. کلیدهای جدا برای استیجینگ و تولید یعنی میتوانید یکی را باطل کنید بدون اینکه دیگری را لمس کنید، و پیشوند در لاگهایتان میگوید کدام سیستم آن فراخوانی را انجام داده است.
- بر پایه گمان باطل کنید، نه بر پایه قطعیت. باطل کردن فوری است و ساختن جانشین چند ثانیه طول میکشد. هیچ حالتی وجود ندارد که انتظار برای قطعیت انتخاب بهتری باشد.
کلیدهای امضای شما اطلاعات محرمانهای از جنس دیگری هستند: بهجای احراز آنچه شما میفرستید، آنچه ما میفرستیم را اعتبارسنجی میکنند. عمداً دو کلید وجود دارد.
- کلید امضای وبهوک رویدادهای دریافتی را اعتبارسنجی میکند. تعویض آن کمهزینه است — مقدار قبلی تا ۲۴ ساعت کار میکند و رویدادهای این بازه با هر دو کلید امضا میشوند، پس کلید تازه را هر وقت خواستید روی سرور قرار میدهید.
- کلید امضای رسید توکنهای رسید را امضا میکند. تعویض آن اثر بازگشتی دارد: پس
از بازهٔ ۲۴ ساعته، هر رسیدی که با کلید قبلی صادر شده از کار میافتد — هم آفلاین و هم از راه
POST /receipts/verify. رسیدهای صادرشده پس از تعویض تأثیری نمیگیرند و پرداختهای قدیمی از راهGET /payments/{id}قابل اثبات میمانند.
هر دو کلید را هر وقت لازم داشتید میتوانید از کنسول خود ببینید — نیازی نیست کلیدی سالم را از بین ببرید تا مقدارش را بدانید. آنها را دقیقاً مثل یک کلید API فقط سمت سرور نگه دارید.
محدود کردن یک کلید به چند نشانی IP
هر کلید میتواند به فهرستی از نشانیها محدود شود. این فهرست را در کنسول کسبوکار، در همان جدول کلیدها، ویرایش میکنید.
- هر مورد یک نشانی IP دقیق یا یک بازه CIDR است — هم IPv4 و هم IPv6. مثلاً
203.0.113.7،198.51.100.0/24یا2001:db8::/32. - فهرست خالی یعنی هیچ محدودیتی نیست، و همین حالت پیشفرض است. کلیدی که فهرستی ندارد از هر نشانیای کار میکند.
- بهمحض اینکه حتی یک مورد ثبت کنید، کلید فقط از همان نشانیها کار میکند. هر درخواستی از نشانی دیگری
با
UNAUTHORIZEDرد میشود — همان پاسخی که یک کلید ناشناخته یا باطلشده میگیرد، پس از روی پاسخ نمیتوان فهمید کدام نشانی مجاز است. - موردی که شکل درستی نداشته باشد همان لحظه ذخیرهشدن با
MERCHANT_KEY_IP_INVALIDرد میشود، نه بعداً سر یک فراخوانی واقعی.
اگر روی بستر بدون سرور اجرا میکنید، فهرست را خالی بگذارید
روی سرویسهای بدون سرور (serverless) نشانی خروجی سرور شما ثابت نیست و بین فراخوانیها عوض میشود. ثبت نشانی در چنین حالتی درگاه شما را از کار میاندازد. این قابلیت برای سرورهایی است که نشانی خروجی مشخص و ثابتی دارند.
این محدودیت یک لایه دوم است، نه جایگزین کلید: کلید همچنان باید محرمانه بماند و فقط روی سرور شما باشد.
همه جا HTTPS
سه نشانی از شما گرفته میشود و هر سه باید https باشند:
| نشانی | کجا | چرا |
|---|---|---|
| نشانی وبهوک | کنسول کسبوکار | وبهوک بدون رمزنگاری با MERCHANT_WEBHOOK_URL_INVALID رد میشود. شناسه پرداخت را روی اینترنت باز حمل میکند |
return_url | برای هر جلسه | یک توکن رسید را در رشته پرسوجو حمل میکند |
cancel_url | برای هر جلسه | برای یکدستی، و صفحهای است که مشتری از کوینلند روی آن فرود میآید |
نشانی وبهوک شما باید از اینترنت عمومی هم قابل دسترسی باشد. ما نمیتوانیم به localhost، یک آدرس خصوصی،
یا هر چیزی پشت VPN شما ارسال کنیم. برای توسعه محلی از یک تونل استفاده کنید و کنسول را به نشانی https عمومی
آن تونل بدهید.
مدیریت مبالغ
هرگز یک مبلغ را به عدد شناور تبدیل نکنید
هر مبلغ در این API یک رشته اعشاری است و باید تا رسیدن به یک نوع اعشاری دقیق رشته بماند.
parseFloat("24.90") عددی است که نمیتواند ۲۴٫۹۰ را دقیق نمایش دهد، و خطا از همان لحظهای که مبالغ یک روز
را جمع میزنید انباشته میشود.
- از نوع اعشاری زبان خودتان استفاده کنید:
BigDecimal،decimal.Decimal،Decimalاز یک کتابخانه، یا یک عدد صحیح از کوچکترین واحد آن ارز. amount،fee_amountوnet_amountرا بهصورت رشته یا نوع اعشاری در پایگاه دادهتان ذخیره کنید. یک ستونfloatیک باگ مغایرتگیری آهسته است.- مبالغ سفارش را با
amountو حسابهای خودتان را باnet_amountمغایرتگیری کنید. این دو به اندازه کارمزد کوینلند تفاوت دارند، و استفاده از یکی برای هر دو همان چیزی است که دفتر حساب را دچار انحراف میکند. پرداختها را ببینید. - مبالغ را با مقایسه اعشاری بسنجید، هرگز با
==روی عددهای پارسشده.
پیش از اولین پرداخت واقعی
کلید را بررسی کنید. GET /api/pay/v1/me کد ۲۰۰ برمیگرداند و accepted_currencies هر ارزی را دارد که
قصد قیمتگذاری با آن را دارید. کد شما آن فهرست را میخواند و ارزها را ثابت نکرده است.
یک جلسه بسازید و بخوانید. POST /sessions کد ۲۰۱ برمیگرداند و
GET /sessions/{reference_id} آن را با شناسه خودتان پیدا میکند. هر دو مبلغ رشته اعشاری هستند.
ایدمپوتنسی را اثبات کنید. همان POST /sessions را دو بار بفرستید. همان شناسه جلسه را میگیرید، نه دو
جلسه. بعد بار سوم با مبلغی تغییریافته بفرستید و تأیید کنید که PAY_DUPLICATE_REFERENCE میگیرید.
خودتان یکی را پرداخت کنید. با مبلغی کوچک از ارزی که دارید. تأیید کنید ویجت باز میشود، پرداخت تسویه
میشود، و موجودی شما به اندازه net_amount تغییر میکند.
تأیید کنید وبهوک میرسد و اعتبارسنجی میشود. هندلر شما امضا را بررسی میکند، پنجره پنجدقیقهای را اعمال میکند، در زمان ثابت مقایسه میکند، و درخواستی را که بدنهاش را عمداً دستکاری کردهاید رد میکند.
حذف تکراریها را اثبات کنید. همان ارسال را دوباره به اندپوینت خودتان بفرستید. سفارش باید یک بار تحویل
شود. سازوکار، یک قید یگانگی روی event_id است؛ یک SELECT و بعد INSERT رقابتی دارد که دو تلاش همزمان
پیدایش میکنند.
مسیر هدایت را آزمایش کنید. پنجرههای بازشو را در مرورگرتان مسدود کنید و دوباره پرداخت کنید. صفحه
return_url شما باید تحمل کند که پیش از رسیدن وبهوک باز شود و بهجای خطا حالت «در انتظار» نشان دهد.
لغو و انقضا را آزمایش کنید. یک جلسه را لغو کنید و تأیید کنید سفارشتان بسته میشود. بگذارید یکی منقضی
شود و تأیید کنید رویداد session.expired سبد را آزاد میکند.
یک رسید را آفلاین اعتبارسنجی کنید. توکن پرداخت آزمایشیتان را بردارید، با کلید امضای رسید بررسی کنید، بعد یک کاراکتر از محتوا را عوض کنید و تأیید کنید کد اعتبارسنجی شما آن را رد میکند.
پرداخت را بازخوانی کنید. GET /payments/{receipt_no} آن را با شماره رسید پیدا میکند و مبالغ با آنچه
مطالبه کرده بودید یکی است.
هویت مشتری
هر جلسه یکی از مشتریان شما را نام میبرد، و اولین پرداخت
حساب کوینلند پرداختکننده را برای همیشه به همان customer.id متصل میکند. سه چیز که
باید پیش از انتشار تعیین تکلیف شوند، و هیچکدام فقط کد نیستند:
- هویت واقعی بفرستید، هرگز مقدار جایگزین. شیء
customerباید از پایگاه داده مشتریان خودتان بیاید: شناسه داخلی واقعی، نام کامل واقعی به خط لاتین (و هر جا داریدnative_name)، ایمیل واقعی. مقداری مثل"guest"یا"test-user"میانبر نیست — یک حساب کوینلند واقعی را برای همیشه به هویت اشتباه گره میزند، و تنها راه خروج قطع اتصال و یک فرایند تازه است. اگر فروشگاهتان مسیر خرید مهمان دارد، اول رکورد مشتری را بسازید و همان را بفرستید. - رویداد
binding.reviewرا دریافت کنید و به یک انسان برسانید. اتصالی که در بررسی است یعنی مشتریای که خواست پرداخت کند و رد شد؛ تا کسی تأیید یا رد نکند، پول او نمیتواند برسد. صف بررسیِ بیناظر، درآمدِ بیصدا ازدسترفته است. - تعیین کنید چه کسی در کسبوکار شما اتصالهای در انتظار را بررسی میکند. صف در زبانه «مشتریان»
کنسول کسبوکار و پشت
POST /customers/{id}/binding/reviewاست — مالکش را انتخاب کنید و قاعدهای که اعمال میکند را به او بدهید: وقتی ناهمخوانی نام توضیحپذیر است تأیید، و وقتی نیست رد.
پیش از اولین پرداخت به مشتری
فقط اگر پول به بیرون میفرستید. پرداخت به مشتری یک مرحله مسلحسازی جداگانه است و بخشی از راهاندازی پرداختگیری شما نیست.
تأیید کنید مسلح هستید. کوینلند پرداخت به مشتری را برای کسبوکار شما فعال کرده و هر دو سقف دلاری
را تنظیم کرده باشد. تا وقتی هر دو برقرار نباشند، هر پرداختی MERCHANT_PAYOUTS_DISABLED میگیرد — سقفِ
تنظیمنشده یعنی «همه چیز رد میشود»، نه «بینهایت».
مبلغ کوچکی تسویه کنید با payer_id — هندلی که از خرید آزمایشیِ یک حساب آزمایشی دوم ساخته شده
(پرداخت به حساب کسبوکار خودتان بهعنوان تسویه به خود رد میشود). تأیید کنید آن حساب دقیقاً
amount را میگیرد و کیفپول کسبوکارتان به اندازه debited_amount کم میشود.
ایدمپوتنسی پرداخت را اثبات کنید. همان POST /payouts را دو بار بفرستید. بار دوم با کد ۲۰۱ و همان
شناسه پرداخت پاسخ میدهد و هیچ پولی جابهجا نمیکند. این مهمترین چیزی است که روی این ریل باید بررسی
کنید، چون حالت خرابیاش این است که به کسی دو بار پول بدهید.
یک پرداخت را جزئی بازپرداخت کنید. بعد باقیمانده را بازپرداخت کنید، بعد یکی دیگر امتحان کنید و تأیید
کنید PAY_REFUND_EXCEEDS_PAYMENT میگیرید. بررسی کنید که fee_amount در هر دو "0" بوده است.
سقف خودتان را عمداً رد کنید. پرداختی بالاتر از بیشینه هر پرداخت امتحان کنید و تأیید کنید کد شما
PAY_PAYOUT_LIMIT را به یک انسان نشان میدهد، نه اینکه مثل یک خطای گذرا دوباره تلاش کند.
عادتهای عملیاتی
فقط به وبهوک تکیه نکنید. وبهوک مسیر اصلی است، نه تنها مسیر. دو عادت ارزان، یکپارچهسازی را در برابر ارسالی که هرگز نمیرسد مقاوم میکند:
- صفحه
return_urlشماGET /sessions/{id}را استعلام میکند، در حالی که مشتری همانجا نگاه میکند، پس حالت رایج در یک ثانیه و مستقل از زمانبندی وبهوک حل میشود. - یک بازبینی روزانه پرداختهای اخیر را میخواند و با سفارشهای باز مغایرتگیری میکند، که هر چیزی را هم که وقتی سرور شما خواب بود پرداخت شده میگیرد.
به وبهوک سریع پاسخ دهید و کار را بعد انجام دهید. هندلری که پیش از پاسخ دادن کالا را ارسال میکند دیر یا زود از مهلت ارسال عبور میکند، و تلاش مجدد، بررسی ایدمپوتنسی شما را تنها چیزی مییابد که میان یک سفارش و دو سفارش ایستاده است.
کد و شناسهها را ثبت کنید. در هر خطا، کد ماشینی قالب خطا، شناسه جلسه و reference_id خودتان
را ثبت کنید. همین سهگانه برای پشتیبانی کوینلند کافی است تا رویداد دقیق را بدون رفتوبرگشت پیدا کند.
روی سکوت هشدار بگذارید. یک روز با صفر رویداد payment.completed در فروشگاهی که معمولاً پرداخت میگیرد،
نشانهای است که چیزی در سمت شما یا سمت ما شکسته است. هیچکس متوجه اندپوینت وبهوکی که بیصدا از کار افتاده
نمیشود، تا وقتی که حسابها کم بیایند.
کاری که این ریل انجام نمیدهد
ارزش دارد پیش از طراحی بر پایه آن بدانید:
- بازگشت خودکار ندارد. پرداخت تسویهشده نه خودبهخود برمیگردد و نه با فرایند اعتراض. برگرداندن پول یک بازپرداخت است که خودتان تصمیم به فرستادنش میگیرید، و کوینلند کارمزدی را که روی پرداخت اصلی گرفته نگه میدارد.
- دریافت جزئی و بلوکه کردن اعتبار ندارد. پرداخت بهصورت کامل تسویه میشود یا انجام نمیشود.
- تبدیل ارز ندارد. شما در هر ارزی که میپذیرید قیمت میگذارید و مشتری دقیقاً همان را میپردازد. همخوانی بین ارزها و ریسک بازار آن، مال شماست. جلسههای پرداخت را ببینید.
- پرداخت دورهای ندارد. در این ریل اشتراک وجود ندارد. هر پرداخت تکرارشونده یک جلسه تازه است که مشتری تأییدش میکند.
- فقط مشتریان کوینلند میتوانند پرداخت کنند. پرداختکننده به یک حساب کوینلند با موجودی نیاز دارد. این ریلی برای رسیدن به مشتریان کوینلند است، نه یک درگاه کارت عمومی.