Lewati ke konten utama

PSP Tester API

Sandbox endpoint to test PSP integration without touching the production PSP or bank.

Auth: Bearer JWT staff dengan role superAdmin (atau UUID di SUPER_ADMIN_USER_IDS), divalidasi requireSuperAdmin middleware. Bukan header X-Internal-API-Key, bukan cookie session.

Base URL: /api/integration/v1/psp di integration_api (port 8092)

info
PSP Tester ada di integration_api

PSP Tester dan PSP External Tester dimiliki integration_api (port 8092) sejak cutover 2026-06-16. Tidak ada handler PSP tester di dashboard_api (services/dashboard_api/) — endpoint dipanggil langsung ke integration_api di /api/integration/v1/psp/{keys,execute}. Client Flutter (merchant_integration) memakai base /api/integration/v1.

Service Mapping
  • Tests untuk Events API (/psp/v1/events, /psp/v1/settlements) → request dikirim dari integration_api ke payment_service port 8085 secara internal
  • Tests untuk Lookup API (/api/psp/v1/merchants/*) → loopback ke dashboard_api:8082 (lookup API tetap dimiliki dashboard_api)
  • Tester endpoint hanya tersedia via integration_api:8092
Tidak Ada Auto-Seeding

Tidak ada auto-seeding merchant test. Gunakan merchant sandbox yang sudah ada (lihat setup di docs/sandbox-merchant-setup.md).

Use Cases

  • QA end-to-end payment flow testing without charging a real card
  • Load testing before releasing transaction features
  • Simulating edge cases: duplicate event, late webhook, invalid signature
  • Testing Flow A vs Flow B routing based on NMID

List API Keys Aktif

GET /api/integration/v1/psp/keys

Menampilkan PSP API keys yang aktif untuk sandbox.

curl -X GET https://api-merchant.kesles.com/api/integration/v1/psp/keys \
-H "Authorization: Bearer <superadmin_staff_jwt>"

Execute Test Event

POST /api/integration/v1/psp/execute

PSP Internal Tester panel menggunakan format langsung: pilih method + path + body di panel, lalu execute. Panel tidak menggunakan field simulate_type — request dikirim sesuai path yang dipilih operator.

integration_api melakukan HMAC signing di server side sebelum forward ke target service. Secret tidak pernah keluar ke browser.

Tiga Jalur Eksekusi

1. PSP Lookup API (/api/psp/v1/merchants/*)

Pilih API key dari dropdown, pilih endpoint lookup (mis. by-nmid, by-mid, by-code, by-serial, {id}/devices), isi path param, klik Execute. Backend melakukan HMAC sign dengan X-API-Key-ID / X-Timestamp / X-Signature lalu loopback ke dashboard_api:8082.

Contoh eksekusi langsung via curl (alternatif panel):

curl -X POST https://api-merchant.kesles.com/api/integration/v1/psp/execute \
-H "Authorization: Bearer <superadmin_staff_jwt>" \
-H "Content-Type: application/json" \
-d '{
"method": "GET",
"path": "/api/psp/v1/merchants/by-nmid/ID102326873XXXX",
"body": ""
}'

2. Payment Events (/psp/v1/events, /psp/v1/settlements)

Backend sign menggunakan PSP_TESTER_PAYMENT_KEY_ID dari env, lalu forward ke payment_service:8085. Menggunakan X-PSP-Key-ID / X-PSP-Timestamp / X-PSP-Signature.

Contoh kirim event transaksi sukses:

curl -X POST https://api-merchant.kesles.com/api/integration/v1/psp/execute \
-H "Authorization: Bearer <superadmin_staff_jwt>" \
-H "Content-Type: application/json" \
-d '{
"method": "POST",
"path": "/psp/v1/events",
"body": "{\"external_event_id\":\"test-evt-001\",\"event_type\":\"transaction.success\",\"nmid\":\"ID102326873XXXX\",\"gross_amount\":50000,\"status\":\"success\"}"
}'

3. Static Key (/internal/transactions/*, /internal/notifications/*)

Tidak menggunakan HMAC. Request diteruskan ke merchant_core_api dengan header X-Internal-API-Key dari env. Digunakan untuk test push notification, transaction status update, dan test-psp-event.


Merchant & Outlet Picker (Multi-Outlet)

Panel PSP Tester punya picker merchant untuk mengisi field NMID / MID / TID otomatis. Sejak platform multi-outlet, NMID/MID berbeda per outlet (merchant.merchant_outlets.nmid/mid), sedangkan TID per terminal/device (payment_terminal_inventory.tid, kini di inventory_service). Karena itu picker bertahap:

  1. Pilih merchant → set merchant_code + ambil identifier merchant-level (fallback).
  2. Pilih outlet (Default / Cabang) → isi NMID / MID dari outlet terpilih.

Perilaku:

  • 1 outlet → NMID/MID otomatis dari outlet itu (tanpa dialog).
  • >1 outlet → muncul dialog Pilih Outlet (label + NMID per outlet; outlet is_default diberi badge Default) → pilih → field terisi.
  • Outlet tanpa NMID ditandai NMID: — (belum di-assign).
  • Gagal fetch / outlet kosong → fallback ke NMID/MID merchant-level (perilaku lama).
  • TID tetap dari merchant-level/manual (per-device — di luar scope picker outlet).

GET /api/integration/v1/merchants/{id}/outlets

Mengembalikan daftar outlet satu merchant dengan nmid/mid per-outlet untuk picker. requireSuperAdmin; proxy ke merchant_core_api GET /internal/merchants/{id}/outlets (header X-Internal-API-Key).

curl -X GET https://api-merchant.kesles.com/api/integration/v1/merchants/<merchant_uuid>/outlets \
-H "Authorization: Bearer <superadmin_staff_jwt>"

Response:

{
"outlets": [
{
"outlet_name": "KESLES SANDBOX",
"is_default": true,
"nmid": "ID0000000000001",
"mid": "000000000000001"
},
{
"outlet_name": "Cabang Pembantu",
"is_default": false,
"nmid": "",
"mid": ""
}
],
"count": 2
}
PSP lookup outlet-aware

Resolver PSP nyata (/api/psp/v1/merchants/by-nmid) sudah punya jalur Tier-2 yang resolve via merchant_outlets.nmid, di balik feature flag MultiOutletPSPLookup (internal_psp_lookup_handlers.go). Picker di tester hanya mengisi field; aktifkan flag bila ingin resolver produksi membaca NMID per-outlet.


Push Warning Test (Merchant Inactive)

POST /internal/notifications/push/test-psp-event

Auth: X-Internal-API-Key (static key forward ke merchant_core_api)

Kirim test FCM push ke merchant, mensimulasikan notifikasi dari event PSP (mis. merchant inactive warning).

Request body:

{
"payload": {
"merchant_code": "MRC-...",
"mid": "",
"nmid": "",
"status": "inactive",
"title": "Peringatan Merchant",
"body": "Status merchant Anda sedang tidak aktif",
"amount": 0
}
}

Salah satu dari merchant_code, mid, atau nmid wajib diisi untuk resolve merchant.

Contoh via tester panel: pilih path /internal/notifications/push/test-psp-event, method POST, isi body JSON di atas dengan merchant_code merchant sandbox.

Auth Header Comparison

Test targetKey ID headerTimestamp headerSignature headersigned_payload order
Lookup API (/api/psp/v1/merchants/*)X-API-Key-IDX-TimestampX-Signaturetimestamp\nmethod\npath\nbody
Events API (/psp/v1/events)X-PSP-Key-IDX-PSP-TimestampX-PSP-Signaturemethod\npath\ntimestamp\nbody

X-PSP-Timestamp menggunakan format RFC3339, contoh: 2026-06-08T10:30:00+07:00.

Access Gate

EndpointGate
GET /api/integration/v1/psp/keysrequireSuperAdmin (Bearer JWT staff role superAdmin)
POST /api/integration/v1/psp/executerequireSuperAdmin (Bearer JWT staff role superAdmin)

Akses dibatasi oleh requireSuperAdmin middleware: hanya JWT staff dengan role superAdmin (atau UUID di SUPER_ADMIN_USER_IDS) yang lolos; selain itu dikembalikan 403. Tidak ada APP_ENV guard terpisah — gating murni berbasis role.