跳到主要内容

API Endpoints (WmsSyncHubApi)

All endpoints are served by WmsSyncHubApi.exe on http://localhost:5006 by default. The public reverse proxy at https://wms-sync.prismatechnology.com.my maps to the same host.

GET /api/ping

Liveness probe. The plugin calls this on form launch to decide whether the API is reachable.

Request

GET /api/ping

Response

{ "ok": true, "version": "1.0.0", "uptimeSeconds": 1234 }

No auth.


GET /api/wms-status

Deep health — pings the WMS gateway too.

Request

GET /api/wms-status

Response

{
"ok": true,
"wmsReachable": true,
"lastPollAt": "2026-04-23T15:30:06Z",
"workers": {
"PickingNoteWorker": "running",
"ItemSyncWorker": "running",
"CancellationWorker": "running",
"AsnCreateWorker": "running",
"AsnCancellationWorker": "running"
}
}

No auth.


POST /api/po-transfer

Triggered by the plugin's PO → ASN Sync tab when the user hits "Transfer PO → ASN". Creates Z_WmsPoSyncStatus rows so AsnCreateWorker picks them up on the next poll.

Request

POST /api/po-transfer
{
"poNumbers": ["PO-20260401-001", "PO-20260401-002"]
}

Response

{
"ok": true,
"queued": 2,
"alreadyPushed": 0,
"skipped": []
}

POST /api/wms-callback

The webhook endpoint WMS calls when order / ASN status changes. MD5- validated against the partner key.

Request (form-urlencoded, per WMS spec)

POST /api/wms-callback
serviceType=GLINK_UPDATE_ORDER_STATUS
partnerId=MELODIESTEST_wsgpprod1776049378721
bizData={...JSON with order/items and shipped qty...}
sign=<md5 lower-hex>

Response

{ "success": true, "code": "SUCCESS" }

Side effects depending on serviceType:

  • GLINK_UPDATE_ORDER_STATUS → upsert Z_WmsPickingNoteStatus + Z_WmsPickingNoteItemStatus with UOM-divided shipped qty, map status → DtlStatus.
  • GLINK_UPDATE_ASN_STATUS → upsert Z_WmsAsnReceiving, create GRN when ASN reaches Received state.

Signature validation is mandatory. Bad signatures get 401 and are logged to Z_WmsErrorLog.


GET /api/logs

Query Z_WmsErrorLog. Requires x-api-key header.

Request

GET /api/logs?from=2026-04-23T00:00:00Z&to=2026-04-23T23:59:59Z
&level=Error&source=PickingNoteWorker&limit=100
x-api-key: <LogAccess.ApiKey>

Response

{
"count": 3,
"rows": [
{
"errorLogId": 1234,
"createdOn": "2026-04-23T15:30:06Z",
"source": "PickingNoteWorker",
"level": "Error",
"message": "WMS returned INVALID_OPERATION",
"exception": null
}
]
}

GET /api/logs/summary

Aggregate counts. Requires x-api-key.

Response

{
"byDay": [
{ "day": "2026-04-23", "error": 2, "warning": 5 },
{ "day": "2026-04-22", "error": 0, "warning": 1 }
],
"bySource": [
{ "source": "PickingNoteWorker", "error": 1, "warning": 3 },
{ "source": "AsnCreateWorker", "error": 1, "warning": 0 }
]
}

GET /api/logs/files

List the Serilog files on disk. Requires x-api-key.

Response

{
"files": [
{ "name": "wmssynchubapi-20260423.log", "sizeKb": 132 },
{ "name": "wmssynchubapi-20260422.log", "sizeKb": 98 }
]
}

GET /api/logs/file/{name}

Tail the Nth last lines of a Serilog file. Requires x-api-key.

Request

GET /api/logs/file/wmssynchubapi-20260423.log?tail=200
x-api-key: <key>

Responsetext/plain, last 200 lines of the file.

Caution

:::caution The callback endpoint is the only public-facing route we proxy Only /api/wms-callback is mapped through the public reverse proxy. The /api/logs* endpoints should be locked down to internal or VPN — they leak everything. The LogAccess.ApiKey is a mitigation, not a substitute for network isolation. :::