مستندات API

راهنمای کامل یکپارچه‌سازی درگاه پرداخت با بک‌اند، تلگرام و اپ اندروید

🔗 Base URL: https://yourdomain.com/api/v1  —  تمام درخواست‌ها نیاز به هدر X-API-Key: YOUR_SECRET_KEY دارند

🏗️ معماری کلی سیستم

🛒 فروشگاه
🧾 Invoice
💳 Gateway
✅ Callback
↑                                                ↓
📱 SMS Reader (Android)
✈️ Telegram Bot
🖥️ Backend API
⚙️ Admin Panel

⚡ جریان پرداخت ریالی

1
فروشگاه → Invoice.html
با پارامترهای order_id, amount, customer, redirect ریدایرکت کنید
2
Invoice مبلغ یکتا تولید می‌کند
base + 1000-4990 ریال تصادفی (مضرب ۱۰) — در ۲۴ ساعت تکرار نمی‌شود (localStorage)
3
POST /transactions/create
مشتری وارد درگاه می‌شود، تراکنش در بک‌اند ثبت می‌شود
4
مشتری واریز می‌کند
پیامک بانک روی گوشی ادمین می‌آید
5
Android App پیامک را می‌خواند
مبلغ و ۴ رقم آخر کارت را extract می‌کند → به بات تلگرام می‌فرستد
6
POST /sms/incoming
بات تلگرام این endpoint را صدا می‌زند — سیستم مبلغ را با تراکنش‌های pending تطبیق می‌دهد
7
تایید خودکار + Callback
تراکنش confirmed می‌شود → POST به redirect URL فروشگاه → مشتری به سایت برمی‌گردد

📋 تراکنش‌ها

POST /transactions/create ایجاد تراکنش جدید

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"
}
GET /transactions/{txn_id} وضعیت تراکنش (polling)

درگاه هر ۷ ثانیه این endpoint را صدا می‌زند تا وضعیت را بررسی کند.

{
  "txn_id":  "TXN-XK92MN",
  "status":  "confirmed",  // "pending" | "confirmed" | "failed" | "expired"
  "amount":  1202430,
  "confirmed_at": "2024-01-15T13:52:18Z"
}

وقتی status برابر confirmed شد، درگاه صدا می‌زند و به redirect_url برمی‌گردد.

POST /transactions/{txn_id}/confirm تایید دستی از پنل
{ "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 جعلی نباشد

📱 تطبیق پیامک

POST /sms/incoming دریافت پیامک از Android / تلگرام
{
  "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

🏦 مدیریت کارت‌ها

MethodEndpointتوضیح
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": "ارژنگ بزرگمهر"
  }
}

🔗 مدیریت کیف پول‌ها

MethodEndpointتوضیح
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}`);

✈️ راه‌اندازی بات تلگرام

1
بات بسازید: به @BotFather در تلگرام بروید → /newbot → توکن را ذخیره کنید
2
Webhook ست کنید:
https://api.telegram.org/bot{TOKEN}/setWebhook?url=https://yourserver.com/telegram-webhook
3
اپ اندروید پیامک را forward می‌کند به این بات
4
بات webhook دریافت می‌کند → متن پیام را parse می‌کند → POST /sms/incoming را صدا می‌زند

کد 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

✅ کد کامل Kotlin زیر را در Android Studio قرار دهید — نیاز به کامپایل دارد

۱. 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")
}
⚠️ مهم: در اندروید 6+ باید در Runtime هم دسترسی SMS بخواهید. در اندروید 10+ پیامک‌های بانکی معمولاً از سرشماره‌های خاص (Service Number) می‌آیند که باید آن‌ها را به لیست BANK_SENDERS اضافه کنید.

⛓️ وب‌هوک بلاکچین (کریپتو)

از سرویس‌هایی مثل NOWPayments یا CryptoAPIs یا node خودتان استفاده کنید:

POST /wallets/blockchain-confirm تایید تراکنش بلاکچین
{
  "txhash":  "0xabc123...",
  "to":      "0xc9cF01Eb8...",   // آدرس کیف پول ما
  "amount":  25.599720,            // مقدار USDT
  "coin":    "USDT",
  "network": "BEP20",
  "confirmations": 12
}

بک‌اند این مقدار را با تراکنش‌های pending کریپتو تطبیق می‌دهد.

🪙 کریپتو — فاز ۲/۳/۴ (HD Wallet چندشبکه)

سیستم HD Wallet از TRC20 (Tron)، BEP20 (BSC) و POLYGON پشتیبانی می‌کند. آدرس یکتا برای هر تراکنش مشتق می‌شود.

POST /api.php?action=create_transaction ایجاد تراکنش کریپتو
{
  "base_amount":  5000000,      // مبلغ پایه ریال
  "method":       "crypto",
  "order_id":     "ORD-001",
  "redirect_url": "https://shop.ir/callback"
}

پاسخ شامل hd_address (آدرس یکتا مشتق‌شده از xpub) و crypto_amount (مقدار USDT) است.

POST /api.php?action=submit_crypto_txhash ارسال txhash برای تأیید (TRC20 و EVM)

TRC20 (Tron):

{
  "txn_code": "TXN-XXXX",
  "txhash":   "a3f1c2d4e5..."  // 64 کاراکتر hex (بدون 0x)
}

BEP20 / POLYGON (EVM):

{
  "txn_code": "TXN-XXXX",
  "txhash":   "0xa3f1c2d4e5..."  // 0x + 64 کاراکتر hex
}

شبکه به‌صورت خودکار از روی تراکنش و آدرس مقصد شناسایی می‌شود.

GET /api.php?action=get_hd_settings دریافت تنظیمات HD Wallet (نیاز به admin token)
{
  "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
}
POST /api.php?action=save_hd_settings ذخیره تنظیمات HD Wallet
{
  "hd_xpub":         "xpub6...",    // TRC20
  "hd_xpub_bep20":   "xpub6...",    // BEP20
  "hd_xpub_polygon": "xpub6...",    // POLYGON
  "hd_mode":         true,
  "hd_network":      "POLYGON"
}
GET /api.php?action=list_addresses_for_sweep لیست آدرس‌های آماده جارو (sweep)

آدرس‌هایی که تراکنش confirmed دارند و هنوز swept نشده‌اند.

{
  "pending_sweep": [ { "address": "T...", "crypto_amount": 25.6, ... } ],
  "count": 3,
  "total_usdt": 76.8
}
POST /api.php?action=mark_addresses_swept علامت‌گذاری آدرس‌ها به عنوان swept
{
  "sweep_txhash": "abc123...",
  "address_ids": [1, 2, 3]
}
GET /api.php?action=crypto_pnl_report گزارش سود/زیان کریپتو
{
  "current_rate":   68500000,
  "total_usdt":     150.5,
  "total_pnl_rial": 12500000,
  "rows": [...]
}
GET /api.php?action=sweep_stats آمار کلی sweep
{
  "pending_sweep_count": 5,
  "swept_count":         42,
  "pending_usdt":        128.3
}

🔗 فایل‌های پروژه

🔐 Login ⚙️ Admin Panel 🧾 Invoice 💳 Gateway