API Reference パートナー予約連携API

Hướng dẫn API (Liên kết đặt chỗ đối tác)

Xác thực

API GOVIGO dùng xác thực bằng API key. Hãy thêm header X-API-Key vào mọi yêu cầu.

Ví dụ header yêu cầu
GET /api/golf-clubs/plans.php?golf_club_id=1 HTTP/1.1
Host: govigolf.comX-API-Key: YOUR_API_KEY
API key được cấp từ trang quản trị. Mỗi key có các scope (quyền); hãy dùng key được cấp scope phù hợp với thao tác cần thiết. Đối tác đặt chỗ được cấp key loại partner.

Các scope khả dụng:

ScopeMô tả
golf_clubs:readXem thông tin sân golf / gói
tee_times:readXem tình trạng trống / lịch giá
reservations:readXem báo giá / thông tin đặt chỗ
reservations:writeTạo / sửa / hủy đặt chỗ
integration:read / integration:writeQuản lý Webhook và liên kết phía sân golf (mô tả sau)

Định dạng phản hồi chung

Tất cả phản hồi API được trả về theo định dạng chung sau.

{
  "success": true,
  "data": { ... },
  "message": "",
  "http_code": 200
}
TrườngKiểuMô tả
successbooleantrue khi thành công, false khi thất bại
dataobject|nullDữ liệu phản hồi (null khi lỗi)
messagestringThông điệp (nội dung lỗi khi có lỗi)
http_codeintegerMã trạng thái HTTP

Mã lỗi

Mã HTTPÝ nghĩaMô tả
400Bad RequestTham số yêu cầu không hợp lệ
401UnauthorizedAPI key không hợp lệ hoặc thiếu
403ForbiddenThiếu scope
404Not FoundTài nguyên không tồn tại (hoặc không có quyền)
405Method Not AllowedPhương thức HTTP không hợp lệ
409ConflictXung đột tài nguyên (đặt trùng, trạng thái không sửa được, v.v.)
429Too Many RequestsVượt giới hạn tần suất
500Internal Server ErrorLỗi nội bộ máy chủ

Tra cứu & phân quyền đặt chỗ

Có thể tham chiếu đặt chỗ bằng hai khóa.

KhóaMô tả
reservation_id / idID đặt chỗ nội bộ GOVIGO (số nguyên). Được trả về trong phản hồi.
external_refID tham chiếu đặt chỗ của hệ thống đối tác (chuỗi). Nếu truyền khi tạo, sau đó có thể tra cứu / sửa / hủy bằng ID của chính bạn. Khuyến nghị dùng.
Phân quyền (quan trọng): API key áp dụng phạm vi chủ sở hữu. Key đối tác chỉ tham chiếu / thao tác được trên các đặt chỗ do chính nó tạo. Chỉ định ID đặt chỗ của bên khác sẽ trả về 404 Not Found. Hãy giữ external_ref duy nhất trong cùng một đối tác (trùng sẽ trả về đặt chỗ hiện có).

Kiểm tra kết nối

GET /api/ping.php any

Kiểm tra tính hợp lệ của API key, chủ sở hữu, scope được cấp và giới hạn tần suất. Dùng để kiểm tra kết nối ban đầu (không cần scope).

Ví dụ phản hồi
{
  "success": true,
  "data": {
    "authenticated": true,
    "owner": { "type": "partner", "id": 3, "name": "Partner A" },
    "key_prefix": "a1b2c3d4",
    "scopes": ["golf_clubs:read", "tee_times:read", "reservations:read", "reservations:write"],
    "rate_limit": 120,
    "expires_at": null,
    "server_time": "2026-06-01T10:00:00+07:00"
  },
  "message": "pong",
  "http_code": 200
}

Thông tin sân golf & gói

GET /api/golf-clubs/detail.php golf_clubs:read

Lấy thông tin chi tiết sân golf. Bỏ qua id để trả về danh sách.

Tham sốKiểuBắt buộcMô tả
idintegerTùy chọnID sân golf
countryintegerTùy chọnMã quốc gia (0=Việt Nam, 1=Thái Lan, 2=Nhật Bản)
Ví dụ phản hồi
{
  "success": true,
  "data": {
    "count": 1,
    "golf_clubs": [
      {
        "id": 1,
        "name": "Sample Golf Club",
        "area": "Hanoi",
        "country": 0,
        "address": "123 Golf Street",
        "google_map": "https://maps.google.com/...",
        "course_info": "18 lỗ, par 72",
        "cancel_policy": "Miễn phí đến 3 ngày trước",
        "cancel_policy_govigo": "..."
      }
    ]
  },
  "message": "",
  "http_code": 200
}
GET /api/golf-clubs/plans.php golf_clubs:read

Lấy danh sách gói của sân golf. id lấy ở đây chính là golf_plan_id (bắt buộc) khi đặt chỗ.

Tham sốKiểuBắt buộcMô tả
golf_club_idintegerBắt buộcID sân golf
datestringTùy chọnChỉ các gói hiệu lực vào ngày chỉ định (YYYY-MM-DD)
Ví dụ phản hồi
{
  "success": true,
  "data": {
    "golf_club_id": 1,
    "count": 1,
    "plans": [
      {
        "id": 10,
        "source": "golf_plan",
        "name": "Gói ngày thường",
        "day_type": "weekday",
        "price_local": 1500000,
        "price_inbound": 2000000,
        "partner_price_local": 1450000,
        "partner_price_inbound": 1850000,
        "apply_period": { "from": "2026-01-01", "to": "2026-12-31" },
        "time_range": "06:00-10:00",
        "minimum_players": 1,
        "summary": "Gói ưu đãi chỉ ngày thường",
        "rental_club_fee": 300000,
        "rental_shoes_fee": 100000
      }
    ]
  },
  "message": "",
  "http_code": 200
}
price_local là giá nội địa, price_inbound là giá inbound (khách thăm). Khi đặt / báo giá, giá tương ứng được áp dụng theo số người chơi từng loại (local / inbound, có thể trộn lẫn trong cùng một đặt chỗ). Đặt / báo giá được xác định theo partner_price_local / partner_price_inbound (giá đối tác). Chỉ các gói có bookable: true (source: golf_plan) mới đặt được.
GET /api/golf-clubs/cancel-policy.php golf_clubs:read

Lấy chính sách hủy của sân golf.

Tham sốKiểuBắt buộcMô tả
golf_club_idintegerBắt buộcID sân golf
Ví dụ phản hồi
{
  "success": true,
  "data": {
    "golf_club_id": 1,
    "cancel_policy": "Hủy miễn phí đến 3 ngày trước",
    "cancel_policy_govigo": "Đặt chỗ qua GOVIGO...",
    "rules": [
      { "days_before": 3, "cancel_fee_rate": 0 },
      { "days_before": 1, "cancel_fee_rate": 50 },
      { "days_before": 0, "cancel_fee_rate": 100 }
    ]
  },
  "message": "",
  "http_code": 200
}

Tình trạng trống

GET /api/tee-times/available.php tee_times:read

Lấy các khung giờ tee trống cho ngày chỉ định. Nếu dùng khung giờ tee, truyền tee_time_slot_id khi đặt (tùy chọn).

Tham sốKiểuBắt buộcMô tả
golf_club_idintegerBắt buộcID sân golf
datestringBắt buộcNgày (YYYY-MM-DD)
Ví dụ phản hồi
{
  "success": true,
  "data": {
    "golf_club_id": 1,
    "date": "2026-03-15",
    "is_closed": false,
    "count": 1,
    "slots": [
      {
        "slot_id": 101,
        "tee_date": "2026-03-15",
        "tee_time": "07:00",
        "total_slots": 4,
        "available_slots": 2,
        "allow_join": true,
        "plan": { "id": 10, "name": "Gói ngày thường", "price": 1500000 }
      }
    ]
  },
  "message": "",
  "http_code": 200
}
GET /api/tee-times/min-prices.php tee_times:read

Lấy giá tối thiểu theo ngày trong tháng chỉ định (để hiển thị lịch).

Tham sốKiểuBắt buộcMô tả
golf_club_idintegerBắt buộcID sân golf
yearintegerTùy chọnNăm (mặc định: năm nay)
monthintegerTùy chọnTháng (mặc định: tháng này)
Ví dụ phản hồi
{
  "success": true,
  "data": {
    "golf_club_id": 1,
    "year": 2026,
    "month": 3,
    "prices": {
      "2026-03-01": 1500000,
      "2026-03-02": 1800000
    }
  },
  "message": "",
  "http_code": 200
}

Báo giá

GET /api/reservations/quote.php reservations:read

Lấy số tiền cuối cùng trước khi tạo đặt chỗ. API create tính lại bằng cùng logic nên khớp với báo giá này. Số tiền trả về là giá đối tác (giá thường trừ chiết khấu đối tác).

Tham sốKiểuBắt buộcMô tả
golf_club_idintegerBắt buộcID sân golf
golf_plan_idintegerBắt buộcID gói (id từ plans)
local_playersintegerBắt buộc*Số người chơi theo giá nội địa
inbound_playersintegerBắt buộc*Số người chơi theo giá inbound (* phải có ít nhất một trong hai. Tổng 1-20. Có thể trộn lẫn)
datestringTùy chọnNgày chơi (YYYY-MM-DD). Nếu có, kiểm tra cả thời hạn áp dụng / ngày trong tuần của gói
rental_clubintegerTùy chọnSố bộ gậy thuê
rental_shoesintegerTùy chọnSố đôi giày thuê
Ví dụ phản hồi
{
  "success": true,
  "data": {
    "plan_id": 10,
    "plan_name": "Gói ngày thường",
    "players": {
      "local":   { "count": 2, "regular_unit_price": 1500000, "discount_per_player": 50000, "unit_price": 1450000, "amount": 2900000 },
      "inbound": { "count": 2, "regular_unit_price": 2000000, "discount_per_player": 150000, "unit_price": 1850000, "amount": 3700000 }
    },
    "player_count": 4,
    "minimum_players": 1,
    "base_amount": 6600000,
    "rental": {
      "club_count": 2, "club_fee": 600000,
      "shoes_count": 0, "shoes_fee": 0,
      "subtotal": 600000
    },
    "currency": "VND",
    "total_amount": 7200000,
    "golf_club_id": 1
  },
  "message": "Quote calculated.",
  "http_code": 200
}

Đặt chỗ

POST /api/reservations/create.php reservations:write

Tạo đặt chỗ mới. Thân yêu cầu là JSON. Số tiền (total_amount) được tính lại ở máy chủ từ golf_plan_id, nên không cần chỉ định trong yêu cầu.

Tham sốKiểuBắt buộcMô tả
golf_club_idintegerBắt buộcID sân golf
golf_plan_idintegerBắt buộcID gói (id từ plans)
tee_datestringBắt buộcNgày chơi(YYYY-MM-DD)
customer_namestringBắt buộcTên người đặt
customer_emailstringBắt buộcEmail người đặt
customer_phonestringBắt buộcSĐT người đặt
playersobjectBắt buộcSố người chơi theo loại giá {local?, inbound?} (có thể trộn lẫn; tổng 1-20)
tee_timestringTùy chọnGiờ tee mong muốn (HH:MM). Chỉ đặt thường. Mặc định 08:00
tee_time_slot_idintegerTùy chọnNếu chỉ định, xác nhận tức thì theo khung real-time và phản ánh lên bảng giờ tee của sân golf (lấy qua available). Ngày của khung phải khớp với tee_date. Nếu bỏ qua, là đặt thường (yêu cầu)
optionsobjectTùy chọnThuê v.v. {rental_club, rental_shoes}
remarkstringTùy chọnGhi chú
attendeesarrayTùy chọnDanh sách người đi cùng ({name, email?, phone?})
external_refstringTùy chọnID tham chiếu đặt chỗ của đối tác (khuyến nghị, duy nhất)
Ví dụ yêu cầu
POST /api/reservations/create.php HTTP/1.1
Host: govigolf.comX-API-Key: YOUR_API_KEY
Content-Type: application/json

{
  "golf_club_id": 1,
  "golf_plan_id": 10,
  "tee_date": "2026-03-15",
  "customer_name": "Taro Tanaka",
  "customer_email": "tanaka@example.com",
  "customer_phone": "090-1234-5678",
  "players": { "local": 2, "inbound": 2 },
  "options": { "rental_club": 2 },
  "external_ref": "EXT-2026-00500"
}
Ví dụ phản hồi (201 Created)
{
  "success": true,
  "data": {
    "reservation_id": 500,
    "status": 1,
    "golf_club_id": 1,
    "tee_date": "2026-03-15",
    "tee_time": "08:00",
    "player_count": 4,
    "players": { "local": 2, "inbound": 2 },
    "total_amount": 7200000,
    "source": "api_partner"
  },
  "message": "Reservation created successfully.",
  "http_code": 201
}
GET /api/reservations/list.php reservations:read

Lấy danh sách đặt chỗ (chỉ đặt chỗ do bạn tạo). Hỗ trợ phân trang.

Tham sốKiểuBắt buộcMô tả
golf_club_idintegerTùy chọnLọc theo ID sân golf
statusintegerTùy chọnMã trạng thái (1=đã yêu cầu, 2=sân đang xác nhận, 3=yêu cầu thanh toán, 4=đã thanh toán/xác nhận, 5=đang đổi lịch, 6=yêu cầu hủy, 7=đang hủy(không hoàn), 8=đang hủy(có hoàn), 9=hoàn tất, 10=hoàn tất(đã hủy))
date_fromstringTùy chọnNgày chơi bắt đầu (YYYY-MM-DD)
date_tostringTùy chọnNgày chơi kết thúc (YYYY-MM-DD)
pageintegerTùy chọnSố trang (mặc định: 1)
per_pageintegerTùy chọnSố mục mỗi trang (mặc định: 20, tối đa: 100)
sortstringTùy chọnTrường sắp xếp (tee_date / created)
orderstringTùy chọnThứ tự sắp xếp (asc / desc)
Ví dụ phản hồi
{
  "success": true,
  "data": {
    "reservations": [
      {
        "id": 500,
        "golf_club_id": 1,
        "golf_club_name": "Sample Golf Club",
        "customer_name": "Taro Tanaka",
        "tee_date": "2026-03-15",
        "tee_time": "08:00",
        "player_count": 4,
        "players": { "local": 2, "inbound": 2 },
        "total_amount": 7200000,
        "status": "1.đã yêu cầu",
        "status_code": 1,
        "source": "api_partner",
        "external_ref": "EXT-2026-00500",
        "created_at": "2026-03-01 10:00:00"
      }
    ],
    "pagination": {
      "page": 1, "per_page": 20, "total_count": 1,
      "total_pages": 1, "has_next": false, "has_prev": false
    }
  },
  "message": "",
  "http_code": 200
}
GET /api/reservations/detail.php reservations:read

Lấy chi tiết đặt chỗ. Chỉ định id hoặc external_ref.

Tham sốKiểuBắt buộcMô tả
idintegermột trongID đặt chỗ GOVIGO
external_refstringmột trongID tham chiếu đối tác
Ví dụ phản hồi
{
  "success": true,
  "data": {
    "reservation": {
      "id": 500,
      "golf_club_id": 1,
      "golf_club_name": "Sample Golf Club",
      "plan_id": 10,
      "plan_name": "Gói ngày thường",
      "customer_name": "Taro Tanaka",
      "customer_email": "tanaka@example.com",
      "customer_phone": "090-1234-5678",
      "tee_date": "2026-03-15",
      "tee_time": "08:00",
      "player_count": 4,
      "players": { "local": 2, "inbound": 2 },
      "total_amount": 7200000,
      "remark": null,
      "options": { "rental_club": 2, "rental_shoes": 0 },
      "status": "1.đã yêu cầu",
      "status_code": 1,
      "source": "api_partner",
      "external_ref": "EXT-2026-00500",
      "created_at": "2026-03-01 10:00:00",
      "updated_at": "2026-03-01 10:00:00",
      "attendees": [
        { "name": "Hanako Sato", "email": null, "phone": null }
      ]
    }
  },
  "message": "",
  "http_code": 200
}
POST /api/reservations/update.php reservations:write

Cập nhật đặt chỗ. Chỉ cập nhật các trường được chỉ định. Nếu players / options thay đổi, total_amount được tính lại ở máy chủ. players được hiểu giống như khi tạo đặt chỗ: các loại bị bỏ qua được coi là 0 người (luôn chỉ định số người cho tất cả các loại). Với đặt real-time, thay đổi tổng số người cũng điều chỉnh tồn kho phía sân golf. Đặt chỗ đã hủy (status=6-8) / hoàn tất (status=9,10) không thể sửa.

Tham sốKiểuBắt buộcMô tả
reservation_id / external_refinteger/stringBắt buộc (một trong)Khóa tham chiếu của đặt chỗ mục tiêu
playersobjectTùy chọnSố người chơi theo loại giá {local?, inbound?} (tính lại tổng tiền; các loại bị bỏ qua được coi là 0)
optionsobjectTùy chọnThuê v.v. (tính lại tiền khi đổi)
customer_name / customer_email / customer_phonestringTùy chọnThông tin người đặt
tee_datestringTùy chọnNgày chơi(YYYY-MM-DD). Đặt real-time (có tee_time_slot_id) không thể thay đổi (hãy hủy rồi tạo lại)
remarkstringTùy chọnGhi chú
attendeesarrayTùy chọnNgười đi cùng (thay toàn bộ nếu chỉ định)
Ví dụ yêu cầu
POST /api/reservations/update.php HTTP/1.1
Host: govigolf.comX-API-Key: YOUR_API_KEY
Content-Type: application/json

{
  "external_ref": "EXT-2026-00500",
  "players": { "local": 2, "inbound": 1 },
  "remark": "Hủy 1 người"
}
Ví dụ phản hồi
{
  "success": true,
  "data": {
    "reservation_id": 500,
    "golf_club_id": 1,
    "plan_id": 10,
    "player_count": 3,
    "players": { "local": 2, "inbound": 1 },
    "total_amount": 5350000,
    "status": "1.đã yêu cầu",
    "status_code": 1,
    "external_ref": "EXT-2026-00500",
    "updated_at": "2026-03-02 09:00:00"
  },
  "message": "Reservation updated.",
  "http_code": 200
}
POST /api/reservations/cancel.php reservations:write

Hủy đặt chỗ. Chỉ định reservation_id hoặc external_ref. Giống đặt chỗ hội viên, được tiếp nhận như yêu cầu hủy (status=6) và nhân viên xác nhận. Đặt real-time tự khôi phục tồn kho phía sân golf. Đặt chỗ đang hủy (status=6-8) / hoàn tất (status=9,10) không thể hủy.

Tham sốKiểuBắt buộcMô tả
reservation_id / external_refinteger/stringBắt buộc (một trong)Khóa tham chiếu của đặt chỗ mục tiêu
reasonstringTùy chọnLý do hủy
Ví dụ yêu cầu
POST /api/reservations/cancel.php HTTP/1.1
Host: govigolf.comX-API-Key: YOUR_API_KEY
Content-Type: application/json

{
  "external_ref": "EXT-2026-00500",
  "reason": "Do thay đổi lịch"
}
Ví dụ phản hồi
{
  "success": true,
  "data": {
    "reservation_id": 500,
    "status": "cancel_requested",
    "status_code": 6,
    "cancelled_at": "2026-03-02T10:00:00+07:00"
  },
  "message": "Reservation cancelled successfully.",
  "http_code": 200
}

Webhook

Cơ chế thông báo cho hệ thống của bạn về thay đổi trạng thái đặt chỗ. Thông báo gửi qua HTTPS POST khi có sự kiện.

Sự kiện khả dụng:
reservation.created / reservation.updated / reservation.cancelled / reservation.status_changed / *(tất cả sự kiện)
POST /api/integration/webhooks/subscribe.php integration:write

Đăng ký URL nhận Webhook.

Tham sốKiểuBắt buộcMô tả
golf_club_idintegerBắt buộcID sân golf
urlstringBắt buộcURL nhận Webhook (bắt buộc HTTPS)
eventsarrayBắt buộcLoại sự kiện đăng ký
Ví dụ yêu cầu
POST /api/integration/webhooks/subscribe.php HTTP/1.1
Host: govigolf.comX-API-Key: YOUR_API_KEY
Content-Type: application/json

{
  "golf_club_id": 1,
  "url": "https://your-system.com/webhook/govigo",
  "events": ["reservation.created", "reservation.updated", "reservation.cancelled"]
}
Ví dụ phản hồi (201 Created)
{
  "success": true,
  "data": {
    "subscription_id": 10,
    "golf_club_id": 1,
    "url": "https://your-system.com/webhook/govigo",
    "events": ["reservation.created", "reservation.updated", "reservation.cancelled"],
    "secret": "a1b2c3d4e5f6..."
  },
  "message": "",
  "http_code": 201
}
secret dùng để xác minh HMAC của payload Webhook. Hãy xác minh chữ ký khi nhận để xác nhận tính hợp lệ.
GET /api/integration/webhooks/list.php integration:read

Lấy danh sách Webhook đã đăng ký.

Tham sốKiểuBắt buộcMô tả
golf_club_idintegerBắt buộcID sân golf
Ví dụ phản hồi
{
  "success": true,
  "data": {
    "golf_club_id": 1,
    "count": 1,
    "subscriptions": [
      {
        "id": 10,
        "golf_club_id": 1,
        "url": "https://your-system.com/webhook/govigo",
        "events": ["reservation.created", "reservation.cancelled"],
        "is_active": true,
        "created_at": "2026-03-01 10:00:00",
        "updated_at": "2026-03-01 10:00:00"
      }
    ]
  },
  "message": "",
  "http_code": 200
}
POST /api/integration/webhooks/unsubscribe.php integration:write

Hủy đăng ký một Webhook đã đăng ký.

Tham sốKiểuBắt buộcMô tả
subscription_idintegerBắt buộcID đăng ký cần hủy
Ví dụ yêu cầu
POST /api/integration/webhooks/unsubscribe.php HTTP/1.1
Host: govigolf.comX-API-Key: YOUR_API_KEY
Content-Type: application/json

{ "subscription_id": 10 }
POST /api/integration/webhooks/test.php integration:write

Gửi thông báo thử đến Webhook đã đăng ký để kiểm tra kết nối URL và xác minh chữ ký.

Tham sốKiểuBắt buộcMô tả
subscription_idintegerBắt buộcID đăng ký cần thử
Ví dụ yêu cầu
POST /api/integration/webhooks/test.php HTTP/1.1
Host: govigolf.comX-API-Key: YOUR_API_KEY
Content-Type: application/json

{ "subscription_id": 10 }