Dashboard Admin API
Admin endpoints for the internal dashboard — merchant lifecycle, audit, feature flags.
Auth: JWT Bearer (role admin or superadmin) issued by the dashboard login.
Base URL: https://kesles.com/merchant/dashboard-api/admin (production) / http://localhost:8082/admin (local).
Merchant Lifecycle
Suspend Merchant
POST /admin/merchants/{id}/suspend
Suspend a merchant — transactions are rejected, but data is not deleted.
curl -X POST https://kesles.com/merchant/dashboard-api/admin/merchants/{id}/suspend \
-H "Authorization: Bearer $ADMIN_JWT" \
-H "Content-Type: application/json" \
-d '{"reason":"pending KYC re-verification","suspended_by":"admin-uuid"}'
Response
{ "merchant_id": "...", "status": "suspended", "suspended_at": "..." }
Reactivate Merchant
POST /admin/merchants/{id}/reactivate
Re-activate a suspended/inactive merchant.
Terminate Merchant
POST /admin/merchants/{id}/terminate
Terminate a merchant — status deleted, disconnected from the PSP.
Termination cannot be undone. 2-eyes approval is required.
KYC Review
List Pending Review
GET /admin/merchants/pending-review
List merchants with status pending_review (KYC submitted, not yet approved).
Approve KYC
POST /admin/merchants/{id}/kyc/approve
Approve merchant KYC. Promotes from pending_review → active.
Reject KYC
POST /admin/merchants/{id}/kyc/reject
Reject KYC with a reason.
PSP Merchant Management
PSP merchant lookup sekarang dilakukan via dashboard_api sebagai proxy ke
merchant_core_api /internal/psp/merchants/* (Phase 3 reader cutover).
Tidak ada SQL langsung ke main DB.
List PSP Merchants
GET /api/psp/v1/merchants
List semua PSP merchant yang terdaftar.
Lookup by ID
GET /api/psp/v1/merchants/{id}
Lookup by NMID
GET /api/psp/v1/merchants/by-nmid/{nmid}
NMID korporat untuk QRIS Plus adalah ID9999999999999 (singleton di psp.qris_config).
Lookup by MID
GET /api/psp/v1/merchants/by-mid/{mid}
Lookup by Merchant Code
GET /api/psp/v1/merchants/by-code/{code}
Search
GET /api/psp/v1/merchants/search?q={keyword}
List Devices (per merchant)
GET /api/psp/v1/merchants/{id}/devices
Lookup by Serial Number
GET /api/psp/v1/merchants/by-serial/{serial}
Format SN Aisino Q161: 11 digit pure numeric (mis. 00087000668).
QRIS Config
GET /api/dashboard/settings/qris
Singleton konfigurasi QRIS korporat. Data bersumber dari payment_service /internal/qris-config (Phase 3 cutover).
Feature Flags
List Flags
GET /admin/flags
List all feature flags + their current state.
Toggle Flag
POST /admin/flags/{flag_name}
Toggle a feature flag.
curl -X POST https://kesles.com/merchant/dashboard-api/admin/flags/new_transaction_flow \
-H "Authorization: Bearer $ADMIN_JWT" \
-d '{"enabled": false, "reason": "rollback due to incident"}'
Audit Log
Query Audit Log
GET /admin/audit-logs
Query the audit log with filters: actor, action, resource_type, from, to.
curl -G https://kesles.com/merchant/dashboard-api/admin/audit-logs \
-H "Authorization: Bearer $ADMIN_JWT" \
-d actor=admin-uuid \
-d from=2026-04-01 \
-d to=2026-04-24
Transactions
Recent Transactions
GET /api/dashboard/transactions
Recent transactions. Data bersumber dari payment_service /internal/transactions
(Phase 3 reader cutover — tidak lagi query SQL langsung ke merchant.transactions).
Query params: merchant_id, limit, page, from, to, status.
Sales — Orders
Base path: /api/dashboard/sales/sales-orders. Read roles: super_admin,
admin, operations, finance, support. Write actions
(mark-paid/accept/start-processing/complete/cancel) require role operations
or super_admin.
List Sales Orders
GET /api/dashboard/sales/sales-orders?status=&search=&sort=&limit=10&page=1
Query params:
status:awaiting_activation/pending/accepted/pending_no_proof(virtual: pending without proof) /pending_with_proof(virtual: pending with proof) /payment_received/processing/completed/cancelledsearch: substring on order_number, merchant_name, merchant_code, contact_phone, contact_emailsort:oldest/total_desc/total_asc(default: newest)
Response (per row):
{
"id": "uuid",
"order_number": "SO-0000000000000067",
"status": "pending",
"merchant_id": "uuid|''",
"merchant_registration_id": "uuid|''",
"merchant_code": "MRC-...",
"merchant_name": "Coffe Mappasitujue",
"device_name": "QRIS Plus",
"device_quantity": 1,
"items": [
{
"line_no": 1,
"device_name": "QRIS Plus",
"quantity": 1,
"unit_price_amount": 1200000,
"promo_amount": 850000,
"line_total_amount": 388500
}
],
"bank_verification": {
"status": "success",
"provider_name": "BCA Virtual Account",
"reference_number": "BCA20260502091234567",
"payment_method": "BANK_TRANSFER",
"amount": 466200,
"paid_at": "2026-05-02T17:11:25Z",
"payer_name": "Kopi Udin",
"payer_account": "8201xxxxxxxxxx",
"raw_note": "Settled via BCA VA"
},
"subtotal_amount": 420000,
"shipping_fee_amount": 30000,
"promo_amount": 850000,
"total_amount": 466200,
"payment_proof_url": "...",
"created_at": "2026-05-02T16:58:00Z",
"updated_at": "..."
}
The items array is the per-line breakdown — used by the Order Detail
dialog in the dashboard to render the list of purchased items, not just the
total. Empty when the order has no lines yet.
bank_verification is the payment verification result from the acquiring
bank / virtual account / PSP API. Optional (omitted from JSON when the
backend is not yet integrated with the bank or verification has not been
performed). When present, the Review Payment dialog in the dashboard
auto-renders the "Bank Verification" section with a status badge
(green/red/amber) + cross-checks the amount vs the order total. Status
enum: success / paid / pending / failed / rejected / not_found
/ refunded.
Order State Transitions
POST /api/dashboard/sales/sales-orders/{id}/{action} — action ∈
mark-paid, accept, start-processing, complete, cancel. State
machine: pending → accepted → payment_received → processing → completed.
cancel is valid from any non-terminal status.
Catatan mark-paid: Endpoint ini adalah Jalur A (manual) untuk menandai order
sebagai sudah dibayar. Jalur B (otomatis) dilakukan oleh payment_service via
order_service /internal/orders/{id}/mark-paid saat PSP webhook masuk.
Lihat Sales Order State Machine §4.
Sales — Shipping Orders
Base path: /api/dashboard/sales/shipping-orders.
Create Shipping
POST /api/dashboard/sales/shipping-orders
Body: {sales_order_id, courier, tracking_number, notes} — courier &
tracking are optional (can be filled later via the dispatch action). The
backend auto-promotes the sales_order to processing and reserves the
terminal stock.
Shipping Actions
POST /api/dashboard/sales/shipping-orders/{id}/{action} — action ∈
mark-packed, dispatch, mark-delivered. mark-delivered triggers a
Goods Received notification in the Notification Center.
Notification Center
List Notifications
GET /api/dashboard/notifications?limit=25
Aggregate event stream for the top-bar bell. Polling-based from the frontend (default interval 60s). Read roles are the same as sales-orders.
Source events (window: last 7 days):
new_order—sales_orderswith statuspending/accepted+payment_proof_url=''payment_sent—sales_orderswith statuspending/accepted+payment_proof_url<>''goods_received—shipping_orderswithdelivered_at IS NOT NULL
Response:
{
"items": [
{
"id": "so:uuid",
"type": "new_order",
"title": "New Order",
"message": "Order SO-... received from Merchant X.",
"occurred_at": "2026-05-02T19:30:00Z",
"ref_id": "uuid",
"ref_number": "SO-0000000000000067"
}
],
"meta": { "total": 25 }
}
Sort: occurred_at DESC. The frontend resolves type → icon + tint:
new_order→ blue#1F7AE0payment_sent→ amber#D97706goods_received→ green#0E9F6E
Rate Limit
admin/*endpoints: 120 req/min per admin useradmin/merchants/*/terminate: 5 req/day per admin (hard limit, for the 2-eyes guard)dashboard/notifications: no specific hard limit, polled every 60s from the UI
OpenAPI Spec (Draft)
Sales Orders + Shipping Orders + Notification Center have a formal
OpenAPI 3.0.3 schema in
admin-openapi-draft.yaml (di repo, di luar Docusaurus)
— import into Postman / Stoplight or use it for client code-gen.
Related
- Dashboard API Architecture — Phase 3 reader cutover detail
- PSP Tester API — test PSP integration without touching production PSP
- Service Topology
- Sales Order State Machine
- Transaction Notification Flow