tarunpoonia905/OfcDevShopBotPublic · Bot Template
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
commands/_onBuyCheck.js
javascript · 547 lines
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}