Doc API

Dokumentasi REST API buat integrasi bot Telegram, WhatsApp, atau aplikasi lain.

🔐 Autentikasi

Semua endpoint /api/v1/* butuh header:

X-API-Key: <API_KEY_KAMU>

Dapetin API key di halaman Dashboard.

1. Buat Pembayaran

POST /api/v1/create-payment

Request Body

{
  "amount": 25000,
  "ref": "ORDER-123",
  "customerName": "Budi"
}

Cuma amount yang wajib. Sisanya opsional.

Response

{
  "orderId": "abc123",
  "amount": 25123,           // nominal UNIK yang harus dibayar
  "baseAmount": 25000,       // harga asli
  "uniqueCode": 123,         // kode unik
  "qrisString": "00020101...",
  "qrUrl": "https://api.qrserver.com/...",
  "expiresAt": "2026-09-17T01:15:00.000Z"
}

⚠️ PENTING — NOMINAL UNIK

API bakal balikin amount yang berbeda dari yang lo minta. Contoh: lo minta Rp25.000, tapi API balikin Rp25.123. Itu nominal yang harus dibayar user.

Tampilkan nominal dari response API, bukan nominal yang lo input. Kalau user bayar beda → pembayaran gak terdeteksi otomatis.

Contoh cURL

curl -X POST https://wilzu-pge.vercel.app/api/v1/create-payment \
  -H "Content-Type: application/json" \
  -H "X-API-Key: wlz_xxxxx" \
  -d '{"amount":5000}'

2. Cek Status Pembayaran

GET /api/v1/check-payment/:orderId

Response

{
  "orderId": "abc123",
  "status": "pending" | "paid" | "expired",
  "amount": 25123,
  "ref": "ORDER-123",
  "paidAt": "2026-09-17T..." | null,
  "expiresAt": "2026-09-17T01:15:00.000Z"
}

Status Order

StatusArti
pendingNunggu dibayar
paidUdah dibayar ✅
expiredKadaluarsa (15 menit)

3. Cek Saldo

GET /api/v1/balance

Response

{
  "balance": 150000
}

⚡ Contoh Bot Telegram (Node.js)

const TelegramBot = require('node-telegram-bot-api');
const axios = require('axios');

const TOKEN = 'BOT_TOKEN';
const API_KEY = 'wlz_xxxxx';
const BASE = 'https://wilzu-pge.vercel.app/api/v1';

const bot = new TelegramBot(TOKEN, { polling: true });

bot.onText(/\/bayar(?:\s+(\d+))?/, async (msg, match) => {
  const chatId = msg.chat.id;
  const amount = parseInt(match[1]);
  if (!amount || amount < 500) {
    return bot.sendMessage(chatId, 'Format: /bayar 5000');
  }

  const { data } = await axios.post(
    `${BASE}/create-payment`,
    { amount },
    { headers: { 'X-API-Key': API_KEY } }
  );

  // ⚠️ PAKAI data.amount (nominal unik), bukan amount input
  await bot.sendPhoto(chatId, data.qrUrl, {
    caption:
      `💳 *Pembayaran QRIS*\n\n` +
      `⚠️ *Bayar PERSIS:*\n` +
      `*Rp ${data.amount.toLocaleString('id-ID')}*\n\n` +
      `Order: \`${data.orderId}\``,
    parse_mode: 'Markdown',
  });

  pollStatus(chatId, data.orderId);
});

function pollStatus(chatId, orderId) {
  const t = setInterval(async () => {
    const { data } = await axios.get(
      `${BASE}/check-payment/${orderId}`,
      { headers: { 'X-API-Key': API_KEY } }
    );
    if (data.status === 'paid') {
      clearInterval(t);
      bot.sendMessage(chatId, '✅ Pembayaran diterima!');
    } else if (data.status === 'expired') {
      clearInterval(t);
      bot.sendMessage(chatId, '❌ QRIS expired. Bikin baru: /bayar');
    }
  }, 5000);
}

bot.launch();

⏱️ Masa Berlaku QRIS

Setiap order punya masa berlaku 15 menit. Setelah lewat, status otomatis berubah jadi expired.

Bot lo harusnya stop polling kalau status udah expired atau paid.