7.4 KiB
Panduan QA End-to-End: Payment Link
Dokumen ini menjelaskan alur end-to-end Payment Link yang tersedia di proyek, mencakup konfigurasi, endpoint backend, format token, langkah QA dengan contoh request, hingga troubleshooting dan integrasi frontend.
Ringkasan Alur
- ERP/eksternal membuat Payment Link via
POST /createtransaksidan menerimaurlsertatoken. - Frontend membuka halaman
Paydi routepay/:token, lalu me-resolve token viaGET /api/payment-links/:token. - Pengguna memilih metode pembayaran (sesuai
allowed_methodsdan toggle runtime), kemudian frontend memanggilPOST /api/payments/charge. - Status pembayaran dapat dicek via
GET /api/payments/:orderId/statusdan disinkronkan via webhookPOST /api/payments/webhook.
Prasyarat & Konfigurasi
- Backend: jalankan
node server/index.cjs(default port8000). - Frontend: jalankan
npm run dev(contoh dev port:5175). - Penyesuaian environment penting:
EXTERNAL_API_KEY: API Key luar untukPOST /createtransaksi. Jika tidak diset, di dev akan diizinkan tanpa key.PAYMENT_LINK_SECRET: secret untuk penandatanganan token Payment Link (HMAC SHA-256). Default dev:dev-secret.PAYMENT_LINK_TTL_MINUTES: waktu kedaluwarsa token (default:30).PAYMENT_LINK_BASE: base URL untuk halamanPay(default:http://localhost:5174/pay). Sesuaikan ke port frontend yang aktif (misalhttp://localhost:5175/pay).PORT: port backend (default:8000).ERP_NOTIFICATION_URL,ERP_CLIENT_ID,ERP_MERCANT_ID,ERP_ENABLE_NOTIF: konfigurasi notifikasi ERP saat settlement.- Midtrans keys: Server Key dan Client Key harus tersedia untuk charge/status.
- Frontend env:
VITE_API_BASE_URL(contoh:http://localhost:8000/api),VITE_MIDTRANS_CLIENT_KEY.
Endpoint Backend
-
POST /createtransaksi- Header:
X-API-KEY(opsional di dev jikaEXTERNAL_API_KEYtidak diset). - Body:
{ item_id | order_id, nominal, customer?, allowed_methods? } - Respon:
{ url, token, order_id, nominal, expire_at } - Error:
UNAUTHORIZED,BAD_REQUEST,ORDER_COMPLETED,ORDER_ACTIVE,CREATE_ERROR.
- Header:
-
GET /api/payment-links/:token- Respon:
{ order_id, nominal, customer?, expire_at?, allowed_methods? } - Error:
410 TOKEN_EXPIRED,400 INVALID_*(di dev ada fallback payload jika token invalid).
- Respon:
-
POST /api/payments/charge- Body: payload Midtrans (contoh di bawah). Diblokir jika method dimatikan oleh runtime toggles.
- Error:
PAYMENT_TYPE_DISABLED,CHARGE_ERROR.
-
GET /api/payments/:orderId/status- Respon: pass-through dari Midtrans (transaction status, VA, dll.).
-
POST /api/payments/webhook- Verifikasi signature:
sha512(orderId + statusCode + grossAmount + serverKey). - Pada sukses (settlement atau capture+accept untuk kartu), backend kirim notifikasi ke ERP (jika diaktifkan) dan menandai order sebagai completed.
- Verifikasi signature:
-
GET /api/health,GET/POST /api/config- Health: cek ketersediaan key dan environment.
- Config: baca/ubah toggles (dev-only untuk
POST).
Format Token Payment Link
- Token adalah
base64url(JSON)dengan fields minimal:{ v, order_id, nominal, expire_at, sig, customer?, allowed_methods? }. sigadalah HMAC SHA-256 dari string kanonik:"order_id|nominal|expire_at"menggunakanPAYMENT_LINK_SECRET.
Langkah QA (Contoh)
- Buat Payment Link
PowerShell (Windows):
$body = @{
item_id = 'INV-PL-001';
nominal = 150000;
customer = @{ name='QA Tester'; phone='081234567890'; email='qa@example.com' };
allowed_methods = @('bank_transfer','cstore','gopay','credit_card')
} | ConvertTo-Json -Depth 5;
Invoke-RestMethod -Method POST -Uri 'http://localhost:8000/createtransaksi' -ContentType 'application/json' -Body $body | ConvertTo-Json -Depth 5
curl:
curl -X POST http://localhost:8000/createtransaksi \
-H 'Content-Type: application/json' \
-H 'X-API-KEY: <jika-diperlukan>' \
-d '{
"item_id":"INV-PL-001",
"nominal":150000,
"customer": {"name":"QA Tester","phone":"081234567890","email":"qa@example.com"},
"allowed_methods":["bank_transfer","cstore","gopay","credit_card"]
}'
- Resolve Token
Invoke-RestMethod -Method GET -Uri "http://localhost:8000/api/payment-links/<token>" | ConvertTo-Json -Depth 5
- Buka Halaman Pay
- Buka
http://localhost:5175/pay/<token>(sesuaikanPAYMENT_LINK_BASEdengan port frontend). - Periksa daftar metode, panel, serta batasan dari
allowed_methodsdan runtime toggles.
- Charge Bank Transfer (BCA)
$bt = @{
payment_type = 'bank_transfer';
transaction_details = @{ order_id = 'INV-PL-001'; gross_amount = 150000 };
bank_transfer = @{ bank = 'bca' }
} | ConvertTo-Json -Depth 5;
Invoke-RestMethod -Method POST -Uri 'http://localhost:8000/api/payments/charge' -ContentType 'application/json' -Body $bt | ConvertTo-Json -Depth 5
- Charge GoPay/QR (opsional)
$qr = @{
payment_type = 'gopay';
transaction_details = @{ order_id = 'INV-PL-001'; gross_amount = 150000 };
gopay = @{ enable_qr = $true }
} | ConvertTo-Json -Depth 5;
Invoke-RestMethod -Method POST -Uri 'http://localhost:8000/api/payments/charge' -ContentType 'application/json' -Body $qr | ConvertTo-Json -Depth 5
Catatan: Bila 400 Bad Request, cek konfigurasi akun sandbox dan parameter GoPay/QRIS (lihat bagian troubleshooting).
- Status Check
Invoke-RestMethod -Method GET -Uri 'http://localhost:8000/api/payments/INV-PL-001/status' | ConvertTo-Json -Depth 5
- Webhook (uji manual)
Untuk uji manual, kirim payload menyerupai notifikasi Midtrans dengan signature_key yang valid. Signature dihitung:
// Node.js contoh perhitungan signature
const crypto = require('crypto')
function computeMidtransSignature(orderId, statusCode, grossAmount, secretKey) {
const raw = String(orderId) + String(statusCode) + String(grossAmount) + String(secretKey)
return crypto.createHash('sha512').update(raw).digest('hex')
}
Kemudian POST ke http://localhost:8000/api/payments/webhook dengan body berisi fields Midtrans (order_id, status_code, gross_amount, signature_key, dll.).
Troubleshooting
- Frontend tidak sesuai
PAYMENT_LINK_BASE(5174 vs 5175): setPAYMENT_LINK_BASE=http://localhost:5175/paydi backend agar URL link mengarah ke port yang benar. 400 Bad Requestuntuk GoPay/QR:- Pastikan
gopaypayload memenuhi kebutuhan sandbox (mis.enable_qr, kadang perluqr_black_white, ataucallback_url). - Periksa toggles runtime (
/api/config) dan ketersediaan Midtrans keys. - Beberapa merchant sandbox memiliki batasan; rujuk dokumentasi Midtrans untuk parameter terbaru.
- Pastikan
UNAUTHORIZEDsaatcreatetransaksi: set headerX-API-KEYsesuaiEXTERNAL_API_KEYjika dikonfigurasi.ORDER_ACTIVEatauORDER_COMPLETED: backend menjagaactiveOrdersdannotifiedOrdersuntuk mencegah duplikasi; tunggu TTL atau gunakan order baru.
Integrasi Frontend
- Route:
pay/:token(lihatsrc/app/router.tsx). - Resolver:
getPaymentLinkPayload(token)(lihatsrc/services/api.ts). - Toggle & Allowed Methods:
PayPagemenggabungkanruntimeCfg.paymentTogglesdenganallowed_methods. Kunci metode:bank_transfer,credit_card,gopay,cstore,cpay.
Notifikasi ERP
- Di settlement sukses, backend menghitung signature ERP (
sha512) dan mengirim payload keERP_NOTIFICATION_URLjikaERP_ENABLE_NOTIF=truedan konfigurasi lengkap.
Postman Collection
- Anda dapat mengimpor koleksi:
docs/qa/payment-link.postman_collection.jsonuntuk mencoba endpoint di atas.