Files
multiverse/jumpa-iam/lib/xendit-engine.ts
T

81 lines
2.2 KiB
TypeScript

/**
* XENDIT INDUSTRIAL BILLING ENGINE (X-IBE)
*
* Engine pembayaran murni tanpa dependensi pihak ketiga.
* Menggunakan standar REST API Xendit v2 untuk Invoice & Webhooks.
*/
const XENDIT_SECRET_KEY = process.env.XENDIT_SECRET_KEY || "";
const XENDIT_ENDPOINT = "https://api.xendit.co/v2/invoices";
export interface XenditInvoiceRequest {
external_id: string;
amount: number;
payer_email: string;
description: string;
success_redirect_url: string;
failure_redirect_url: string;
currency: string;
items?: Array<{
name: string;
quantity: number;
price: number;
category?: string;
}>;
}
export class XenditEngine {
private static getAuthHeader() {
// Xendit requires Basic Auth with secret key as username and empty password
const auth = Buffer.from(`${XENDIT_SECRET_KEY}:`).toString('base64');
return `Basic ${auth}`;
}
static async createInvoice(req: XenditInvoiceRequest) {
if (!XENDIT_SECRET_KEY) {
console.warn("[XENDIT] Secret Key missing. Using Sandbox Mode (Simulated URL).");
return {
id: "sim_inv_" + Date.now(),
invoice_url: `${req.success_redirect_url}?sim_status=PAID&external_id=${req.external_id}`
};
}
try {
const response = await fetch(XENDIT_ENDPOINT, {
method: 'POST',
headers: {
'Authorization': this.getAuthHeader(),
'Content-Type': 'application/json'
},
body: JSON.stringify({
...req,
should_send_email: true,
payment_methods: ["BNI", "BRI", "MANDIRI", "BCA", "PERMATA", "OVO", "DANA", "QRIS"]
})
});
const data = await response.json();
if (!response.ok) {
throw new Error(data.message || "Xendit API Error");
}
return data; // returns { id, invoice_url, status, etc }
} catch (error) {
console.error("[XENDIT ERROR]", error);
throw error;
}
}
static async getInvoice(invoiceId: string) {
try {
const response = await fetch(`${XENDIT_ENDPOINT}/${invoiceId}`, {
headers: { 'Authorization': this.getAuthHeader() }
});
return await response.json();
} catch (error) {
console.error("[XENDIT GET ERROR]", error);
throw error;
}
}
}