Payment gateway self-hosted di atas GoPay Merchant (GoBiz) β rasa payment gateway beneran, tapi jalan di server sendiri. Bikin QRIS dinamis, pantau pembayaran masuk otomatis, dan tembak webhook bertanda tangan saat lunas.
π Demo: pay.violetics.pw/docs (Swagger UI)
Dibangun di atas library GoBiz dari kavionn/gobiz-payment (lihat Credit).
Warning
Risiko banned: otomatisasi login & polling API GoBiz yang terlalu agresif berisiko membuat akun kamu terblokir. Pakai dengan risiko sendiri. Ini bukan library resmi Gojek/GoPay β mengakses API internal GoBiz.
- π§Ύ Create payment β 1 endpoint, QRIS dinamis + gambar PNG langsung (tanpa upload eksternal)
- π Check by trxId β cek status pakai ID transaksi kamu sendiri (atau auto
TRX-xxxx) - πͺ Webhook otomatis β begitu bayar masuk, callback ditembak (HMAC-SHA256, retry 3Γ)
- π Custom webhook per-trx β
callbackUrldi body meng-overrideWEBHOOK_URLglobal - π° Fee manual β
feeditambah keamount; pembeli bayaramountToPay - π Idempotency β
Idempotency-Keycegah double-charge saat retry - ποΈ SQLite β transaksi persist di
data/transaction.db, tahan restart - π‘οΈ Security β API key (timing-safe), rate limit per-IP, security headers
- π Swagger UI β dokumentasi interaktif di
/docs - π Morgan β log tiap request, satu baris berwarna
- β»οΈ Watcher in-process β polling jalan otomatis di dalam server, PM2 jaga tetap hidup
Butuh Node.js β₯ 22 (pakai node:sqlite bawaan β tanpa dependency SQLite).
git clone https://github.com/cv3inx/gobiz-payment.git
cd gobiz-payment
npm install
cp .env.example .env # lalu isi kredensial + QRIS_STRINGPilih salah satu:
Kalau belum punya password:
- Buka portal.gofoodmerchant.co.id
- Login pakai OTP (nomor HP terdaftar)
- Ke halaman Profile
- Atur / ubah password login, simpan
- Isi
GOPAY_EMAIL+GOPAY_PASSWORDdi.env
Kalau ga mau taruh password, ambil token dari browser:
- Login ke portal GoBiz di browser
- F12 β Application β Cookies β cari
access_token, copy value-nya - Isi
GOPAY_ACCESS_TOKENdi.env - (Opsional) isi
GOPAY_MERCHANT_IDmanual β kalau kosong, dideteksi otomatis dari token
Token menang kalau diisi. Token bisa expired β refresh manual (ambil ulang dari cookies) saat gateway error 401. Untuk jalan jangka panjang tanpa perawatan, Opsi A lebih enak (token di-refresh otomatis).
Ambil QRIS_STRING dengan men-scan gambar QRIS statis dari portal GoBiz Merchant,
paste hasilnya ke .env.
# Kredensial GoBiz β Opsi A (email/password) ATAU Opsi B (token)
GOPAY_EMAIL=email@merchant.com
GOPAY_PASSWORD=password_kamu
# Opsi B: token dari F12 β Cookies β access_token
GOPAY_ACCESS_TOKEN=
GOPAY_MERCHANT_ID=
# QRIS statis merchant (wajib)
QRIS_STRING=00020101021226...
# Gateway
PORT=3000
POLL_MS=7000 # interval cek pembayaran (ms) β jangan < 7000
EXPIRE_MINUTES=5 # umur transaksi default (menit)
RATE_MAX=60 # max request per IP per menit
DB_FILE= # default ./data/transaction.db
# Webhook default (bisa di-override per-trx via callbackUrl)
WEBHOOK_URL=https://app-kamu.com/webhook
WEBHOOK_SECRET=ganti-ini-random-panjang
# Proteksi endpoint tulis (kosongkan = nonaktif)
API_KEY=.gopay_cache.json dibuat otomatis (menyimpan token + merchant ID), token
di-refresh otomatis. Jangan commit .env, .gopay_cache.json, transaction.db.
npm start # jalan biasa
npm test # self-check (QRIS, DB, security)Buka http://localhost:3000/docs untuk Swagger UI interaktif.
Watcher pemantau pembayaran jalan di dalam proses server β begitu server hidup, cek pembayaran + webhook jalan otomatis di background. Tanpa cron, tanpa panggil check manual.
npm i -g pm2
npm run pm2:start # pm2 start ecosystem.config.cjs
pm2 save
pm2 startup # jalankan command yang dicetak β auto-nyala saat reboot
npm run pm2:logs
npm run pm2:restart
npm run pm2:stopImportant
Jalankan 1 instance (fork mode β sudah diset). Jangan cluster mode: poller dobel = webhook ketembak 2Γ.
Detail lengkap: docs/API.md atau Swagger di /docs.
| Method | Path | Auth | Fungsi |
|---|---|---|---|
| POST | /payment/create |
π | Buat pembayaran |
| GET | /payment/:trxId |
β | Cek status by trxId |
| GET | /payment/:trxId/qr.png |
β | Gambar QRIS (PNG) |
| POST | /payment/:trxId/cancel |
π | Batalkan (expire manual) |
| GET | /payments |
π | List transaksi (paginated) |
| GET | /history |
π | History transaksi GoBiz (arsip + ?matched=) |
| GET | /health |
β | Health + counts |
π = butuh X-API-Key: <API_KEY> kalau API_KEY diset.
curl -X POST http://localhost:3000/payment/create \
-H 'Content-Type: application/json' \
-H 'X-API-Key: API_KEY_KAMU' \
-d '{
"amount": 50000,
"fee": 2500,
"trxId": "ORDER-1042",
"callbackUrl": "https://tokoku.com/webhook"
}'Body β cuma amount yang wajib:
| Field | Wajib | Isi |
|---|---|---|
amount |
β | Harga barang (rupiah) |
fee |
β | Biaya admin, ditambah ke amount. Default 0 |
trxId |
β | ID order kamu. Kosong = auto TRX-xxxx |
callbackUrl |
β | Webhook khusus trx ini, override .env |
expireMinutes |
β | Kadaluarsa (menit). Default 5 |
metadata |
β | Data bebas, dikembalikan di webhook |
Respons berisi amountToPay = amount + fee + uniqueCode (kode random 1..999
yang selalu ditambah). Itu satu-satunya angka yang dibayar pembeli dan yang
dicocokkan gateway. Tampilkan amountToPay, bukan amount. Contoh: amount 100 +
uniqueCode 52 β pembeli bayar 152.
Saat PAID / EXPIRED, gateway POST ke callbackUrl (atau WEBHOOK_URL):
{
"event": "payment.paid",
"trxId": "ORDER-1042",
"status": "PAID",
"amount": 50000,
"fee": 2500,
"uniqueCode": 137,
"amountToPay": 52637,
"paidAt": "2026-07-10T12:30:00.000Z",
"metadata": { "orderId": 1042 }
}Header X-Signature = HMAC-SHA256(WEBHOOK_SECRET, rawBody). Verifikasi pakai
verifyWebhookSignature dari src/security.js β lihat docs/API.md.
API GoBiz cuma melaporkan nominal pembayaran masuk β tidak ada cara menautkan
trxId kita ke transfer pembeli. Jadi gateway bikin tiap amountToPay unik:
amount + fee lalu tambah offset 0..99 rupiah kalau nominal itu sedang dipakai
transaksi pending lain. Pembeli scan QR amountToPay, event pembayaran dicocokkan
balik lewat nominal itu.
Konsekuensi: amountToPay bisa lebih tinggi hingga 99 rupiah dari amount + fee.
Selalu render QR + tampilkan amountToPay. Maks 100 transaksi pending boleh berbagi
nominal dasar yang sama sebelum /payment/create balas 503.
server.js Express gateway + wiring watcher (entry point)
lib/gobiz.js library GoBiz (auth, history, watcher) β dari kavionn
src/db.js SQLite (node:sqlite)
src/security.js API key, rate limit, headers, HMAC, SSRF guard
src/openapi.js spec OpenAPI untuk Swagger UI
src/server.test.js self-check
data/transaction.db database SQLite (dibuat otomatis)
docs/API.md dokumentasi API lengkap
ecosystem.config.cjs konfigurasi PM2
demo.js demo QRIS end-to-end (CLI, tanpa server)
Gateway pakai lib/gobiz.js. Kalau mau pakai library-nya langsung:
import GoPayMerchant, { getGoPayWatcher } from './lib/gobiz.js';
const watcher = getGoPayWatcher(7_000);
watcher.on('payment', ({ amount, txId }) => {
console.log('πΈ masuk:', amount, txId);
});| Export | Fungsi |
|---|---|
GoPayMerchant (default) |
init(), getHistory({ days, size }), dst |
GoPayWatcher |
EventEmitter, waitForPayment(amount, opts), event 'payment' |
getGoPayWatcher(intervalMs?) |
Singleton watcher (1 poller per proses) |
Event 'payment' memancarkan { amount, txId, entry }. Detail method ada di
komentar lib/gobiz.js.
- Library GoBiz inti (
lib/gobiz.js,demo.js) berasal dari repo original kavionn/gobiz-payment oleh @kavionn. Terima kasih π - Lapisan payment gateway (Express, SQLite, webhook, security, Swagger, PM2) ditambahkan di fork ini.
MIT β lihat LICENSE.