پیش از شروع
آدرس پایه {pay} |
توسعه: https://pay-dev.karizmastudios.orgاصلی: https://pay.baziness.com |
| چه کسی صدا میزند | سرور شما. کلاینت فقط صفحهی پرداخت را باز میکند و بقیهی کارها را با سرور خود شما انجام میدهد |
pname |
نام بستهی پرداخت شما؛ ممکن است با نام بستهی پلتفرم فرق کند |
sku |
شناسهی محصولی که در داشبورد بازینس ثبت شده (مثلاً example_pack) |
uid |
شناسهی ثابت بازیکن در بازی شما، و باید عددی باشد (به شکل رشته بفرستید، مثلاً "1042"). uid غیرعددی با no_required_params رد میشود |
sequenceDiagram autonumber participant P as Player participant C as Your client participant S as Your server participant Y as Baziness Pay P->>C: taps "Buy" C->>S: start a purchase S-->>C: payment id + payment page URL C->>Y: opens the payment page (new tab) P->>Y: pays P->>C: returns to the game (or taps «پرداخت کردم») C->>S: verify my purchase S->>Y: get_payment Y-->>S: payment token S->>Y: verify_payment Y-->>S: success S->>S: give the item — exactly once S-->>C: done + new balances S->>Y: consume
قدم ۱ — باز کردن صفحهی پرداخت
چه کار میکند: صفحهی پرداخت بازینس را برای یک محصول به بازیکن نشان میدهد.
چطور: وقتی بازیکن «خرید» را میزند، کلاینت از سرور شما میخواهد خرید را شروع کند. سرور یک سفارش ذخیره میکند (قدم ۴ را ببینید)، آدرس صفحه را میسازد و برمیگرداند. کلاینت آن را در تب جدید (وب) یا مرورگر سیستم (موبایل) باز میکند.
GET {pay}/buy?sku=example_pack&uid=1042&pname=com.karizmastudio.example
→ the hosted payment page (opened in a new tab / the system browser)پیشنهاد
مرورگرها تبی را که مستقیم با ضربهی بازیکن باز نشده باشد مسدود میکنند. اول در همان رویداد ضربه یک تب خالی باز کنید، بعد وقتی سرور جواب داد آن را به آدرس ببرید (کد کلاینت).
قدم ۲ — بررسی اینکه بازیکن پرداخت کرده یا نه
چه کار میکند: از بازینس میپرسد این بازیکن برای این محصول پرداخت کاملشده و هنوز مصرفنشدهای دارد یا نه، و اگر دارد توکن پرداخت را برمیگرداند.
کِی صدایش بزنید: وقتی بازیکن به بازی برمیگردد (پنجره یا اپ دوباره فوکوس میگیرد)، وقتی «پرداخت کردم» را میزند، و وقتی فروشگاه باز میشود، برای پرداختهایی که وقتی بازی بسته بود تمام شدهاند.
POST {pay}/get_payment
Content-Type: application/json
{ "uid": "1042", "sku": "example_pack", "pname": "com.karizmastudio.example" }
→ 200 OK (paid, not consumed yet)
{ "uid": "1042", "sku": "example_pack", "token": "TEST-633…", "time": 1791366000000, "success": true }
→ 200 OK (nothing to verify yet — the player hasn't paid)
{ "error": "payment_is_not_valid", "success": false }payment_is_not_valid یعنی «هنوز پرداختی نیست»: بیصدا منتظر بمانید.
قدم ۳ — تأیید پرداخت
چه کار میکند: از بازینس تأیید میگیرد که توکن پرداخت واقعی است. این همان درخواستی است که از شما محافظت میکند: هیچوقت بر اساس حرف کلاینت چیزی ندهید.
POST {pay}/verify_payment
Content-Type: application/x-www-form-urlencoded
uid=1042&token=TEST-633…&sku=example_pack&pname=com.karizmastudio.example
→ 200 OK
{ "success": true }هشدار
verify_paymentبدنه را به شکل فرم (application/x-www-form-urlencoded) میگیرد؛ بقیهی درخواستها JSON. فرستادن JSON در اینجا رایجترین دلیل شکست تأیید است.
قدم ۴ — دادن آیتم، دقیقاً یک بار
بازینس به شما میگوید پرداخت واقعی است؛ اینکه بازیکن آیتم را یک بار بگیرد کار سرور شماست. یک جدول پرداختها در دیتابیس نگه دارید:
| ستون | معنی |
|---|---|
id |
شناسهی سفارش شما (در قدم ۱ به کلاینت برمیگردد) |
user_id، product_id، sku، price |
چه کسی چه چیزی میخرد |
status |
REDIRECTED (صفحهی پرداخت باز شد) ← FULFILLED (آیتم داده شد)، یا FAILED / CANCELLED |
reward_snapshot |
دقیقاً همان چیزی که هنگام زدن «خرید» به بازیکن وعده داده شد |
provider_token |
توکن پرداخت از قدم ۲، با محدودیت یکتا |
بعد از قدم ۳ موفق، در یک تراکنش دیتابیس:
- ردیف سفارش را قفل کنید و ببینید از قبل
FULFILLEDنباشد. اگر هست، بدون دادن دوبارهی آیتم «انجام شد» را برگردانید. - اگر همین توکن پرداخت قبلاً سفارش دیگری را تحویل داده، این یکی را
FAILEDکنید و متوقف شوید. - آیتمهای
reward_snapshotرا بدهید، نه تعریف فعلی محصول را. مدیری که وسط پرداخت بازیکن یک بسته را ویرایش میکند نباید سفارش او را عوض کند. - توکن را ذخیره کنید و سفارش را
FULFILLEDکنید.
قدم ۵ — مصرف کردن خرید
چه کار میکند: خرید را مصرفشده علامت میزند تا همان محصول دوباره قابل خرید باشد. تا وقتی مصرف نشده، قدم ۲ همچنان آن را برمیگرداند و خرید دوم آن SKU مسدود است.
کِی: درست بعد از ثبت نهایی قدم ۴. اگر شکست خورد چند بار دوباره تلاش کنید؛ آیتم قبلاً داده شده، پس شکست این قدم هیچوقت بازیکن را معطل نمیکند.
POST {pay}/consume
Content-Type: application/json
{ "uid": "1042", "sku": "example_pack", "pname": "com.karizmastudio.example" }
→ 200 OK
{ "success": true }چیزی که بازیکن میبیند
| لحظه | کلاینت شما نشان میدهد |
|---|---|
| بعد از زدن «خرید» | یک پنجرهی کوچک: «صفحهی پرداخت بازینس باز شد، بعد از پرداخت به بازی برگرد»، با دکمهی «پرداخت کردم» |
| برگشت به بازی، هنوز پرداختی پیدا نشده | چیز تازهای نشان نمیدهد (بررسی بیصدا)؛ فقط زدن «پرداخت کردم» میگوید «پرداختی پیدا نشد، چند لحظه بعد دوباره بررسی کن» |
| پرداخت تأیید شد | «خرید موفق» و موجودیهای بهروز |
| پنجره پیش از پرداخت بسته شد | چیزی لغو نمیشود؛ دفعهی بعد که فروشگاه باز شود دوباره بررسی میشود |
تست
- روی pay-dev صفحهی پرداخت گزینهی «خرید آزمایشی» دارد: کل جریان، از قدم ۱ تا ۵، بدون پول واقعی اجرا میشود.
- اگر به هیچ درگاهی دسترسی ندارید، از درگاه آزمایشی محلی بازی نمونه استفاده کنید: همان پروتکل را دارد، با دکمهی «پرداخت موفق» (تنظیمات).
بیلدهای فروشگاهی (بازار / مایکت)
بیلدی که در کافهبازار یا مایکت منتشر میشود باید از پرداخت درونبرنامهای خود آن فروشگاه استفاده کند، نه پرداخت بازینس. نام SKUها را در هر دو یکی نگه دارید تا یک فهرست محصول برای همهی بیلدها کافی باشد، و در آن بیلدها buildStore را روی لینک صفحههای بازینس بفرستید (پارامترها).