const PAYKU_API_KEY = 'PAYKU_1234567890'; const PAYKU_SECRET_KEY = '11111aaaaa22222bbbbbb333333cccccccc'; const PAYKU_BASE_URL = 'https://payku.my.id'; const PREMIUM_PRICE = 15000; const PAYMENT_TIMEOUT = 10 * 60 * 1000; const pendingPayments = {}; function isPremium(userId) { return !!botData.premium[userId]; } async function createTransactionComplete(transactionData) { const timestamp = Date.now().toString(); const payload = { ...transactionData, timestamp }; const sortedKeys = Object.keys(payload).sort(); const stringToSign = sortedKeys.map(k => `${k}=${payload[k]}`).join('&'); const signature = crypto.createHmac('sha256', PAYKU_SECRET_KEY).update(stringToSign).digest('hex'); try { const response = await axios.post(`${PAYKU_BASE_URL}/api/create-transaction`, transactionData, { headers: { 'x-api-key': PAYKU_API_KEY, 'x-signature': signature, 'x-timestamp': timestamp, 'Content-Type': 'application/json' } }); if (response.data && response.data.success) { return { success: true, data: response.data.data, message: response.data.message || 'Transaction created successfully' }; } else { throw new Error(response.data?.message || 'Unknown error from API'); } } catch (error) { if (error.response) { const errorMsg = error.response.data?.message || error.response.statusText || 'API Error'; throw new Error(`API Error [${error.response.status}]: ${errorMsg}`); } else if (error.request) { throw new Error('Network Error: Unable to connect to payment gateway'); } else { throw new Error(`Transaction failed: ${error.message}`); } } } async function createPayment(userId, chatId) { try { const timestamp = Date.now().toString(); const transactionData = { external_id: `PREMIUM_${userId}_${timestamp}`, amount: PREMIUM_PRICE, description: "Premium Bot Access", customer_name: `User ${userId}`, customer_email: `user${userId}@telegram.bot`, customer_phone: "08123456789", // Default phone or get from user data webhook_url: process.env.WEBHOOK_URL || "https://your-bot-webhook.com/webhook" }; const result = await createTransactionComplete(transactionData); if (result.success && result.data) { return { success: true, qrUrl: result.data.qris_url, paymentUrl: result.data.payment_url, transactionId: result.data.transaction_id, externalId: transactionData.external_id }; } else { throw new Error(result.message || 'Failed to create transaction'); } } catch (error) { console.error('Error creating Payku payment:', error); return { success: false, error: error.message || 'Gagal membuat pembayaran, coba lagi nanti' }; } } async function checkPaymentStatus(transactionId) { try { const timestamp = Date.now().toString(); const payload = { transaction_id: transactionId, timestamp }; const sortedKeys = Object.keys(payload).sort(); const stringToSign = sortedKeys.map(k => `${k}=${payload[k]}`).join('&'); const signature = crypto.createHmac('sha256', PAYKU_SECRET_KEY).update(stringToSign).digest('hex'); const response = await axios.get(`${PAYKU_BASE_URL}/api/transaction/${transactionId}`, { headers: { 'x-api-key': PAYKU_API_KEY, 'x-signature': signature, 'x-timestamp': timestamp } }); if (response.data && response.data.success && response.data.data) { const transactionData = response.data.data; return { transaction_id: transactionData.transaction_id, external_id: transactionData.external_id, amount: transactionData.amount, total_amount: transactionData.total_amount, status: transactionData.status, // 'pending', 'paid', 'expired', 'cancelled' created_at: transactionData.created_at, expired_at: transactionData.expired_at, paid_at: transactionData.paid_at, payment_method: transactionData.payment_method, transaction_ref: transactionData.transaction_ref }; } else { return null; } } catch (error) { console.error('Error checking payment status:', error); if (error.response) { console.error('API Response Error:', error.response.data); } return null; } } setInterval(async () => { for (const [userId, payment] of Object.entries(pendingPayments)) { if (Date.now() - payment.timestamp > PAYMENT_TIMEOUT) { try { await bot.deleteMessage(payment.chatId, payment.messageId); } catch (e) { console.log('Gagal menghapus pesan timeout:', e); } delete pendingPayments[userId]; continue; } const transactionStatus = await checkPaymentStatus(payment.transactionId); if (transactionStatus) { if (transactionStatus.status === 'paid') { botData.premium[userId] = { activated: new Date().toISOString(), transactionId: payment.transactionId, externalId: transactionStatus.external_id, amount: transactionStatus.amount, totalAmount: transactionStatus.total_amount, paidAt: transactionStatus.paid_at, paymentMethod: transactionStatus.payment_method, transactionRef: transactionStatus.transaction_ref, permanent: true }; try { await bot.editMessageText( `✅ *PEMBAYARAN BERHASIL!*\n\n` + `Anda sekarang memiliki akses *PREMIUM PERMANEN*.\n` + `Seluruh konten premium sekarang dapat diakses.\n\n` + `💳 *Detail Pembayaran:*\n` + `• Transaction ID: ${transactionStatus.transaction_id}\n` + `• Amount: Rp ${transactionStatus.amount.toLocaleString('id-ID')}\n` + `• Total: Rp ${transactionStatus.total_amount.toLocaleString('id-ID')}\n` + `• Method: ${transactionStatus.payment_method}\n` + `• Paid: ${new Date(transactionStatus.paid_at).toLocaleString('id-ID')}`, { chat_id: payment.chatId, message_id: payment.messageId, parse_mode: 'Markdown', reply_markup: { inline_keyboard: [ [{ text: '🔓 LIHAT MEDIA PREMIUM', url: CHANNEL_LINK }], [{ text: '💎 INFO PREMIUM', callback_data: 'premium_info' }] ] } } ); } catch (e) { console.log('Gagal update pesan pembayaran:', e); } simpanData(); delete pendingPayments[userId]; } else if (transactionStatus.status === 'expired' || transactionStatus.status === 'cancelled') { try { await bot.editMessageText( `❌ *PEMBAYARAN ${transactionStatus.status.toUpperCase()}*\n\n` + `Transaksi telah ${transactionStatus.status === 'expired' ? 'kedaluwarsa' : 'dibatalkan'}.\n` + `Silakan buat pembayaran baru untuk mengakses premium.\n\n` + `Transaction ID: ${transactionStatus.transaction_id}`, { chat_id: payment.chatId, message_id: payment.messageId, parse_mode: 'Markdown', reply_markup: { inline_keyboard: [ [{ text: '🔄 BUAT PEMBAYARAN BARU', callback_data: 'create_payment' }] ] } } ); } catch (e) { console.log('Gagal update pesan pembayaran expired/cancelled:', e); } delete pendingPayments[userId]; } } } }, 30000); function handleWebhook(req, res) { try { const { transaction_id, status, external_id, amount, total_amount, payment_method, paid_at, transaction_ref } = req.body; const userId = Object.keys(pendingPayments).find(uid => pendingPayments[uid].transactionId === transaction_id ); if (userId && status === 'paid') { const payment = pendingPayments[userId]; botData.premium[userId] = { activated: new Date().toISOString(), transactionId: transaction_id, externalId: external_id, amount: amount, totalAmount: total_amount, paidAt: paid_at, paymentMethod: payment_method, transactionRef: transaction_ref, permanent: true }; bot.editMessageText( `✅ *PEMBAYARAN BERHASIL!*\n\n` + `Anda sekarang memiliki akses *PREMIUM PERMANEN*.\n` + `Seluruh konten premium sekarang dapat diakses.\n\n` + `💳 *Detail Pembayaran:*\n` + `• Transaction ID: ${transaction_id}\n` + `• Amount: Rp ${amount.toLocaleString('id-ID')}\n` + `• Total: Rp ${total_amount.toLocaleString('id-ID')}\n` + `• Method: ${payment_method}\n` + `• Paid: ${new Date(paid_at).toLocaleString('id-ID')}`, { chat_id: payment.chatId, message_id: payment.messageId, parse_mode: 'Markdown', reply_markup: { inline_keyboard: [ [{ text: '🔓 LIHAT MEDIA PREMIUM', url: CHANNEL_LINK }], [{ text: '💎 INFO PREMIUM', callback_data: 'premium_info' }] ] } } ).catch(console.error); simpanData(); delete pendingPayments[userId]; } else if (userId && (status === 'expired' || status === 'cancelled')) { const payment = pendingPayments[userId]; bot.editMessageText( `❌ *PEMBAYARAN ${status.toUpperCase()}*\n\n` + `Transaksi telah ${status === 'expired' ? 'kedaluwarsa' : 'dibatalkan'}.\n` + `Silakan buat pembayaran baru untuk mengakses premium.\n\n` + `Transaction ID: ${transaction_id}`, { chat_id: payment.chatId, message_id: payment.messageId, parse_mode: 'Markdown', reply_markup: { inline_keyboard: [ [{ text: '🔄 BUAT PEMBAYARAN BARU', callback_data: 'create_payment' }] ] } } ).catch(console.error); delete pendingPayments[userId]; } res.status(200).json({ success: true }); } catch (error) { console.error('Webhook error:', error); res.status(500).json({ success: false, error: error.message }); } } async function getTransactionDetails(transactionId) { try { const transactionData = await checkPaymentStatus(transactionId); if (transactionData) { return { success: true, data: transactionData }; } else { return { success: false, error: 'Transaction not found' }; } } catch (error) { return { success: false, error: error.message }; } }