@crediblemark/buayar 0.7.0 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -123,6 +123,9 @@ var CANONICAL_TO_IPAYMU = {
123
123
  permata_va: { paymentMethod: "va", paymentChannel: "permata" },
124
124
  danamon_va: { paymentMethod: "va", paymentChannel: "danamon" },
125
125
  bsi_va: { paymentMethod: "va", paymentChannel: "bsi" },
126
+ bag_va: { paymentMethod: "va", paymentChannel: "bag" },
127
+ muamalat_va: { paymentMethod: "va", paymentChannel: "bmi" },
128
+ bmi_va: { paymentMethod: "va", paymentChannel: "bmi" },
126
129
  qris: { paymentMethod: "qris", paymentChannel: "mpm" },
127
130
  gopay_qris: { paymentMethod: "qris", paymentChannel: "mpm" },
128
131
  shopeepay_qris: { paymentMethod: "qris", paymentChannel: "mpm" },
@@ -1548,8 +1551,8 @@ var MidtransProvider = class extends BasePaymentProvider {
1548
1551
  // src/providers/ipaymu/signature.ts
1549
1552
  function generateIpaymuSignature(method, va, apiKey, body) {
1550
1553
  const timestamp = Date.now().toString();
1551
- const bodyString = body ? typeof body === "string" ? body : JSON.stringify(body) : "";
1552
- const bodyHash = body ? sha256(bodyString).toLowerCase() : "";
1554
+ const bodyString = body ? typeof body === "string" ? body : JSON.stringify(body) : "{}";
1555
+ const bodyHash = sha256(bodyString).toLowerCase();
1553
1556
  const stringToSign = `${method.toUpperCase()}:${va}:${bodyHash}:${apiKey}`;
1554
1557
  const signature = hmacSha256(stringToSign, apiKey);
1555
1558
  return { signature, timestamp };
@@ -1580,35 +1583,51 @@ var IpaymuProvider = class extends BasePaymentProvider {
1580
1583
  const baseUrl = this.getBaseUrl(sandbox);
1581
1584
  const endpoint = isDirect ? "/payment/direct" : "/payment";
1582
1585
  const url = `${baseUrl}${endpoint}`;
1586
+ const notifyUrl = callbackUrl || config.callbackUrl || "https://localhost/callback";
1587
+ const redirectUrl = returnUrl || config.returnUrl || "https://localhost/return";
1588
+ const feeDirection = params.feeDirection || params.extra?.feeDirection || config.extra?.feeDirection;
1589
+ const escrow = params.escrow !== void 0 ? params.escrow : params.extra?.escrow !== void 0 ? params.extra?.escrow : config.extra?.escrow;
1590
+ const subAccount = params.subAccountId || params.extra?.subAccountId || params.extra?.account || params.extra?.childAccount || params.account || config.extra?.account;
1583
1591
  let payload;
1584
1592
  if (isDirect) {
1585
1593
  payload = {
1586
1594
  name: customer.name,
1587
1595
  email: customer.email,
1588
- phone: customer.phone || "",
1596
+ phone: customer.phone || "081234567890",
1589
1597
  amount: integerAmount,
1590
- notifyUrl: callbackUrl || config.callbackUrl || "",
1598
+ notifyUrl,
1591
1599
  expired: 24,
1592
1600
  expiredType: "hours",
1593
1601
  comments: productDetails,
1594
1602
  referenceId: orderId,
1595
1603
  paymentMethod: ipaymuMethod.paymentMethod,
1596
1604
  ...ipaymuMethod.paymentChannel ? { paymentChannel: ipaymuMethod.paymentChannel } : {},
1605
+ ...feeDirection ? { feeDirection } : {},
1606
+ ...escrow !== void 0 ? { escrow } : {},
1607
+ ...subAccount ? { account: subAccount } : {},
1597
1608
  ...params.providerParams
1598
1609
  };
1599
1610
  } else {
1611
+ const hasItems = params.items && params.items.length > 0;
1612
+ const product = hasItems ? params.items.map((i) => i.name) : [productDetails.length > 50 ? productDetails.substring(0, 47) + "..." : productDetails];
1613
+ const qty = hasItems ? params.items.map((i) => i.quantity) : [1];
1614
+ const price = hasItems ? params.items.map((i) => Math.round(i.price)) : [integerAmount];
1615
+ const description = hasItems ? params.items.map((i) => i.description || i.name) : [productDetails];
1600
1616
  payload = {
1601
- product: [productDetails.length > 50 ? productDetails.substring(0, 47) + "..." : productDetails],
1602
- qty: [1],
1603
- price: [integerAmount],
1604
- description: [productDetails],
1605
- returnUrl: returnUrl || config.returnUrl || "",
1606
- notifyUrl: callbackUrl || config.callbackUrl || "",
1607
- cancelUrl: returnUrl || config.returnUrl || "",
1617
+ product,
1618
+ qty,
1619
+ price,
1620
+ description,
1621
+ returnUrl: redirectUrl,
1622
+ notifyUrl,
1623
+ cancelUrl: redirectUrl,
1608
1624
  referenceId: orderId,
1609
1625
  buyerName: customer.name,
1610
1626
  buyerEmail: customer.email,
1611
- buyerPhone: customer.phone || "",
1627
+ buyerPhone: customer.phone || "081234567890",
1628
+ ...feeDirection ? { feeDirection } : {},
1629
+ ...escrow !== void 0 ? { escrow } : {},
1630
+ ...subAccount ? { account: subAccount } : {},
1612
1631
  ...params.providerParams
1613
1632
  };
1614
1633
  }
@@ -1648,8 +1667,8 @@ var IpaymuProvider = class extends BasePaymentProvider {
1648
1667
  provider: "ipaymu",
1649
1668
  orderId,
1650
1669
  amount: integerAmount,
1651
- reference: resData.TransactionId ? String(resData.TransactionId) : String(resData.SessionId || ""),
1652
- paymentUrl: resData.Url,
1670
+ reference: resData.TransactionId ? String(resData.TransactionId) : String(resData.SessionId || resData.SessionID || ""),
1671
+ paymentUrl: resData.Url || resData.url,
1653
1672
  rawResponse: data
1654
1673
  };
1655
1674
  if (resData.PaymentNo) {
@@ -1708,126 +1727,109 @@ var IpaymuProvider = class extends BasePaymentProvider {
1708
1727
  };
1709
1728
  }
1710
1729
  async getPaymentMethods(params, config) {
1711
- const staticMethods = [
1712
- {
1713
- paymentMethod: "bca_va",
1714
- code: "bca_va",
1715
- paymentName: "BCA Virtual Account",
1716
- paymentImage: "https://my.ipaymu.com/images/banks/bca.png",
1717
- totalFee: "IDR 3,500",
1718
- category: "Virtual Account"
1719
- },
1720
- {
1721
- paymentMethod: "mandiri_va",
1722
- code: "mandiri_va",
1723
- paymentName: "Mandiri Virtual Account",
1724
- paymentImage: "https://my.ipaymu.com/images/banks/mandiri.png",
1725
- totalFee: "IDR 3,500",
1726
- category: "Virtual Account"
1727
- },
1728
- {
1729
- paymentMethod: "bni_va",
1730
- code: "bni_va",
1731
- paymentName: "BNI Virtual Account",
1732
- paymentImage: "https://my.ipaymu.com/images/banks/bni.png",
1733
- totalFee: "IDR 3,500",
1734
- category: "Virtual Account"
1735
- },
1736
- {
1737
- paymentMethod: "bri_va",
1738
- code: "bri_va",
1739
- paymentName: "BRI Virtual Account",
1740
- paymentImage: "https://my.ipaymu.com/images/banks/bri.png",
1741
- totalFee: "IDR 3,500",
1742
- category: "Virtual Account"
1743
- },
1744
- {
1745
- paymentMethod: "cimb_va",
1746
- code: "cimb_va",
1747
- paymentName: "CIMB Niaga Virtual Account",
1748
- paymentImage: "https://my.ipaymu.com/images/banks/cimb.png",
1749
- totalFee: "IDR 3,500",
1750
- category: "Virtual Account"
1751
- },
1752
- {
1753
- paymentMethod: "permata_va",
1754
- code: "permata_va",
1755
- paymentName: "Permata Virtual Account",
1756
- paymentImage: "https://my.ipaymu.com/images/banks/permata.png",
1757
- totalFee: "IDR 3,500",
1758
- category: "Virtual Account"
1759
- },
1760
- {
1761
- paymentMethod: "danamon_va",
1762
- code: "danamon_va",
1763
- paymentName: "Danamon Virtual Account",
1764
- paymentImage: "https://my.ipaymu.com/images/banks/danamon.png",
1765
- totalFee: "IDR 3,500",
1766
- category: "Virtual Account"
1767
- },
1768
- {
1769
- paymentMethod: "bsi_va",
1770
- code: "bsi_va",
1771
- paymentName: "BSI Virtual Account",
1772
- paymentImage: "https://my.ipaymu.com/images/banks/bsi.png",
1773
- totalFee: "IDR 3,500",
1774
- category: "Virtual Account"
1775
- },
1776
- {
1777
- paymentMethod: "qris",
1778
- code: "qris",
1779
- paymentName: "QRIS (GoPay, ShopeePay, DANA, OVO, LinkAja)",
1780
- paymentImage: "https://my.ipaymu.com/images/banks/qris.png",
1781
- totalFee: "0.7%",
1782
- category: "QRIS"
1783
- },
1784
- {
1785
- paymentMethod: "alfamart",
1786
- code: "alfamart",
1787
- paymentName: "Alfamart",
1788
- paymentImage: "https://my.ipaymu.com/images/banks/alfamart.png",
1789
- totalFee: "IDR 5,000",
1790
- category: "Retail / Gerai"
1791
- },
1792
- {
1793
- paymentMethod: "indomaret",
1794
- code: "indomaret",
1795
- paymentName: "Indomaret",
1796
- paymentImage: "https://my.ipaymu.com/images/banks/indomaret.png",
1797
- totalFee: "IDR 5,000",
1798
- category: "Retail / Gerai"
1799
- },
1800
- {
1801
- paymentMethod: "credit_card",
1802
- code: "credit_card",
1803
- paymentName: "Credit / Debit Card (Visa, Mastercard)",
1804
- paymentImage: "https://my.ipaymu.com/images/banks/cc.png",
1805
- totalFee: "2.9% + IDR 2,000",
1806
- category: "Kartu Kredit"
1807
- },
1808
- {
1809
- paymentMethod: "akulaku",
1810
- code: "akulaku",
1811
- paymentName: "Akulaku Paylater",
1812
- paymentImage: "https://my.ipaymu.com/images/banks/akulaku.png",
1813
- totalFee: "1.7%",
1814
- category: "Paylater / Cicilan"
1815
- }
1816
- ];
1817
- const categories = {};
1818
- for (const item of staticMethods) {
1819
- if (!categories[item.category]) {
1820
- categories[item.category] = [];
1730
+ const va = config.merchantCode || config.merchantId || "";
1731
+ const apiKey = config.apiKey || "";
1732
+ const sandbox = !!config.sandbox;
1733
+ if (!va || !apiKey) {
1734
+ return {
1735
+ success: false,
1736
+ provider: "ipaymu",
1737
+ methods: [],
1738
+ categories: {},
1739
+ error: "Missing iPaymu credentials (BUAYAR_MERCHANT_CODE/VA or BUAYAR_API_KEY)",
1740
+ rawResponse: null
1741
+ };
1742
+ }
1743
+ try {
1744
+ const url = `${this.getBaseUrl(sandbox)}/payment-channels`;
1745
+ const { signature, timestamp } = generateIpaymuSignature("GET", va, apiKey);
1746
+ const response = await fetch(url, {
1747
+ method: "GET",
1748
+ headers: {
1749
+ "Content-Type": "application/json",
1750
+ "Accept": "application/json",
1751
+ "va": va,
1752
+ "signature": signature,
1753
+ "timestamp": timestamp
1754
+ }
1755
+ });
1756
+ const data = await response.json().catch(() => null);
1757
+ if (response.ok && data?.Data && Array.isArray(data.Data)) {
1758
+ const methods = [];
1759
+ const categories = {};
1760
+ for (const group of data.Data) {
1761
+ const groupCode = (group.Code || "").toLowerCase();
1762
+ const groupName = group.Name || group.Description || "Lainnya";
1763
+ const channels = group.Channels || [];
1764
+ let category = "Lainnya";
1765
+ if (groupCode === "va") category = "Virtual Account";
1766
+ else if (groupCode === "cstore") category = "Retail / Gerai";
1767
+ else if (groupCode === "qris") category = "QRIS";
1768
+ else if (groupCode === "cc") category = "Kartu Kredit";
1769
+ else if (groupCode === "paylater") category = "Paylater / Cicilan";
1770
+ else if (groupCode === "cod") category = "COD";
1771
+ else category = groupName;
1772
+ for (const ch of channels) {
1773
+ const chCode = (ch.Code || "").toLowerCase();
1774
+ let canonicalCode = chCode;
1775
+ if (groupCode === "va") {
1776
+ canonicalCode = chCode === "bag" ? "bag_va" : chCode === "bmi" ? "muamalat_va" : `${chCode}_va`;
1777
+ } else if (groupCode === "cc") {
1778
+ canonicalCode = "credit_card";
1779
+ }
1780
+ let totalFee = "-";
1781
+ if (ch.TransactionFee) {
1782
+ if (ch.TransactionFee.ActualFeeType === "PERCENT") {
1783
+ totalFee = `${ch.TransactionFee.ActualFee}%`;
1784
+ } else if (ch.TransactionFee.ActualFee !== void 0) {
1785
+ totalFee = `IDR ${Number(ch.TransactionFee.ActualFee).toLocaleString()}`;
1786
+ }
1787
+ }
1788
+ const pm = {
1789
+ paymentMethod: canonicalCode,
1790
+ code: canonicalCode,
1791
+ paymentName: ch.Name || ch.Description || canonicalCode,
1792
+ paymentImage: ch.Logo || `https://my.ipaymu.com/images/banks/${chCode}.png`,
1793
+ totalFee,
1794
+ category,
1795
+ extra: {
1796
+ healthStatus: ch.HealthStatus,
1797
+ featureStatus: ch.FeatureStatus,
1798
+ instructionsDoc: ch.PaymentInstructionsDoc,
1799
+ feeDetail: ch.TransactionFee
1800
+ }
1801
+ };
1802
+ methods.push(pm);
1803
+ if (!categories[category]) categories[category] = [];
1804
+ categories[category].push(pm);
1805
+ }
1806
+ }
1807
+ return {
1808
+ success: true,
1809
+ provider: "ipaymu",
1810
+ methods,
1811
+ categories,
1812
+ rawResponse: data
1813
+ };
1821
1814
  }
1822
- categories[item.category].push(item);
1815
+ return {
1816
+ success: false,
1817
+ provider: "ipaymu",
1818
+ methods: [],
1819
+ categories: {},
1820
+ error: data?.Message || data?.message || `Failed to fetch payment channels (HTTP ${response.status})`,
1821
+ rawResponse: data
1822
+ };
1823
+ } catch (err) {
1824
+ return {
1825
+ success: false,
1826
+ provider: "ipaymu",
1827
+ methods: [],
1828
+ categories: {},
1829
+ error: err.message || "Failed to fetch iPaymu payment channels",
1830
+ rawResponse: null
1831
+ };
1823
1832
  }
1824
- return {
1825
- success: true,
1826
- provider: "ipaymu",
1827
- methods: staticMethods,
1828
- categories,
1829
- rawResponse: staticMethods
1830
- };
1831
1833
  }
1832
1834
  async checkTransaction(params, config) {
1833
1835
  const { merchantOrderId } = params;
@@ -1874,11 +1876,14 @@ var IpaymuProvider = class extends BasePaymentProvider {
1874
1876
  };
1875
1877
  }
1876
1878
  const txData = data.Data || {};
1877
- const statusText = (txData.Status || txData.status || "").toString().toLowerCase();
1878
- const isPaid = statusText === "berhasil" || statusText === "success" || txData.StatusCode === 1;
1879
- const isPending = statusText === "pending" || txData.StatusCode === 0;
1880
- const isFailed = !isPaid && !isPending;
1881
- const isExpired = statusText === "expired";
1879
+ const rawStatus = txData.Status !== void 0 ? txData.Status : txData.status;
1880
+ const statusDesc = (txData.StatusDesc || "").toString().toLowerCase();
1881
+ const paidStatus = (txData.PaidStatus || "").toString().toLowerCase();
1882
+ const statusCode = txData.StatusCode !== void 0 ? Number(txData.StatusCode) : rawStatus !== void 0 ? Number(rawStatus) : void 0;
1883
+ const isPaid = statusCode === 1 || paidStatus === "paid" || statusDesc.includes("berhasil") || statusDesc.includes("success");
1884
+ const isPending = statusCode === 0 || paidStatus === "unpaid" || statusDesc.includes("menunggu") || statusDesc.includes("pending");
1885
+ const isExpired = statusCode === 2 || statusDesc.includes("expired") || statusDesc.includes("kadaluarsa");
1886
+ const isFailed = !isPaid && !isPending && !isExpired;
1882
1887
  const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
1883
1888
  return {
1884
1889
  success: true,
@@ -8094,6 +8099,137 @@ var IpaymuClient = class {
8094
8099
  async checkTransaction(transactionId) {
8095
8100
  return this.request("POST", "/transaction", { transactionId });
8096
8101
  }
8102
+ /**
8103
+ * Ambil daftar channel pembayaran aktif milik merchant (Official v2: GET /payment-channels)
8104
+ */
8105
+ async getPaymentMethods() {
8106
+ return this.request("GET", "/payment-channels");
8107
+ }
8108
+ /**
8109
+ * Alias untuk getPaymentMethods (Official v2)
8110
+ */
8111
+ async getPaymentChannels() {
8112
+ return this.request("GET", "/payment-channels");
8113
+ }
8114
+ /**
8115
+ * Ambil riwayat transaksi merchant berpaginasi (Official v2: POST /history)
8116
+ */
8117
+ async getHistory(params) {
8118
+ const payload = {
8119
+ account: this.va,
8120
+ page: params?.page || 1,
8121
+ limit: params?.limit || 10,
8122
+ ...params
8123
+ };
8124
+ return this.request("POST", "/history", payload);
8125
+ }
8126
+ /**
8127
+ * Ambil daftar seluruh bank di Indonesia (Official v2: POST /banklist)
8128
+ */
8129
+ async getBankList() {
8130
+ return this.request("POST", "/banklist", { account: this.va });
8131
+ }
8132
+ /**
8133
+ * Cari jangkauan area pengiriman COD (Official v2: GET /cod/area?area=keyword)
8134
+ */
8135
+ async getCodArea(area) {
8136
+ const query = { area };
8137
+ return this.request("GET", `/cod/area?area=${encodeURIComponent(area)}`, query);
8138
+ }
8139
+ /**
8140
+ * Hitung tarif ongkir pengiriman COD (Official v2: POST /cod/shipping-calculate)
8141
+ */
8142
+ async getCodRate(params) {
8143
+ const { pickupArea, deliveryArea, ...rest } = params;
8144
+ const pickupId = params.pickup_area_id !== void 0 ? params.pickup_area_id : pickupArea;
8145
+ const destId = params.destination_area_id !== void 0 ? params.destination_area_id : deliveryArea;
8146
+ const payload = {
8147
+ ...rest,
8148
+ pickup_area_id: pickupId !== void 0 ? String(pickupId) : void 0,
8149
+ destination_area_id: destId !== void 0 ? String(destId) : void 0,
8150
+ amount: params.amount || 0
8151
+ };
8152
+ return this.request("POST", "/cod/shipping-calculate", payload);
8153
+ }
8154
+ /**
8155
+ * Request pickup kurir COD (Official v2: POST /cod/pickup)
8156
+ */
8157
+ async getCodPickup(params) {
8158
+ const { transactionId, ...rest } = params;
8159
+ const payload = {
8160
+ ...rest,
8161
+ transaction_id: params.transaction_id || transactionId
8162
+ };
8163
+ return this.request("POST", "/cod/pickup", payload);
8164
+ }
8165
+ /**
8166
+ * Unduh label pengiriman / AWB COD (Official v2: GET /cod/download-label/:transaction_id)
8167
+ */
8168
+ async getCodAwb(transactionId) {
8169
+ return this.request("GET", `/cod/download-label/${transactionId}`);
8170
+ }
8171
+ /**
8172
+ * Lacak status pengiriman kurir COD berdasarkan no resi / AWB (Official v2: POST /cod/tracking)
8173
+ */
8174
+ async getCodTracking(params) {
8175
+ const payload = typeof params === "string" ? { awb: params } : {
8176
+ awb: params.awb,
8177
+ transaction_id: params.transaction_id || params.transactionId
8178
+ };
8179
+ return this.request("POST", "/cod/tracking", payload);
8180
+ }
8181
+ // ==========================================
8182
+ // Public Area Lookup API (docs.ipaymu.com/en/docs/area-api)
8183
+ // Read-only endpoint untuk provinsi, kota/kabupaten, kecamatan, dan kelurahan
8184
+ // ==========================================
8185
+ /**
8186
+ * Ambil daftar seluruh provinsi di Indonesia
8187
+ */
8188
+ async getAreasProvince() {
8189
+ const res = await fetch("https://my.ipaymu.com/api/areas/province");
8190
+ return res.json();
8191
+ }
8192
+ /**
8193
+ * Ambil daftar kota / kabupaten berdasarkan ID provinsi
8194
+ */
8195
+ async getAreasCity(provinceId) {
8196
+ const res = await fetch(`https://my.ipaymu.com/api/areas/city/${provinceId}`);
8197
+ return res.json();
8198
+ }
8199
+ /**
8200
+ * Ambil daftar kecamatan berdasarkan ID kota / kabupaten
8201
+ */
8202
+ async getAreasDistrict(cityId) {
8203
+ const res = await fetch(`https://my.ipaymu.com/api/areas/district/${cityId}`);
8204
+ return res.json();
8205
+ }
8206
+ /**
8207
+ * Ambil daftar kelurahan berdasarkan ID kecamatan
8208
+ */
8209
+ async getAreasVillage(districtId) {
8210
+ const res = await fetch(`https://my.ipaymu.com/api/areas/village/${districtId}`);
8211
+ return res.json();
8212
+ }
8213
+ // ==========================================
8214
+ // Split Payment — Single Register API
8215
+ // https://ipaymu.com/en/split-payment/
8216
+ // ==========================================
8217
+ /**
8218
+ * Daftarkan agen / reseller / mitra baru untuk Split Payment (Single Register API: POST /api/v2/register)
8219
+ * Mengembalikan VA child account yang siap digunakan untuk parameter `subAccountId` saat membuat transaksi.
8220
+ */
8221
+ async registerUser(params) {
8222
+ const { name, email, phone, password, ...rest } = params;
8223
+ const payload = {
8224
+ ...rest,
8225
+ account: this.va,
8226
+ name,
8227
+ email,
8228
+ phone,
8229
+ password: password || "Password123!"
8230
+ };
8231
+ return this.request("POST", "/register", payload);
8232
+ }
8097
8233
  };
8098
8234
 
8099
8235
  // src/clients/xendit.ts
package/docs/guide.md CHANGED
@@ -19,7 +19,8 @@ Panduan ini adalah **satu-satunya** panduan yang Anda butuhkan untuk mengintegra
19
19
  9. [Provider Dinamis & Autodetect](#-provider-dinamis--autodetect)
20
20
  10. [Cek Capability Provider (Portabilitas)](#-cek-capability-provider-portabilitas)
21
21
  11. [Fitur Khusus Provider (`<X>Client`)](#-fitur-khusus-provider-xclient)
22
- 12. [Kamus Variabel `.env` per Provider](#-kamus-variabel-env-per-provider)
22
+ 12. [Panduan Pengisian Variabel Universal (`BUAYAR_*`) per Provider](#-panduan-pengisian-variabel-universal-buayar_-per-provider)
23
+ 13. [Daftar Canonical Payment Methods](#-daftar-canonical-payment-methods)
23
24
 
24
25
  ---
25
26
 
@@ -370,57 +371,59 @@ const balance = await xendit.checkBalance("CASH");
370
371
 
371
372
  Rangkuman kemampuan ekstra tiap provider:
372
373
 
373
- | Provider | Getter | Kemampuan ekstra |
374
- | :--- | :--- | :--- |
375
- | Midtrans | `getMidtransClient()` | cancel/refund/expire/approve/deny/capture, GoPay tokenization, Subscription, Payment Link, IRIS balance |
376
- | Duitku | `getDuitkuClient()` | balance, listBanks, inquiryBankAccount, disburse, checkDisbursementStatus |
377
- | iPaymu | `getIpaymuClient()` | balance, checkTransaction |
378
- | Xendit | `getXenditClient()` | balance, expireInvoice, createDisbursement |
379
- | DOKU | `getDokuClient()` | checkTransaction |
380
- | PrismaLink | `getPrismalinkClient()` | checkTransaction |
381
- | Faspay | `getFaspayClient()` | cancelTransaction, checkTransaction |
382
- | Finpay | `getFinpayClient()` | checkTransaction |
383
- | Nicepay | `getNicepayClient()` | cancelTransaction, checkTransaction |
384
- | OY! Bisnis | `getOyClient()` | checkTransaction, balance, remit (transfer dana) |
385
- | Stripe | `getStripeClient()` | balance, createRefund, retrieveCheckoutSession, retrievePaymentIntent |
386
- | PayPal | `getPaypalClient()` | captureOrder, getOrder, refundCapture, checkBalance, verifyWebhookSignature |
387
- | Adyen | `getAdyenClient()` | capturePayment, cancelPayment, refundPayment, getPaymentDetails, getAvailablePaymentMethods |
388
- | Checkout.com | `getCheckoutComClient()` | balance, refundPayment, voidPayment, getPaymentDetails, listPaymentLinks |
389
- | Razorpay | `getRazorpayClient()` | capturePayment, createRefund, checkBalance, fetchPayment, listPayments |
390
- | Square | `getSquareClient()` | retrieveBalance, refundPayment, cancelPayment, getPayment, listLocations |
391
- | PayU | `getPayuClient()` | cancelOrder, getOrder, refundOrder |
392
- | Braintree | `getBraintreeClient()` | getClientToken, findTransaction, refundTransaction, voidTransaction |
393
- | 2Checkout | `getTwoCheckoutClient()` | getOrder, listOrders, getSubscription, refundOrder |
374
+ | Provider | Status | Getter | Kemampuan ekstra |
375
+ | :--- | :---: | :--- | :--- |
376
+ | Midtrans | - | `getMidtransClient()` | cancel/refund/expire/approve/deny/capture, GoPay tokenization, Subscription, Payment Link, IRIS balance |
377
+ | Duitku | - | `getDuitkuClient()` | balance, listBanks, inquiryBankAccount, disburse, checkDisbursementStatus |
378
+ | [iPaymu](ipaymu.md) | Tested | `getIpaymuClient()` | balance, checkTransaction, getHistory, getBankList, getPaymentMethods/getPaymentChannels, Split Payment (registerUser / subAccountId), COD logistics (getArea, getRate, getPickup, getAwb, getTracking), Public Area API (Province, City, District, Village). *Lihat [panduan lengkap iPaymu](ipaymu.md)* |
379
+ | Xendit | - | `getXenditClient()` | balance, expireInvoice, createDisbursement |
380
+ | DOKU | - | `getDokuClient()` | checkTransaction |
381
+ | PrismaLink | - | `getPrismalinkClient()` | checkTransaction |
382
+ | Faspay | - | `getFaspayClient()` | cancelTransaction, checkTransaction |
383
+ | Finpay | - | `getFinpayClient()` | checkTransaction |
384
+ | Nicepay | - | `getNicepayClient()` | cancelTransaction, checkTransaction |
385
+ | OY! Bisnis | - | `getOyClient()` | checkTransaction, balance, remit (transfer dana) |
386
+ | Stripe | - | `getStripeClient()` | balance, createRefund, retrieveCheckoutSession, retrievePaymentIntent |
387
+ | PayPal | - | `getPaypalClient()` | captureOrder, getOrder, refundCapture, checkBalance, verifyWebhookSignature |
388
+ | Adyen | - | `getAdyenClient()` | capturePayment, cancelPayment, refundPayment, getPaymentDetails, getAvailablePaymentMethods |
389
+ | Checkout.com | - | `getCheckoutComClient()` | balance, refundPayment, voidPayment, getPaymentDetails, listPaymentLinks |
390
+ | Razorpay | - | `getRazorpayClient()` | capturePayment, createRefund, checkBalance, fetchPayment, listPayments |
391
+ | Square | - | `getSquareClient()` | retrieveBalance, refundPayment, cancelPayment, getPayment, listLocations |
392
+ | PayU | - | `getPayuClient()` | cancelOrder, getOrder, refundOrder |
393
+ | Braintree | - | `getBraintreeClient()` | getClientToken, findTransaction, refundTransaction, voidTransaction |
394
+ | 2Checkout | - | `getTwoCheckoutClient()` | getOrder, listOrders, getSubscription, refundOrder |
394
395
 
395
396
  ---
396
397
 
397
- ## 📚 Kamus Variabel `.env` per Provider
398
-
399
- Anda hanya perlu mengisi kredensial provider yang **sedang aktif**. Gunakan variabel universal (`BUAYAR_*`) bila ingin kode benar-benar provider-agnostic, atau variabel spesifik di bawah.
400
-
401
- | Provider | Variabel `.env` |
402
- | :--- | :--- |
403
- | Midtrans | `MIDTRANS_SERVER_KEY`, `MIDTRANS_CLIENT_KEY` |
404
- | Duitku | `DUITKU_API_KEY`, `DUITKU_MERCHANT_CODE` |
405
- | iPaymu | `IPAYMU_API_KEY`, `IPAYMU_VA` |
406
- | Xendit | `XENDIT_SECRET_KEY`, `XENDIT_WEBHOOK_TOKEN` |
407
- | DOKU | `DOKU_CLIENT_ID`, `DOKU_SECRET_KEY` |
408
- | PrismaLink | `PRISMALINK_MERCHANT_ID`, `PRISMALINK_SECRET_KEY` |
409
- | Faspay | `FASPAY_MERCHANT_ID`, `FASPAY_USER_ID`, `FASPAY_PASSWORD`, `FASPAY_MERCHANT_NAME` |
410
- | Finpay | `FINPAY_MERCHANT_ID`, `FINPAY_MERCHANT_KEY` |
411
- | Nicepay | `NICEPAY_IMID`, `NICEPAY_KEY` |
412
- | OY! Bisnis | `OY_USERNAME`, `OY_API_KEY` |
413
- | Stripe | `STRIPE_SECRET_KEY`, `STRIPE_PUBLIC_KEY`, `STRIPE_WEBHOOK_SECRET` |
414
- | PayPal | `PAYPAL_CLIENT_ID`, `PAYPAL_CLIENT_SECRET`, `PAYPAL_WEBHOOK_ID` |
415
- | Adyen | `ADYEN_API_KEY`, `ADYEN_MERCHANT_ACCOUNT`, `ADYEN_CLIENT_KEY`, `ADYEN_HMAC_KEY`, `ADYEN_LIVE_URL_PREFIX` |
416
- | Checkout.com | `CHECKOUTCOM_SECRET_KEY`, `CHECKOUTCOM_PUBLIC_KEY`, `CHECKOUTCOM_WEBHOOK_SECRET` |
417
- | Razorpay | `RAZORPAY_KEY_ID`, `RAZORPAY_KEY_SECRET`, `RAZORPAY_WEBHOOK_SECRET` |
418
- | Square | `SQUARE_ACCESS_TOKEN`, `SQUARE_APPLICATION_ID`, `SQUARE_LOCATION_ID`, `SQUARE_WEBHOOK_SIGNATURE_KEY` |
419
- | PayU | `PAYU_POS_ID`, `PAYU_MD5_KEY`, `PAYU_OAUTH_CLIENT_ID`, `PAYU_OAUTH_CLIENT_SECRET` |
420
- | Braintree | `BRAINTREE_MERCHANT_ID`, `BRAINTREE_PUBLIC_KEY`, `BRAINTREE_PRIVATE_KEY` |
421
- | 2Checkout | `TWOCHECKOUT_MERCHANT_CODE`, `TWOCHECKOUT_SECRET_KEY`, `TWOCHECKOUT_SECRET_WORD` |
422
-
423
- Sandbox: otomatis terdeteksi dari `BUAYAR_SANDBOX`/`NODE_ENV`, atau set per-provider (mis. `STRIPE_SANDBOX=true`, `MIDTRANS_SANDBOX=true`).
398
+ ## 📚 Panduan Pengisian Variabel Universal (`BUAYAR_*`) per Provider
399
+
400
+ Anda **tidak perlu** membuat nama variabel khusus per provider (seperti `IPAYMU_API_KEY`, `DUITKU_API_KEY`, dsb.). Cukup gunakan set variabel seragam **`BUAYAR_*`**.
401
+
402
+ Tabel berikut menunjukkan data apa dari dashboard masing-masing payment gateway yang perlu Anda masukkan ke variabel `BUAYAR_*`:
403
+
404
+ | Provider | `BUAYAR_PROVIDER` | `BUAYAR_API_KEY` | `BUAYAR_MERCHANT_CODE` | `BUAYAR_CLIENT_KEY` / Tambahan |
405
+ | :--- | :--- | :--- | :--- | :--- |
406
+ | **Midtrans** | `midtrans` | Server Key | *(opsional)* | Client Key |
407
+ | **Duitku** | `duitku` | API Key | Merchant Code | *(tidak perlu)* |
408
+ | **iPaymu** | `ipaymu` | API Key | Nomor Virtual Account (VA) | *(tidak perlu)* |
409
+ | **Xendit** | `xendit` | Secret Key | *(opsional)* | Webhook Verification Token (`BUAYAR_WEBHOOK_SECRET`) |
410
+ | **DOKU Jokul** | `doku` | Secret Key | Client ID / Merchant ID | Client ID |
411
+ | **PrismaLink** | `prismalink` | Secret Key | Merchant ID | *(tidak perlu)* |
412
+ | **Faspay** | `faspay` | Password | Merchant ID | User ID |
413
+ | **Finpay** | `finpay` | Merchant Key | Merchant ID | *(tidak perlu)* |
414
+ | **Nicepay** | `nicepay` | Server Key (Secret) | I-MID (Merchant ID) | *(tidak perlu)* |
415
+ | **OY! Bisnis** | `oy` | API Key | Username | Username |
416
+ | **Stripe** | `stripe` | Secret Key (`sk_...`) | *(tidak perlu)* | Publishable Key (`pk_...`) / Webhook Secret |
417
+ | **PayPal** | `paypal` | Client Secret | Client ID | Client ID |
418
+ | **Adyen** | `adyen` | API Key | Merchant Account Name | Client Key / HMAC Key (`BUAYAR_WEBHOOK_SECRET`) |
419
+ | **Checkout.com** | `checkoutcom` | Secret Key (`sk_...`) | *(tidak perlu)* | Public Key (`pk_...`) / Webhook Secret |
420
+ | **Razorpay** | `razorpay` | Key Secret | Key ID | Key ID |
421
+ | **Square** | `square` | Access Token | Application ID | Location ID (`BUAYAR_PROJECT_ID`) |
422
+ | **PayU** | `payu` | MD5 Key / Secret | POS ID | POS ID |
423
+ | **Braintree** | `braintree` | Private Key | Merchant ID | Public Key |
424
+ | **2Checkout** | `twocheckout` | Secret Key | Merchant Code | Secret Word (`BUAYAR_WEBHOOK_SECRET`) |
425
+
426
+ > 💡 **Mode Sandbox:** Cukup tambahkan `BUAYAR_SANDBOX=true` (atau `false` saat production), SDK otomatis menyesuaikan URL endpoint API seluruh provider di atas tanpa perlu konfigurasi tambahan.
424
427
 
425
428
  ---
426
429
 
@@ -428,7 +431,7 @@ Sandbox: otomatis terdeteksi dari `BUAYAR_SANDBOX`/`NODE_ENV`, atau set per-prov
428
431
 
429
432
  | Kategori | Canonical Code |
430
433
  | :--- | :--- |
431
- | **Virtual Account** | `bca_va`, `mandiri_va`, `bni_va`, `bri_va`, `permata_va`, `cimb_va`, `danamon_va`, `bsi_va`, `seabank_va` |
434
+ | **Virtual Account** | `bca_va`, `mandiri_va`, `bni_va`, `bri_va`, `permata_va`, `cimb_va`, `danamon_va`, `bsi_va`, `seabank_va`, `bag_va`, `muamalat_va` |
432
435
  | **QRIS** | `qris`, `gopay_qris`, `shopeepay_qris`, `nobu_qris` |
433
436
  | **E-Wallet** | `gopay`, `shopeepay`, `ovo`, `dana`, `linkaja`, `jenius` |
434
437
  | **Retail** | `alfamart`, `indomaret`, `pos` |