### Check Balance Response Source: https://docs.ipaymu.com/id/docs/balance/check-balance Example response from the balance check endpoint. Shows the merchant balance and member balance. ```json { "Status": 200, "Data": { "Va": "YOUR_IPAYMU_VA", "MerchantBalance": "1500000", "MemberBalance": "0" }, "Message": "success" } ``` -------------------------------- ### Required Headers Source: https://docs.ipaymu.com/id/docs/payment/direct-payment Lists the required HTTP headers for iPaymu Direct Payment API requests, including their types, example values, and descriptions. ```APIDOC ## Required Headers ### Description These headers must be included in every iPaymu Direct Payment API request. ### Headers #### Content-Type - **Type**: string - **Example**: `application/json` - **Description**: MIME type for the JSON request body. #### va - **Type**: string - **Example**: `YOUR_VA` - **Description**: Merchant Virtual Account number. Obtain from the Integration menu in the iPaymu dashboard (Production/Sandbox). Use the VA corresponding to the selected environment. #### signature - **Type**: string (64 hex) - **Example**: `GENERATED_SIGNATURE` - **Description**: HMAC-SHA256 signature for this request using the API Key from Production/Sandbox. Do not fill this header with the API Key. See Signature Generation. #### timestamp - **Type**: string (14 digits) - **Example**: `20260102153045` - **Description**: Time the request was created, format `YYYYMMDDHHmmss` (e.g., 2 Jan 2026, 15:30:45). Follow endpoint guidelines if ISO 8601 is required. ### Example ``` Content-Type: application/json va: YOUR_VA signature: GENERATED_SIGNATURE timestamp: 20260102153045 ``` ``` -------------------------------- ### POST /payment/redirect Source: https://docs.ipaymu.com/id/docs/payment/redirect-payment Creates a redirect payment session. Sends product details and URLs, and returns a payment URL to redirect the user to. ```APIDOC ## POST /payment/redirect ### Description Creates a redirect payment session. Sends product details and URLs, and returns a payment URL to redirect the user to. ### Method POST ### Endpoint /payment/redirect ### Parameters #### Request Body - **product[]** (array) - Required - Daftar nama produk. - **qty[]** (array) - Required - Daftar jumlah produk. - **price[]** (array) - Required - Daftar harga produk. - **description[]** (array) - Required - Daftar deskripsi produk. - **imageUrl[]** (array) - Optional - Opsional. Ganti gambar produk di halaman pembayaran iPaymu. Diurutkan berdasarkan index. - **returnUrl** (string) - Required - URL untuk redirect setelah pembayaran berhasil. - **notifyUrl** (string) - Required - URL untuk menerima notifikasi webhook. - **cancelUrl** (string) - Required - URL untuk redirect setelah pembayaran gagal/dibatalkan. - **referenceId** (string) - Optional - ID transaksi unik Anda. - **buyerName** (string) - Optional - Nama pembeli. - **buyerEmail** (string) - Optional - Email pembeli. - **buyerPhone** (string) - Optional - Telepon pembeli. - **expired** (number) - Optional - Waktu kedaluwarsa kustom dalam jam. - **feeDirection** (string) - Optional - `BUYER` atau `MERCHANT`. - **paymentMethod** (string) - Optional - Pilih metode pembayaran pra-seleksi (misal: `va`, `cc`). - **account** (string) - Optional - ID Child account VA (opsional). ### Request Example ```json { "product": ["T-Shirt"], "qty": ["1"], "price": ["100000"], "description": ["Blue Size L"], "imageUrl": ["https://images.com/example.jpg"], "returnUrl": "https://your-website.com/thank-you", "notifyUrl": "https://your-website.com/callback", "cancelUrl": "https://your-website.com/cancel", "referenceId": "INV-002" } ``` ### Response #### Success Response (200) - **Status** (number) - Status code. - **Message** (string) - Response message. - **Data** (object) - Contains SessionID and Url. - **SessionID** (string) - Unique session identifier. - **Url** (string) - Payment URL to redirect the user to. #### Response Example ```json { "Status": 200, "Message": "success", "Data": { "SessionID": "91538218-5158-459B-8716-DD97FFE3EDAB", "Url": "https://sandbox.ipaymu.com/payment/91538218-5158-459B-8716-DD97FFE3EDAB" } } ``` ### Notes Anda harus mengarahkan pengguna ke `Url` yang disediakan dalam response. ``` -------------------------------- ### Get Provinces - curl Request Source: https://docs.ipaymu.com/id/docs/area-api Example curl command to call the Get Provinces endpoint. Requires Content-Type, va, signature, and timestamp headers. ```bash curl --location 'https://sandbox.ipaymu.com/api/areas/province' \ --header 'Content-Type: application/json' \ --header 'va: YOUR_IPAYMU_VA' \ --header 'signature: ' \ --header 'timestamp: 20260629103000' ``` -------------------------------- ### Get Villages by District - curl Request Source: https://docs.ipaymu.com/id/docs/area-api Example curl command to call the Get Villages by District endpoint with district code 517101. Requires the same headers as other endpoints. ```bash curl --location 'https://sandbox.ipaymu.com/api/areas/village/517101' \ --header 'Content-Type: application/json' \ --header 'va: YOUR_IPAYMU_VA' \ --header 'signature: ' \ --header 'timestamp: 20260629103000' ``` -------------------------------- ### POST /api/v2/payment/direct Source: https://docs.ipaymu.com/id/docs/payment/direct-payment Endpoint untuk memproses pembayaran langsung (Direct Payment). Merchant mengirim HTTP POST dengan detail transaksi, paymentMethod, dan paymentChannel, lalu menerima respons berupa nomor pembayaran atau URL redirect. ```APIDOC ## POST /api/v2/payment/direct ### Description Endpoint ini digunakan untuk memproses pembayaran langsung (Direct Payment). Merchant mengirim HTTP POST ke endpoint ini berisi detail transaksi, paymentMethod & paymentChannel. ### Method POST ### Endpoint `/api/v2/payment/direct` ### Environment - Sandbox: `https://sandbox.ipaymu.com/api/v2/payment/direct` - Production: `https://production.ipaymu.com/api/v2/payment/direct` (as per text: Production environment uses the same path with production credentials) ### Authentication Gunakan kredensial sesuai lingkungan yang dipilih. Kredensial Sandbox dan Production berbeda. Dalam mode Production, pastikan server Anda menggunakan IP Statis dan domain Anda terdaftar. ### Request Body Merchant mengirim detail transaksi, paymentMethod & paymentChannel. (Specific fields not listed in source) ### Response #### Success Response (200 OK) iPaymu mengembalikan PaymentNo (Virtual Account) atau Url redirect/QR (e-Wallet/QRIS) kepada Merchant. ### Flow 1. Merchant mengirim HTTP POST ke /api/v2/payment/direct berisi detail transaksi, paymentMethod & paymentChannel. 2. Server iPaymu memverifikasi signature header & membuat nomor pembayaran / QR / URL e-Wallet. 3. iPaymu mengembalikan PaymentNo (Virtual Account) atau Url redirect/QR (e-Wallet/QRIS) kepada Merchant. 4. Pelanggan membayar via M-Banking / minimarket / scan QRIS / buka aplikasi e-Wallet. 5. iPaymu secara otomatis mengirimkan HTTP POST notifikasi callback ke notifyUrl Merchant. 6. Merchant mengunci status transaksi menjadi PAID di database & memberikan produk/layanan. ``` -------------------------------- ### Correct: Locale-aware key sorting Source: https://docs.ipaymu.com/id/docs/callback Correct approach: use localeCompare for case-insensitive sorting to match iPaymu's expected order. ```javascript const sorted = Object.keys(data).sort((a, b) => a.localeCompare(b)); ``` -------------------------------- ### Get Districts by City - curl Request Source: https://docs.ipaymu.com/id/docs/area-api Example curl command to call the Get Districts by City endpoint with city code 5171 (Denpasar). Requires the same headers as other endpoints. ```bash curl --location 'https://sandbox.ipaymu.com/api/areas/district/5171' \ --header 'Content-Type: application/json' \ --header 'va: YOUR_IPAYMU_VA' \ --header 'signature: ' \ --header 'timestamp: 20260629103000' ``` -------------------------------- ### Validasi Signature Callback iPaymu (JavaScript/Express, x-www-form-urlencoded) Source: https://docs.ipaymu.com/id/docs/callback Implementasi callback iPaymu dengan Express.js untuk memvalidasi signature HMAC-SHA256 pada request x-www-form-urlencoded. Menormalkan tipe data field, mengurutkan key, serialisasi JSON dengan escape garis miring, lalu membandingkan hash dengan header X-Signature. Secret key menggunakan nomor VA dari Dashboard > Integration > API Key. ```javascript import crypto from 'crypto'; import express from 'express'; const app = express(); app.use(express.urlencoded({ extended: true })); function normalizeData(rawData) { const result = {}; for (const key in rawData) { let val = rawData[key]; if (key === 'is_escrow') { result[key] = (val === 'true' || val === '1' || val === 1); } else if (['trx_id', 'status_code', 'transaction_status_code', 'paid_off'].includes(key)) { result[key] = parseInt(val, 10); } else if (key === 'additional_info') { if (val === '[]') result[key] = []; else result[key] = val; } else { result[key] = String(val); } } if (!result.hasOwnProperty('additional_info')) { result['additional_info'] = []; } return result; } function phpKsort(obj) { return Object.keys(obj) .sort((a, b) => a.localeCompare(b)) .reduce((sortedObj, key) => { sortedObj[key] = obj[key]; return sortedObj; }, {}); } app.post('/callback', (req, res) => { const secretKey = '123456'; // Nomor VA akun iPaymu Anda (lihat di Dashboard > Integration > API Key) const receivedSignature = req.headers['x-signature']; // Step 1 & 2: Ambil dan normalisasi data const normalizedData = normalizeData(req.body); if (normalizedData.signature) delete normalizedData.signature; // Step 3 & 4: Sort key const sortedData = phpKsort(normalizedData); // Step 5 & 6: Konversi ke JSON dengan escape let jsonBody = JSON.stringify(sortedData); jsonBody = jsonBody.replace(/\//g, '\\/'); // Step 7: Generate hash const calculatedSignature = crypto .createHmac('sha256', secretKey) .update(jsonBody) .digest('hex'); // Step 8: Bandingkan signature if (calculatedSignature === receivedSignature) { console.log('✅ Signature valid'); // TODO: Update status transaksi di database // TODO: Pastikan idempotency - cek apakah sudah diproses sebelumnya res.status(200).json({ status: 'OK' }); } else { console.log('❌ Signature tidak valid'); console.log('Expected:', receivedSignature); console.log('Got: ', calculatedSignature); res.status(400).send('Invalid Signature'); } }); app.listen(PORT, () => { console.log('═══════════════════════════════════════════════════'); console.log(' iPaymu Callback Handler - URL-encoded'); console.log('═══════════════════════════════════════════════════'); console.log(` Server running on http://localhost:${PORT}`); console.log(` Endpoint: POST http://localhost:${PORT}/callback`); console.log('═══════════════════════════════════════════════════'); }); ``` -------------------------------- ### Get Cities by Province - curl Request Source: https://docs.ipaymu.com/id/docs/area-api Example curl command to call the Get Cities by Province endpoint with province code 51 (Bali). Requires the same headers as other endpoints. ```bash curl --location 'https://sandbox.ipaymu.com/api/areas/city/51' \ --header 'Content-Type: application/json' \ --header 'va: YOUR_IPAYMU_VA' \ --header 'signature: ' \ --header 'timestamp: 20260629103000' ``` -------------------------------- ### Direct Payment Response JSON Source: https://docs.ipaymu.com/id/docs/payment/direct-payment Example JSON response from iPaymu after a direct payment request. Contains transaction ID, reference ID, payment channel details, total amount, fee, expiry, and payment URL. ```json { "Status": 200, "Success": true, "Message": "Success", "Data": { "TransactionId": 12345, "ReferenceId": "REF123456", "Via": "va", "Channel": "bca", "PaymentNo": "1234567890", "PaymentName": "BCA Virtual Account", "Total": 10000, "Fee": 0, "Expired": "2023-12-31 23:59:59", "Note": null, "Url": "https://sandbox.ipaymu.com/payment/12345" } } ``` -------------------------------- ### Node.js Signature Generation Example Source: https://docs.ipaymu.com/id/docs/area-api Node.js code using the crypto module to generate the signature for a GET request. It hashes an empty JSON body '{}', constructs the string to sign, and produces the HMAC-SHA256 signature and timestamp. ```javascript const crypto = require('crypto'); const va = 'YOUR_IPAYMU_VA'; const apiKey = 'YOUR_API_KEY'; const method = 'GET'; const body = '{}'; const requestBody = crypto.createHash('sha256').update(body).digest('hex').toLowerCase(); const stringToSign = `${method}:${va}:${requestBody}:${apiKey}`; const signature = crypto.createHmac('sha256', apiKey).update(stringToSign).digest('hex'); const timestamp = new Date().toISOString().replace(/[-:T]/g, '').slice(0, 14); ``` -------------------------------- ### Get Cities by Province - Endpoint Path Source: https://docs.ipaymu.com/id/docs/area-api GET request to retrieve cities/regencies for a given province. The {province} path parameter is the province code from the Get Provinces endpoint. ```http GET /areas/city/{province} ``` -------------------------------- ### POST /api/v2/payment/direct Source: https://docs.ipaymu.com/id/docs/cod Membuat transaksi pembayaran COD. Endpoint ini menerima data pembeli, jumlah, metode pembayaran, dan detail pengiriman. ```APIDOC ## [POST] /api/v2/payment/direct ### Description Membuat transaksi pembayaran COD (Cash On Delivery) dengan menyertakan detail pengiriman dan produk. ### Method POST ### Endpoint https://sandbox.ipaymu.com/api/v2/payment/direct ### Parameters #### Request Body - **name** (string) - Wajib - Nama pembeli. - **amount** (number) - Wajib - Total jumlah transaksi. - **paymentMethod** (string) - Wajib - Harus diisi `cod`. - **paymentChannel** (string) - Wajib - Kode channel pembayaran (misal: `rpx`). - **deliveryArea** (string) - Wajib - Kode pos pengiriman. - **deliveryAddress** (string) - Wajib - Alamat lengkap pengiriman. - **shipping** (string) - Wajib - Nama jasa pengiriman (misal: `RPX`). - **shippingService** (string) - Wajib - Tipe layanan pengiriman (misal: `REG`). ### Response #### Success Response Mengembalikan detail transaksi yang berhasil dibuat. Detail respons tidak dijelaskan dalam sumber. ``` -------------------------------- ### Example Request JSON for Redirect Payment Source: https://docs.ipaymu.com/id/docs/payment/redirect-payment Shows the JSON payload for a redirect payment request. Includes product details, return/notify/cancel URLs, and a reference ID. The imageUrl field is optional and ordered by index. ```json { "product": ["T-Shirt"], "qty": ["1"], "price": ["100000"], "description": ["Blue Size L"], "imageUrl": ["https://images.com/example.jpg"], "returnUrl": "https://your-website.com/thank-you", "notifyUrl": "https://your-website.com/callback", "cancelUrl": "https://your-website.com/cancel", "referenceId": "INV-002" } ``` -------------------------------- ### Get Districts by City - Endpoint Path Source: https://docs.ipaymu.com/id/docs/area-api GET request to retrieve districts for a given city/regency. The {city} path parameter is the city code from the Get Cities endpoint. ```http GET /areas/district/{city} ``` -------------------------------- ### Direct Payment Request JSON Source: https://docs.ipaymu.com/id/docs/payment/direct-payment Example JSON payload for creating a direct payment via iPaymu. Includes buyer details, amount, expiry, payment method (va) and channel (bca), product list, and delivery information. ```json { "name": "Buyer", "phone": "08123456789", "email": "buyer@mail.com", "amount": 10000, "notifyUrl": "https://mywebsite.com/callback", "expired": 24, "expiredType": "hours", "comments": "Payment for Order #123", "referenceId": "REF123456", "paymentMethod": "va", "paymentChannel": "bca", "product": ["Product A"], "qty": [1], "price": [10000], "weight": [1], "width": [1], "height": [1], "length": [1], "deliveryArea": "76111", "deliveryAddress": "Jalan Raya No. 1" } ``` -------------------------------- ### Get Villages by District - Endpoint Path Source: https://docs.ipaymu.com/id/docs/area-api GET request to retrieve villages for a given district. The {district} path parameter is the district code from the Get Districts endpoint. ```http GET /areas/village/{district} ``` -------------------------------- ### Get Provinces - Endpoint Path Source: https://docs.ipaymu.com/id/docs/area-api GET request to retrieve all provinces, sorted by name (A-Z). No parameters required. ```http GET /areas/province ``` -------------------------------- ### Example Success Response JSON Source: https://docs.ipaymu.com/id/docs/payment/redirect-payment Shows the JSON response for a successful redirect payment request. Contains a Status of 200, a success message, and a Data object with a SessionID and the payment Url. The user must redirect the customer to the provided Url. ```json { "Status": 200, "Message": "success", "Data": { "SessionID": "91538218-5158-459B-8716-DD97FFE3EDAB", "Url": "https://sandbox.ipaymu.com/payment/91538218-5158-459B-8716-DD97FFE3EDAB" } } ``` -------------------------------- ### Get Provinces - Response 200 OK Source: https://docs.ipaymu.com/id/docs/area-api Sample response for the Get Provinces endpoint, returning an array of province objects with code and name fields. ```json { "Status": 200, "Success": true, "Message": "Success", "Data": [ { "code": "11", "name": "ACEH" }, { "code": "51", "name": "BALI" }, { "code": "36", "name": "BANTEN" } ] } ``` -------------------------------- ### Correct: Use VA number as secret key Source: https://docs.ipaymu.com/id/docs/callback Correct approach: use the VA number from the iPaymu dashboard as the secret key. ```javascript const secretKey = '123456'; // Nomor VA akun iPaymu Anda (lihat di Dashboard > Integration > API Key) ``` -------------------------------- ### Get Districts by City - Response 200 OK Source: https://docs.ipaymu.com/id/docs/area-api Sample response for the Get Districts by City endpoint, returning an array of district objects with code and name fields. ```json { "Status": 200, "Success": true, "Message": "Success", "Data": [ { "code": "517101", "name": "DENPASAR SELATAN" }, { "code": "517102", "name": "DENPASAR TIMUR" } ] } ``` -------------------------------- ### iPaymu callback payload in JSON format Source: https://docs.ipaymu.com/id/docs/callback Example of the full callback payload sent by iPaymu when the Content-Type is application/json. Shows the JSON object with all callback parameters. Use this to understand the structure of JSON-encoded callbacks. ```json { "buyer_email": "customer@example.com", "buyer_name": "John Doe", "buyer_phone": "081234567890", "created_at": "2025-11-11 10:00:00", "expired_at": "2025-11-11 11:00:00", "fee": "1500", "paid_at": "2025-11-11 10:10:52", "reference_id": "ORDER123456", "sid": "SESSION789", "status": "berhasil", "status_code": "1", "status_desc": "Success", "channel": "bca", "paid_off": "98500", "product": "Product Name", "quantity": "1", "merchant": "YOUR_IPAYMU_VA", "merchant_name": "Your Store", "system_notes": "Payment completed", "trscode": "TRX789012", "trx_id": "12345678", "unique_code": "0", "via": "va", "payment_no": "1234567890", "va": "1234567890", "url": "https://your-domain.com/callback", "additional_info": [], "transaction_status_code": "1", "settlement_status": "unsettle", "settlement_date": null, "expired_time": "3600", "expired_unix": "1762842000", "is_escrow": "0", "is_refund": "0", "is_sandbox": "false", "total": "100000", "amount": "100000", "sub_total": "100000", "referenceId": "ORDER123456" } ``` -------------------------------- ### Get Cities by Province - Response 200 OK Source: https://docs.ipaymu.com/id/docs/area-api Sample response for the Get Cities by Province endpoint, returning an array of city objects with code and name fields. ```json { "Status": 200, "Success": true, "Message": "Success", "Data": [ { "code": "5171", "name": "KOTA DENPASAR" }, { "code": "5103", "name": "KABUPATEN BADUNG" } ] } ```