Developer Documentation
Connect travel websites to EasyTourAgent
คู่มือสำหรับทำเว็บทัวร์แบบ white-label: ดึงรายการทัวร์จริง, เปิดหน้ารายละเอียด, โหลดรอบเดินทาง, สร้าง booking และเตรียม webhook สำหรับเชื่อมระบบลูกค้า.
Endpoint Index
Frontend-safe tour list for iframe or custom search UI
Widget token
Server-side tour catalog with tenant visibility applied
catalog:read
Tour detail by UUID or slug
catalog:read
Departure dates, seats, prices, and tenant prices
catalog:read
Edge availability with Redis cache and API-key rate limit
catalog:read
No-cache seat hold with Postgres row locking
booking:create
Create booking lead and reserve seats when a departure is selected
booking:create
01 / Overview
ETA API คืออะไร
ETA API ใช้สำหรับให้เว็บไซต์ลูกค้าดึง catalog ทัวร์จากระบบ EasyTourAgent และสร้าง booking กลับเข้าระบบกลางได้ โดยแยก tenant, visibility, ราคา และสิทธิ์การใช้งานตาม key ของแต่ละเจ้า.
Widget
ฝัง iframe หรือเรียก API ที่ปลอดภัยสำหรับหน้าเว็บด้วย jt_widget token.
Server API
ใช้ jt_live key จาก server ของลูกค้าเท่านั้น ห้ามฝังใน browser.
Tenant-aware
ทุก endpoint ถูกกรองด้วย tenant visibility ก่อนส่งข้อมูลออก.
02 / Quick Start
เชื่อมต่อแบบเร็วที่สุด
- สร้าง tenant ในหน้า admin และตั้งสถานะเป็น trial หรือ active.
- ออก Widget token สำหรับเว็บที่ต้องการฝังหน้าค้นหาทัวร์.
- ออก Server API key พร้อม scope ที่ต้องใช้ เช่น
catalog:readและbooking:create. - ทดสอบดึง catalog, tour detail, departures และสร้าง booking ตัวอย่าง.
- ล็อก allowed origins, ตรวจราคา/รอบเดินทาง และตั้ง monitoring ก่อนเปิดจริง.
curl "https://easytouragent.com/api/tenant/catalog?limit=5&continent=asia" \
-H "Authorization: Bearer jt_live_xxx"03 / Authentication
Key, token และ scope
API key
ขึ้นต้นด้วย jt_live ใช้กับ server-to-server เท่านั้น และตรวจ scope ทุก request.
Widget token
ขึ้นต้นด้วย jt_widget ใช้กับ iframe หรือ widget API และผูก allowed origin ได้.
| Field | Type | Description |
|---|---|---|
| Authorization | header | Bearer jt_live_xxx สำหรับ server API |
| api_key | query | ใช้สำรองได้ แต่แนะนำ header เพราะไม่หลุดใน log ง่าย |
| token | query | Widget token สำหรับ /api/widget/tours และ /embed/tours |
| x-jongtour-widget-token | header | legacy widget header ที่ระบบยังรองรับอยู่ |
04 / Widget API
ฝังหน้าทัวร์หรือสร้างกล่องค้นหาเอง
ถ้าลูกค้ายังไม่มีทีม dev ให้เริ่มจาก iframe ก่อน เพราะใช้งานเร็วและปลอดภัยกว่า. ถ้าต้องการ UI ของตัวเอง ให้เรียก widget API ด้วย token ที่ล็อก origin แล้ว.
<iframe
src="https://easytouragent.com/embed/tours?token=jt_widget_xxx"
width="100%"
height="720"
style="border:0"
></iframe>GET https://easytouragent.com/api/widget/tours?token=jt_widget_xxx&limit=12&continent=asia&q=japan| Field | Type | Description |
|---|---|---|
| limit | 1-30 | จำนวนรายการที่ต้องการ ค่าเริ่มต้น 12 |
| continent | string | กรองทวีป เช่น asia, europe |
| q | string | ค้นหาจากชื่อทัวร์ |
05 / Catalog API
Catalog, detail และ departures
Server API เหมาะกับเว็บลูกค้าที่มี frontend/SEO ของตัวเอง และต้องการควบคุมหน้ารายละเอียดเองทั้งหมด.
curl "https://easytouragent.com/api/tenant/catalog?limit=24&continent=europe" \
-H "Authorization: Bearer jt_live_xxx"curl "https://easytouragent.com/api/tenant/tours/japan-autumn-5d" \
-H "Authorization: Bearer jt_live_xxx"
curl "https://easytouragent.com/api/tenant/tours/japan-autumn-5d/departures" \
-H "Authorization: Bearer jt_live_xxx"| Field | Type | Description |
|---|---|---|
| limit | 1-100 | จำนวน catalog ต่อหน้า ค่าเริ่มต้น 24 |
| continent | string | กรองทวีป |
| id | UUID | slug | ใช้ได้ทั้ง tour UUID และ slug |
| tenant_prices | object | ราคาที่คำนวณตาม tenant pricing layer |
06 / Tour API Gateway
เช็กที่นั่งเร็วและ Hold แบบกัน Overbooking
ใช้ gateway endpoint สำหรับเว็บลูกข่ายที่ยิงเช็กที่นั่งถี่ ๆ หลายเว็บไซต์พร้อมกัน. Availability รันบน Edge พร้อม SWR 60 วินาทีและ Redis cache; Hold เป็น no-cache และเรียก RPC ที่ล็อกแถว departure ด้วย SELECT ... FOR UPDATE.
curl "https://easytouragent.com/api/gateway/tours/japan-autumn-5d/availability?departure_date=2026-10-12" \
-H "Authorization: Bearer jt_live_xxx"curl -X POST "https://easytouragent.com/api/gateway/tours/japan-autumn-5d/hold" \
-H "Authorization: Bearer jt_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"departure_date": "2026-10-12",
"quantity": 2,
"hold_minutes": 10,
"external_ref": "WEB-ORDER-1001",
"customer": {
"name": "Somchai Demo",
"phone": "0812345678",
"email": "somchai@example.com"
}
}'| Field | Type | Description |
|---|---|---|
| UPSTASH_REDIS_REST_URL | env | เปิด distributed cache และ rate limit ข้าม instance |
| UPSTASH_REDIS_REST_TOKEN | env | token ของ Upstash Redis REST API |
| GATEWAY_AVAILABILITY_RPM | env | quota เช็กที่นั่งต่อนาทีต่อ API key ค่าเริ่มต้น 240 |
| GATEWAY_HOLD_RPM | env | quota hold ที่นั่งต่อนาทีต่อ API key ค่าเริ่มต้น 60 |
07 / Booking API
สร้าง booking จากเว็บลูกค้า
Booking API จะตรวจ tour visibility, ตรวจ departure ถ้าระบุวันที่, คำนวณราคา tenant และสร้าง lead สถานะ pending payment.
curl -X POST "https://easytouragent.com/api/tenant/bookings" \
-H "Authorization: Bearer jt_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"tour_id": "japan-autumn-5d",
"departure_date": "2026-10-12",
"name": "Somchai Demo",
"phone": "0812345678",
"email": "somchai@example.com",
"adults": 2,
"payment_method": "reserve",
"external_ref": "WEB-ORDER-1001"
}'| Field | Type | Description |
|---|---|---|
| tour_id | required | UUID หรือ slug ของทัวร์ |
| departure_date | optional | YYYY-MM-DD ถ้าระบุ ระบบจะพยายาม reserve seat |
| name | required | ชื่อลูกค้า |
| phone | required | เบอร์โทร ระบบ normalize เบื้องต้น |
| required | อีเมลลูกค้า | |
| adults | optional | ค่าเริ่มต้น 1 |
| payment_method | bank | reserve | stripe | ช่องทางชำระเงินของ tenant |
| external_ref | optional | เลขอ้างอิงจากเว็บลูกค้า |
{
"ok": true,
"booking_ref": "JT-12345",
"lead_id": 12345,
"tenant": { "id": "uuid", "slug": "happy-tour" },
"total_price": 59800,
"deposit_total": 20000,
"status": "pending_payment"
}07 / Webhooks
สถานะ webhook ตอนนี้
ระบบสร้าง pending delivery สำหรับ event booking.created แล้ว แต่ก่อนใช้กับลูกค้า production ขนาดใหญ่ ต้องทำ worker ส่ง webhook จริง, signing secret, retry policy และหน้า monitor delivery ให้ครบ.
{
"event_type": "booking.created",
"booking_ref": "JT-12345",
"lead_id": 12345,
"source": "tenant_api",
"external_ref": "WEB-ORDER-1001",
"customer": {
"name": "Somchai Demo",
"phone": "0812345678",
"email": "somchai@example.com"
},
"departure_date": "2026-10-12",
"total_price": 59800
}08 / Errors
Error codes ที่ต้องรองรับ
401 Unauthorized
API key ผิด, หมดอายุ, inactive หรือไม่มี scope ที่ต้องใช้
404 Tour not found
tour ไม่อยู่ใน tenant visibility หรือ slug/id ไม่ถูกต้อง
409 Departure not available
รอบเดินทางไม่มีแล้ว ยกเลิกแล้ว หรือที่นั่งไม่พอ
500 Server error
ฐานข้อมูลหรือ upstream service มีปัญหา ควร retry แบบ exponential backoff
09 / Production Checklist
Checklist ก่อนส่งให้ลูกค้าเชื่อม API
Tenant active
tenant status เป็น trial หรือ active
Catalog ready
มี tour visible และ quality audit ไม่มี critical
API key scoped
ออก key แยกตามเว็บและให้ scope เท่าที่จำเป็น
Widget origin locked
allowed origins เป็น domain จริง ไม่ใช้ *
Pricing verified
สุ่มตรวจราคาและรอบเดินทางกับ supplier อย่างน้อย 5 รายการ
Booking tested
ทดสอบ create booking, reserve seat, และกรณี seat ไม่พอ
Webhook configured
ตั้ง endpoint, signature, retry และ monitor
Rate limit plan
กำหนด quota ตามแพ็กเกจและแจ้งเตือนเมื่อใช้สูงผิดปกติ
Ready for integration
ขั้นต่อไปคือออก key จริงและทดสอบ staging กับเว็บลูกค้า
ห้ามส่ง jt_live key ไปใน browser หรือแอปมือถือโดยตรง. ถ้าต้องแสดง catalog ฝั่ง browser ให้ใช้ widget token หรือทำ proxy ผ่าน server ของลูกค้าเท่านั้น.
Plug-in model
เริ่มจาก widget ได้ก่อน แล้วค่อยย้ายเป็น API-first เมื่อเว็บลูกค้าพร้อม.
Security first
แยก key ต่อ tenant, แยก scope และล็อก origin เพื่อกันข้อมูลรั่ว.
Full guide
ไฟล์ docs/eta-api-integration-guide.md ใช้ส่งให้ทีม dev หรือแนบใน proposal ได้.