tarunpoonia905/OfcDevShopBotPublic · Bot Template

ProfileTelegram

AIDEV SHOP appears to be a Telegram automation bot. Commands include /confirm_delete_stock, /addstock_id, /extkey_menu, /partner_api, /apidelete, /buy_hack_cat, /admin_manage_products, /check_buy. Observed in code: messaging, keyboards, payments, libs, web, http, games.

Utilityutility
228 commands0 envUpdated 12d agoCreated Oct 18, 2026
Back to folder

commands/_onBuyCheck.js

javascript · 547 lines

Raw
1/**#command2name: /onBuyCheck3answer: 4keyboard: 5parse_mode: markdown6aliases: 7allow_only_group: false8need_reply: false9is_web: 010#command**/11 12/*#SIZE_V1*/try{(function(){var z=Bot.getProperty("ui_btn_size");var mx=z==="large"?1:(z==="medium"?2:0);if(!mx||Api.__sz)return;var NAV=/^[◀▶⬅➡«»‹›⏪⏩]|\d+\s*\/\s*\d+|prev|next|page/i;var T=function(m){try{var o=typeof m==="string"?JSON.parse(m):m;if(!o||!o.inline_keyboard)return m;var out=[],cnt=0;o.inline_keyboard.forEach(function(row){var nav=row.some(function(b){return NAV.test(String(b.text||"").trim());});if(row.length<=mx||nav){out.push(row);cnt+=row.length;return;}for(var i=0;i<row.length;i+=mx){var c=row.slice(i,i+mx);out.push(c);cnt+=c.length;}});if(cnt>100||out.length>100)return m;o.inline_keyboard=out;return typeof m==="string"?JSON.stringify(o):o;}catch(e){return m;}};["sendMessage","editMessageText","editMessageCaption","editMessageReplyMarkup","sendPhoto","sendVideo","sendAnimation","sendDocument"].forEach(function(n){var f=Api[n];if(typeof f!=="function")return;Api[n]=function(p){try{if(p&&p.reply_markup)p.reply_markup=T(p.reply_markup);}catch(e){}return f.apply(Api,arguments);};});Api.__sz=true;})();}catch(__szE){}13/*#ANIM_V1*/try{(function(){var M={party:"5046509860389126442",fire:"5104841245755180586",heart:"5159385139981059251",like:"5107584321108051014"};var a=Bot.getProperty("ui_anim");if(!a||!M[a]||Api.__an)return;var E=M[a];var OK=/PURCHASE SUCCESSFUL|PAYMENT SUCCESSFUL|Payment verified|CONGRATULATIONS/i;var priv=function(p){return p&&p.chat_id&&String(p.chat_id).charAt(0)!=="-";};["sendMessage","sendPhoto","sendVideo","sendAnimation"].forEach(function(n){var f=Api[n];if(typeof f!=="function")return;Api[n]=function(p){try{if(priv(p)&&!p.message_effect_id&&OK.test(String(p.text||p.caption||"")))p.message_effect_id=E;}catch(e){}return f.apply(Api,arguments);};});var fe=Api.editMessageText;if(typeof fe==="function"){Api.editMessageText=function(p){var r=fe.apply(Api,arguments);try{if(priv(p)&&OK.test(String(p.text||"")))Api.sendMessage({chat_id:p.chat_id,text:"🎉",message_effect_id:E});}catch(e){}return r;};}Api.__an=true;})();}catch(__anE){}14/*#PREMIUM_UI_V1*/try{(function(){if(Bot.getProperty("ui_premium")!==true||Api.__pm)return;var R=function(t,c){var s=(String(t||"")+" "+String(c||"")).toLowerCase();if(/back|cancel|close|delete|remove|clear|reject|stop|ban|exit/.test(s))return"danger";if(/pay|buy|confirm|verify|paid|add|deposit|shop|claim|yes|receive|wallet|download|update/.test(s))return"success";return"primary";};var T=function(m){try{var o=typeof m==="string"?JSON.parse(m):m;if(!o||!o.inline_keyboard)return m;o.inline_keyboard.forEach(function(row){row.forEach(function(b){if(b.copy_text||b.url||b.callback_data||b.web_app){b.style=R(b.text,b.callback_data||b.url);if(!b.icon_custom_emoji_id&&b.text&&!/^[\u2600-\u27BF\uD83C-\uD83E]/.test(String(b.text).trim())&&!/^[✦✨💎]/.test(b.text))b.text="✦ "+b.text;}});});return typeof m==="string"?JSON.stringify(o):o;}catch(e){return m;}};["sendMessage","editMessageText","editMessageCaption","editMessageReplyMarkup","sendPhoto","sendVideo","sendAnimation","sendDocument"].forEach(function(n){var f=Api[n];if(typeof f!=="function")return;Api[n]=function(p){try{if(p&&p.reply_markup)p.reply_markup=T(p.reply_markup);}catch(e){}return f.apply(Api,arguments);};});Api.__pm=true;})();}catch(__pmE){}15 16 17function resolveApiDuration(plan, cleanPlanDays, planUnit, productNameOverride) {18  // IMPORTANT: Keep the admin/API duration name exactly as entered.19  // The product-specific day ranges below are used only when the stored plan20  // contains a plain numeric Day duration; this lets 1-30 Day plans target21  // the exact website/API names requested by the admin without changing any22  // other product data or purchase logic.23  var raw = String((plan && (plan.api_duration || plan.name_on_website || plan.durationDisplay || plan.name || plan.title)) || "").replace(/\s+/g, " ").trim();24 25  // Already-custom API labels (including casing/suffixes) must pass through unchanged.26  if (raw && !/^[0-9]+(?:\.[0-9]+)?\s*(day|days)$/i.test(raw)) {27    return raw;28  }29 30  var dayMatch = raw.match(/^([0-9]+(?:\.[0-9]+)?)\s*(day|days)$/i);31  var n = dayMatch ? dayMatch[1] : String(cleanPlanDays || "1");32  var productName = String(productNameOverride || (plan && (plan.product_name || plan.productName || plan.product || plan.category)) || "").trim().toLowerCase();33 34  // If product name is not stored on the plan, the caller's raw API label is35  // still preserved above. Generic numeric Day plans remain "N Days".36  if (/pc\s*aim\s*silent/.test(productName)) return n + " Day Pc Aim Silent";37  if (/pc\s*modmenu\s*x86/.test(productName)) return n + " Day Pc Modmenu x86";38  if (/pc\s*bypass\s*\+\s*silent/.test(productName) || /bypass\s*\+\s*silent/.test(productName)) return n + " Days Pc Bypass + Silent";39  if (/nonroot/.test(productName) && !/root\s*\+\s*nonroot/.test(productName)) return n + " DaYS NONROOT";40  if (/pc\s*aimkill/.test(productName) || /aimkill/.test(productName)) return n + " DaYS PC AIMKILL";41  if (/root\s*\+\s*nonroot/.test(productName)) return n + " DaYs Root + Nonroot";42  if (/fluo?rite\s*ff/.test(productName)) return n + " DAYs FluoRite FF";43  if (/\broot\b/.test(productName)) return n + " DaYs ROOT";44  if (/all\s*colou?rs\s*mix/.test(productName)) return n + " DaYs All Colours Mix";45  if (/\bbasic\b/.test(productName)) return n + " DaYs Basic";46  if (/\bpro\b/.test(productName)) return n + " DaYs PRO";47  if (/\bsafe\b/.test(productName)) return n + " DaYs SAFE";48  if (/\bbrutal\b/.test(productName)) return n + " DaYs BRUTAL";49  if (/\bbrutal\b/.test(productName)) return n + " DaYs";50 51  // Hours/minutes are preserved exactly; no existing API duration is removed.52  var gh = raw.match(/^([0-9]+(?:\.[0-9]+)?)\s*(hour|hours)$/i);53  if (gh) return gh[1] + " Hours";54  var gm = raw.match(/^([0-9]+(?:\.[0-9]+)?)\s*(minute|minutes)$/i);55  if (gm) return gm[1] + (Number(gm[1]) === 1 ? " Minute" : " Minutes");56 57  return raw || n + " Days";58}59 60 61try {62  function __paytmNorm(r, lockedAmt, orderIdX) {63    if (!r || typeof r !== "object") return r;64    if (String(r.status).toLowerCase() === "success" && r.data) return r;65    var d = (r.data && typeof r.data === "object") ? r.data : r;66    var st = String(d.status || d.txn_status || d.STATUS || d.payment_status || r.status || r.txn_status || "").toUpperCase();67    var paidSt = ["TXN_SUCCESS", "SUCCESS", "PAID", "COMPLETED", "CAPTURED", "CREDITED"];68    var failSt = ["PENDING", "FAILURE", "FAILED", "EXPIRED", "CANCELLED", "CREATED", "NOT_FOUND", "TXN_FAILURE", "ERROR"];69    var paid = (paidSt.indexOf(st) !== -1 && failSt.indexOf(st) === -1) || d.paid === true || d.is_paid === true || r.paid === true || r.is_paid === true;70    if (!paid) return r;71    var amt = parseFloat(d.amount || d.txn_amount || d.TXNAMOUNT || d.paid_amount || r.amount || r.txn_amount || 0) || 0;72    if (!(amt > 0)) amt = Number(lockedAmt || 0);73    return { status: "success", data: {74      amount: amt,75      utr: d.utr || d.rrn || d.bank_txn_id || d.transaction_id || d.txn_id || d.txnid || r.utr || r.transaction_id || r.txn_id || orderIdX,76      sender_name: d.sender_name || d.payer_name || r.sender_name || "Valued User",77      payment_time_ist: d.payment_time_ist || d.txn_date || d.payment_time || r.payment_time_ist || "N/A"78    }};79  }80  var userId = user.telegramid;81 82  // ✅ CRITICAL FIX: Proper atomic duplicate-payment prevention83  var utrFromContent = null;84  85  // Parse content to get UTR early86  if (content) {87    var res = (typeof content === "object") ? content : JSON.parse(content);88 89  // Normalize Paytm Business verify response.90  res = __paytmNorm(res, Number(User.getProperty("buy_needpay") || User.getProperty("buy_expected_amount") || 0), User.getProperty("buy_pending_order_id"));91    if (res && res.data && res.data.utr) {92      utrFromContent = res.data.utr;93    }94  }95 96  // 🛑 STEP 1: Check if payment already processed using UTR (most reliable identifier)97  if (utrFromContent && Bot.getProperty("paid_" + utrFromContent)) {98    // ✅ FIX: Vanish the QR completely instead of leaving a stale "already used" caption behind99    try {100      Api.deleteMessage({ chat_id: chat.chatid, message_id: request.message.message_id });101    } catch (e) {}102 103    try {104      Bot.setProperty("buy_qr_msg_id_" + userId, null, "string");105      User.setProperty("buy_qr_msg_id_" + userId, null, "string");106    } catch (e) {}107 108    if (request && request.id) {109      try {110        Api.answerCallbackQuery({111          callback_query_id: String(request.id),112          text: "✅ ALREADY CLAIMED ✅\nYe order pehle hi deliver ho chuka hai.",113          show_alert: true114        });115      } catch (e) {}116    }117 118    Api.sendMessage({119      chat_id: chat.chatid,120      text: "<blockquote><tg-emoji emoji-id='5330237710655306682'>✅</tg-emoji> <b>ORDER ALREADY CLAIMED</b>\n<i>Ye payment pehle hi verify ho kar item deliver ho chuka hai. Apni keys 'All History' me check karein.</i></blockquote>",121      parse_mode: "HTML",122      reply_markup: JSON.stringify({123        inline_keyboard: [[124          { text: "📜 My Keys", callback_data: "/mykey", style: "primary" },125          { text: "🛒 Shop Menu", callback_data: "/buy_hack", style: "success" }126        ]]127      })128    });129    return;130  }131 132  // 🛑 STEP 2: Duplicate-click lock check133  var isChecking = User.getProperty("buy_verifying_lock_" + userId);134  if (isChecking) {135    if (request && request.id) {136      Api.answerCallbackQuery({137        callback_query_id: String(request.id),138        text: "⏳ ALREADY CHECKING — PLEASE WAIT...",139        show_alert: true140      });141    }142    return;143  }144  145  // 🛑 STEP 3: SET LOCK IMMEDIATELY before any async operations146  User.setProperty("buy_verifying_lock_" + userId, true, "boolean");147 148  if (!content) {149    Api.editMessageCaption({150      chat_id: chat.chatid, message_id: request.message.message_id,151      caption: "<blockquote>⚠️ <b>Server didn't respond.</b>\nClick 'I have paid' again.</blockquote>", parse_mode: "HTML"152    });153    User.setProperty("buy_verifying_lock_" + userId, false, "boolean");154    return;155  }156 157  var res = (typeof content === "object") ? content : JSON.parse(content);158  res = __paytmNorm(res, Number(User.getProperty("buy_needpay") || User.getProperty("buy_expected_amount") || 0), User.getProperty("buy_pending_order_id"));159 160  if (res.status === "success" && res.data) {161    var utr = res.data.utr;162    var expectedBuyAmount = Number(User.getProperty("buy_needpay") || User.getProperty("buy_expected_amount") || 0);163    var reportedBuyAmount = Number(res.data.amount || 0);164    if (expectedBuyAmount > 0 && reportedBuyAmount > 0 && (Math.abs(reportedBuyAmount - expectedBuyAmount) > 0.01)) {165      Api.editMessageCaption({166        chat_id: chat.chatid, message_id: request.message.message_id,167        caption: "❌ <b>Amount mismatch.</b> Expected ₹" + expectedBuyAmount.toFixed(2) + ", Paytm reported ₹" + reportedBuyAmount.toFixed(2) + ".",168        parse_mode: "HTML"169      });170      User.setProperty("buy_verifying_lock_" + userId, false, "boolean");171      return;172    }173 174    var isPaid = Bot.getProperty("paid_" + utr);175 176    if (isPaid) {177      // ✅ FIX: Vanish the QR completely instead of leaving a stale "already used" caption behind178      try {179        Api.deleteMessage({ chat_id: chat.chatid, message_id: request.message.message_id });180      } catch (e) {}181 182      try {183        Bot.setProperty("buy_qr_msg_id_" + userId, null, "string");184        User.setProperty("buy_qr_msg_id_" + userId, null, "string");185      } catch (e) {}186 187      if (request && request.id) {188        try {189          Api.answerCallbackQuery({190            callback_query_id: String(request.id),191            text: "✅ ALREADY CLAIMED ✅\nYe order pehle hi deliver ho chuka hai.",192            show_alert: true193          });194        } catch (e) {}195      }196 197      Api.sendMessage({198        chat_id: chat.chatid,199        text: "<blockquote><tg-emoji emoji-id='5330237710655306682'>✅</tg-emoji> <b>ORDER ALREADY CLAIMED</b>\n<i>Ye payment pehle hi verify ho kar item deliver ho chuka hai. Apni keys 'All History' me check karein.</i></blockquote>",200        parse_mode: "HTML",201        reply_markup: JSON.stringify({202          inline_keyboard: [[203            { text: "📜 My Keys", callback_data: "/mykey", style: "primary" },204            { text: "🛒 Shop Menu", callback_data: "/buy_hack", style: "success" }205          ]]206        })207      });208      User.setProperty("buy_verifying_lock_" + userId, false, "boolean");209      return;210    }211    212    // ✅ IMMEDIATELY mark as paid BEFORE any async API calls to prevent race condition213    Bot.setProperty("paid_" + utr, true, "boolean");214 215    Api.editMessageCaption({216      chat_id: chat.chatid, message_id: request.message.message_id,217      caption: "<tg-emoji emoji-id='6192822213486321961'>🔄</tg-emoji> <b>Payment verified! Delivering your key...</b>",218      parse_mode: "HTML"219    });220 221    // ✅ FIX: Detect which purchase pipeline this QR payment belongs to.222    // "ffid" = local stock-based FF ID item (set by /execute_id_buy on low balance)223    // default/"plan" = original plan-based product via external xyzcheats API224    var flowType = User.getProperty("buy_flow_type") || "plan";225 226    if (flowType === "ffid") {227      // =========================================================228      // 🎮 FF ID STOCK DELIVERY (after successful QR payment)229      // =========================================================230      try {231        var rawType = User.getProperty("buy_ffid_rawtype") || "";232        var isResellerFlow = User.getProperty("buy_ffid_is_reseller") === true;233        var finalCost = Number(User.getProperty("buy_price") || 0);234        var displayTypeName = User.getProperty("buy_prod_name") || rawType;235 236        var stockData = [];237        var isDynamicCategory = false;238        var isGeneralCategory = false;239        var selectedCat = null;240 241        var fbCategories = Bot.getProperty("fb_categories") || [];242        if (!Array.isArray(fbCategories)) { fbCategories = []; }243 244        if (rawType.indexOf("fb_") === 0) {245          isDynamicCategory = true;246          var targetCatId = rawType.replace("fb_", "").trim();247          for (var i = 0; i < fbCategories.length; i++) {248            if (fbCategories[i].id === targetCatId) { selectedCat = fbCategories[i]; break; }249          }250          if (selectedCat) { stockData = selectedCat.stock_list || []; }251        } else if (rawType === "fb" || rawType === "google") {252          stockData = Bot.getProperty("ff_stock_" + rawType) || [];253        } else {254          isGeneralCategory = true;255          var categoriesFF = Bot.getProperty("ff_categories") || {};256          selectedCat = categoriesFF[rawType];257          if (selectedCat) {258            var fallbackStock = Bot.getProperty("ff_stock_" + rawType) || [];259            stockData = (selectedCat.stock_list && selectedCat.stock_list.length > 0) ? selectedCat.stock_list : fallbackStock;260          }261        }262 263        if (!stockData || stockData.length === 0) {264          Api.editMessageCaption({265            chat_id: chat.chatid, message_id: request.message.message_id,266            caption: "⚠️ Payment received but item went out of stock. Contact admin with UTR: " + utr,267            parse_mode: "HTML"268          });269          User.setProperty("buy_verifying_lock_" + userId, false, "boolean");270          return;271        }272 273        var accountExtracted = stockData.shift();274 275        if (isDynamicCategory && selectedCat) {276          selectedCat.stock_list = stockData;277          Bot.setProperty("fb_categories", fbCategories, "json");278        } else if (isGeneralCategory && selectedCat) {279          selectedCat.stock_list = stockData;280          var categoriesFF2 = Bot.getProperty("ff_categories") || {};281          categoriesFF2[rawType] = selectedCat;282          Bot.setProperty("ff_categories", categoriesFF2, "json");283          Bot.setProperty("ff_stock_" + rawType, stockData, "json");284        } else {285          Bot.setProperty("ff_stock_" + rawType, stockData, "json");286        }287 288        var fullRawString = String(accountExtracted || "").trim();289        var emailData = fullRawString;290        var passwordData = "No Password Found";291 292        if (fullRawString.indexOf("|") !== -1) {293          var lastPipeIndex = fullRawString.lastIndexOf("|");294          var firstPart = fullRawString.substring(0, lastPipeIndex).trim();295          var secondPart = fullRawString.substring(lastPipeIndex + 1).trim();296 297          if (firstPart.indexOf(" ") !== -1) {298            var spaceParts = firstPart.split(" ");299            emailData = spaceParts[spaceParts.length - 1].trim();300          } else {301            emailData = firstPart;302          }303          passwordData = secondPart;304        }305 306        var purchasedKeys = User.getProperty("my_purchased_keys") || [];307        if (!Array.isArray(purchasedKeys)) { purchasedKeys = []; }308        var currentDate = new Date().toLocaleDateString('en-IN', { timeZone: "Asia/Kolkata" });309        purchasedKeys.push({310          productName: displayTypeName,311          cost: finalCost.toString(),312          key: emailData + (passwordData !== "No Password Found" ? " | " + passwordData : ""),313          days: "Permanent",314          date: currentDate315        });316        User.setProperty("my_purchased_keys", purchasedKeys, "json");317 318        var deliveryText =319          "┏━━━━━━━━━━━━━━━━━━━━━━━━┓\n" +320          "┃ ❤️‍🔥 <b>PURCHASE SUCCESSFUL!</b> ❤️‍🔥 ┃\n" +321          "┗━━━━━━━━━━━━━━━━━━━━━━━━┛\n\n" +322          "📦 <b>Item:</b> <code>" + displayTypeName + "</code>\n" +323          "💰 <b>Paid:</b> <code>₹" + finalCost + "</code> " + (isResellerFlow ? "<b>(Reseller)</b>" : "") + "\n" +324          "━━━━━━━━━━━━━━━━━━━━━━━━━━\n" +325          "👤 <b>ACCOUNT DETAILS:</b>\n\n" +326          "🚀 <b>Email:</b> <code>" + emailData + "</code>\n" +327          "🔒 <b>Password:</b> <code>" + passwordData + "</code>\n" +328          "━━━━━━━━━━━━━━━━━━━━━━━━━━\n" +329          "⚠️ <i>Copy details instantly.</i>";330 331        Api.sendMessage({332          chat_id: chat.chatid,333          text: deliveryText,334          parse_mode: "HTML"335        });336 337        var adminLogChannel = String(Bot.getProperty("owner_id") || "7127818616");338        var adminNotificationMsg =339          "<blockquote>⚠️ <b>NEW ORDER ALERT (QR)</b>" + (isResellerFlow ? " [RESELLER]" : "") + "</blockquote>\n" +340          "👤 <b>User:</b> <a href='tg://user?id=" + userId + "'>" + user.first_name + "</a> (<code>" + userId + "</code>)\n" +341          "📦 <b>Item:</b> <code>" + displayTypeName + "</code>\n" +342          "💰 <b>Revenue:</b> <code>₹" + finalCost + "</code>\n" +343          "⚡ <b>Stock Left:</b> <code>" + stockData.length + " units</code>\n\n" +344          "🖥 <b>ACCOUNT DETAILS:</b>\n" +345          "➔ <b>Email:</b> <code>" + emailData + "</code>\n" +346          "➔ <b>Password:</b> <code>" + passwordData + "</code>";347 348        Api.sendMessage({349          chat_id: adminLogChannel,350          text: adminNotificationMsg,351          parse_mode: "HTML"352        });353 354        // Cleanup all buy_ state for this order355        User.setProperty("buy_flow_type", null, "string");356        User.setProperty("buy_ffid_rawtype", null, "string");357        User.setProperty("buy_ffid_is_reseller", null, "boolean");358        User.setProperty("buy_price", null, "number");359        User.setProperty("buy_needpay", null, "number");360        User.setProperty("buy_selected_gateway", null, "string");361        User.setProperty("buy_prod_name", null, "string");362        User.setProperty("buy_plan_unit", null, "string");363        User.setProperty("buy_plan_name_on_website", null, "string");364        User.setProperty("buy_pending_order_id", null);365        Bot.setProperty("buy_qr_msg_id_" + userId, null, "string");366        User.setProperty("buy_qr_msg_id_" + userId, null, "string");367        Bot.setProperty("buy_qr_caption_" + userId, null, "string");368        User.setProperty("buy_qr_caption_" + userId, null, "string");369        Bot.setProperty("buy_qr_buttons_" + userId, null, "string");370        User.setProperty("buy_qr_buttons_" + userId, null, "string");371 372      } catch (ffErr) {373        Api.editMessageCaption({374          chat_id: chat.chatid, message_id: request.message.message_id,375          caption: "⚠️ Delivery error. Contact admin with UTR: " + utr + " | Error: " + ffErr.message,376          parse_mode: "HTML"377        });378      }379      User.setProperty("buy_verifying_lock_" + userId, false, "boolean");380      return;381    }382 383    // =========================================================384    // 📦 ORIGINAL PLAN-BASED DELIVERY (external xyzcheats API)385    // =========================================================386    var prodIdx = User.getProperty("buy_prod_idx");387    var planIdx = User.getProperty("buy_plan_idx");388    var productList = Bot.getProperty("stored_products") || [];389    var product = productList[prodIdx];390    var plan = product && product.plans ? product.plans[planIdx] : null;391 392    if (!product || !plan) {393      Api.editMessageCaption({394        chat_id: chat.chatid, message_id: request.message.message_id,395        caption: "⚠️ Payment received but product data missing. Contact admin with UTR: " + utr,396        parse_mode: "HTML"397      });398      User.setProperty("buy_verifying_lock_" + userId, false, "boolean");399      return;400    }401 402    // ✅ PID is plan-level: Add Plan stores the API PID on the selected plan.403    // Product itself no longer needs a PID.404    var webProductId = String((plan && (plan.pid || plan.product_id || plan.variant_id)) || "").trim();405    if (!webProductId) {406      Api.sendMessage({ chat_id: chat.chatid, text: "⚠️ Is plan ka PID set nahi hai. Admin ko Add Plan me PID number add karna hoga.", parse_mode: "HTML" });407      User.setProperty("buy_verifying_lock_" + userId, false, "boolean");408      return;409    }410    var cleanPlanDays = User.getProperty("buy_plan_days") || String(plan.days);411    var planUnit = User.getProperty("buy_plan_unit") || plan.unit || "day";412    var prodNameLower = String(product.name).toLowerCase();413    var durationParam = resolveApiDuration(plan, cleanPlanDays, planUnit, product && product.name);414 415    // 🔌 Use configured multi-API system instead of a hardcoded API.416    var apiRegistry = Bot.getProperty("api_registry") || {};417    var activeApiId = Bot.getProperty("active_reseller_api") || "";418    var selectedApi = activeApiId ? apiRegistry[activeApiId] : null;419    // 🌐 Product ko alag website assign hai (Multi Website)? To usi ka API use hoga.420    var __prodApiId = (product && product.api_id) ? String(product.api_id).trim() : "";421    if (__prodApiId && apiRegistry[__prodApiId]) { selectedApi = apiRegistry[__prodApiId]; activeApiId = __prodApiId; }422    if (!selectedApi) {423      selectedApi = null;424    }425    if (!selectedApi) {426      Bot.sendMessage("❌ No reseller API configured. Admin ko /apiadd se apna online API add karke /apiset se active karna hoga.");427      return;428    }429    if (selectedApi.enabled === false) {430      Bot.sendMessage("❌ Selected API is disabled. Admin ko /apiset se active API select karna hoga.");431      return;432    }433    var variantId = String((plan && (plan.pid || plan.product_id || plan.variant_id || plan.variantId)) || "").trim();434    if (!variantId) {435      Api.sendMessage({ chat_id: chat.chatid, text: "⚠️ Is plan ka PID set nahi hai. Admin ko Add Plan me PID number add karna hoga.", parse_mode: "HTML" });436      return;437    }438    var postFields = { api_key:selectedApi.api_key || "", action:"buy", variant_id:variantId, quantity:1, product_id:webProductId, duration:durationParam };439    if (selectedApi.policy) postFields.policy = String(selectedApi.policy);440    if (selectedApi.side) postFields.side = String(selectedApi.side);441    if (selectedApi.user_number) postFields.user_number = String(selectedApi.user_number);442    var savedAndroidId = User.getProperty("android_id") || User.getProperty("android_id_" + userId) || Bot.getProperty("android_id_" + userId) || "";443    if (selectedApi.android_required && !savedAndroidId) {444      Bot.sendMessage("⚠️ Android ID required for this API/product.");445      return;446    }447    if (savedAndroidId) postFields.android_id = String(savedAndroidId);448    var postFieldsString = Object.keys(postFields).map(function(k){ return encodeURIComponent(k) + "=" + encodeURIComponent(postFields[k]); }).join("&");449    User.setProperty("last_pending_api_id", String(selectedApi.id || activeApiId || ""), "string");450 451    User.setProperty("last_pending_price", User.getProperty("buy_price"), "number");452    User.setProperty("last_pending_prod_id", webProductId, "string");453    User.setProperty("last_pending_prod_name", String(product.name).trim(), "string");454    User.setProperty("last_pending_plan_days", cleanPlanDays, "string");455    User.setProperty("last_pending_plan_unit", planUnit, "string");456 457  // =====================================================458  // 🔌 ACCOUNTS API ADAPTER (reseller_v1 / generate_key POST|GET + extra params)459  // =====================================================460  var __apiSend = function (api, fields, hdrs) {461    var f = {}, h = {};462    Object.keys(fields).forEach(function (k) { f[k] = fields[k]; });463    Object.keys(hdrs).forEach(function (k) { h[k] = hdrs[k]; });464    var mode = String(api.mode || "reseller_v1");465    if (/hkmodz\.shop\/api\/v1\/generate_key\.php/i.test(String(api.url || ""))) mode = "hkmodz"; // URL se auto-detect466    var method = String(api.method || "POST").toUpperCase();467    if (mode === "hkmodz") {468      // HK MODZ API contract from the supplied client: POST generate_key.php,469      // X-API-Token header, variant_id + quantity. Do not send a fake "buy" action.470      var hkPid = String(f.variant_id || f.product_id || f.pid || "").trim();471      var hkQty = Math.max(1, Math.min(100, parseInt(f.quantity || 1, 10) || 1));472      f = { variant_id: hkPid, quantity: hkQty };473      h["X-API-Token"] = String(api.api_key || "");474      h["Accept"] = "application/json";475      h["Content-Type"] = "application/x-www-form-urlencoded";476      // Master key is kept separately in this account profile. The supplied HK client477      // documents X-API-Token as the auth header; send master key only as an optional header.478      if (api.master_key) h["X-Master-Key"] = String(api.master_key);479    } else if (mode === "generate_key") {480      var pidv = String(f.variant_id || f.product_id || "");481      if (api.action) f.action = String(api.action); else delete f.action;482      f.pid = pidv; f.plan_id = pidv; f.product_id = pidv; f.variant_id = pidv;483      if (api.master_key) { f.master_key = String(api.master_key); f.master = String(api.master_key); }484      if (api.api_key) { h["x-api-key"] = String(api.api_key); h["Authorization"] = "Bearer " + String(api.api_key); }485    }486    if (api.extra) {487      String(api.extra).split("&").forEach(function (kv) {488        var i = kv.indexOf("=");489        if (i > 0) f[kv.slice(0, i).trim()] = kv.slice(i + 1).trim();490      });491    }492    var body = Object.keys(f).map(function (k) { return encodeURIComponent(k) + "=" + encodeURIComponent(f[k]); }).join("&");493    if (method === "GET") {494      delete h["Content-Type"];495      HTTP.get({ url: String(api.url) + (String(api.url).indexOf("?") > -1 ? "&" : "?") + body, headers: h, success: "/onWebKeyReceive", error: "/onWebKeyError" });496    } else {497      HTTP.post({ url: String(api.url), body: body, headers: h, success: "/onWebKeyReceive", error: "/onWebKeyError" });498    }499  };500 501  __apiSend(selectedApi, postFields, (function(){ var h={"Content-Type":"application/x-www-form-urlencoded"}; if(selectedApi.master_key) h["x-master-key"]=selectedApi.master_key; if(selectedApi.policy) h["x-policy"]=String(selectedApi.policy); if(selectedApi.side) h["x-side"]=String(selectedApi.side); if(selectedApi.user_number) h["x-user-number"]=String(selectedApi.user_number); return h; })());502 503    User.setProperty("buy_pending_order_id", null);504    User.setProperty("buy_prod_idx", null);505    User.setProperty("buy_plan_idx", null);506    Bot.setProperty("buy_qr_msg_id_" + userId, null, "string");507    User.setProperty("buy_qr_msg_id_" + userId, null, "string");508    Bot.setProperty("buy_qr_caption_" + userId, null, "string");509    User.setProperty("buy_qr_caption_" + userId, null, "string");510    Bot.setProperty("buy_qr_buttons_" + userId, null, "string");511    User.setProperty("buy_qr_buttons_" + userId, null, "string");512    513    User.setProperty("buy_verifying_lock_" + userId, false, "boolean");514 515  } else {516    // ❌ Payment not found — restore original QR caption/buttons, then show dismissible notice517    try {518      var origCaption = Bot.getProperty("buy_qr_caption_" + userId) || User.getProperty("buy_qr_caption_" + userId);519      var origButtons = Bot.getProperty("buy_qr_buttons_" + userId) || User.getProperty("buy_qr_buttons_" + userId);520 521      if (origCaption) {522        Api.editMessageCaption({523          chat_id: chat.chatid,524          message_id: request.message.message_id,525          caption: origCaption,526          parse_mode: "HTML",527          reply_markup: origButtons ? origButtons : undefined528        });529      }530    } catch (e) {}531 532    if (request && request.id) {533      Api.answerCallbackQuery({534        callback_query_id: String(request.id),535        text: "❌ PAYMENT NOT FOUND ❌\nPlease complete the payment first, then tap again.",536        show_alert: true537      });538    }539    User.setProperty("buy_verifying_lock_" + userId, false, "boolean");540  }541 542} catch (err) {543  try {544    User.setProperty("buy_verifying_lock_" + user.telegramid, false, "boolean");545  } catch (e) {}546  Bot.sendMessage("⚠️ <b>Verification Exception:</b> " + err.message, { parse_mode: "HTML" });547}