اول این چهار کار (برای همه)
- کارت را ثبت کنید. پنل ← «کارتها». پول مستقیم به همین کارت واریز میشود.
- گوشی را وصل کنید. اپ رسیدینو را روی گوشیای نصب کنید که پیامک بانک همان کارت به آن میرسد، و از پنل ← «گوشیها» با QR وصلش کنید. تا «سلامت اتصال» سبز نشده، ادامه ندهید.
- کلید API بسازید. پنل ← «اتصال و API» ← «کلید تازه». کلید یک رشتهٔ ۶۴ کاراکتری مثل
9f2c…e41aاست و فقط یکبار نمایش داده میشود؛ همان لحظه جای امن بگذارید. - اول آزمایشی، بعد واقعی. بالای پنل حالت «آزمایشی» را بزنید و یک کلید آزمایشی بسازید. با آن پرداختها واقعی نیستند و از صفحهٔ هر پرداخت میتوانید «واریز آزمایشی» را شبیهسازی کنید.
مسیر شما کدام است؟
ربات یا سایت شما رسیدینو را دارد
- در تنظیمات درگاههای ربات، «رسیدینو» را فعال کنید.
- کلید API را در فیلد «کلید رسیدینو» بگذارید. آدرس سرور لازم نیست؛ داخل ربات ثابت است.
- اگر ربات «آدرس وبهوک» نشان میدهد، آن را در پنل ← «اتصال و API» ← «وبهوک» ثبت کنید و «رمز امضا»ی پنل را در ربات بگذارید.
- یک خرید آزمایشی با کلید آزمایشی انجام دهید، از پنل واریز را شبیهسازی کنید و ببینید سفارش در ربات تأیید میشود. بعد کلید واقعی را بگذارید.
ربات شما هنوز رسیدینو را ندارد؟ لینک همین صفحه را برای سازندهاش بفرستید؛ تب «سازندهٔ ربات فروش هستم» دقیقاً برای اوست.
برای سازندگان ربات فروش
کل اتصال پنج قدم است. آدرس پایه را در کد ثابت بگذارید و از فروشنده فقط کلید بخواهید:
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.
قدم ۵: آزمایش و انتشار
- با کلید آزمایشی یک خرید بسازید؛ در پنل (حالت آزمایشی) ← «پرداختها» ← همان پرداخت ← «شبیهسازی واریز».
- ببینید سفارش یکبار تحویل شد. بعد همان درخواست وبهوک را (با همان بدنه و امضا که در لاگ گیرنده دارید) یکبار دیگر خودتان به گیرنده بفرستید و مطمئن شوید دوبار تحویل نمیشود.
- یک پرداخت را منقضی کنید و بعد شبیهسازی کنید؛ تحویل دیرهنگام باید درست کار کند.
- کلید را در لاگها ننویسید و در پیام خطا به کاربر نشان ندهید.
نمونهکد
هر نمونه کامل است: مهلت درخواست، بررسی کد پاسخ و بررسی امضا را دارد. کلید را در تنظیمات یا متغیر محیطی نگه دارید، نه در کد.
<?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);
import hashlib, hmac, httpx
BASE = "https://api.residino.com"
async def residino_pay(key: str, toman: int, order_id: str, title: str) -> dict:
async with httpx.AsyncClient(timeout=15) as c:
r = await c.post(f"{BASE}/api/v1/pay",
headers={"Authorization": f"Bearer {key}"},
json={"amount": toman, "order_id": order_id, "title": title, "expires_in": "30m"})
r.raise_for_status()
return r.json() # pay_url, payable_amount, card, slug
def valid_signature(raw: bytes, header: str, secret: str) -> bool:
expected = "sha256=" + hmac.new(secret.encode(), raw, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, header or "")
// Node.js 18+ (fetch داخلی) — ساخت پرداخت و بررسی امضای وبهوک
import crypto from "node:crypto";
const BASE = "https://api.residino.com";
export async function residinoPay(key, toman, orderId, title) {
const res = await fetch(`${BASE}/api/v1/pay`, {
method: "POST",
headers: { Authorization: `Bearer ${key}`, "Content-Type": "application/json" },
body: JSON.stringify({ amount: toman, order_id: orderId, title, expires_in: "30m" }),
signal: AbortSignal.timeout(15000),
});
const data = await res.json();
if (!res.ok) throw new Error(data.error ?? "residino_unavailable");
return data; // pay_url, payable_amount, card, slug
}
// بدنهٔ خام را امضا کنید، نه JSON دوبارهساختهشده را
export function validSignature(rawBody, header, secret) {
const expected = "sha256=" + crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
const a = Buffer.from(expected), b = Buffer.from(header ?? "");
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
# ساخت پرداخت
curl -sS -X POST "https://api.residino.com/api/v1/pay" -H "Authorization: Bearer $RESIDINO_KEY" -H "Content-Type: application/json" -d '{"amount": 250000, "order_id": "inv-1204", "title": "اشتراک یکماهه"}'
# وضعیت پرداخت
curl -sS "https://api.residino.com/api/v1/pay/3b72…" -H "Authorization: Bearer $RESIDINO_KEY"
خطاهای رایج و پیامی که به مشتری نشان دهید
| خطا | یعنی | به مشتری بگویید |
|---|---|---|
unauthorized | کلید اشتباه یا باطل شده | «درگاه موقتاً در دسترس نیست»؛ به فروشنده خبر دهید |
amount_out_of_range | مبلغ خارج از کمترین/بیشترین مبلغ تنظیمات فروشنده | «این مبلغ با کارتبهکارت قابل پرداخت نیست» |
no_card_available | کارت فعالی نیست یا سقف روزانه پر شده | «کمی بعد دوباره تلاش کنید» |
subscription_inactive | اشتراک فروشنده تمام شده | «درگاه موقتاً در دسترس نیست» |
rate_limited | درخواست زیاد در زمان کوتاه | چند ثانیه بعد خودکار دوباره تلاش کنید |
برای سایتهای فروشگاهی
همان پنج قدم بالا، با دو نکته:
- هنگام ساخت پرداخت
return_urlبدهید تا مشتری بعد از پرداخت به سایت برگردد. به آدرس شماslugوstatusاضافه میشود، اما سفارش را فقط بعد از خواندن وضعیت با API یا رسیدن وبهوک تأیید کنید. - برای امنیت، در پنل ← «تنظیمات» ← «پیشوند مجاز آدرس بازگشت» دامنهٔ سایت خود را بگذارید تا آدرس بازگشت دیگری پذیرفته نشود.
اگر سایت شما مبلغ را به ریال نگه میدارد، از API اختصاصی (POST /v1/payments با amount_rial) استفاده کنید. افزونهٔ آمادهٔ ووکامرس در راه است.
خطاهای رایج و پیامی که به مشتری نشان دهید در تب «سازندهٔ ربات فروش هستم» آمده است.
بدون سایت و ربات: لینک فروش
- در پنل ← «لینک فروش» عنوان و مبلغ را بنویسید؛ یا بگذارید مشتری مبلغ را خودش وارد کند (مثلاً برای شارژ کیف پول).
- لینک کوتاه را کپی کنید و در بیو اینستاگرام، استوری، کانال یا پیام بگذارید؛ QR آن را هم میتوانید چاپ کنید.
- هر مشتری با باز کردن لینک، پرداخت خودش با مبلغ یکتا را میگیرد و واریزش چند ثانیه بعد تأیید میشود. فروشها در «پرداختها» و تلگرامتان دیده میشوند.
جایی گیر کردید؟ بخش «وبهوک» در پنل ← «اتصال و API» نشان میدهد هر رویداد تحویل شد یا نه و گیرندهٔ شما چه کد پاسخی داد. برای سازندگان ربات، کمک در اتصال رایگان است.