مستندات API
راهنمای کامل یکپارچهسازی درگاه پرداخت با بکاند، تلگرام و اپ اندروید
https://yourdomain.com/api/v1
— تمام درخواستها نیاز به هدر X-API-Key: YOUR_SECRET_KEY دارند
🏗️ معماری کلی سیستم
⚡ جریان پرداخت ریالی
با پارامترهای
order_id, amount, customer, redirect ریدایرکت کنیدbase + 1000-4990 ریال تصادفی (مضرب ۱۰) — در ۲۴ ساعت تکرار نمیشود (localStorage)
مشتری وارد درگاه میشود، تراکنش در بکاند ثبت میشود
پیامک بانک روی گوشی ادمین میآید
مبلغ و ۴ رقم آخر کارت را extract میکند → به بات تلگرام میفرستد
بات تلگرام این endpoint را صدا میزند — سیستم مبلغ را با تراکنشهای pending تطبیق میدهد
تراکنش confirmed میشود → POST به redirect URL فروشگاه → مشتری به سایت برمیگردد
📋 تراکنشها
Request Body
// وقتی مشتری وارد درگاه میشود این را صدا بزنید { "order_id": "ORD-A1B2C3", "customer": "علی محمدی", "amount": 1202430, // ریال — همان عدد یکتا "base_amount": 1200000, // ریال — مبلغ اصلی "product": "اشتراک ماهانه", "method": "rial", // "rial" | "crypto" "redirect_url": "https://yoursite.com/callback" }
Response
{
"status": "ok",
"txn_id": "TXN-XK92MN",
"card": {
"number": "6037-9975-1144-8820",
"bank": "بانک ملی",
"holder": "ارژنگ بزرگمهر"
},
"expires_at": "2024-01-15T14:30:00Z"
}
درگاه هر ۷ ثانیه این endpoint را صدا میزند تا وضعیت را بررسی کند.
{
"txn_id": "TXN-XK92MN",
"status": "confirmed", // "pending" | "confirmed" | "failed" | "expired"
"amount": 1202430,
"confirmed_at": "2024-01-15T13:52:18Z"
}
وقتی status برابر confirmed شد، درگاه صدا میزند و به redirect_url برمیگردد.
{ "admin_note": "تایید دستی پس از بررسی رسید" }
Callback به فروشگاه
پس از تایید، بکاند یک POST به redirect_url میزند:
{
"status": "confirmed",
"order_id": "ORD-A1B2C3",
"txn_id": "TXN-XK92MN",
"amount": 1202430,
"signature": "sha256(order_id+amount+secret_key)" // اعتبارسنجی
}
signature را در فروشگاه خودتان verify کنید تا callback جعلی نباشد📱 تطبیق پیامک
{
"source": "sms", // "sms" | "telegram" | "whatsapp"
"sender": "bank-mellat", // شماره یا شناسه فرستنده
"text": "انتقال وجه 1202430 ریال از کارت ****9501 تایید شد",
"amount": 1202430, // اگر extract شده باشد، در غیر اینصورت null
"card_last4": "9501", // اگر extract شده باشد
"timestamp": "2024-01-15T13:52:00Z"
}
Response
{
"matched": true,
"txn_id": "TXN-XK92MN",
"auto_confirmed": true, // اگر مبلغ دقیقاً منطبق بود
"confidence": "high" // "high" | "low"
}
منطق تطبیق در بکاند
// pseudo-code pending_txns = Transaction.where(status: "pending", method: "rial") .where(expires_at: > now) .order(created_at: :desc) match = pending_txns.find { |t| t.amount == incoming.amount } if match match.update(status: "confirmed", sms_text: incoming.text) send_callback(match.redirect_url, match) // notify store return { matched: true, auto_confirmed: true } else // ذخیره برای بررسی دستی SmsLog.create(incoming.merge(matched: false)) return { matched: false } end
🏦 مدیریت کارتها
| Method | Endpoint | توضیح |
|---|---|---|
| GET | /cards | لیست کارتهای فعال |
| POST | /cards | افزودن کارت جدید |
| POST | /cards/{id}/toggle | فعال/غیرفعال کردن |
| GET | /cards/next | کارت بعدی برای تراکنش (rotation) |
// GET /cards/next — منطق چرخش کارت { "card": { "id": 2, "number": "6104-3311-4429-9501", "bank": "بانک ملت", "holder": "ارژنگ بزرگمهر" } }
🔗 مدیریت کیف پولها
| Method | Endpoint | توضیح |
|---|---|---|
| GET | /wallets | لیست کیف پولهای فعال |
| POST | /wallets | افزودن کیف پول |
| POST | /wallets/blockchain-confirm | وبهوک تایید بلاکچین |
🧾 اتصال فاکتور به فروشگاه
از فروشگاهتان با یک لینک ساده به Invoice.html ریدایرکت کنید:
# PHP مثال: $params = http_build_query([ 'order_id' => $order->id, 'customer' => $user->name, 'amount' => $order->total_rial, // ریال — تومان در سامانه ممنوع 'product' => $order->description, 'redirect' => url('/payment/callback'), 'site' => config('app.name'), ]); return redirect("https://pay.yoursite.com/Invoice.html?$params");
// Node.js مثال:
const params = new URLSearchParams({
order_id: order.id,
customer: user.name,
amount: order.totalToman,
product: order.description,
redirect: `${BASE_URL}/payment/callback`,
});
res.redirect(`https://pay.yoursite.com/Invoice.html?${params}`);
✈️ راهاندازی بات تلگرام
https://api.telegram.org/bot{TOKEN}/setWebhook?url=https://yourserver.com/telegram-webhookکد Node.js Webhook Handler
// telegram-webhook.js const express = require('express'); const axios = require('axios'); const app = express(); app.use(express.json()); const API_URL = 'https://yourserver.com/api/v1'; const API_KEY = process.env.API_SECRET_KEY; // شمارههای بانکی که باید listen کنیم const BANK_SENDERS = ['bank-mellat', 'bank-melli', 'banksaman', '10008486']; function extractAmount(text) { const match = text.match(/(\d[\d,٬]+)\s*(ریال|تومان|رﻳﺎﻝ)/); if (!match) return null; return parseInt(match[1].replace(/[,٬]/g, '')); } function extractCard(text) { const match = text.match(/\*{2,4}(\d{4})/); return match ? match[1] : null; } app.post('/telegram-webhook', async (req, res) => { const msg = req.body?.message; if (!msg?.text) return res.sendStatus(200); const text = msg.text; const amount = extractAmount(text); const cardLast4 = extractCard(text); // فقط پیامکهای بانکی را پردازش کن const isBank = BANK_SENDERS.some(s => text.toLowerCase().includes(s)); if (amount || isBank) { await axios.post(`${API_URL}/sms/incoming`, { source: 'telegram', sender: msg.from?.id, text, amount, card_last4: cardLast4, timestamp: new Date().toISOString(), }, { headers: { 'X-API-Key': API_KEY } }); } res.sendStatus(200); }); app.listen(3000);
📱 اپ اندروید — SMS Reader
۱. AndroidManifest.xml — دسترسیهای لازم
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
<uses-permission android:name="android.permission.READ_SMS"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<receiver android:name=".SmsReceiver"
android:exported="true">
<intent-filter android:priority="999">
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
۲. SmsReceiver.kt — دریافت و parse پیامک
package com.yourapp.smsreader
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.telephony.SmsMessage
import kotlinx.coroutines.*
import okhttp3.*
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.RequestBody.Companion.toRequestBody
import org.json.JSONObject
class SmsReceiver : BroadcastReceiver() {
// شمارههای بانکی که باید پردازش شوند
private val BANK_SENDERS = listOf(
"bank-mellat", "bankmellat", "10008486",
"bank-melli", "bankmelli", "10008522",
"banksaman", "saman-bank", "20006",
"parsian", "bank-pasargad"
)
// شماره تلگرام بات و توکن
private val BOT_TOKEN = "YOUR_BOT_TOKEN"
private val CHAT_ID = "YOUR_CHAT_ID" // chat ID ادمین
override fun onReceive(context: Context, intent: Intent) {
val pdus = intent.extras?.get("pdus") as? Array<*> ?: return
val format = intent.getStringExtra("format") ?: "3gpp"
for (pdu in pdus) {
val sms = SmsMessage.createFromPdu(pdu as ByteArray, format)
val sender = sms.originatingAddress?.lowercase() ?: ""
val body = sms.messageBody ?: ""
val isBank = BANK_SENDERS.any { sender.contains(it) || body.contains(it) }
val amount = extractAmount(body)
if (isBank || amount != null) {
forwardToTelegram(context, sender, body, amount)
}
}
}
private fun extractAmount(text: String): Long? {
val patterns = listOf(
Regex("""(\d[\d,،٬]+)\s*(ریال|رﻳﺎﻝ)"""),
Regex("""([\d,،٬]+)\s*ریال"""),
Regex("""مبلغ\s*([\d,،٬]+)"""),
)
for (p in patterns) {
val match = p.find(text) ?: continue
val numStr = match.groupValues[1].replace(Regex("[,،٬]"), "")
return numStr.toLongOrNull()
}
return null
}
private fun extractCardLast4(text: String): String? {
return Regex("""\*{2,4}(\d{4})""").find(text)?.groupValues?.get(1)
}
private fun forwardToTelegram(ctx: Context, sender: String, body: String, amount: Long?) {
CoroutineScope(Dispatchers.IO).launch {
try {
val message = buildString {
append("📱 *پیامک بانکی دریافت شد*\n\n")
append("📤 فرستنده: `$sender`\n")
append("💬 متن:\n```\n$body\n```\n")
amount?.let { append("\n💰 مبلغ استخراجشده: *${it} ریال*") }
extractCardLast4(body)?.let { append("\n💳 آخر کارت: `****$it`") }
}
val json = JSONObject().apply {
put("chat_id", CHAT_ID)
put("text", message)
put("parse_mode", "Markdown")
}
OkHttpClient().newCall(
Request.Builder()
.url("https://api.telegram.org/bot$BOT_TOKEN/sendMessage")
.post(json.toString().toRequestBody("application/json".toMediaType()))
.build()
).execute()
} catch (e: Exception) {
e.printStackTrace()
}
}
}
}
۳. build.gradle — dependencies
dependencies {
implementation("com.squareup.okhttp3:okhttp:4.12.0")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3")
}
⛓️ وبهوک بلاکچین (کریپتو)
از سرویسهایی مثل NOWPayments یا CryptoAPIs یا node خودتان استفاده کنید:
{
"txhash": "0xabc123...",
"to": "0xc9cF01Eb8...", // آدرس کیف پول ما
"amount": 25.599720, // مقدار USDT
"coin": "USDT",
"network": "BEP20",
"confirmations": 12
}
بکاند این مقدار را با تراکنشهای pending کریپتو تطبیق میدهد.
🪙 کریپتو — فاز ۲/۳/۴ (HD Wallet چندشبکه)
سیستم HD Wallet از TRC20 (Tron)، BEP20 (BSC) و POLYGON پشتیبانی میکند. آدرس یکتا برای هر تراکنش مشتق میشود.
{
"base_amount": 5000000, // مبلغ پایه ریال
"method": "crypto",
"order_id": "ORD-001",
"redirect_url": "https://shop.ir/callback"
}
پاسخ شامل hd_address (آدرس یکتا مشتقشده از xpub) و crypto_amount (مقدار USDT) است.
TRC20 (Tron):
{
"txn_code": "TXN-XXXX",
"txhash": "a3f1c2d4e5..." // 64 کاراکتر hex (بدون 0x)
}
BEP20 / POLYGON (EVM):
{
"txn_code": "TXN-XXXX",
"txhash": "0xa3f1c2d4e5..." // 0x + 64 کاراکتر hex
}
شبکه بهصورت خودکار از روی تراکنش و آدرس مقصد شناسایی میشود.
{
"hd_xpub": "xpub6...", // TRC20
"hd_xpub_bep20": "xpub6...", // BEP20
"hd_xpub_polygon": "xpub6...", // POLYGON
"hd_mode": true,
"hd_network": "TRC20", // TRC20 | BEP20 | POLYGON
"hd_index": 42,
"hd_index_bep20": 17,
"hd_index_polygon": 5,
"hd_addresses_trc20": 42,
"hd_addresses_bep20": 17,
"hd_addresses_polygon":5
}
{
"hd_xpub": "xpub6...", // TRC20
"hd_xpub_bep20": "xpub6...", // BEP20
"hd_xpub_polygon": "xpub6...", // POLYGON
"hd_mode": true,
"hd_network": "POLYGON"
}
آدرسهایی که تراکنش confirmed دارند و هنوز swept نشدهاند.
{
"pending_sweep": [ { "address": "T...", "crypto_amount": 25.6, ... } ],
"count": 3,
"total_usdt": 76.8
}
{
"sweep_txhash": "abc123...",
"address_ids": [1, 2, 3]
}
{
"current_rate": 68500000,
"total_usdt": 150.5,
"total_pnl_rial": 12500000,
"rows": [...]
}
{
"pending_sweep_count": 5,
"swept_count": 42,
"pending_usdt": 128.3
}
🔗 فایلهای پروژه