راهنمای اتصال

اتصال ربات، سایت یا لینک فروش

این راهنما را نوشته‌ایم که اتصال بار اول درست انجام شود. اول چهار کار مشترک، بعد فقط مسیر خودتان را بخوانید.

اول این چهار کار (برای همه)

  1. کارت را ثبت کنید. پنل ← «کارت‌ها». پول مستقیم به همین کارت واریز می‌شود.
  2. گوشی را وصل کنید. اپ رسیدینو را روی گوشی‌ای نصب کنید که پیامک بانک همان کارت به آن می‌رسد، و از پنل ← «گوشی‌ها» با QR وصلش کنید. تا «سلامت اتصال» سبز نشده، ادامه ندهید.
  3. کلید API بسازید. پنل ← «اتصال و API» ← «کلید تازه». کلید یک رشتهٔ ۶۴ کاراکتری مثل 9f2c…e41a است و فقط یک‌بار نمایش داده می‌شود؛ همان لحظه جای امن بگذارید.
  4. اول آزمایشی، بعد واقعی. بالای پنل حالت «آزمایشی» را بزنید و یک کلید آزمایشی بسازید. با آن پرداخت‌ها واقعی نیستند و از صفحهٔ هر پرداخت می‌توانید «واریز آزمایشی» را شبیه‌سازی کنید.

مسیر شما کدام است؟

ربات یا سایت شما رسیدینو را دارد

  1. در تنظیمات درگاه‌های ربات، «رسیدینو» را فعال کنید.
  2. کلید API را در فیلد «کلید رسیدینو» بگذارید. آدرس سرور لازم نیست؛ داخل ربات ثابت است.
  3. اگر ربات «آدرس وب‌هوک» نشان می‌دهد، آن را در پنل ← «اتصال و API» ← «وب‌هوک» ثبت کنید و «رمز امضا»ی پنل را در ربات بگذارید.
  4. یک خرید آزمایشی با کلید آزمایشی انجام دهید، از پنل واریز را شبیه‌سازی کنید و ببینید سفارش در ربات تأیید می‌شود. بعد کلید واقعی را بگذارید.

ربات شما هنوز رسیدینو را ندارد؟ لینک همین صفحه را برای سازنده‌اش بفرستید؛ تب «سازندهٔ ربات فروش هستم» دقیقاً برای اوست.

برای سازندگان ربات فروش

کل اتصال پنج قدم است. آدرس پایه را در کد ثابت بگذارید و از فروشنده فقط کلید بخواهید:

RESIDINO_BASE = "https://api.residino.com"     // ثابت در کد ربات
RESIDINO_KEY  = تنظیمات ← «کلید رسیدینو» (۶۴ کاراکتر)

قدم ۱: ساخت پرداخت وقتی کاربر «خرید» می‌زند

POST https://api.residino.com/api/v1/pay
Authorization: Bearer <کلید>
Content-Type: application/json

{"amount": 250000, "order_id": "inv-1204", "title": "سرویس یک‌ماهه", "expires_in": "30m"}
  • amount به تومان و عدد صحیح است.
  • order_id شناسهٔ فاکتور خود ربات است. اگر درخواست به هر دلیلی تکرار شد، با همان order_id همان پرداخت قبلی برمی‌گردد و فاکتور دوتایی ساخته نمی‌شود. حروف انگلیسی، عدد و - _ . : تا ۶۴ کاراکتر.
  • expires_in مهلت پرداخت است، مثل "15m"، "1h" (بین ۲ دقیقه تا ۱ روز).
{"slug":"3b72…","pay_url":"https://api.residino.com/p/3b72…","order_id":"inv-1204",
 "amount":250000,"payable_amount":249900,"currency":"IRT",
 "card":{"number":"6104…","last4":"6650","holder":"…","bank_name":"ملت"},
 "expires_in":1800,"status":"pending"}

slug را کنار فاکتور ذخیره کنید؛ از این به بعد با همین شناسه پرداخت را پیدا می‌کنید.

قدم ۲: نشان دادن پرداخت به کاربر

روش پیشنهادی: یک دکمهٔ شیشه‌ای (inline) با متن «پرداخت» که به pay_url می‌رود. صفحهٔ پرداخت کارت، مبلغ دقیق، شمارش معکوس و تأیید لحظه‌ای را خودش نشان می‌دهد.

روش داخل ربات: اگر می‌خواهید کارت را در خود پیام نشان دهید، حتماً payable_amount را نشان دهید، نه amount. وقتی چند پرداخت هم‌مبلغ هم‌زمان باز است، مبلغ قابل پرداخت چند تومان فرق می‌کند تا واریزها با هم قاطی نشوند؛ مشتری باید دقیقاً همان را واریز کند.

💳 6104 3388 •••• 1234، بانک ملت، سارا ا…یدی

💰 دقیقاً ۲۴۹٬۹۰۰ تومان واریز کنید (گرد نکنید)

⏳ تا ۳۰ دقیقه. بعد از واریز خودکار تأیید می‌شود؛ رسید نفرستید.

قدم ۳: فهمیدن اینکه پرداخت انجام شد

با وب‌هوک (پیشنهادی): ربات یک آدرس عمومی مثل https://bot.example.com/residino.php دارد که فروشنده در پنل ثبت می‌کند. بعد از هر رویداد، رسیدینو یک درخواست POST با بدنهٔ JSON و هدر امضا می‌فرستد:

X-Webhook-Signature: sha256=<HMAC-SHA256(بدنهٔ خام، رمز امضا)>

{"event":"payment.paid","event_id":"…","slug":"3b72…","order_ref":"inv-1204",
 "amount":250000,"payable_amount_rial":2499000,"status":"paid","via":"auto"}

بدون آدرس عمومی: تا وقتی فاکتور باز است، هر ۱۰ تا ۱۵ ثانیه GET https://api.residino.com/api/v1/pay/{slug} را بخوانید و منتظر "status":"paid" بمانید. بعد از پایان مهلت، فاصله را بیشتر کنید (مثلاً هر ۵ دقیقه تا یک روز)، چون فروشنده ممکن است واریز دیرهنگام را دستی تأیید کند.

قدم ۴: تحویل سفارش دقیقاً یک‌بار

  • امضا را با hash_equals بررسی کنید؛ بدون امضای درست هیچ کاری نکنید.
  • وب‌هوک ممکن است بیش از یک‌بار برسد (اگر پاسخ ۲۰۰ ندهید، تا حدود ۱٫۵ روز دوباره فرستاده می‌شود). تحویل را فقط وقتی انجام دهید که فاکتور هنوز «پرداخت‌نشده» است، و هر دو را در یک تراکنش دیتابیس: UPDATE invoices SET status='paid' WHERE id=? AND status='unpaid' و فقط اگر یک ردیف تغییر کرد، سرویس را بسازید یا کیف پول را شارژ کنید.
  • payment.paid ممکن است بعد از payment.expired برسد (واریز دیرهنگامی که فروشنده تأیید کرده؛ "via":"late"). فاکتور منقضی را دوباره باز کنید و تحویل دهید؛ مشتری پول داده است.
  • هرگز به return_url یا پیام کاربر اعتماد نکنید؛ تأیید فقط از وب‌هوک امضاشده یا خواندن وضعیت با کلید API.

قدم ۵: آزمایش و انتشار

  1. با کلید آزمایشی یک خرید بسازید؛ در پنل (حالت آزمایشی) ← «پرداخت‌ها» ← همان پرداخت ← «شبیه‌سازی واریز».
  2. ببینید سفارش یک‌بار تحویل شد. بعد همان درخواست وب‌هوک را (با همان بدنه و امضا که در لاگ گیرنده دارید) یک‌بار دیگر خودتان به گیرنده بفرستید و مطمئن شوید دوبار تحویل نمی‌شود.
  3. یک پرداخت را منقضی کنید و بعد شبیه‌سازی کنید؛ تحویل دیرهنگام باید درست کار کند.
  4. کلید را در لاگ‌ها ننویسید و در پیام خطا به کاربر نشان ندهید.

نمونه‌کد

هر نمونه کامل است: مهلت درخواست، بررسی کد پاسخ و بررسی امضا را دارد. کلید را در تنظیمات یا متغیر محیطی نگه دارید، نه در کد.

<?php
// ساخت پرداخت
function residino_pay(string $key, int $toman, string $orderId, string $title): array {
    $ch = curl_init('https://api.residino.com/api/v1/pay');
    curl_setopt_array($ch, [
        CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 15,
        CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $key, 'Content-Type: application/json'],
        CURLOPT_POSTFIELDS => json_encode(['amount' => $toman, 'order_id' => $orderId, 'title' => $title, 'expires_in' => '30m']),
    ]);
    $res = json_decode((string) curl_exec($ch), true) ?: [];
    $code = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
    curl_close($ch);
    if ($code !== 200) {
        throw new RuntimeException($res['error'] ?? 'residino_unavailable');
    }
    return $res; // pay_url, payable_amount, card, slug
}

// residino.php — گیرندهٔ وب‌هوک
$raw = file_get_contents('php://input');
$sig = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';
if (!hash_equals('sha256=' . hash_hmac('sha256', $raw, RESIDINO_WEBHOOK_SECRET), $sig)) {
    http_response_code(400);
    exit;
}
$e = json_decode($raw, true);
if ($e['event'] === 'payment.paid') {
    $pdo->beginTransaction();
    $q = $pdo->prepare("UPDATE invoices SET status = 'paid' WHERE order_id = ? AND status IN ('unpaid', 'expired')");
    $q->execute([$e['order_ref']]);
    if ($q->rowCount() === 1) {
        deliver_order($e['order_ref']); // ساخت سرویس / شارژ کیف پول، فقط همین‌جا
    }
    $pdo->commit();
}
http_response_code(200);

خطاهای رایج و پیامی که به مشتری نشان دهید

خطایعنیبه مشتری بگویید
unauthorizedکلید اشتباه یا باطل شده«درگاه موقتاً در دسترس نیست»؛ به فروشنده خبر دهید
amount_out_of_rangeمبلغ خارج از کمترین/بیشترین مبلغ تنظیمات فروشنده«این مبلغ با کارت‌به‌کارت قابل پرداخت نیست»
no_card_availableکارت فعالی نیست یا سقف روزانه پر شده«کمی بعد دوباره تلاش کنید»
subscription_inactiveاشتراک فروشنده تمام شده«درگاه موقتاً در دسترس نیست»
rate_limitedدرخواست زیاد در زمان کوتاهچند ثانیه بعد خودکار دوباره تلاش کنید

برای سایت‌های فروشگاهی

همان پنج قدم بالا، با دو نکته:

  • هنگام ساخت پرداخت return_url بدهید تا مشتری بعد از پرداخت به سایت برگردد. به آدرس شما slug و status اضافه می‌شود، اما سفارش را فقط بعد از خواندن وضعیت با API یا رسیدن وب‌هوک تأیید کنید.
  • برای امنیت، در پنل ← «تنظیمات» ← «پیشوند مجاز آدرس بازگشت» دامنهٔ سایت خود را بگذارید تا آدرس بازگشت دیگری پذیرفته نشود.

اگر سایت شما مبلغ را به ریال نگه می‌دارد، از API اختصاصی (POST /v1/payments با amount_rial) استفاده کنید. افزونهٔ آمادهٔ ووکامرس در راه است.

خطاهای رایج و پیامی که به مشتری نشان دهید در تب «سازندهٔ ربات فروش هستم» آمده است.

جایی گیر کردید؟ بخش «وب‌هوک» در پنل ← «اتصال و API» نشان می‌دهد هر رویداد تحویل شد یا نه و گیرندهٔ شما چه کد پاسخی داد. برای سازندگان ربات، کمک در اتصال رایگان است.