const crypto = require('crypto'); const axios = require('axios'); class PayKuGateway { constructor(apiKey, secretKey, baseURL = "https://payku.my.id") { this.apiKey = apiKey; this.secretKey = secretKey; this.baseURL = baseURL; } generateSignature(payload) { const timestamp = Date.now().toString(); const payloadWithTimestamp = { ...payload, timestamp }; const sortedKeys = Object.keys(payloadWithTimestamp).sort(); const stringToSign = sortedKeys.map(k => `${k}=${payloadWithTimestamp[k]}`).join('&'); const signature = crypto.createHmac('sha256', this.secretKey).update(stringToSign).digest('hex'); return { signature, timestamp }; } // request qris async createTransaction(transactionData) { const { signature, timestamp } = this.generateSignature(transactionData); try { const response = await axios.post(`${this.baseURL}/api/create-transaction`, transactionData, { headers: { 'x-api-key': this.apiKey, '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) { return this.handleError(error, 'Create Transaction'); } } // cek transaksi async getTransactionStatus(transactionId) { const { signature, timestamp } = this.generateSignature({ transaction_id: transactionId }); try { const response = await axios.get(`${this.baseURL}/api/transaction/${transactionId}`, { headers: { 'x-api-key': this.apiKey, 'x-signature': signature, 'x-timestamp': timestamp, 'Content-Type': 'application/json' } }); if (response.data && response.data.success) { return { success: true, data: response.data.data, message: 'Transaction status retrieved successfully' }; } else { throw new Error(response.data?.message || 'Failed to get transaction status'); } } catch (error) { return this.handleError(error, 'Get Transaction Status'); } } // cancel request async cancelTransaction(transactionId) { const { signature, timestamp } = this.generateSignature({ transaction_id: transactionId }); try { const response = await axios.post(`${this.baseURL}/api/transaction/${transactionId}/cancel`, {}, { headers: { 'x-api-key': this.apiKey, 'x-signature': signature, 'x-timestamp': timestamp, 'Content-Type': 'application/json' } }); if (response.data && response.data.success) { return { success: true, message: response.data.message || 'Transaction cancelled successfully' }; } else { throw new Error(response.data?.message || 'Failed to cancel transaction'); } } catch (error) { return this.handleError(error, 'Cancel Transaction'); } } handleError(error, operation) { if (error.response) { const errorMsg = error.response.data?.message || error.response.statusText || 'API Error'; return { success: false, error: `${operation} API Error [${error.response.status}]: ${errorMsg}` }; } else if (error.request) { return { success: false, error: `${operation} Network Error: Unable to connect to payment gateway` }; } else { return { success: false, error: `${operation} failed: ${error.message}` }; } } } // ========== CONTOH PENGGUNAAN ========== const main = async () => { const payku = new PayKuGateway( "PAYKU_1234567890", // API Key "11111aaaaa22222bbbbbb333333cccccccc" // Secret Key ); try { const timestamp = Date.now().toString(); // request qris const createResult = await payku.createTransaction({ external_id: "SN" + timestamp, amount: 1000, description: "Test Payku Integration", customer_name: "Demo", customer_email: "demo@gmail.com", customer_phone: "08123456789", webhook_url: "https://payku.my.id/webhook" }); if (!createResult.success) { console.error('❌ Create Transaction Error:', createResult.error); return; } const transactionId = createResult.data.transaction_id; // cek status const statusResult = await payku.getTransactionStatus(transactionId); if (statusResult.success) { if (statusResult.data.paid_at) { } } else { console.error('❌ Get Status Error:', statusResult.error); } // cancel request yg belum sukses if (statusResult.success && statusResult.data.status !== 'paid') { const cancelResult = await payku.cancelTransaction(transactionId); if (cancelResult.success) { } else { console.error('❌ Cancel Transaction Error:', cancelResult.error); } } else if (statusResult.success && statusResult.data.status === 'paid') { console.log('\n⚠️ Cannot cancel paid transaction'); } } catch (error) { console.error('❌ Unexpected Error:', error.message); } }; main();