راهنمای اتصال نمایندگان (API)
آدرس پایه: https://pay.tomanpay.online
شروع سریع
- در ربات، از منوی 🔑 کلید API یک کلید بسازید. کلید فقط یکبار نمایش داده میشود؛ آن را امن ذخیره کنید.
- از منوی ⚙️ تنظیمات وبهوک:
- آدرس وبهوک را تنظیم کنید.
- کلید امضا را دریافت کنید.
- در صورت تمایل، دامنههای مجاز بازگشت را تعیین کنید.
- در سایت خود:
- با
requestپرداخت بسازید و کاربر را بهpayment_urlبفرستید. - پس از بازگشت کاربر، امضا را بررسی کنید یا با
inquiryوضعیت را بپرسید.
curl -X POST https://pay.tomanpay.online/v1/payments/request -H "Authorization: Bearer tp_xxxxxxxxxxxx_xxxxxxxx" -H "Content-Type: application/json" -d '{"amount": 250000, "callback_url": "https://shop.com/payment/return", "order_id": "1001"}'
قواعد کلی
همه درخواستها POST با بدنه JSON هستند و هدر زیر را لازم دارند:
Authorization: Bearer <کلید API شما>
محدودیت: ۶۰ درخواست در دقیقه برای هر کلید API (خطای 60، با هدر Retry-After).
همه پاسخها با کد HTTP 200 برمیگردند. موفقیت: "status": "success"؛ خطا:
{"status": "error", "error_code": "..", "error_message": ".."}.
مشخصات OpenAPI (برای Postman و ابزارهای مشابه): https://pay.tomanpay.online/openapi.json
ایجاد پرداخت — POST /v1/payments/request
| فیلد | نوع | توضیح |
|---|---|---|
amount |
عدد صحیح (تومان) | حداقل ۱۰٬۰۰۰ (یا حداقل تعیینشده برای شما)، حداکثر ۵۰۰٬۰۰۰٬۰۰۰ |
callback_url |
رشته | آدرس http(s) که کاربر پس از پرداخت به آن هدایت میشود |
description |
رشته، اختیاری | حداکثر ۲۵۵ کاراکتر |
order_id |
رشته، اختیاری | شناسه سفارش خودتان؛ در بازگشت به شما برگردانده میشود |
customer_fee_percent |
عدد ۰ تا ۱۰۰، اختیاری | چند درصد از کارمزد به مبلغ مشتری اضافه شود. اگر ارسال نشود، از تنظیم پیشفرض شما در ربات («⚙️ تنظیمات» ← «💳 سهم مشتری از کارمزد») استفاده میشود. |
پاسخ: {"status": "success", "payment_id": "...", "payment_url": "...", "amount": 100000, "paid_amount": 120000, "customer_fee": 20000}
amount: مبلغ سفارش شما، همان مقداری که فرستادید.paid_amount: مبلغی که مشتری میپردازد، یعنیamount + customer_fee.customer_fee: بخشی از کارمزد که روی مبلغ مشتری اضافه شده است.
مثال با کارمزد ۲۰٪: اگر سهم مشتری ۱۰۰٪ باشد، مشتری ۱۲۰٬۰۰۰ میپردازد و ۱۰۰٬۰۰۰ به موجودی شما اضافه میشود. اگر ۰٪ باشد، مشتری ۱۰۰٬۰۰۰ میپردازد و ۸۰٬۰۰۰ به شما میرسد.
کاربر را به payment_url هدایت کنید.
مسیر پرداخت مشتری
payment_urlصفحهی پیش از پرداخت تومنپی است (https://pay.tomanpay.online/p/<payment_id>): نام نمایشی و لوگوی شما (پس از تأیید مدیریت)، مبلغ و جزئیات کارمزد، توضیحات و زمان باقیمانده تا انقضای لینک.- با زدن دکمهی «پرداخت»، فاکتور درگاه ساخته میشود و مشتری به صفحهی درگاه (FastPay) برای وارد کردن اطلاعات کارت منتقل میشود. رفرش صفحه یا چند بار زدن دکمه، فاکتور تکراری نمیسازد.
- پس از پرداخت، وضعیت با استعلام از درگاه تأیید و رسید تومنپی به مشتری نمایش داده میشود:
- موفق: دکمهی «بازگشت به فروشگاه» و بازگشت خودکار به
callback_urlشما پس از ۵ ثانیه، با پارامترهای امضاشده. - ناموفق / لغو / منقضی: دلیل به فارسی و دکمهی «بازگشت به فروشگاه» (بدون بازگشت خودکار).
- اگر
callback_urlنفرستاده باشید (لینک پرداخت بدون سایت)، فقط رسید نمایش داده میشود.
تا وقتی مشتری «پرداخت» را نزده، وضعیت پرداخت در استعلام pending است. لینکهایی که تا مهلتشان باز نشوند expired میشوند. خطاهای موقت درگاه (مثل تکمیل ظرفیت) بهجای پاسخ API شما، در همان صفحه به مشتری نمایش داده میشوند تا دوباره تلاش کند.
استعلام — POST /v1/payments/inquiry
بدنه: {"payment_id": "..."}
پاسخ: payment_status یکی از pending، paid، canceled، failed، expired بههمراه
amount، paid_amount، customer_fee و
amount، order_id، tracking_number، created_at، paid_at.
فقط وضعیت paid یعنی پول دریافت شده است. قبل از تحویل سفارش همیشه یا امضا را بررسی کنید
یا استعلام بگیرید.
بازگشت کاربر به callback_url
کاربر (از روی رسید تومنپی) با GET و این پارامترها به آدرس شما هدایت میشود:
payment_id، status، amount، paid_amount، order_id، tracking_number، signature
بررسی امضا
signature = HMAC-SHA256 با «کلید وبهوک» شما (از منوی ربات) روی رشته زیر، بهصورت hex:
همه پارامترهای بالا بهجز signature، مرتبشده بر اساس نام، به شکل name=value و با &
به هم وصل شده. مثال:
amount=100000&order_id=ord-1&paid_amount=120000&payment_id=5f0c...&status=paid&tracking_number=123456
PHP:
$p = $_GET;
$sig = $p['signature'];
$keys = ['amount', 'order_id', 'paid_amount', 'payment_id', 'status', 'tracking_number'];
$parts = [];
foreach ($keys as $k) { $parts[] = $k . '=' . ($p[$k] ?? ''); }
$expected = hash_hmac('sha256', implode('&', $parts), $WEBHOOK_SECRET);
if (!hash_equals($expected, $sig)) { http_response_code(400); exit('bad signature'); }
if ($p['status'] === 'paid') { /* مبلغ و order_id را با سفارش خود مقایسه و سفارش را تأیید کنید */ }
Python:
import hmac, hashlib
keys = ["amount", "order_id", "paid_amount", "payment_id", "status", "tracking_number"]
msg = "&".join(f"{k}={params.get(k, '')}" for k in keys)
expected = hmac.new(secret.encode(), msg.encode(), hashlib.sha256).hexdigest()
ok = hmac.compare_digest(expected, params["signature"])
علاوه بر امضا، amount و order_id را با سفارش خود مقایسه کنید و هر payment_id را فقط
یکبار تحویل دهید.
کدهای خطا
| کد | معنی |
|---|---|
| 10 | کلید API نامعتبر یا ارسالنشده |
| 11 | حساب نماینده فعال نیست |
| 12 | حساب نماینده هنوز تنظیم نشده |
| 20 | خطای اعتبارسنجی ورودی |
| 21 | مبلغ نامعتبر (کمتر از حداقل یا بیشتر از حداکثر) |
| 22 | callback_url نامعتبر یا خارج از دامنههای مجاز |
| 30 | سقف تعداد درخواست روزانه |
| 31 | سقف مبلغ روزانه |
| 40 | پرداخت یافت نشد |
| 50 | سرویس موقتاً در دسترس نیست — کمی بعد دوباره تلاش کنید |
| 51 | ایجاد پرداخت ممکن نشد |
| 60 | تعداد درخواست بیش از حد مجاز |
| 99 | خطای داخلی |
وبهوک سرور-به-سرور
اگر کاربر بعد از پرداخت به سایت شما برنگردد، وبهوک تنها راه باخبر شدن است. آدرس وبهوک را در ربات تنظیم کنید؛ بدون آن وبهوکی ارسال نمیشود.
- متد
POSTبا بدنه JSON:event،payment_id،status،amount،paid_amount،order_id،tracking_number،paid_at - رویدادها:
paid: پرداخت موفق.late_paid: پرداخت بعد از انقضا یا لغو انجام شده و مبلغ به حساب شما منظور شده است. در این حالت اگر سفارش را لغو کردهاید، دوباره فعالش کنید.canceled: کاربر پرداخت را لغو کرده است.- هدرها:
X-TomanPay-Event: نوع رویداد.X-TomanPay-Delivery: شناسهی ارسال. در ارسالهای مجدد همین شناسه تکرار میشود، پس رویداد تکراری را با آن تشخیص دهید.X-TomanPay-Signature: به شکلt=<زمان یونیکس>,v1=<امضا>.- امضا: HMAC-SHA256 با کلید وبهوک شما روی رشتهی
"<t>." + بدنهی خام درخواست. - بدنهی خام را قبل از parse کردن JSON بخوانید.
- درخواستی را که
tآن بیشتر از ۵ دقیقه با زمان فعلی فاصله دارد رد کنید. - پاسخ و تلاش مجدد: هر پاسخ 2xx یعنی وبهوک دریافت شده است. در غیر این صورت ارسال با فاصلههای افزایشی (۳۰ ثانیه، ۱ دقیقه، ۲ دقیقه، … حداکثر ۶ ساعت) و حداکثر ۱۲ بار تکرار میشود. ریدایرکت دنبال نمیشود.
PHP:
$raw = file_get_contents('php://input');
$sig = [];
foreach (explode(',', $_SERVER['HTTP_X_TOMANPAY_SIGNATURE'] ?? '') as $part) {
[$k, $v] = array_pad(explode('=', $part, 2), 2, '');
$sig[$k] = $v;
}
$expected = hash_hmac('sha256', ($sig['t'] ?? '') . '.' . $raw, $WEBHOOK_SECRET);
if (!hash_equals($expected, $sig['v1'] ?? '') || abs(time() - (int)($sig['t'] ?? 0)) > 300) {
http_response_code(400); exit;
}
$event = json_decode($raw, true);
// سفارش را با $event['payment_id'] پیدا کنید، مبلغ را بررسی و فقط یکبار تحویل دهید
http_response_code(200);