พัฒนาบน API ของ MG Ship
ดึงข้อมูลการมองเห็นการขนส่งแบบเรียลไทม์เข้าสู่ระบบของคุณเองด้วย REST API ที่ใช้งานง่ายและมีการจัดเวอร์ชัน
ภาพรวม
MG Ship API เป็น REST API ที่คืนค่าเป็น JSON ผ่าน HTTPS โดยให้ระบบของคุณเข้าถึงข้อมูลการมองเห็นการขนส่งแบบเป็นโปรแกรมได้ ทั้งรายการการขนส่ง บันทึกการขนส่งฉบับเต็ม และไทม์ไลน์การติดตาม เพื่อให้คุณสามารถดึงเหตุการณ์สำคัญ (milestone) เข้าสู่ TMS, ERP หรือพอร์ทัลลูกค้าของคุณเองได้
ทุกเอนด์พอยต์อยู่ภายใต้เส้นทางฐานที่มีการจัดเวอร์ชันด้านล่าง API มีการจัดเวอร์ชันในเส้นทาง URL (v1) การเปลี่ยนแปลงที่ทำให้เกิดความไม่เข้ากัน (breaking changes) จะเผยแพร่ภายใต้เส้นทางใหม่ (v2) พร้อมระยะเวลาเลิกใช้งาน 12 เดือนสำหรับเวอร์ชันก่อนหน้า ดังนั้นการเชื่อมต่อที่สร้างขึ้นบน v1 จะยังคงทำงานได้ต่อไป
Base URL
เลือก Base URL สำหรับสภาพแวดล้อมที่คุณกำลังเชื่อมต่อด้วย เส้นทางของทุกเอนด์พอยต์ด้านล่างเป็นเส้นทางสัมพัทธ์กับ Base URL นี้ Staging และ Test (VPS) มีไว้สำหรับการพัฒนาและทดสอบ ใช้ Production เฉพาะกับคีย์จริงเท่านั้น
| สภาพแวดล้อม | Base URL |
|---|---|
| Production | https://api.mglobalship.com/api/v1/external |
| Staging | https://api.staging.mglobalship.com/api/v1/external |
| Test (VPS) | https://mgs.aipipis.com/api/v1/external |
การยืนยันตัวตน
ยืนยันตัวตนทุกคำขอด้วยคีย์ API ที่ส่งเป็น Bearer token ในส่วนหัว Authorization คีย์จะออกให้แยกตามผู้เช่า (tenant) จาก API Portal จะแสดงเพียงครั้งเดียวเมื่อสร้าง มีขอบเขตที่ระบุไว้อย่างชัดเจน (เช่น shipments.read) และสามารถหมุนเวียนหรือเพิกถอนได้ทุกเมื่อ
เก็บคีย์ไว้ฝั่งเซิร์ฟเวอร์เสมอ อย่านำไปใส่ในโค้ดของเบราว์เซอร์หรือมือถือ หากคีย์ถูกเปิดเผย ให้หมุนเวียนคีย์จาก API Portal แล้วคีย์เดิมจะหยุดทำงานทันที
curl https://api.staging.mglobalship.com/api/v1/external/health \
-H "Authorization: Bearer mgs_live_xxxxxxxxxxxxxxxxxxxxxxxx"ข้อกำหนด
การแบ่งหน้า
เอนด์พอยต์แบบรายการใช้การแบ่งหน้าด้วยเคอร์เซอร์ (cursor) ส่งค่า limit (1–100, ค่าเริ่มต้น 20) เพื่อกำหนดขนาดหน้า เมื่อมีผลลัพธ์เพิ่มเติม การตอบกลับจะตั้งค่า has_more เป็น true และคืนค่า next_cursor ให้ส่งค่านี้กลับมาเป็นพารามิเตอร์การค้นหา cursor เพื่อดึงหน้าถัดไป เคอร์เซอร์เป็นค่าทึบ (opaque) ให้ปฏิบัติต่อมันเสมือนโทเค็น อย่าสร้างขึ้นเอง
ขีดจำกัดอัตรา
คำขอถูกจำกัดอัตราต่อนาทีตามระดับ (tier) ของบัญชีคุณ ทุกการตอบกลับจะมีส่วนหัว X-RateLimit-Limit, X-RateLimit-Remaining และ X-RateLimit-Reset (วินาทีจนกว่าหน้าต่างจะรีเซ็ต) การใช้งานเกินขีดจำกัดจะคืนค่า 429 พร้อมค่า retry_after_seconds ในเนื้อหา คีย์แต่ละตัวสามารถได้รับขีดจำกัดสูงสุดที่สูงขึ้นได้ตามคำขอ
| ระดับ | คำขอ / นาที |
|---|---|
| Bronze | 60 |
| Silver | 300 |
| Gold | 1,000 |
| Platinum | 5,000 |
| Enterprise | ไม่จำกัด |
Idempotency
เอนด์พอยต์การเขียน (เช่น POST /shipments) ต้องใช้ส่วนหัว Idempotency-Key การลองส่งคำขอใหม่ด้วยคีย์เดิมจะคืนผลลัพธ์เดิมแทนที่จะสร้างรายการซ้ำ ดังนั้นการลองใหม่ผ่านเครือข่ายจึงปลอดภัยเสมอ เอนด์พอยต์แบบอ่านอย่างเดียว (GET) ไม่จำเป็นต้องใช้
เอนด์พอยต์
/healthตรวจสอบว่าคีย์ของคุณใช้งานได้ และดูระดับ (tier) ปัจจุบันพร้อมสถานะขีดจำกัดอัตรา เป็นการเรียกขนาดเล็กเพื่อยืนยันการเชื่อมต่อ
curl https://api.staging.mglobalship.com/api/v1/external/health \
-H "Authorization: Bearer mgs_live_..."{
"status": "ok",
"tenant_id": 123,
"tier": "silver",
"rate_limit": {
"limit": 300,
"remaining": 299,
"reset_seconds": 59
}
}/shipmentsลงทะเบียนการขนส่งเพื่อให้แพลตฟอร์มเริ่มติดตาม ต้องมีขอบเขต shipments.write และส่วนหัว Idempotency-Key ที่ไม่ซ้ำกัน การขนส่งนี้จะถูกนับรวมในโควตารายเดือนของแพ็กเกจของคุณ
| พารามิเตอร์ | ประเภท | คำอธิบาย |
|---|---|---|
Idempotency-Key* | string (header) | ไม่ซ้ำกันต่อคำขอ การลองใหม่ด้วยค่าเดิมจะคืนการขนส่งเดิมแทนที่จะสร้างรายการซ้ำ |
tracking_number* | string | หมายเลข AWB / B-L / หมายเลขติดตาม |
carrier_code* | string | รหัสผู้ขนส่งหรือสายการบิน (รหัส PCS, รหัสสายการบิน IATA หรือ courier slug ของ AfterShip) |
mode* | string | โหมดการขนส่ง: sea, air หรือ courier |
curl -X POST https://api.staging.mglobalship.com/api/v1/external/shipments \
-H "Authorization: Bearer mgs_live_..." \
-H "Idempotency-Key: a1b2c3d4-e5f6-7890" \
-H "Content-Type: application/json" \
-d '{
"tracking_number": "160-12345675",
"carrier_code": "pcs",
"mode": "air"
}'{
"object": "shipment",
"id": 12346,
"tracking_number": "160-12345675",
"carrier_code": "pcs",
"mode": "air",
"status": "pending",
"awb_number": "160-12345675",
"_links": {
"self": "/api/v1/external/shipments/12346",
"tracking": "/api/v1/external/shipments/12346/tracking"
}
}/shipmentsแสดงรายการการขนส่งของคุณ โดยเรียงจากใหม่สุดก่อน พร้อมการแบ่งหน้าด้วยเคอร์เซอร์และตัวกรองเสริม
| พารามิเตอร์ | ประเภท | คำอธิบาย |
|---|---|---|
limit | integer | 1–100, ค่าเริ่มต้น 20 |
cursor | string | เคอร์เซอร์แบบทึบจากหน้าก่อนหน้า |
status | string | กรองตามสถานะการขนส่ง เช่น in_transit |
q | string | ค้นหาแบบเต็มข้อความในฟิลด์การขนส่ง |
mode | string | air, sea, rail หรือ road |
carrier_code | string | กรองตามผู้ขนส่ง เช่น maersk |
po | string | กรองตามเลขที่ใบสั่งซื้อ (purchase order) |
curl "https://api.staging.mglobalship.com/api/v1/external/shipments?status=in_transit&limit=20" \
-H "Authorization: Bearer mgs_live_..."{
"object": "list",
"data": [
{
"object": "shipment",
"id": 12345,
"tracking_number": "MAEU1234567",
"carrier_code": "maersk",
"mode": "sea",
"status": "in_transit",
"origin": { "country": "CN", "city": "Shanghai", "port_code": "CNSHA" },
"destination": { "country": "MY", "city": "Port Klang", "port_code": "MYPKG" },
"po_number": "PO-2026-001",
"estimated_arrival": "2026-04-30T14:00:00+08:00",
"_links": {
"self": "/api/v1/external/shipments/12345",
"tracking": "/api/v1/external/shipments/12345/tracking"
}
}
],
"has_more": false,
"next_cursor": null,
"_links": { "self": "/api/v1/external/shipments" }
}/shipments/{id}ดึงข้อมูลการขนส่งรายการเดียวพร้อมรายละเอียดสินค้าฉบับเต็มและประวัติเหตุการณ์สำคัญ (milestone)
| พารามิเตอร์ | ประเภท | คำอธิบาย |
|---|---|---|
id* | integer | รหัสการขนส่ง (พารามิเตอร์ในเส้นทาง) |
curl https://api.staging.mglobalship.com/api/v1/external/shipments/12345 \
-H "Authorization: Bearer mgs_live_..."{
"object": "shipment",
"id": 12345,
"tracking_number": "MAEU1234567",
"carrier_code": "maersk",
"mode": "sea",
"status": "in_transit",
"origin": { "country": "CN", "city": "Shanghai", "port_code": "CNSHA" },
"destination": { "country": "MY", "city": "Port Klang", "port_code": "MYPKG" },
"po_number": "PO-2026-001",
"container_no": "MAEU123456789",
"estimated_arrival": "2026-04-30T14:00:00+08:00",
"vessel_name": "MSC GULSUN",
"voyage_number": "2026W0105",
"cargo": {
"weight_kg": 18000.5,
"volume_cbm": 45.25,
"pieces": 120,
"description": "Electronics",
"hs_code": "8471.30",
"container_size": "40HQ",
"declared_value": { "amount": 499900, "currency": "USD" }
},
"milestones": [
{
"object": "milestone",
"status_code": "PICKED_UP",
"status_text": "Picked up",
"location": "Shanghai",
"occurred_at": "2026-04-22T08:15:00+08:00",
"source": "maersk_direct_api"
}
],
"_links": {
"self": "/api/v1/external/shipments/12345",
"tracking": "/api/v1/external/shipments/12345/tracking"
}
}/shipments/{id}/weatherรับสภาพอากาศปัจจุบัน/พยากรณ์ (Open-Meteo) ที่ต้นทางและปลายทางของการขนส่ง การเสริมข้อมูลแบบออนดีมานด์ แคชไว้ประมาณ 30 นาที ช่วงการเดินทาง (leg) จะเป็น null เมื่อไม่สามารถระบุตำแหน่งได้
| พารามิเตอร์ | ประเภท | คำอธิบาย |
|---|---|---|
id* | integer | รหัสการขนส่ง (พารามิเตอร์ในเส้นทาง) |
curl https://api.staging.mglobalship.com/api/v1/external/shipments/12345/weather \
-H "Authorization: Bearer mgs_live_..."{
"object": "weather",
"shipment_id": 12345,
"origin": {
"label": "Singapore, SG",
"lat": 1.29,
"lng": 103.85,
"observed_at": "2026-06-25T12:00:00+00:00",
"temperature_c": 29.4,
"wind_mps": 2.7,
"condition_id": 803,
"condition_main": "Clouds",
"severity": "low",
"summary": "Clouds",
"alerts_count": 0
},
"destination": {
"label": "New York, US",
"lat": 40.71,
"lng": -74.0,
"observed_at": "2026-06-25T12:00:00+00:00",
"temperature_c": 17.1,
"wind_mps": 0.5,
"condition_id": 803,
"condition_main": "Clouds",
"severity": "low",
"summary": "Clouds",
"alerts_count": 0
},
"_links": {
"self": "/api/v1/external/shipments/12345/weather",
"shipment": "/api/v1/external/shipments/12345"
}
}/shipments/{id}/riskรับเหตุการณ์ความขัดแย้ง/ความไม่สงบของพลเรือนใกล้ต้นทางและปลายทางของการขนส่ง (ภายในระยะ 100 km ในช่วง 7 days ที่ผ่านมา) การเสริมข้อมูลแบบออนดีมานด์พร้อมแคชผลลัพธ์จากผู้ให้บริการ
| พารามิเตอร์ | ประเภท | คำอธิบาย |
|---|---|---|
id* | integer | รหัสการขนส่ง (พารามิเตอร์ในเส้นทาง) |
curl https://api.staging.mglobalship.com/api/v1/external/shipments/12345/risk \
-H "Authorization: Bearer mgs_live_..."{
"object": "geopolitical_risk",
"shipment_id": 12345,
"origin": {
"label": "Singapore, SG",
"lat": 1.29,
"lng": 103.85,
"observed_at": "2026-06-25T12:00:00+00:00",
"severity": "high",
"radius_km": 100,
"since_days": 7,
"summary": "High: 1 violence_civilians event",
"events_count": 1,
"top_events": [
{
"occurred_on": "2026-06-21",
"type": "violence_civilians",
"sub_type": "Attack",
"location": "Singapore",
"fatalities": 0,
"distance_km": 12.0,
"description": "High: 1 violence_civilians event"
}
]
},
"destination": null,
"_links": {
"self": "/api/v1/external/shipments/12345/risk",
"shipment": "/api/v1/external/shipments/12345"
}
}/shipments/{id}/trackingรับไทม์ไลน์การติดตามแบบกระชับ (เหตุการณ์สำคัญที่เรียงลำดับ) ของการขนส่ง
| พารามิเตอร์ | ประเภท | คำอธิบาย |
|---|---|---|
id* | integer | รหัสการขนส่ง (พารามิเตอร์ในเส้นทาง) |
curl https://api.staging.mglobalship.com/api/v1/external/shipments/12345/tracking \
-H "Authorization: Bearer mgs_live_..."{
"object": "tracking",
"shipment_id": 12345,
"status": "in_transit",
"estimated_arrival": "2026-04-30T14:00:00+08:00",
"last_event_at": "2026-04-23T06:00:00+08:00",
"events": [
{
"object": "milestone",
"status_code": "PICKED_UP",
"status_text": "Picked up at origin",
"location": "Shanghai",
"occurred_at": "2026-04-22T08:15:00+08:00",
"source": "maersk_direct_api"
},
{
"object": "milestone",
"status_code": "DEPARTED_ORIGIN",
"status_text": "Departed origin port",
"location": "Shanghai",
"occurred_at": "2026-04-23T06:00:00+08:00",
"source": "maersk_direct_api"
}
],
"_links": {
"self": "/api/v1/external/shipments/12345/tracking",
"shipment": "/api/v1/external/shipments/12345"
}
}Webhook
แทนที่จะสำรวจ (polling) ให้สมัครรับ webhook เพื่อรับการแจ้งเตือนเมื่อมีบางสิ่งเกิดขึ้น เช่น เมื่อการขนส่งพบข้อยกเว้น (exception) คุณกำหนดค่า URL ของเอนด์พอยต์และเลือกประเภทเหตุการณ์ได้ใน API Portal จากนั้นเราจะส่ง POST เพย์โหลด JSON ไปยัง URL ของคุณสำหรับแต่ละเหตุการณ์
การส่งทุกครั้งจะมีการลงนามเพื่อให้คุณตรวจสอบได้ว่ามาจากเราจริง เราส่งลายเซ็นในส่วนหัว X-MGS-Signature ประเภทเหตุการณ์ใน X-MGS-Event และรหัสการส่งที่ไม่ซ้ำกันใน X-MGS-Delivery-Id (นำกลับมาใช้เพื่อให้ตัวจัดการของคุณเป็นแบบ idempotent) การส่งจะถูกลองใหม่ด้วยการถอยกลับแบบเอ็กซ์โพเนนเชียล (exponential backoff) ตลอด 24 ชั่วโมง
X-MGS-Signature มีรูปแบบ t=<timestamp>,v1=<signature> โดยที่ signature คือ HMAC-SHA256 แบบเลขฐานสิบหกของสตริง "<timestamp>.<raw-request-body>" ที่ใช้คีย์เป็นความลับของเอนด์พอยต์ของคุณ วิธีตรวจสอบ: แยก t และ v1 ออกมา คำนวณ HMAC ใหม่ครอบคลุม timestamp จุด (dot) ตามตัวอักษร และเนื้อหาดิบที่ถูกต้องแม่นยำ แล้วเปรียบเทียบ ปฏิเสธหากไม่ตรงกันหรือหาก timestamp เก่าเกินไป
X-MGS-Event: shipment.exception
X-MGS-Delivery-Id: whd_8f3c2a1b
X-MGS-Signature: t=1715241600,v1=4e2c...hex...sha256ข้อผิดพลาด
ข้อผิดพลาดใช้รหัสสถานะ HTTP มาตรฐานและซองหุ้ม JSON ที่สม่ำเสมอ ออบเจกต์ข้อผิดพลาดจะมีรหัส (code) ที่คงที่และข้อความที่อ่านเข้าใจได้เสมอ ข้อผิดพลาดบางอย่างจะเพิ่มฟิลด์บริบทเข้ามา ทุกการตอบกลับจะมี request_id ให้อ้างอิงรหัสนี้เมื่อติดต่อฝ่ายสนับสนุน
| สถานะ | รหัส | เมื่อใด |
|---|---|---|
| 400 | validation_error | เนื้อหาคำขอขาดหายหรือไม่ถูกต้อง (หรือไม่มีส่วนหัว Idempotency-Key) |
| 401 | auth.token_invalid | ไม่มีคีย์ API หรือคีย์ API ไม่ถูกต้อง |
| 402 | shipment.overage_payment_required | โควตาการขนส่งหมดแล้ว กรุณาชำระค่าส่วนเกินที่ค้างอยู่ก่อน |
| 403 | auth.insufficient_scope | คีย์ขาดขอบเขตที่จำเป็น เช่น shipments.read |
| 403 | auth.tenant_suspended | บัญชีผู้เช่า (tenant) ไม่อยู่ในสถานะใช้งาน |
| 404 | shipment.not_found | ไม่มีทรัพยากรที่ร้องขออยู่ |
| 409 | shipment.duplicate | มีการขนส่งที่ใช้หมายเลขติดตามและผู้ขนส่งนี้อยู่แล้ว |
| 429 | rate_limit_exceeded | ถึงขีดจำกัดอัตราแล้ว ดูที่ retry_after_seconds |
{
"error": {
"code": "auth.token_invalid",
"message": "Token invalid."
},
"request_id": "req_9a8b7c6d"
}{
"error": {
"code": "rate_limit_exceeded",
"message": "Rate limit exceeded for Silver tier (300 req/min). Wait 23s.",
"retry_after_seconds": 23
},
"request_id": "req_1f2e3d4c"
}