indrajitghosh20006/Igstore_01botPublic ยท Bot Template

ProfileTelegram

AIThe bot provides an admin interface for a digital store, allowing the owner or coโ€‘admins to add balances, products, plans, and categories. It supports payment workflows via UPI and Binance Pay, automatically generating QR codes and handling manual approval of deposits. The code patches inline keyboards to use premium emoji icons and includes helper functions for user and bot properties. Overall, it serves as a commerce management tool for a Telegram-based storefront.

Commercestoreadminbalanceproductplancategory
170 commands0 envUpdated 8h agoCreated Oct 30, 2026
Back to folder

commands/_onBuyCheck.js

javascript ยท 580 lines

Raw
1/**#command2name: /onBuyCheck3answer: 4keyboard: 5parse_mode: markdown6aliases: 7allow_only_group: false8need_reply: false9is_web: 010#command**/11 12/**#command13name: /onBuyCheck14answer: 15keyboard: 16parse_mode: markdown17aliases: 18allow_only_group: false19need_reply: 020case_insensitive: false21is_web: 022#command**/23 24/**#command25name: /onBuyCheck26answer: 27keyboard: 28parse_mode: markdown29aliases: 30allow_only_group: false31need_reply: false32case_insensitive: false33is_web: 034#command**/35 36function resolveApiDuration(plan, cleanPlanDays, planUnit, productNameOverride) {37  // IMPORTANT: Keep the admin/API duration name exactly as entered.38  // The product-specific day ranges below are used only when the stored plan39  // contains a plain numeric Day duration; this lets 1-30 Day plans target40  // the exact website/API names requested by the admin without changing any41  // other product data or purchase logic.42  var raw = String((plan && (plan.api_duration || plan.name_on_website || plan.durationDisplay || plan.name || plan.title)) || "").replace(/\s+/g, " ").trim();43 44  // Already-custom API labels (including casing/suffixes) must pass through unchanged.45  if (raw && !/^[0-9]+(?:\.[0-9]+)?\s*(day|days)$/i.test(raw)) {46    return raw;47  }48 49  var dayMatch = raw.match(/^([0-9]+(?:\.[0-9]+)?)\s*(day|days)$/i);50  var n = dayMatch ? dayMatch[1] : String(cleanPlanDays || "1");51  var productName = String(productNameOverride || (plan && (plan.product_name || plan.productName || plan.product || plan.category)) || "").trim().toLowerCase();52 53  // If product name is not stored on the plan, the caller's raw API label is54  // still preserved above. Generic numeric Day plans remain "N Days".55  if (/pc\s*aim\s*silent/.test(productName)) return n + " Day Pc Aim Silent";56  if (/pc\s*modmenu\s*x86/.test(productName)) return n + " Day Pc Modmenu x86";57  if (/pc\s*bypass\s*\+\s*silent/.test(productName) || /bypass\s*\+\s*silent/.test(productName)) return n + " Days Pc Bypass + Silent";58  if (/nonroot/.test(productName) && !/root\s*\+\s*nonroot/.test(productName)) return n + " DaYS NONROOT";59  if (/pc\s*aimkill/.test(productName) || /aimkill/.test(productName)) return n + " DaYS PC AIMKILL";60  if (/root\s*\+\s*nonroot/.test(productName)) return n + " DaYs Root + Nonroot";61  if (/fluo?rite\s*ff/.test(productName)) return n + " DAYs FluoRite FF";62  if (/\broot\b/.test(productName)) return n + " DaYs ROOT";63  if (/all\s*colou?rs\s*mix/.test(productName)) return n + " DaYs All Colours Mix";64  if (/\bbasic\b/.test(productName)) return n + " DaYs Basic";65  if (/\bpro\b/.test(productName)) return n + " DaYs PRO";66  if (/\bsafe\b/.test(productName)) return n + " DaYs SAFE";67  if (/\bbrutal\b/.test(productName)) return n + " DaYs BRUTAL";68  if (/\bbrutal\b/.test(productName)) return n + " DaYs";69 70  // Hours/minutes are preserved exactly; no existing API duration is removed.71  var gh = raw.match(/^([0-9]+(?:\.[0-9]+)?)\s*(hour|hours)$/i);72  if (gh) return gh[1] + " Hours";73  var gm = raw.match(/^([0-9]+(?:\.[0-9]+)?)\s*(minute|minutes)$/i);74  if (gm) return gm[1] + (Number(gm[1]) === 1 ? " Minute" : " Minutes");75 76  return raw || n + " Days";77}78 79 80try {81  var userId = user.telegramid;82  var buyQrMessageId = (request && request.message && request.message.message_id) ||83    Bot.getProperty("buy_qr_msg_id_" + userId) || User.getProperty("buy_qr_msg_id_" + userId) || null;84 85  // โœ… CRITICAL FIX: Proper atomic duplicate-payment prevention86  var utrFromContent = null;87  88  // Parse content to get UTR early89  if (content) {90    var res = (typeof content === "object") ? content : JSON.parse(content);91 92  // Gram UPI Gateway confirms payment with status:true and data.status="PAID".93    if (res && res.data && res.data.utr) {94      utrFromContent = res.data.utr;95    }96  }97 98  // ๐Ÿ›‘ STEP 1: Check if payment already processed using UTR (most reliable identifier)99  if (utrFromContent && Bot.getProperty("paid_" + utrFromContent)) {100    // โœ… FIX: Vanish the QR completely instead of leaving a stale "already used" caption behind101    try {102      Api.deleteMessage({ chat_id: chat.chatid, message_id: buyQrMessageId });103    } catch (e) {}104 105    try {106      Bot.setProperty("buy_qr_msg_id_" + userId, null, "string");107      User.setProperty("buy_qr_msg_id_" + userId, null, "string");108    } catch (e) {}109 110    if (request && request.id) {111      try {112        Api.answerCallbackQuery({113          callback_query_id: String(request.id),114          text: "โœ… ALREADY CLAIMED โœ…\nYe order pehle hi deliver ho chuka hai.",115          show_alert: true116        });117      } catch (e) {}118    }119 120    Api.sendMessage({121      chat_id: chat.chatid,122      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>",123      parse_mode: "HTML",124      reply_markup: JSON.stringify({125        inline_keyboard: [[126          { text: "๐Ÿ“œ My Keys", callback_data: "/mykey", style: "primary" },127          { text: "๐Ÿ›’ Shop Menu", callback_data: "/buy_hack", style: "success" }128        ]]129      })130    });131    return;132  }133 134  // ๐Ÿ›‘ STEP 2: Duplicate-click lock check135  var isChecking = User.getProperty("buy_verifying_lock_" + userId);136  if (isChecking) {137    if (request && request.id) {138      Api.answerCallbackQuery({139        callback_query_id: String(request.id),140        text: "โณ ALREADY CHECKING โ€” PLEASE WAIT...",141        show_alert: true142      });143    }144    return;145  }146  147  // ๐Ÿ›‘ STEP 3: SET LOCK IMMEDIATELY before any async operations148  User.setProperty("buy_verifying_lock_" + userId, true, "boolean");149 150  if (!content) {151    if (buyQrMessageId && !(typeof options !== "undefined" && options && options.is_background)) {152      try { Api.editMessageCaption({153        chat_id: chat.chatid, message_id: buyQrMessageId,154        caption: "<blockquote>โš ๏ธ <b>Payment status is not available yet.</b>\nAutomatic verification will retry shortly.</blockquote>", parse_mode: "HTML"155      }); } catch (editErr) {}156    }157    User.setProperty("buy_verifying_lock_" + userId, false, "boolean");158    return;159  }160 161  var res = (typeof content === "object") ? content : JSON.parse(content);162 163  if (res.status === true && res.data && String(res.data.status || "").toUpperCase() === "PAID") {164    var expectedOrderId = String(User.getProperty("buy_pending_order_id") || "").trim();165    var reportedOrderId = String(res.data.order_id || "").trim();166    if (!expectedOrderId || !reportedOrderId || reportedOrderId !== expectedOrderId) {167      Api.editMessageCaption({168        chat_id: chat.chatid, message_id: buyQrMessageId,169        caption: "โŒ <b>Payment Order ID mismatch.</b> Ye payment is order ke saath match nahi karti.",170        parse_mode: "HTML"171      });172      User.setProperty("buy_verifying_lock_" + userId, false, "boolean");173      return;174    }175    var utr = res.data.utr || res.data.transaction_id || res.data.txn_id;176    var expectedBuyAmount = Number(User.getProperty("buy_expected_amount") || User.getProperty("buy_needpay") || 0);177    var reportedBuyAmount = Number(res.data.amount || res.data.payable_amount || 0);178    if (expectedBuyAmount > 0 && (!reportedBuyAmount || Math.abs(reportedBuyAmount - expectedBuyAmount) > 0.01)) {179      Api.editMessageCaption({180        chat_id: chat.chatid, message_id: buyQrMessageId,181        caption: "โŒ <b>Amount mismatch.</b> Expected โ‚น" + expectedBuyAmount.toFixed(2) + ", Gram UPI Gateway reported โ‚น" + reportedBuyAmount.toFixed(2) + ".",182        parse_mode: "HTML"183      });184      User.setProperty("buy_verifying_lock_" + userId, false, "boolean");185      return;186    }187 188    // Gateway success + UTR/transaction ID is required before any delivery.189    if (!utr) {190      Api.sendMessage({ chat_id: chat.chatid, text: "โŒ Payment response me valid UTR/transaction ID nahi mila.", parse_mode: "HTML" });191      User.setProperty("buy_verifying_lock_" + userId, false, "boolean");192      return;193    }194    Bot.setProperty("verified_txn_" + utr, { order_id: expectedOrderId, amount: reportedBuyAmount, sender_name: res.data.payer || res.data.sender_name || "", payment_time_ist: res.data.payment_time || res.data.payment_time_ist || "N/A" }, "json");195 196    var isPaid = Bot.getProperty("paid_" + utr);197 198    if (isPaid) {199      // โœ… FIX: Vanish the QR completely instead of leaving a stale "already used" caption behind200      try {201        Api.deleteMessage({ chat_id: chat.chatid, message_id: buyQrMessageId });202      } catch (e) {}203 204      try {205        Bot.setProperty("buy_qr_msg_id_" + userId, null, "string");206        User.setProperty("buy_qr_msg_id_" + userId, null, "string");207      } catch (e) {}208 209      if (request && request.id) {210        try {211          Api.answerCallbackQuery({212            callback_query_id: String(request.id),213            text: "โœ… ALREADY CLAIMED โœ…\nYe order pehle hi deliver ho chuka hai.",214            show_alert: true215          });216        } catch (e) {}217      }218 219      Api.sendMessage({220        chat_id: chat.chatid,221        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>",222        parse_mode: "HTML",223        reply_markup: JSON.stringify({224          inline_keyboard: [[225            { text: "๐Ÿ“œ My Keys", callback_data: "/mykey", style: "primary" },226            { text: "๐Ÿ›’ Shop Menu", callback_data: "/buy_hack", style: "success" }227          ]]228        })229      });230      User.setProperty("buy_verifying_lock_" + userId, false, "boolean");231      return;232    }233    234    // โœ… IMMEDIATELY mark as paid BEFORE any async API calls to prevent race condition235    Bot.setProperty("paid_" + utr, true, "boolean");236    Bot.setProperty("paid_order_" + expectedOrderId, true, "boolean");237    try { Bot.clearRunAfter({ label: "gram_buy_verify_" + expectedOrderId }); } catch (clearVerifyErr) {}238 239    if (buyQrMessageId) Api.editMessageCaption({240      chat_id: chat.chatid, message_id: buyQrMessageId,241      caption: "<tg-emoji emoji-id='6192822213486321961'>๐Ÿ”„</tg-emoji> <b>Payment verified! Delivering your key...</b>",242      parse_mode: "HTML"243    });244 245    // โœ… FIX: Detect which purchase pipeline this QR payment belongs to.246    // "ffid" = local stock-based FF ID item (set by /execute_id_buy on low balance)247    // default/"plan" = original plan-based product via external xyzcheats API248    var flowType = User.getProperty("buy_flow_type") || "plan";249 250    if (flowType === "ffid") {251      // =========================================================252      // ๐ŸŽฎ FF ID STOCK DELIVERY (after successful QR payment)253      // =========================================================254      try {255        var rawType = User.getProperty("buy_ffid_rawtype") || "";256        var isResellerFlow = User.getProperty("buy_ffid_is_reseller") === true;257        var finalCost = Number(User.getProperty("buy_price") || 0);258        var displayTypeName = User.getProperty("buy_prod_name") || rawType;259 260        var stockData = [];261        var isDynamicCategory = false;262        var isGeneralCategory = false;263        var selectedCat = null;264 265        var fbCategories = Bot.getProperty("fb_categories") || [];266        if (!Array.isArray(fbCategories)) { fbCategories = []; }267 268        if (rawType.indexOf("fb_") === 0) {269          isDynamicCategory = true;270          var targetCatId = rawType.replace("fb_", "").trim();271          for (var i = 0; i < fbCategories.length; i++) {272            if (fbCategories[i].id === targetCatId) { selectedCat = fbCategories[i]; break; }273          }274          if (selectedCat) { stockData = selectedCat.stock_list || []; }275        } else if (rawType === "fb" || rawType === "google") {276          stockData = Bot.getProperty("ff_stock_" + rawType) || [];277        } else {278          isGeneralCategory = true;279          var categoriesFF = Bot.getProperty("ff_categories") || {};280          selectedCat = categoriesFF[rawType];281          if (selectedCat) {282            var fallbackStock = Bot.getProperty("ff_stock_" + rawType) || [];283            stockData = (selectedCat.stock_list && selectedCat.stock_list.length > 0) ? selectedCat.stock_list : fallbackStock;284          }285        }286 287        if (!stockData || stockData.length === 0) {288          Api.editMessageCaption({289            chat_id: chat.chatid, message_id: buyQrMessageId,290            caption: "โš ๏ธ Payment received but item went out of stock. Contact admin with UTR: " + utr,291            parse_mode: "HTML"292          });293          User.setProperty("buy_verifying_lock_" + userId, false, "boolean");294          return;295        }296 297        var accountExtracted = stockData.shift();298 299        if (isDynamicCategory && selectedCat) {300          selectedCat.stock_list = stockData;301          Bot.setProperty("fb_categories", fbCategories, "json");302        } else if (isGeneralCategory && selectedCat) {303          selectedCat.stock_list = stockData;304          var categoriesFF2 = Bot.getProperty("ff_categories") || {};305          categoriesFF2[rawType] = selectedCat;306          Bot.setProperty("ff_categories", categoriesFF2, "json");307          Bot.setProperty("ff_stock_" + rawType, stockData, "json");308        } else {309          Bot.setProperty("ff_stock_" + rawType, stockData, "json");310        }311 312        var fullRawString = String(accountExtracted || "").trim();313        var emailData = fullRawString;314        var passwordData = "No Password Found";315 316        if (fullRawString.indexOf("|") !== -1) {317          var lastPipeIndex = fullRawString.lastIndexOf("|");318          var firstPart = fullRawString.substring(0, lastPipeIndex).trim();319          var secondPart = fullRawString.substring(lastPipeIndex + 1).trim();320 321          if (firstPart.indexOf(" ") !== -1) {322            var spaceParts = firstPart.split(" ");323            emailData = spaceParts[spaceParts.length - 1].trim();324          } else {325            emailData = firstPart;326          }327          passwordData = secondPart;328        }329 330        var purchasedKeys = User.getProperty("my_purchased_keys") || [];331        if (!Array.isArray(purchasedKeys)) { purchasedKeys = []; }332        var currentDate = new Date().toLocaleDateString('en-IN', { timeZone: "Asia/Kolkata" });333        purchasedKeys.push({334          productName: displayTypeName,335          cost: finalCost.toString(),336          key: emailData + (passwordData !== "No Password Found" ? " | " + passwordData : ""),337          days: "Permanent",338          date: currentDate339        });340        User.setProperty("my_purchased_keys", purchasedKeys, "json");341 342        var deliveryText =343          "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”“\n" +344          "โ”ƒ โค๏ธโ€๐Ÿ”ฅ <b>PURCHASE SUCCESSFUL!</b> โค๏ธโ€๐Ÿ”ฅ โ”ƒ\n" +345          "โ”—โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”›\n\n" +346          "๐Ÿ“ฆ <b>Item:</b> <code>" + displayTypeName + "</code>\n" +347          "๐Ÿ’ฐ <b>Paid:</b> <code>โ‚น" + finalCost + "</code> " + (isResellerFlow ? "<b>(Reseller)</b>" : "") + "\n" +348          "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n" +349          "๐Ÿ‘ค <b>ACCOUNT DETAILS:</b>\n\n" +350          "๐Ÿš€ <b>Email:</b> <code>" + emailData + "</code>\n" +351          "๐Ÿ”’ <b>Password:</b> <code>" + passwordData + "</code>\n" +352          "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n" +353          "โš ๏ธ <i>Copy details instantly.</i>";354 355        Api.sendMessage({356          chat_id: chat.chatid,357          text: deliveryText,358          parse_mode: "HTML"359        });360 361        var adminLogChannel = "7839151435";362        var adminNotificationMsg =363          "<blockquote>โš ๏ธ <b>NEW ORDER ALERT (QR)</b>" + (isResellerFlow ? " [RESELLER]" : "") + "</blockquote>\n" +364          "๐Ÿ‘ค <b>User:</b> <a href='tg://user?id=" + userId + "'>" + user.first_name + "</a> (<code>" + userId + "</code>)\n" +365          "๐Ÿ“ฆ <b>Item:</b> <code>" + displayTypeName + "</code>\n" +366          "๐Ÿ’ฐ <b>Revenue:</b> <code>โ‚น" + finalCost + "</code>\n" +367          "โšก <b>Stock Left:</b> <code>" + stockData.length + " units</code>\n\n" +368          "๐Ÿ–ฅ <b>ACCOUNT DETAILS:</b>\n" +369          "โž” <b>Email:</b> <code>" + emailData + "</code>\n" +370          "โž” <b>Password:</b> <code>" + passwordData + "</code>";371 372        Api.sendMessage({373          chat_id: adminLogChannel,374          text: adminNotificationMsg,375          parse_mode: "HTML"376        });377 378        // Cleanup all buy_ state for this order379        User.setProperty("buy_flow_type", null, "string");380        User.setProperty("buy_ffid_rawtype", null, "string");381        User.setProperty("buy_ffid_is_reseller", null, "boolean");382        User.setProperty("buy_price", null, "number");383        User.setProperty("buy_needpay", null, "number");384        User.setProperty("buy_prod_name", null, "string");385        User.setProperty("buy_plan_unit", null, "string");386        User.setProperty("buy_plan_name_on_website", null, "string");387        Bot.setProperty("pay_order_amount_" + expectedOrderId, null, "number");388        User.setProperty("pay_order_amount_" + expectedOrderId, null, "number");389        User.setProperty("buy_pending_order_id", null);390        Bot.setProperty("buy_qr_msg_id_" + userId, null, "string");391        User.setProperty("buy_qr_msg_id_" + userId, null, "string");392        Bot.setProperty("buy_qr_caption_" + userId, null, "string");393        User.setProperty("buy_qr_caption_" + userId, null, "string");394        Bot.setProperty("buy_qr_buttons_" + userId, null, "string");395        User.setProperty("buy_qr_buttons_" + userId, null, "string");396 397      } catch (ffErr) {398        Api.editMessageCaption({399          chat_id: chat.chatid, message_id: buyQrMessageId,400          caption: "โš ๏ธ Delivery error. Contact admin with UTR: " + utr + " | Error: " + ffErr.message,401          parse_mode: "HTML"402        });403      }404      User.setProperty("buy_verifying_lock_" + userId, false, "boolean");405      return;406    }407 408    // =========================================================409    // ๐Ÿ“ฆ ORIGINAL PLAN-BASED DELIVERY (external xyzcheats API)410    // =========================================================411    var prodIdx = User.getProperty("buy_prod_idx");412    var planIdx = User.getProperty("buy_plan_idx");413    var productList = Bot.getProperty("stored_products") || [];414    var product = productList[prodIdx];415    var plan = product && product.plans ? product.plans[planIdx] : null;416 417    if (!product || !plan) {418      Api.editMessageCaption({419        chat_id: chat.chatid, message_id: buyQrMessageId,420        caption: "โš ๏ธ Payment received but product data missing. Contact admin with UTR: " + utr,421        parse_mode: "HTML"422      });423      User.setProperty("buy_verifying_lock_" + userId, false, "boolean");424      return;425    }426 427    // =========================================================428    // ๐Ÿ“ฆ MANUAL STOCK FIRST FOR PAID PLAN ORDERS429    // If admin already added a key with /addstock, deliver that key here430    // instead of trying to generate/fetch another key from the website API.431    // The verified QR amount is first credited to the wallet temporarily;432    // /confirm_buyitem then performs the normal full-price deduction and433    // manual-stock delivery using the existing purchase path.434    // =========================================================435    try {436      var pDaysManual = String(User.getProperty("buy_plan_days") || plan.days || "").replace(/[^0-9.]/g, "").trim();437      var pUnitManual = User.getProperty("buy_plan_unit") || plan.unit || "day";438      var prodSlugManual = String(product.name || "").trim().toUpperCase().replace(/[^A-Z0-9_-]/g, "_");439      var manualStorageKey = "manual_keys_" + prodSlugManual + "_" + pDaysManual + "_" + pUnitManual;440      var legacyManualKey = "manual_keys_" + String(product.name || "").trim().toUpperCase() + "_" + pDaysManual;441      var backupManualKey = "stock_" + String(product.name || "").trim() + "_" + pDaysManual + "_Day";442      var manualCheckStock = Bot.getProperty(manualStorageKey);443 444      if ((!manualCheckStock || (Array.isArray(manualCheckStock) && manualCheckStock.length === 0)) &&445          pUnitManual === "day" && legacyManualKey !== manualStorageKey) {446        manualCheckStock = Bot.getProperty(legacyManualKey);447      }448      if (!manualCheckStock || (Array.isArray(manualCheckStock) && manualCheckStock.length === 0)) {449        manualCheckStock = Bot.getProperty(backupManualKey);450      }451      if (typeof manualCheckStock === "string" && manualCheckStock.trim() !== "") {452        try { manualCheckStock = JSON.parse(manualCheckStock); }453        catch (eStock) { manualCheckStock = manualCheckStock.split("\n").map(function(k){ return k.trim(); }).filter(Boolean); }454      }455 456      if (Array.isArray(manualCheckStock) && manualCheckStock.length > 0) {457        var verifiedCredit = Number(addedAmount || 0);458        if (!(verifiedCredit > 0)) throw new Error("Verified payment amount is invalid");459 460        // Credit only the verified QR payment; existing wallet balance stays intact.461        try { Libs.ResourcesLib.userRes("balance").add(verifiedCredit); } catch (eBal) {}462 463        User.setProperty("buy_manual_stock_paid", true, "boolean");464        Bot.run({465          command: "/confirm_buyitem",466          options: { params: String(prodIdx) + " " + String(planIdx) }467        });468 469        User.setProperty("buy_verifying_lock_" + userId, false, "boolean");470        return;471      }472    } catch (manualFlowErr) {473      // If manual-stock handoff fails, continue with the existing website/API flow.474    }475 476    // โœ… PID is plan-level: Add Plan stores the API PID on the selected plan.477    // Product itself no longer needs a PID.478    var webProductId = String((plan && (plan.pid || plan.product_id || plan.variant_id)) || "").trim();479    if (!webProductId) {480      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" });481      User.setProperty("buy_verifying_lock_" + userId, false, "boolean");482      return;483    }484    var cleanPlanDays = User.getProperty("buy_plan_days") || String(plan.days);485    var planUnit = User.getProperty("buy_plan_unit") || plan.unit || "day";486    var prodNameLower = String(product.name).toLowerCase();487    var durationParam = resolveApiDuration(plan, cleanPlanDays, planUnit, product && product.name);488 489    // ๐Ÿ”Œ Use configured multi-API system instead of a hardcoded API.490    var apiRegistry = Bot.getProperty("api_registry") || {};491    var activeApiId = Bot.getProperty("active_reseller_api") || "";492    var selectedApi = activeApiId ? apiRegistry[activeApiId] : null;493    if (!selectedApi) {494      selectedApi = null;495    }496    if (!selectedApi) {497      Bot.sendMessage("โŒ No reseller API configured. Admin ko /apiadd se apna online API add karke /apiset se active karna hoga.");498      return;499    }500    if (selectedApi.enabled === false) {501      Bot.sendMessage("โŒ Selected API is disabled. Admin ko /apiset se active API select karna hoga.");502      return;503    }504    var variantId = String((plan && (plan.pid || plan.product_id || plan.variant_id || plan.variantId)) || "").trim();505    if (!variantId) {506      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" });507      return;508    }509    var postFields = { api_key:selectedApi.api_key || "", action:"buy", variant_id:variantId, quantity:1, product_id:webProductId, duration:durationParam };510    if (selectedApi.policy) postFields.policy = String(selectedApi.policy);511    if (selectedApi.side) postFields.side = String(selectedApi.side);512    if (selectedApi.user_number) postFields.user_number = String(selectedApi.user_number);513    var savedAndroidId = User.getProperty("android_id") || User.getProperty("android_id_" + userId) || Bot.getProperty("android_id_" + userId) || "";514    if (selectedApi.android_required && !savedAndroidId) {515      Bot.sendMessage("โš ๏ธ Android ID required for this API/product.");516      return;517    }518    if (savedAndroidId) postFields.android_id = String(savedAndroidId);519    var postFieldsString = Object.keys(postFields).map(function(k){ return encodeURIComponent(k) + "=" + encodeURIComponent(postFields[k]); }).join("&");520    User.setProperty("last_pending_api_id", String(selectedApi.id || activeApiId || ""), "string");521 522    User.setProperty("last_pending_price", User.getProperty("buy_price"), "number");523    User.setProperty("last_pending_prod_id", webProductId, "string");524    User.setProperty("last_pending_prod_name", String(product.name).trim(), "string");525    User.setProperty("last_pending_plan_days", cleanPlanDays, "string");526    User.setProperty("last_pending_plan_unit", planUnit, "string");527 528    HTTP.post({529      url: selectedApi.url,530      body: postFieldsString,531      headers: (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; })(),532      success: "/onWebKeyReceive",533      error: "/onWebKeyError"534    });535 536    User.setProperty("buy_pending_order_id", null);537    User.setProperty("buy_prod_idx", null);538    User.setProperty("buy_plan_idx", null);539    Bot.setProperty("buy_qr_msg_id_" + userId, null, "string");540    User.setProperty("buy_qr_msg_id_" + userId, null, "string");541    Bot.setProperty("buy_qr_caption_" + userId, null, "string");542    User.setProperty("buy_qr_caption_" + userId, null, "string");543    Bot.setProperty("buy_qr_buttons_" + userId, null, "string");544    User.setProperty("buy_qr_buttons_" + userId, null, "string");545    546    User.setProperty("buy_verifying_lock_" + userId, false, "boolean");547 548  } else {549    // โŒ Payment not found โ€” restore original QR caption/buttons, then show dismissible notice550    try {551      var origCaption = Bot.getProperty("buy_qr_caption_" + userId) || User.getProperty("buy_qr_caption_" + userId);552      var origButtons = Bot.getProperty("buy_qr_buttons_" + userId) || User.getProperty("buy_qr_buttons_" + userId);553 554      if (origCaption) {555        Api.editMessageCaption({556          chat_id: chat.chatid,557          message_id: buyQrMessageId,558          caption: origCaption,559          parse_mode: "HTML",560          reply_markup: origButtons ? origButtons : undefined561        });562      }563    } catch (e) {}564 565    if (request && request.id) {566      Api.answerCallbackQuery({567        callback_query_id: String(request.id),568        text: "โŒ PAYMENT NOT FOUND โŒ\nPlease complete the payment first, then tap again.",569        show_alert: true570      });571    }572    User.setProperty("buy_verifying_lock_" + userId, false, "boolean");573  }574 575} catch (err) {576  try {577    User.setProperty("buy_verifying_lock_" + user.telegramid, false, "boolean");578  } catch (e) {}579  Bot.sendMessage("โš ๏ธ <b>Verification Exception:</b> " + err.message, { parse_mode: "HTML" });580}