Skip to main content

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.

warning

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_reviewactive.

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}

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 / cancelled
  • search: substring on order_number, merchant_name, merchant_code, contact_phone, contact_email
  • sort: 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}actionmark-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_ordersales_orders with status pending/accepted + payment_proof_url=''
  • payment_sentsales_orders with status pending/accepted + payment_proof_url<>''
  • goods_receivedshipping_orders with delivered_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 #1F7AE0
  • payment_sent → amber #D97706
  • goods_received → green #0E9F6E

Rate Limit

  • admin/* endpoints: 120 req/min per admin user
  • admin/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.