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 7h agoCreated Oct 30, 2026
Back to folder

commands/_confirm_buyitem.js

javascript Β· 542 lines

Raw
1/**#command2name: /confirm_buyitem3answer: 4keyboard: 5parse_mode: markdown6aliases: 7allow_only_group: false8need_reply: false9is_web: 010#command**/11 12// PREMIUM BUTTON ICONS13(function(){14  try {15    if (!JSON.__premiumPatched) {16      var __origStringify = JSON.stringify;17      JSON.stringify = function(value, replacer, space) {18        try {19          if (value && value.inline_keyboard && Array.isArray(value.inline_keyboard)) {20            var premiumIds = [21              "6143444134125379822",22              "6091379307907652768",23              "6147534454819661264",24              "6147817325660741985",25              "6235683689292897318",26              "6102856637343600044"27            ];28            var rows = value.inline_keyboard.map(function(row, ri) {29              if (!Array.isArray(row)) return row;30              return row.map(function(btn, bi) {31                if (!btn || typeof btn !== "object") return btn;32                var copy = {};33                for (var k in btn) copy[k] = btn[k];34                if (!copy.icon_custom_emoji_id) copy.icon_custom_emoji_id = premiumIds[(ri + bi) % premiumIds.length];35                return copy;36              });37            });38            var cloned = {};39            for (var key in value) cloned[key] = value[key];40            cloned.inline_keyboard = rows;41            return __origStringify.call(JSON, cloned, replacer, space);42          }43        } catch (e) {}44        return __origStringify.call(JSON, value, replacer, space);45      };46      JSON.__premiumPatched = true;47    }48  } catch (e) {}49})();50 51/**#command52name: /confirm_buyitem53answer: 54keyboard: 55parse_mode: markdown56aliases: 57allow_only_group: false58need_reply: false59case_insensitive: false60is_web: 061#command**/62 63function resolveApiDuration(plan, cleanPlanDays, planUnit, productNameOverride) {64  // IMPORTANT: Keep the admin/API duration name exactly as entered.65  // The product-specific day ranges below are used only when the stored plan66  // contains a plain numeric Day duration; this lets 1-30 Day plans target67  // the exact website/API names requested by the admin without changing any68  // other product data or purchase logic.69  var raw = String((plan && (plan.api_duration || plan.name_on_website || plan.durationDisplay || plan.name || plan.title)) || "").replace(/\s+/g, " ").trim();70 71  // Already-custom API labels (including casing/suffixes) must pass through unchanged.72  if (raw && !/^[0-9]+(?:\.[0-9]+)?\s*(day|days)$/i.test(raw)) {73    return raw;74  }75 76  var dayMatch = raw.match(/^([0-9]+(?:\.[0-9]+)?)\s*(day|days)$/i);77  var n = dayMatch ? dayMatch[1] : String(cleanPlanDays || "1");78  var productName = String(productNameOverride || (plan && (plan.product_name || plan.productName || plan.product || plan.category)) || "").trim().toLowerCase();79 80  // If product name is not stored on the plan, the caller's raw API label is81  // still preserved above. Generic numeric Day plans remain "N Days".82  if (/pc\s*aim\s*silent/.test(productName)) return n + " Day Pc Aim Silent";83  if (/pc\s*modmenu\s*x86/.test(productName)) return n + " Day Pc Modmenu x86";84  if (/pc\s*bypass\s*\+\s*silent/.test(productName) || /bypass\s*\+\s*silent/.test(productName)) return n + " Days Pc Bypass + Silent";85  if (/nonroot/.test(productName) && !/root\s*\+\s*nonroot/.test(productName)) return n + " DaYS NONROOT";86  if (/pc\s*aimkill/.test(productName) || /aimkill/.test(productName)) return n + " DaYS PC AIMKILL";87  if (/root\s*\+\s*nonroot/.test(productName)) return n + " DaYs Root + Nonroot";88  if (/fluo?rite\s*ff/.test(productName)) return n + " DAYs FluoRite FF";89  if (/\broot\b/.test(productName)) return n + " DaYs ROOT";90  if (/all\s*colou?rs\s*mix/.test(productName)) return n + " DaYs All Colours Mix";91  if (/\bbasic\b/.test(productName)) return n + " DaYs Basic";92  if (/\bpro\b/.test(productName)) return n + " DaYs PRO";93  if (/\bsafe\b/.test(productName)) return n + " DaYs SAFE";94  if (/\bbrutal\b/.test(productName)) return n + " DaYs BRUTAL";95  if (/\bbrutal\b/.test(productName)) return n + " DaYs";96 97  // Hours/minutes are preserved exactly; no existing API duration is removed.98  var gh = raw.match(/^([0-9]+(?:\.[0-9]+)?)\s*(hour|hours)$/i);99  if (gh) return gh[1] + " Hours";100  var gm = raw.match(/^([0-9]+(?:\.[0-9]+)?)\s*(minute|minutes)$/i);101  if (gm) return gm[1] + (Number(gm[1]) === 1 ? " Minute" : " Minutes");102 103  return raw || n + " Days";104}105 106 107// =========================================================108// βœ… ACTUAL PURCHASE EXECUTION β€” runs after user taps "Confirm" on the109// premium confirmation screen, OR automatically right after a shortfall110// QR payment is verified (see _onCheck.js), so key delivery is fully automatic.111// =========================================================112 113try {114 115  // πŸ›  PANEL MAINTENANCE GUARD116  // Re-check at every purchase/payment stage so an admin can switch a panel117  // OFF even if a user already opened the checkout screen.118  function isPanelUnderMaintenance(product) {119    if (!product) return false;120    var mKey = "panel_maintenance_" +121      String(product.id || product.name || "").toUpperCase().replace(/[^A-Z0-9_-]/g, "_");122    return Bot.getProperty(mKey) === true;123  }124 125  var productList = Bot.getProperty("stored_products") || [];126  var chatId = chat.chatid;127  var userId = user.telegramid;128 129  var parts = params ? String(params).trim().split(" ") : [];130  var prodIdx = Number(parts[0]);131  var planIdx = Number(parts[1]);132 133  var product = productList[prodIdx];134  // πŸ›  PANEL MAINTENANCE CHECK135  var panelMaintenanceKey = "panel_maintenance_" +136    String(product && (product.id || product.name) || prodIdx).toUpperCase().replace(/[^A-Z0-9_-]/g, "_");137  if (product && Bot.getProperty(panelMaintenanceKey) === true) {138    var maintenanceText = "πŸ›  <b>PANEL UNDER MAINTENANCE</b>\n\n" +139      "πŸ“¦ <b>Panel:</b> <code>" + String(product.name || "Product") + "</code>\n\n" +140      "⏳ Purchase/payment is temporarily disabled for this panel.\nPlease try again later.";141    var maintenanceCb = (request && request.id) ? request.id : ((request && request.callback_query && request.callback_query.id) || null);142    if (maintenanceCb) {143      try { Api.answerCallbackQuery({ callback_query_id: String(maintenanceCb), text: "πŸ›  Panel is under maintenance", show_alert: true }); } catch (e) {}144    }145    if (request && request.message && request.message.message_id) {146      try {147        Api.editMessageText({148          chat_id: String(chatId),149          message_id: Number(request.message.message_id),150          text: maintenanceText,151          parse_mode: "HTML",152          reply_markup: JSON.stringify({ inline_keyboard: [[153            { text: "⬅️ Back to Shop", callback_data: "/buy_hack", style: "danger", icon_custom_emoji_id: "5893163582194978381" }154          ]] })155        });156      } catch (e) {157        Api.sendMessage({ chat_id: String(chatId), text: maintenanceText, parse_mode: "HTML" });158      }159    } else {160      Api.sendMessage({ chat_id: String(chatId), text: maintenanceText, parse_mode: "HTML" });161    }162    return;163  }164 165  if (!product || !product.plans || !product.plans[planIdx]) {166    Api.sendMessage({ chat_id: chatId, text: "❌ Product or Plan configuration missing!" });167    return;168  }169 170  var plan = product.plans[planIdx];171  var planUnit = plan.unit || "day";172  var isReseller = Bot.getProperty("is_reseller_" + userId) === true;173 174  var cleanProdName = product.name.trim().toUpperCase();175  var cleanPlanDays = String(plan.days).replace(/[^0-9.]/g, "").trim();176  var unitLabelWord = (planUnit === "hour") ? (Number(cleanPlanDays) === 1 ? "Hour" : "Hours") :177                       (planUnit === "minute") ? (Number(cleanPlanDays) === 1 ? "Minute" : "Minutes") :178                       (Number(cleanPlanDays) === 1 ? "Day" : "Days");179  var durationDisplay = plan.durationDisplay || (cleanPlanDays + " " + unitLabelWord);180 181  var priceKeySuffix = (planUnit === "day") ? cleanPlanDays : (cleanPlanDays + "_" + planUnit);182  var normalKey = "price_normal_" + cleanProdName + "_" + priceKeySuffix;183  var resellerKey = "price_reseller_" + cleanProdName + "_" + priceKeySuffix;184 185  var adminNormalPrice = Bot.getProperty(normalKey);186  var adminResellerPrice = Bot.getProperty(resellerKey);187 188  var currentNormal = (adminNormalPrice !== undefined && adminNormalPrice !== null) ? adminNormalPrice : plan.normal_price;189  var currentReseller = (adminResellerPrice !== undefined && adminResellerPrice !== null) ? adminResellerPrice : plan.reseller_price;190 191  var basePrice = isReseller ? Number(currentReseller) : Number(currentNormal);192  var memberPriceKey = "member_custom_price_" + userId + "_" + cleanProdName.replace(/[^A-Z0-9_-]/g, "_") + "_" + ((planUnit === "day") ? cleanPlanDays : (cleanPlanDays + "_hour"));193  var memberCustomPrice = Bot.getProperty(memberPriceKey);194  var hasMemberCustomPrice = memberCustomPrice !== undefined && memberCustomPrice !== null && isFinite(Number(memberCustomPrice));195  var originalPrice = hasMemberCustomPrice ? Number(memberCustomPrice) : basePrice;196  var price = originalPrice;197 198  var planSpecificDiscKey = "auto_discount_" + cleanProdName + "_" + cleanPlanDays + "_" + planUnit.toUpperCase();199  var productWideDiscKey = "auto_discount_" + cleanProdName + "_ALL";200  var autoDiscountPercent = Bot.getProperty(planSpecificDiscKey) || Bot.getProperty(productWideDiscKey) || Bot.getProperty("auto_discount_global") || 0;201 202  // 🎟 Apply coupon discount (if any was applied for this exact prod/plan) β€” coupon overrides auto-discount203  var appliedCouponCode = User.getProperty("applied_coupon_" + prodIdx + "_" + planIdx);204  var couponDiscountPercent = 0;205  if (appliedCouponCode) {206    var couponRec0 = Bot.getProperty("coupon_" + appliedCouponCode);207    if (couponRec0 && couponRec0.discountPercent) {208      couponDiscountPercent = couponRec0.discountPercent;209      price = Number((originalPrice * (1 - couponDiscountPercent / 100)).toFixed(2));210    }211    User.setProperty("applied_coupon_" + prodIdx + "_" + planIdx, null, "string");212  } else if (autoDiscountPercent > 0) {213    couponDiscountPercent = autoDiscountPercent;214    price = Number((originalPrice * (1 - autoDiscountPercent / 100)).toFixed(2));215  }216 217  // πŸ›‘οΈ Safety re-check: balance abhi bhi sufficient hai ya nahi (race-condition guard)218  var unifiedBal = (function () {219    var resBal = 0;220    try { resBal = Number(Libs.ResourcesLib.userRes("balance").value()) || 0; } catch (e) {}221    var bonusBal = Number(Bot.getProperty("balance" + userId) || 0);222    return resBal + bonusBal;223  })();224 225  if (unifiedBal < price) {226    Api.sendMessage({227      chat_id: chatId,228      text: "⚠️ <b>Balance abhi kam hai.</b> Kripya phir se try karein.",229      parse_mode: "HTML"230    });231    return;232  }233 234  // =====================================================235  // πŸ”‘ STEP 0 β€” MANUAL STOCK FIRST CHECK (βœ… NEW)236  // Agar admin ne manually koi key already daal rakhi hai, to wahi seedha237  // deliver karo aur PAID EXTERNAL API ko bilkul call hi mat karo β€” taaki238  // "1 available key ke liye 2 keys spend" (1 manual + 1 wasted API buy)239  // wala bug kabhi na ho. API sirf tabhi call hoga jab manual stock khaali ho.240  // =====================================================241  var pDaysNumOnly = cleanPlanDays;242  // Isolate stock by PRODUCT + duration + unit. 1 DAY and 1 HOUR never share stock.243  var productStockSlug = cleanProdName.replace(/[^A-Z0-9_-]/g, "_");244  var unitAwareManualKey = "manual_keys_" + productStockSlug + "_" + pDaysNumOnly + "_" + planUnit;245  var legacyDayKey = "manual_keys_" + cleanProdName + "_" + pDaysNumOnly;246  var manualKeysStorageKey = unitAwareManualKey;247  var backupStockKey = "stock_" + product.name.trim() + "_" + pDaysNumOnly + "_Day";248  var isBackupUsed = false;249 250  var manualStock = Bot.getProperty(manualKeysStorageKey);251 252  // Backward compatibility for old Day-only stock buckets.253  if ((!manualStock || (Array.isArray(manualStock) && manualStock.length === 0)) &&254      planUnit === "day" && legacyDayKey !== manualKeysStorageKey) {255    manualStock = Bot.getProperty(legacyDayKey);256    if (manualStock && (!Array.isArray(manualStock) || manualStock.length > 0)) {257      manualKeysStorageKey = legacyDayKey;258    }259  }260 261  if (!manualStock || (Array.isArray(manualStock) && manualStock.length === 0)) {262    manualStock = Bot.getProperty(backupStockKey);263    isBackupUsed = true;264  }265  if (typeof manualStock === "string" && manualStock.trim() !== "") {266    try {267      manualStock = JSON.parse(manualStock);268    } catch (err) {269      manualStock = manualStock.split("\n").map(function (k) { return k.trim(); }).filter(Boolean);270    }271  }272 273  if (Array.isArray(manualStock) && manualStock.length > 0) {274    var generatedKey = manualStock.shift();275 276    if (isBackupUsed) {277      Bot.setProperty(backupStockKey, manualStock, "json");278      var mainStock = Bot.getProperty(manualKeysStorageKey) || [];279      if (typeof mainStock === "string") { mainStock = mainStock.split("\n").map(function (k) { return k.trim(); }).filter(Boolean); }280      if (Array.isArray(mainStock)) {281        var idx1 = mainStock.indexOf(generatedKey);282        if (idx1 > -1) { mainStock.splice(idx1, 1); }283        Bot.setProperty(manualKeysStorageKey, mainStock, "json");284      }285    } else {286      Bot.setProperty(manualKeysStorageKey, manualStock, "json");287      var backupStock2 = Bot.getProperty(backupStockKey) || [];288      if (typeof backupStock2 === "string") { backupStock2 = backupStock2.split("\n").map(function (k) { return k.trim(); }).filter(Boolean); }289      if (Array.isArray(backupStock2)) {290        var idx2 = backupStock2.indexOf(generatedKey);291        if (idx2 > -1) { backupStock2.splice(idx2, 1); }292        Bot.setProperty(backupStockKey, backupStock2, "json");293      }294    }295 296    // Permanently remember delivered manual keys so they cannot be added again.297    var soldKeyIndex = Bot.getProperty("manual_sold_key_index") || {};298    if (!soldKeyIndex || typeof soldKeyIndex !== "object") soldKeyIndex = {};299    soldKeyIndex[String(generatedKey)] = {300      product: String(product.name).trim(),301      duration: durationDisplay,302      user_id: String(userId),303      sold_at: new Date().toISOString()304    };305    Bot.setProperty("manual_sold_key_index", soldKeyIndex, "json");306 307    // πŸ’° Deduct balance + record purchase (same accounting as API path)308    Libs.ResourcesLib.userRes("balance").add(-price);309    var pastSpent2 = Bot.getProperty("total_spent_by_" + userId) || 0;310    Bot.setProperty("total_spent_by_" + userId, Number(pastSpent2) + price, "number");311 312 313    var keysHistory2 = User.getProperty("my_purchased_keys") || [];314    keysHistory2.push({315      product: String(product.name).trim(),316      product_id: (plan && (plan.pid || plan.product_id || plan.variant_id)) || null,317      days: pDaysNumOnly,318      price: price,319      key: generatedKey,320      date: new Date().toLocaleDateString()321    });322    User.setProperty("my_purchased_keys", keysHistory2, "json");323 324    var remainingBal2 = Libs.ResourcesLib.userRes("balance").value().toFixed(2);325 326    // βœ… NEW: Key ke saath automatic "Join Updates" button attach hota hai (agar admin ne link set kiya ho)327    var updateLinkForKey = Bot.getProperty("update_channel_link");328    var keyDeliveryButtons = [[{ text: "πŸ“‹ Copy Key", copy_text: { text: generatedKey } }]];329    if (updateLinkForKey) {330      keyDeliveryButtons.push([{ text: "πŸ“₯ Join Updates", url: updateLinkForKey, style: "primary", icon_custom_emoji_id: "6091571559233755994" }]);331    }332    keyDeliveryButtons.push([{ text: "Back to Menu", callback_data: "/back", style: "primary", icon_custom_emoji_id: "5877536313623711363" }]);333    var keyDeliveryMarkup = JSON.stringify({ inline_keyboard: keyDeliveryButtons });334 335    var deliverText2 = "<blockquote>" +336      "<tg-emoji emoji-id='5350447674971660988'>βœ…</tg-emoji> <b>PURCHASE SUCCESSFUL!</b>\n\n" +337      "<tg-emoji emoji-id='6147767796097884213'>πŸ“¦</tg-emoji> <b>Product:</b> <code>" + String(product.name).trim() + "</code>\n" +338      "<tg-emoji emoji-id='6284816251143331422'>πŸ—</tg-emoji> <b>Validity:</b> <code>" + durationDisplay + "</code>\n" +339      "<tg-emoji emoji-id='5352825278672412291'>πŸ‘†</tg-emoji> <b>Your Key:</b> <code>" + generatedKey + "</code>\n\n" +340      "━━━━━ <tg-emoji emoji-id='6147934084346682063'>#⃣</tg-emoji> <b>BALANCE DETAILS</b> ━━━━━\n" +341      "<tg-emoji emoji-id='6195037488898121775'>✨</tg-emoji> <b>Total Invest:</b> β‚Ή" + price.toFixed(2) + "\n" +342      "<tg-emoji emoji-id='5409048419211682843'>πŸ’΅</tg-emoji> <b>New Wallet Balance:</b> β‚Ή" + remainingBal2 + "\n\n" +343      "<i>Enjoy your purchase. <tg-emoji emoji-id='6057881002540274780'>πŸ₯³</tg-emoji></i>" +344      "</blockquote>";345 346    if (request && request.message) {347      try {348        Api.editMessageText({349          chat_id: String(chatId),350          message_id: Number(request.message.message_id),351          text: deliverText2,352          parse_mode: "HTML",353          reply_markup: keyDeliveryMarkup354        });355      } catch (e) {356        Api.sendMessage({ chat_id: chatId, text: deliverText2, parse_mode: "HTML", reply_markup: keyDeliveryMarkup });357      }358    } else {359      Api.sendMessage({ chat_id: chatId, text: deliverText2, parse_mode: "HTML", reply_markup: keyDeliveryMarkup });360    }361 362    var adminId3 = "7839151435";363    Api.sendMessage({364      chat_id: adminId3,365      text: "πŸ”” <b>NEW PURCHASE DELIVERED (MANUAL STOCK)</b> βœ”οΈ\n\n" +366            "πŸ‘€ <b>Buyer:</b> " + (user.first_name || "User") + " (<code>" + userId + "</code>)\n" +367            "πŸ“¦ <b>Product:</b> " + String(product.name).trim() + "\n" +368            "⏳ <b>Plan:</b> " + durationDisplay + "\n" +369            "πŸ’Έ <b>Price Deducted:</b> β‚Ή" + price.toFixed(2) + "\n" +370            "πŸ’³ <b>User Remaining Bal:</b> β‚Ή" + remainingBal2 + "\n" +371            "πŸ”‘ <b>Key:</b> <code>" + generatedKey + "</code>\n\n" +372            "<i>βœ… Manual stock se deliver hui β€” external paid API call SKIP ki gayi.</i>",373      parse_mode: "HTML"374    });375 376    var qId0 = request ? (request.id || (request.callback_query && request.callback_query.id)) : null;377    if (qId0) {378      try { Api.answerCallbackQuery({ callback_query_id: String(qId0), text: "βœ… Key Delivered!", show_alert: false }); } catch (e) {}379    }380 381    return; // 🚫 STOP β€” external API bilkul call nahi hui382  }383 384  // βœ… PID is plan-level: Add Plan stores the API PID on the selected plan.385    // Product itself no longer needs a PID.386    var webProductId = String((plan && (plan.pid || plan.product_id || plan.variant_id)) || "").trim();387    if (!webProductId) {388      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" });389      User.setProperty("buy_verifying_lock_" + userId, false, "boolean");390      return;391    }392  var prodNameLower = String(product.name).toLowerCase();393 394  var durationParam = resolveApiDuration(plan, cleanPlanDays, planUnit, product && product.name);395 396  // =====================================================397  // πŸ”Œ MULTI-API SYSTEM398  // Admin can add/update/select multiple reseller APIs.399  // The active API is used for external purchases.400  // =====================================================401  var apiRegistry = Bot.getProperty("api_registry") || {};402  var activeApiId = Bot.getProperty("active_reseller_api");403  var selectedApi = activeApiId ? apiRegistry[activeApiId] : null;404 405  if (!selectedApi) {406    Api.sendMessage({chat_id: chatId, text: "❌ No reseller API configured. Admin ko /apiadd se apna online API add karke /apiset se active karna hoga."});407    return;408  }409 410  if (selectedApi.enabled === false) {411    Api.sendMessage({chat_id: chatId, text: "❌ Selected API is disabled. Admin ko /apiset se another API select karna hoga."});412    return;413  }414 415  // βœ… PID is plan-level: Add Plan stores the API PID on the selected plan.416    // Product itself no longer needs a PID.417    var webProductId = String((plan && (plan.pid || plan.product_id || plan.variant_id)) || "").trim();418    if (!webProductId) {419      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" });420      User.setProperty("buy_verifying_lock_" + userId, false, "boolean");421      return;422    }423  var prodNameLower = String(product.name).toLowerCase();424 425  var durationParam = resolveApiDuration(plan, cleanPlanDays, planUnit, product && product.name);426 427  // Product-level API override is supported: product.api_id.428  var productApiId = product.api_id ? String(product.api_id).trim() : "";429  if (productApiId && apiRegistry[productApiId] && apiRegistry[productApiId].enabled !== false) {430    selectedApi = apiRegistry[productApiId];431    activeApiId = productApiId;432  }433 434  var variantId = String((plan && (plan.pid || plan.product_id || plan.variant_id || plan.variantId)) || "").trim();435    if (!variantId) {436      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" });437      return;438    }439  var postFields = {440    api_key: selectedApi.api_key || "",441    action: "buy",442    // keyspanelshop reseller_api.php accepts variant_id for key generation.443    variant_id: variantId,444    quantity: 1,445    // Keep these fields for backward compatibility with older API configs.446    product_id: webProductId,447    duration: durationParam448  };449  if (selectedApi.policy) postFields.policy = String(selectedApi.policy);450  if (selectedApi.side) postFields.side = String(selectedApi.side);451  if (selectedApi.user_number) postFields.user_number = String(selectedApi.user_number);452 453  // Device-bound APIs can require android_id. The value may be saved by454  // your existing product/user flow as android_id_<USER_ID>.455  var savedAndroidId = User.getProperty("android_id") || User.getProperty("android_id_" + userId) ||456                       Bot.getProperty("android_id_" + userId) || "";457  if (selectedApi.android_required) {458    if (!savedAndroidId) {459      Api.sendMessage({460        chat_id: chatId,461        text: "⚠️ <b>Android ID required</b>\nIs API/product ke liye Android ID zaroori hai. Pehle user ka Android ID save karein.",462        parse_mode: "HTML"463      });464      return;465    }466    postFields.android_id = String(savedAndroidId);467  } else if (savedAndroidId) {468    // Optional APIs may also accept it.469    postFields.android_id = String(savedAndroidId);470  }471 472  var apiHeaders = {473    "Content-Type": "application/x-www-form-urlencoded"474  };475  if (selectedApi.master_key) apiHeaders["x-master-key"] = selectedApi.master_key;476  if (selectedApi.policy) apiHeaders["x-policy"] = String(selectedApi.policy);477  if (selectedApi.side) apiHeaders["x-side"] = String(selectedApi.side);478  if (selectedApi.user_number) apiHeaders["x-user-number"] = String(selectedApi.user_number);479 480  var postFieldsString = Object.keys(postFields).map(function(k) {481    return encodeURIComponent(k) + "=" + encodeURIComponent(postFields[k]);482  }).join("&");483 484  User.setProperty("last_pending_price", Number(price), "number");485  User.setProperty("last_pending_prod_id", webProductId, "string");486  User.setProperty("last_pending_prod_name", String(product.name).trim(), "string");487  User.setProperty("last_pending_plan_days", cleanPlanDays, "string");488  User.setProperty("last_pending_plan_unit", planUnit, "string");489  User.setProperty("last_pending_api_id", String(selectedApi.id || activeApiId || ""), "string");490 491  var queryId = request ? (request.id || (request.callback_query && request.callback_query.id)) : null;492 493  var processingText = "<tg-emoji emoji-id='6147936236125298267'>⏳</tg-emoji> <b>Processing your order... please wait!</b>";494  if (request && request.message) {495    try {496      Api.editMessageText({497        chat_id: String(chatId),498        message_id: Number(request.message.message_id),499        text: processingText,500        parse_mode: "HTML"501      });502      Bot.setProperty("gen_msg_id_" + userId, request.message.message_id, "string");503      User.setProperty("gen_msg_id_" + userId, request.message.message_id, "string");504    } catch (e) {505      var pm1 = Api.sendMessage({ chat_id: chatId, text: processingText, parse_mode: "HTML" });506      try {507        var pmid1 = (pm1 && pm1.result && pm1.result.message_id) ? pm1.result.message_id : (pm1 && pm1.message_id ? pm1.message_id : null);508        if (pmid1) { Bot.setProperty("gen_msg_id_" + userId, pmid1, "string"); User.setProperty("gen_msg_id_" + userId, pmid1, "string"); }509      } catch (e2) {}510    }511  } else {512    var pm2 = Api.sendMessage({ chat_id: chatId, text: processingText, parse_mode: "HTML" });513    try {514      var pmid2 = (pm2 && pm2.result && pm2.result.message_id) ? pm2.result.message_id : (pm2 && pm2.message_id ? pm2.message_id : null);515      if (pmid2) { Bot.setProperty("gen_msg_id_" + userId, pmid2, "string"); User.setProperty("gen_msg_id_" + userId, pmid2, "string"); }516    } catch (e2) {}517  }518 519  HTTP.post({520    url: selectedApi.url,521    body: postFieldsString,522    headers: apiHeaders,523    success: "/onWebKeyReceive",524    error: "/onWebKeyError"525  });526 527  if (queryId) {528    try {529      Api.answerCallbackQuery({530        callback_query_id: String(queryId),531        text: "⏳ Processing your order... Please wait!",532        show_alert: false533      });534    } catch (e) {}535  }536 537} catch (e) {538  var errChatId = (typeof chat !== "undefined" && chat && chat.chatid) ? chat.chatid : null;539  if (errChatId) {540    try { Api.sendMessage({ chat_id: errChatId, text: "❌ <b>Error:</b> <code>" + e.message + "</code>", parse_mode: "HTML" }); } catch (fatal) {}541  }542}