فروشگاه: پرداختها
Nexora Shop هیچ درگاه پرداختی همراه ندارد. چیزی که همراه دارد راههایی برای گرفتن پول است که اصلاً درگاه نیستند (کارتبهکارت، که یک نفر از روی رسید مشتری یا پیامک بانک شما تأییدش میکند) و یک توانایی عمومی: یک درگاه HTTP عمومی، قرارداد کوچکی بر پایهٔ JSON که میتوانید به هر واسطهای که انتخاب میکنید وصلش کنید. اینکه آن واسطه کدام باشد، و اینکه اجازهٔ استفاده از آن را دارید یا نه، تصمیم و مسئولیت خودتان است.
همهٔ اینها را زیر روشهای پرداخت در بخش مدیریت فروشگاه تنظیم کنید.
پول و کیف پول
هر مبلغ یک عدد صحیح به کوچکترین واحد ارز است، کنار کد ارز. پولی که مشتری میپردازد اول به کیف پول او میرود و سفارش از آنجا پرداخت میشود. اگر کمی بیشتر بپردازد، باقیاش در کیف پول میماند، و سفارشی که کیف پول از قبل پوشش میدهد اصلاً پرداختی لازم ندارد.
کارتبهکارت
کارتهایتان را اضافه کنید (شماره، بانک، صاحب کارت، ارز). کارتهای یک ارز به نوبت داده میشوند: به هر پرداخت کارتی میرسد که مدت بیشتری از آخرین استفادهاش گذشته است.
هر پرداخت کارتی از مشتری یک مبلغ یکتا میخواهد: قیمت بهعلاوهٔ چند واحد، طوری که هیچ پرداخت باز دیگری در همان ارز همان مبلغ را نخواهد. این چند واحد در کیف پول مشتری میماند. مبلغ یکتا راهی است که هر واریز با پرداختش جفت میشود.
- هر پرداخت به طور پیشفرض ۶۰ دقیقه باز است، اما مبلغش تا یک روز نگه داشته میشود، تا واریزی که دیر میرسد باز هم روی پرداخت خودش بنشیند.
- مشتریای که دوباره برای همان سفارش پرداخت بخواهد، همان پرداخت باز را میبیند.
- هر مشتری به طور پیشفرض حداکثر ۱۰ پرداخت کارتی در روز باز میکند، تا کلیکهای رهاشده یا یک اسکریپت نتوانند همهٔ مبلغهای نزدیک یک قیمت را نگه دارند.
پرداخت کارتی به یکی از دو راه تأیید میشود.
یک نفر، از روی رسید
مشتری چهار رقم آخر کارتی را که از آن پرداخته، همراه با عکس یا PDF رسید یا شمارهٔ پیگیری بانک میفرستد. رسید در رسیدها در بخش مدیریت فروشگاه منتظر میماند و، وقتی ربات تنظیم شده باشد، در یک تاپیک فروم در گروه تلگرام ادمینهایتان با دکمههای تأیید و رد.
- فقط کاربرهای تلگرامی که به عنوان تأییدکننده فهرست کردهاید میتوانند دربارهٔ رسید تصمیم بگیرند.
- رسیدی که در هر جا (بخش مدیریت، تلگرام یا پیامک بانک) دربارهٔ آن تصمیم گرفته شود روی پستش علامت میخورد. دو بار تأیید کردن، یا تأیید همزمان از دو جا، یک بار پرداخت میکند.
- شمارهٔ پیگیریای که قبلاً استفاده شده رد میشود، و همینطور همان رسید دوباره، حتی اگر بار اول رد شده باشد.
- تصویری که فقط شبیه یک رسید قبلی است پذیرفته میشود اما با پرداختی که به آن شبیه است علامت میخورد. رسیدهای یک بانک چیدمان یکسانی دارند، پس مقایسه با شماست.
با پیامک بانک شما
پیامکهای بانکتان را از گوشی به فروشگاه بفرستید. مبلغ واریز، همان پرداختی را که دقیقاً آن مبلغ را خواسته تأیید میکند، بدون نیاز به هیچ آدمی. فرستنده هر پیامک را به https://<shop>/pay/hook/card میفرستد، امضاشده با رمز پیامک که زیر روشهای پرداخت نشان داده میشود (پایینتر).
- بدنه JSON با
textپیامک است، یا خود متن پیامک. میتواندamountداشته باشد وقتی فرستنده مبلغ را خودش میخواند، وcardوقتی یک گوشی پیامک چند کارت را میگیرد. - فروشگاه واریز را از شکلهای رایج، از جمله با ارقام فارسی، میخواند و هرگز از مانده، تاریخ، ساعت یا شمارهٔ حساب پوشاندهشده. برداشت هیچ چیزی را تأیید نمیکند.
- واحد پیامک به هر واحد یک کارت، واحد بانک را به ارز کارت تبدیل میکند: بانکها ریال میشمارند، پس کارتی با ارز تومان مبلغ پیامک را بر ۱۰ تقسیم میکند. اگر پیامک بانکتان تومان میشمارد، آن را ۱ بگذارید.
- همان پیامک اگر دو بار فرستاده شود، پرداخت را یک بار ثبت میکند. پیامکی که مبلغش را هیچ پرداخت بازی نخواسته، برای بررسی شما نگه داشته میشود.
- پیامکی با مبلغ پرداختی که رسیدش رد شده هیچ چیزی ثبت نمیکند: رسید به رسیدها برمیگردد تا یک نفر بررسیاش کند.
- اگر رمز لو رفت، ساختن رمز تازه را بزنید؛ رمز قبلی همان لحظه از کار میافتد.
پیامک بدون امضا
فرستندهای که نمیتواند امضا کند میتواند خود رمز را بفرستد، اما فقط وقتی پیامکهایی را که بهجای امضا خود رمز را دارند هم بپذیر را روشن کنید. هر کسی که چنین درخواستی را ببیند میتواند واریز جعل کند، پس تا فرستندهتان به آن نیاز ندارد خاموشش بگذارید.
جوابهای فروشگاه:
| وضعیت | معنی |
|---|---|
2xx | پذیرفته شد. همان پیامک اگر بعد از ثبت دوباره امضا و فرستاده شود، با 200 به عنوان «قبلاً شنیدهشده» جواب میگیرد. |
401 | امضا اشتباه است، یا زمانش بیش از پنج دقیقه با ساعت فروشگاه فاصله دارد. ساعت فرستنده را بررسی کنید و دوباره امضا کنید. |
409 | دقیقاً همان درخواست امضاشده بعد از ثبت پرداخت: آن را انجامشده بدانید. |
429 | این نشانی در ده دقیقه بیست درخواست ردشده فرستاده است. صبر کنید. |
503 | فروشگاه همین الان نتوانست آن را نگه دارد یا ثبت کند. دوباره بفرستید، با امضای زمان فعلی. |
400 | بدنه پیامک نیست. فرستادن دوباره چیزی را تغییر نمیدهد. |
درگاه HTTP عمومی
یک درگاه در فروشگاه چهار آدرس در سمت شما است، معمولاً یک رلهٔ کوچک جلوی واسطهای که انتخاب کردهاید، بهعلاوهٔ یک رمز مشترک:
| آدرس | الزامی | فروشگاه با آن چه میکند |
|---|---|---|
| Create | بله | صفحهٔ پرداخت میخواهد. |
| Verify | میپرسد آیا پرداختی انجام شده است. | |
| Refund | میخواهد پول برگردانده شود. | |
| Health | بررسی میکند درگاه میتواند پول بگیرد یا نه. |
هر درگاه ارزهای خودش و یک کلید روشن و خاموش دارد. اگر رمز را ندهید، فروشگاه خودش یکی میسازد. آدرس عمومی فروشگاه باید تنظیم شده باشد، چون درگاه مشتری را به آنجا برمیگرداند (فروشگاه: پورتال مشتری).
امضا
هر درخواست در هر دو جهت، و هر درخواستی که فروشگاه به سرویسی از شما میفرستد، به یک شکل امضا میشود: هدر X-Nexora-Timestamp (ثانیهٔ Unix) و X-Nexora-Signature، یعنی HMAC-SHA256 به صورت hex روی <timestamp>.<raw body> با رمز. امضای فروشگاه را در رلهتان بررسی کنید. فروشگاه callbackی را که امضایش اشتباه است یا زمانش بیش از پنج دقیقه با ساعت فروشگاه فاصله دارد رد میکند.
TS=$(date +%s)
BODY='{"text":"..."}'
SIG=$(printf '%s.%s' "$TS" "$BODY" | openssl dgst -sha256 -hmac "$SECRET" -hex | sed 's/^.* //')
curl -X POST https://shop.example.com/pay/hook/card \
-H "X-Nexora-Timestamp: $TS" -H "X-Nexora-Signature: $SIG" \
-H 'Content-Type: application/json' --data "$BODY"Create
POST <create address>
{"checkout": "ck_9f2…", "amount": 150000, "currency": "IRT",
"description": "order 12", "language": "en",
"callbackUrl": "https://<shop>/pay/hook/gateway-1",
"returnUrl": "https://<shop>/pay/return/ck_9f2…"}با 200 و {"payUrl": "https://…", "reference": "<your id>"} جواب دهید. فروشگاه مشتری را به payUrl میفرستد. وقتی کارش تمام شد، او را به returnUrl برگردانید؛ فروشگاه بعد verify را میپرسد و نتیجه را نشان میدهد. language زبان خود مشتری است: fa، en، ru یا zh.
Callback
POST <callbackUrl>
{"checkout": "ck_9f2…", "reference": "<your id>", "status": "paid",
"amount": 150000, "currency": "IRT"}status یکی از paid، pending یا failed است. وقتی درگاه آدرس verify دارد، callback فقط یک اشاره است: فروشگاه پیش از ثبت هر چیزی verify را میپرسد. تکرار callback بیخطر است؛ هر checkout یک بار پرداخت میشود. کدهای وضعیتی که فروشگاه جواب میدهد همان معنای پیامک بانک در بالا را دارند: 409 وقتی پرداخت ثبت شده (فرستادنش را متوقف کنید)، 503 برای فرستادن دوباره با امضای زمان فعلی، 400 برای بدنهای که مطابق قرارداد نیست، 429 بعد از بیست callback با امضای بد در ده دقیقه از یک نشانی.
Verify
POST <verify address>
{"checkout": "ck_9f2…", "reference": "<your id>", "amount": 150000, "currency": "IRT"}با همان شکل callback جواب دهید. فروشگاه وقتی میپرسد که مشتری برمیگردد، وقتی callback میرسد، هر چند دقیقه تا سه ساعت برای پرداختی که callbackش هرگز نرسید، و هر ربع ساعت تا یک روز دربارهٔ checkoutی که در سمت فروشگاه بسته شده، تا پولی که با این حال در درگاه پرداخت شده باز هم به کیف پول مشتری برسد. پولی که به ارزی غیر از ارز خواستهشده پرداخت شده، منتظر تأیید شما میماند.
Refund
POST <refund address>
Idempotency-Key: shop-refund-7-3f9a…
{"checkout": "ck_9f2…", "reference": "<your id>", "amount": 50000,
"currency": "IRT", "idempotencyKey": "shop-refund-7-3f9a…"}فروشگاه مبلغ را پیش از پرسیدن از کیف پول مشتری برمیدارد، و هر بازپرداخت را با یک کلید نامگذاری میکند. رلهٔ شما برای هر کلید یک بازپرداخت انجام میدهد: کلیدی که دوباره پرسیده شود همان جواب بار اول را میگیرد و هرگز دو بار بازپرداخت نمیشود.
| جواب شما | کاری که فروشگاه میکند |
|---|---|
2xx | بازپرداخت انجام شده است. |
یک 4xx با {"refused": true, "reason": "…"} | با این کلید هیچ چیزی بازپرداخت نشده و نخواهد شد. پول به کیف پول برمیگردد و مدیر دلیل را میبیند. فقط وقتی این را بفرستید که مطمئن باشید. |
| هر چیز دیگر | هیچ چیزی قطعی نیست. بازپرداخت در راه میماند، بیرون از کیف پول، و مدیر میتواند با همان کلید دوباره بپرسد. |
بدون آدرس refund، پول مشتری را دستی با برداشت در صفحهٔ او زیر مشتریها برگردانید.
Health
health یک GET است که تا وقتی درگاه میتواند پول بگیرد 2xx جواب میدهد. فروشگاه هر دقیقه میپرسد؛ پرداختی که نتوانست باز کند هم همین حساب را دارد. بعد از سه شکست پشت سر هم درگاه از کار افتاده است: به مشتریها راههای دیگر پرداخت پیشنهاد میشود، و به گروه تلگرام ادمینها و داشبورد خبر داده میشود. اولین جواب سالم آن را برمیگرداند. درگاهی که آدرس health ندارد، پانزده دقیقه بعد از ازکارافتادن دوباره امتحان میشود.
نرخ ارز
هر نرخ میگوید یک واحد از یک ارز چند واحد از ارز دیگر میارزد. آن را زیر روشهای پرداخت ← نرخ ارز تنظیم کنید. منبعش هر آدرس JSON است که انتخاب کنید (فروشگاه هیچ منبعی را نام نمیبرد)، با مسیر عدد در جوابش، مثل data.price، و یک ضریب. فروشگاه هر ده دقیقه میپرسد. نرخ دستی وقتی به کار میرود که منبع در محدودهٔ اعتبارش (پیشفرض ۶۰ دقیقه) جواب نداده باشد، یا وقتی خودتان آن را انتخاب کنید.
نرخ دو کار میکند:
- محصولی که فقط قیمت ارز دیگری دارد به ارز فروشگاه و با نرخ روز فروخته میشود، با گرد کردن به بالا تا گامی که تعیین میکنید.
- درگاهی که فقط ارز دیگری میپذیرد برای ارز فروشگاه هم پیشنهاد میشود. checkout مبلغ تبدیلشده را میخواهد و کیف پول را به اندازهٔ مبلغ بدهی شارژ میکند، با نرخی که هنگام باز شدن پرداخت قفل شده است. چنین پرداختی دستی بازپرداخت میشود.
