Skip to content

Push Integration API

REST API ที่ให้ระบบภายนอก (ERP, e-commerce, suppliers) push ข้อมูลเข้า WMS โดยตรง โดย authenticate ผ่าน API Key แทน JWT

Base URL: https://api.example.com/api/v1/integration/v1Auth: ส่ง header X-API-Key: <your-key> (หรือ Authorization: ApiKey <your-key>)


ภาพรวม

หัวข้อรายละเอียด
AuthenticationAPI Key (SHA-256 hashed at rest)
Identifier rulesอ้างถึง items ด้วย sku, partners ด้วย code, warehouses ด้วย warehouseCode — service จะ resolve เป็น UUID ให้
IdempotencyOptional header Idempotency-Key (24h TTL)
Bulk endpointsคืนค่า 207 Multi-Status เมื่อมีบางรายการ error
Tenant scopingผูก API Key กับ tenantId เพื่อจำกัดขอบเขตการมองเห็น

1. Authentication

สร้าง API Key

เข้า Admin Portal → Settings → API Keys → กด + New Key หรือเรียก endpoint:

bash
POST /api/v1/api-keys
Authorization: Bearer <admin-jwt>
Content-Type: application/json

{
  "name": "ERP Integration",
  "scopes": ["read", "write"],
  "tenantId": "00000000-0000-0000-0000-000000000001",
  "expiresAt": "2027-01-01T00:00:00.000Z"
}

ระบบจะส่ง rawKey กลับมา ครั้งเดียว — เก็บไว้ดีๆ ขึ้นต้นด้วย wms_...

ใช้ใน request

bash
curl -X POST https://api.example.com/api/v1/integration/v1/items \
  -H "X-API-Key: wms_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{ ... }'

หรือใช้รูปแบบ Authorization:

bash
curl ... -H "Authorization: ApiKey wms_xxxxxxxx..."

Scopes

Scopeสิทธิ์
readเรียก GET endpoints (inquiry)
writePOST/PUT (upsert master data, สร้าง ASN/GRN/orders)
adminsuper-scope — ผ่านทุก scope check

2. Idempotency

ทุก POST endpoint รองรับ header Idempotency-Key:

bash
curl -X POST .../integration/v1/orders \
  -H "X-API-Key: wms_..." \
  -H "Idempotency-Key: order-2026-06-15-abc123" \
  -d '{ ... }'

กฎ:

  1. ถ้าใช้ key เดิม + body เดิม ภายใน 24 ชม. → ระบบ replay response เดิม (มี header Idempotent-Replay: true)
  2. ถ้าใช้ key เดิมแต่ body ต่าง → ระบบตอบ 409 IDEMPOTENCY_KEY_MISMATCH
  3. หลัง 24 ชม. → key หมดอายุ ระบบสร้าง request ใหม่

Best practice: ใช้ UUID หรือ external order number เป็น Idempotency-Key


3. Response Format

Success

json
{
  "status": "success",
  "data": { ... },
  "requestId": "uuid-v4"
}

Bulk (อาจเป็น success หรือ partial)

json
{
  "status": "partial",
  "total": 3,
  "created": 2,
  "updated": 0,
  "errors": [
    { "index": 1, "key": "SKU-X", "error": "Item SKU \"SKU-X\" not found." }
  ],
  "data": [
    { "index": 0, "key": "SKU-A", "status": "created", "data": { "id": "uuid", "sku": "SKU-A" } },
    { "index": 1, "key": "SKU-X", "status": "error", "error": "..." },
    { "index": 2, "key": "SKU-B", "status": "updated", "data": { "id": "uuid", "sku": "SKU-B" } }
  ],
  "requestId": "uuid-v4"
}

HTTP status: 200 ถ้าทุกรายการผ่าน, 207 ถ้ามี errors

Error

json
{
  "status": "error",
  "code": "VALIDATION_FAILED",
  "message": "...",
  "requestId": "uuid-v4"
}

4. Endpoints

ทั้งหมดอยู่ใต้ prefix /api/v1/integration/v1

Master Data

POST /items — Upsert single item

bash
curl -X POST .../integration/v1/items \
  -H "X-API-Key: wms_..." \
  -H "Content-Type: application/json" \
  -d '{
    "sku": "SKU-001",
    "name": "น้ำดื่มตราสิงห์ 750ml",
    "barcode": "8850000000001",
    "baseUomCode": "EA",
    "category": "Beverages",
    "tracking": "lot",
    "shelfLifeDays": 365,
    "weightKg": 0.75
  }'

POST /items/bulk — Bulk upsert (max 500)

bash
curl -X POST .../integration/v1/items/bulk \
  -H "X-API-Key: wms_..." \
  -d '{
    "items": [
      { "sku": "SKU-001", "name": "Item A", "baseUomCode": "EA" },
      { "sku": "SKU-002", "name": "Item B", "baseUomCode": "BOX" }
    ]
  }'

POST /partners — Upsert partner

json
{
  "code": "SUP-001",
  "name": "บริษัท สยามเทรดดิ้ง จำกัด",
  "type": "supplier",
  "contact": { "phone": "081-234-5678" }
}

POST /partners/bulk — Bulk upsert partners

json
{ "partners": [ {...}, {...} ] }

POST /locations — Upsert location

json
{
  "warehouseCode": "WH-BKK-01",
  "code": "A-01-01-01",
  "zone": "A",
  "type": "storage",
  "pickFace": true
}

POST /locations/bulk — Bulk upsert locations

json
{ "locations": [ {...}, {...} ] }

Inbound

POST /asn — Create ASN

bash
curl -X POST .../integration/v1/asn \
  -H "X-API-Key: wms_..." \
  -H "Idempotency-Key: po-2026-001" \
  -d '{
    "warehouseCode": "WH-BKK-01",
    "supplierCode": "SUP-001",
    "expectedDate": "2026-06-15",
    "referenceNo": "PO-2026-001",
    "lines": [
      { "lineNo": 1, "sku": "SKU-001", "uomCode": "CASE", "expectedQty": 50 },
      { "lineNo": 2, "sku": "SKU-002", "uomCode": "EA", "expectedQty": 200, "lotNo": "LOT-A", "expiryDate": "2027-12-31" }
    ]
  }'

POST /asn/bulk — Multiple ASNs (max 100)

json
{ "asns": [ {...}, {...} ] }

POST /grn — Create GRN

json
{
  "warehouseCode": "WH-BKK-01",
  "asnNo": "ASN-20260615-0001",
  "lines": [
    { "asnLineNo": 1, "sku": "SKU-001", "uomCode": "CASE", "qty": 50 }
  ]
}

ถ้าระบุ asnNo: ระบบจะอัปเดต receivedQty ของแต่ละ ASN line และย้าย ASN ไปสถานะ receiving อัตโนมัติ

Outbound

POST /orders — Create sales order

bash
curl -X POST .../integration/v1/orders \
  -H "X-API-Key: wms_..." \
  -H "Idempotency-Key: ext-order-12345" \
  -d '{
    "warehouseCode": "WH-BKK-01",
    "customerCode": "CUS-001",
    "requiredDate": "2026-06-20",
    "priority": 3,
    "shipTo": { "name": "สมชาย", "address": "123 ถ.สุขุมวิท" },
    "referenceNo": "EXT-ORDER-12345",
    "lines": [
      { "lineNo": 1, "sku": "SKU-001", "uomCode": "EA", "qtyOrdered": 10 }
    ]
  }'

POST /orders/bulk — Multiple orders (max 100)

POST /orders/{orderNo}/cancel — Cancel by order number

bash
curl -X POST .../integration/v1/orders/SO-20260615-0042/cancel \
  -H "X-API-Key: wms_..."

ปล่อย reservations และ allocated qty อัตโนมัติ ถ้ายังไม่ shipped/completed

Inquiry (read-only)

GET /orders/{orderNo}

ตอบกลับ order + lines + pickTasks + summary (totalOrdered/Allocated/Picked/Shipped)

GET /asn/{asnNo}

ตอบกลับ ASN + lines พร้อม receivedQty + รายการ GRNs ที่ผูกอยู่

GET /stock?sku=SKU-001&warehouseCode=WH-BKK-01[&lotNo=LOT-A]

json
{
  "status": "success",
  "data": {
    "sku": "SKU-001",
    "itemName": "...",
    "tracking": "lot",
    "totalOnHand": 1250,
    "totalAllocated": 300,
    "totalAvailable": 950,
    "stocks": [
      { "warehouseCode": "WH-BKK-01", "locationCode": "A-01-01-01", "lotNo": "LOT-A", "qtyOnHand": 500, "qtyAllocated": 100, "qtyAvailable": 400 }
    ]
  }
}

5. Error Codes

HTTPCode / Patternสาเหตุที่พบบ่อย
400VALIDATION_FAILEDDTO ไม่ผ่าน class-validator
400Item SKU "X" not found.SKU ที่อ้างไม่มีใน tenant
400Warehouse code "X" not found...warehouseCode ผิด
400tenantId is required.API Key ไม่ผูกกับ tenant และ DTO ไม่ส่ง tenantId มา
401Missing API keyไม่มี header
401Invalid, revoked, or expired API keykey ไม่ถูกต้องหรือถูก revoke
401API key missing required scope(s)scope ไม่พอ
404Order/ASN "X" not found.ค้นหาด้วย number แล้วไม่เจอ
207(multi-status)bulk operation มีบางรายการ error
409IDEMPOTENCY_KEY_MISMATCHส่ง Idempotency-Key เดิมแต่ body ต่าง

6. Webhook Events (ส่งกลับให้ external systems)

ระบบ WMS รองรับ webhook ผ่าน WebhookSubscription — register ผ่าน Admin Portal แล้วเราจะส่ง POST ไปที่ URL ของคุณเมื่อเหตุการณ์ต่อไปนี้เกิดขึ้น:

EventTrigger
asn.receivedGRN ถูกสร้างต่อ ASN
asn.completedASN รับครบทุก line
order.allocatedStock ถูก allocate ให้ order
order.releasedOrder ถูก release ออกเป็น pick tasks
order.shippedShipment ออกจากคลัง
order.cancelledOrder ถูก cancel
stock.adjustedมี stock adjustment
cyclecount.varianceนับสต๊อกพบความต่าง

Payload format:

json
{
  "event": "order.shipped",
  "timestamp": "2026-06-15T10:30:00.000Z",
  "data": { "orderNo": "SO-...", "shipmentNo": "SHIP-...", "trackingNo": "TH123..." }
}

7. Limits

ทรัพยากรจำกัด
Bulk items / partners / locations500 รายการ / request
Bulk ASNs / orders100 รายการ / request
ขนาด request body1 MB
Idempotency-Key TTL24 ชั่วโมง

ติดต่อ admin ถ้าต้องการ rate-limit หรือ batch ขนาดใหญ่กว่านี้


8. Security & Rate Limiting

แต่ละ API Key สามารถตั้งค่าได้ใน Admin Portal → API Keys

IP Whitelist

  • กำหนดได้ทั้ง exact IP (เช่น 203.0.113.5) และ CIDR (เช่น 203.0.113.0/24)
  • ระบบดูจาก X-Forwarded-For (header แรก) เมื่อ deploy ผ่าน proxy เช่น Render
  • ถ้า list ว่าง → อนุญาตทุก IP
  • ถ้า request มาจาก IP นอก list → ตอบกลับ 403 Forbidden
json
{
  "statusCode": 403,
  "message": "Client IP \"198.51.100.7\" is not in this API key's whitelist."
}

Allowed Origins (CORS)

  • ใช้สำหรับ key ที่อนุญาตให้เรียกจากเบราว์เซอร์เท่านั้น
  • ระบบเช็ค Origin header ของ request
  • ถ้า header Origin ไม่มี (เช่น server-to-server) → อนุญาตเสมอ
  • ถ้ามี Origin แต่ไม่อยู่ใน list → ตอบกลับ 403 Forbidden

Rate Limit

  • กำหนดเป็น requests per minute ต่อ key
  • ตั้ง 0 หรือเว้นว่าง = ไม่จำกัด
  • ใช้ sliding window 60 วินาที (in-memory)
  • เมื่อเกิน → ตอบกลับ 429 Too Many Requests พร้อม header Retry-After
http
HTTP/1.1 429 Too Many Requests
Retry-After: 23
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0

{
  "statusCode": 429,
  "message": "Rate limit exceeded for API key (60 req/min). Retry in 23s.",
  "error": "Too Many Requests",
  "retryAfter": 23
}

Response header ที่ส่งกลับทุก request เมื่อ key มี rate limit:

Headerความหมาย
X-RateLimit-Limitจำนวน req/min ที่อนุญาต
X-RateLimit-Remainingจำนวน req คงเหลือใน window ปัจจุบัน
Retry-After(เฉพาะตอน 429) วินาทีที่ต้องรอ

Request Logging

ทุก request ผ่าน guard จะถูกบันทึกใน api_key_request (async หลัง response):

  • endpoint, method, IP, origin
  • status code, response time
  • ใช้สำหรับ stats / audit ใน Admin Portal

Best practices

  1. Production keys ควรมี IP whitelist เสมอ — ลดความเสียหายถ้า key รั่ว
  2. Rate limit ตามจริง — ตั้งให้สูงพอแต่ป้องกัน abuse (เช่น 120/min สำหรับ ERP)
  3. Allowed Origins ตั้งเฉพาะ key สำหรับเบราว์เซอร์ — server-to-server ไม่ต้อง
  4. Rotate ทุก 90 วัน — สร้าง key ใหม่ แล้วค่อย revoke ของเก่าหลัง verify
  5. แยก key ต่อ integration — ปิด/หมุนได้ทีละตัวโดยไม่กระทบระบบอื่น

เผยแพร่ภายใต้ Digital Outsourcing