API Reference

Golf Club API Guide (Integration & Management)

Overview

The Golf Club API consists of two systems with different purposes. It is separate from the Partner Reservation API (for members).

SystemPathAuthPurpose
Integration/api/integration/*API key (integration scope)Bidirectional sync with external booking/inventory systems (tee time inventory / reservations / Webhook). Inventory consolidated under tee-times/* (sync/pull/reconcile). 1 key = 1 golf club.
Management/api/manage/*API key (per-resource scopes)Golf club operations (reservations, tee time slots, notifications, settings, reports). golf_club_id is determined from the key (owner_id).
All responses are JSON (except CSV export). Dates are YYYY-MM-DD / HH:MM unless noted. Amounts are VND (integer).

Authentication

Integration/api/integration/*

API key authentication. Include the X-API-Key header in every request. Keys are issued by administrators; an integration-type key is bound to one golf club per key (owner_id). The target golf club is determined from the key — do not include golf_club_id in the request (no access to other clubs' data is possible).

Request header example
POST /api/integration/tee-times/sync.php HTTP/1.1
Host: en.govigolf.com
X-API-Key: YOUR_API_KEY
Content-Type: application/json

Scopes: integration:read for read operations, integration:write for write operations.

Management/api/manage/*

API key authentication (X-API-Key header, owner_type='golf_club' key). Handled by GolfClubAuthService. The target golf club is determined from the key (owner_id) — no need to pass golf_club_id as a parameter.

Request header example
GET /api/manage/reservations/list.php HTTP/1.1
Host: en.govigolf.com
X-API-Key: YOUR_API_KEY

Scopes (per resource): reservations:read/write / tee_times:read/write / notifications:read/write / settings:read/write / reports:read.

Common response format

All responses (except CSV export) are returned in the following JSON envelope.

Success
{
  "status": "success",
  "message": "...",
  "data": { ... }
}
Error
{
  "status": "error",
  "message": "Error description",
  "data": null
}

Error codes

HTTPMeaning
400Bad request (missing required parameter, invalid JSON, etc.)
401Authentication failure (invalid API key / not logged in / token expired)
403Insufficient permission (missing scope / no access to target golf club)
404Target resource does not exist
405HTTP method not allowed
429Rate limit exceeded
500Internal server error
Integration API

Integration: Tee times

POST/api/integration/tee-times/sync.phpintegration:write

Syncs tee time slots from an external system into GOVIGO (external → GOVIGO). Maximum 500 slots per request.

ParameterTypeRequiredDescription
slotsarrayRequiredArray of slot objects (max 500)
slots element fields
FieldTypeRequiredDescription
course_idintegerRequiredCourse ID (must belong to your golf club)
tee_timestringRequiredTee time (YYYY-MM-DD HH:MM)
total_slotsintegerOptionalTotal slots (default: 4)
available_slotsintegerOptionalAvailable slots (default: same as total_slots)
statusstringOptionalopen / closed / maintenance (default: open)
plan_idintegerOptionalAssociated plan ID (must belong to your golf club)
Request example
POST /api/integration/tee-times/sync.php HTTP/1.1
Host: en.govigolf.com
X-API-Key: YOUR_API_KEY
Content-Type: application/json

{
  "slots": [
    { "course_id": 10, "tee_time": "2026-07-01 07:30", "total_slots": 4, "available_slots": 4 }
  ]
}
Response data fields
FieldTypeDescription
inserted_countintegerNumber of newly created slots
updated_countintegerNumber of updated slots
error_countintegerNumber of failed items
errorsarrayArray of error detail messages
GET/api/integration/tee-times/pull.phpintegration:read

Retrieves GOVIGO tee times (GOVIGO → external).

ParameterTypeRequiredDescription
date_fromstringRequiredStart date (YYYY-MM-DD)
date_tostringRequiredEnd date (YYYY-MM-DD)
course_idintegerOptionalFilter by course
Request example
GET /api/integration/tee-times/pull.php?date_from=2026-07-01&date_to=2026-07-07 HTTP/1.1
Host: en.govigolf.com
X-API-Key: YOUR_API_KEY
Response data fields
FieldTypeDescription
golf_club_idintegerGolf club ID
date_from / date_tostringRequested date range
countintegerNumber of slots returned
slotsarrayArray of slot objects (see below)
slots element fields
FieldTypeDescription
slot_idintegerSlot ID (GOVIGO internal ID)
course_idintegerCourse ID
course_namestringCourse name
tee_timestringTee time (YYYY-MM-DD HH:MM)
total_slotsintegerTotal slots
available_slotsintegerAvailable slots
statusstringopen / closed / maintenance
allow_joinbooleanJoin (shared booking) allowed
plan_idinteger|nullAssociated plan ID
POST/api/integration/tee-times/reconcile.phpintegration:write

Reconciles the GOVIGO mirror against a full snapshot of slots for the given period from the club side (for fixing drift caused by missed webhooks, etc.). All slots are upserted and slots absent from the snapshot are swept up. Slots with no bookings are logically closed (status=closed — not physically deleted); slots that had bookings but disappeared from the snapshot are returned as conflicts (for manual resolution) rather than being closed. Closed slots are hidden from customer availability views and revert to open automatically when the club resubmits them. Intended to be run periodically by the club (e.g. nightly).

ParameterTypeRequiredDescription
date_from / date_tostringRequiredReconciliation period (YYYY-MM-DD)
course_idintegerOptionalIf specified, reconcile only that course
slotsarrayRequiredAll slots in the period (max 2000; split into narrower periods if needed). Same fields as sync (see above)
Request example
POST /api/integration/tee-times/reconcile.php HTTP/1.1
Host: en.govigolf.com
X-API-Key: YOUR_API_KEY
Content-Type: application/json

{
  "date_from": "2026-07-01",
  "date_to": "2026-07-01",
  "slots": [
    { "course_id": 10, "tee_time": "2026-07-01 07:30", "total_slots": 4, "available_slots": 4 }
  ]
}
Response data fields
FieldTypeDescription
inserted_countintegerNumber of newly created slots
updated_countintegerNumber of updated slots
closed_countintegerNumber of logically closed slots (unbooked and absent from snapshot)
conflict_countintegerNumber of conflicts (booked and absent from snapshot)
conflictsarrayArray of conflict slot objects (see below). Manual resolution required.
error_countintegerNumber of processing errors
errorsarrayArray of error detail messages
conflicts element fields
FieldTypeDescription
tee_time_slot_idintegerSlot ID (GOVIGO internal ID)
course_idintegerCourse ID
tee_timestringTee time (YYYY-MM-DD HH:MM)
total_slotsintegerTotal slots
available_slotsintegerAvailable slots
bookedintegerBooked count (= total - available)

Integration: Reservations

POST/api/integration/reservations/receive.phpintegration:write

Imports a reservation that originated in an external system into GOVIGO (external → GOVIGO). external_ref is the idempotency key; a duplicate submission with the same value returns the existing reservation and exits.

ParameterTypeRequiredDescription
external_refstringRequiredReservation reference key from the external system (idempotency key to prevent duplicate imports)
course_idintegerRequiredCourse ID (must belong to your golf club)
tee_datestringRequiredPlay date (YYYY-MM-DD)
customer_namestringRequiredBooker name
player_countintegerRequiredNumber of players (1 or more)
tee_timestringOptionalTee time (HH:MM). If tee_time_slot_id is given, the slot's time is used.
tee_time_slot_idintegerOptionalGOVIGO slot ID. If specified, reserves inventory for the player count (409 if insufficient).
golf_plan_idintegerOptionalPlan ID (must belong to your golf club)
customer_emailstringOptionalBooker email
customer_phonestringOptionalBooker phone number
total_amountintegerOptionalTotal amount (VND; default: 0)
remarkstringOptionalRemark
optionsobjectOptionalOption information (arbitrary key-value)
attendeesarrayOptionalCompanion list. Each element: {name (required), email?, phone?}
Request example
POST /api/integration/reservations/receive.php HTTP/1.1
Host: en.govigolf.com
X-API-Key: YOUR_API_KEY
Content-Type: application/json

{
  "external_ref": "EXT-12345",
  "course_id": 10,
  "tee_date": "2026-07-01",
  "tee_time": "07:30",
  "customer_name": "John Smith",
  "customer_email": "[email protected]",
  "customer_phone": "+84-90-0000-0000",
  "player_count": 2,
  "total_amount": 3600000
}
Response data fields
FieldTypeDescription
reservation_idintegerGOVIGO-assigned reservation ID
external_refstringExternal reference key (same as request)
statusstringpending (initial status at creation)
duplicatebooleantrue only if the same external_ref already existed (HTTP 200)
POST/api/integration/reservations/update.phpintegration:write

Reflects changes from the external system to the GOVIGO mirror (external → GOVIGO). Only specified fields are updated. Changing player count adjusts inventory by the difference (409 if insufficient slots for an increase). Use cancel.php for cancellations. Date/time changes are not allowed for slot-linked reservations (cancel and re-create instead).

ParameterTypeRequiredDescription
external_refstringOne requiredIdentify target by external reference key
reservation_idintegerOne requiredIdentify target by GOVIGO reservation ID
customer_namestringOptionalBooker name
customer_emailstringOptionalBooker email
customer_phonestringOptionalBooker phone number
tee_datestringOptionalPlay date (YYYY-MM-DD). Not changeable for slot-linked reservations.
tee_timestringOptionalTee time (HH:MM). Not changeable for slot-linked reservations.
player_countintegerOptionalNumber of players. Adjusts slot inventory by difference if slot-linked.
total_amountintegerOptionalTotal amount (VND)
remarkstringOptionalRemark
optionsobjectOptionalOption information
statusintegerOptionalOnly 1=reserved / 3=completed may be specified. Use cancel.php for cancellations.
Request example
POST /api/integration/reservations/update.php HTTP/1.1
Host: en.govigolf.com
X-API-Key: YOUR_API_KEY
Content-Type: application/json

{ "external_ref": "EXT-12345", "player_count": 3, "tee_time": "08:00" }
Response data fields
FieldTypeDescription
reservation_idintegerID of the updated reservation
external_refstring|nullExternal reference key
POST/api/integration/reservations/cancel.phpintegration:write

Reflects a cancellation from the external system into the GOVIGO mirror (external → GOVIGO). Sets status to cancelled and restores slot inventory by the player count if a slot is linked. Idempotent (returns success even if already cancelled).

ParameterTypeRequiredDescription
external_refstringOne requiredIdentify target by external reference key
reservation_idintegerOne requiredIdentify target by GOVIGO reservation ID
Request example
POST /api/integration/reservations/cancel.php HTTP/1.1
Host: en.govigolf.com
X-API-Key: YOUR_API_KEY
Content-Type: application/json

{ "external_ref": "EXT-12345" }
Response data fields
FieldTypeDescription
reservation_idintegerID of the cancelled reservation
external_refstring|nullExternal reference key
statusstringcancelled
alreadybooleantrue only if already cancelled
POST/api/integration/reservations/push.phpintegration:read

Retrieves GOVIGO reservation data (GOVIGO → external). Default range: today to 30 days ahead.

ParameterTypeRequiredDescription
date_fromstringOptionalStart date (YYYY-MM-DD; default: today)
date_tostringOptionalEnd date (YYYY-MM-DD; default: today + 30 days)
statusintegerOptionalFilter by status code (see table below)
include_attendeesbooleanOptionaltrue to include companion information
Response data fields
FieldTypeDescription
golf_club_idintegerGolf club ID
date_from / date_tostringRequested date range
countintegerNumber of reservations returned
reservationsarrayArray of reservation objects (see below)
reservations element fields
FieldTypeDescription
reservation_idintegerGOVIGO reservation ID
course_idintegerCourse ID
course_namestringCourse name
customer_namestringBooker name
customer_emailstringBooker email
customer_phonestringBooker phone
tee_datestringPlay date (YYYY-MM-DD)
tee_timestringTee time (HH:MM)
player_countintegerNumber of players
total_amountintegerTotal amount (VND)
statusstringpending_payment / reserved / cancelled / completed
status_codeintegerStatus code (0=pending payment / 1=reserved / 2=cancelled / 3=completed)
sourcestringBooking source (api_integration etc.)
external_refstring|nullExternal reference key
created_atstringCreated at
updated_atstringUpdated at
attendeesarrayOnly when include_attendees=true. Array of {name, email, phone}

Integration: Webhook

POST/api/integration/webhooks/subscribe.phpintegration:write

Registers a URL to receive event notifications for reservations, inventory, etc.

ParameterTypeRequiredDescription
urlstringRequiredWebhook receiving URL (HTTPS required)
eventsarrayRequiredEvent types to subscribe (reservation.created/updated/cancelled/status_changed, tee_time.updated, *)
Request example
POST /api/integration/webhooks/subscribe.php HTTP/1.1
Host: en.govigolf.com
X-API-Key: YOUR_API_KEY
Content-Type: application/json

{ "url": "https://example.com/hook", "events": ["reservation.created", "reservation.cancelled"] }
GET/api/integration/webhooks/list.phpintegration:read

Returns the list of registered Webhooks (no parameters; target golf club determined from the key).

POST/api/integration/webhooks/unsubscribe.phpintegration:write

Unsubscribes a registered Webhook.

ParameterTypeRequiredDescription
subscription_idintegerRequiredSubscription ID to unsubscribe
POST/api/integration/webhooks/test.phpintegration:write

Sends a test event to the specified subscription.

ParameterTypeRequiredDescription
subscription_idintegerRequiredSubscription ID to test
Management API

Management: Reservations

GET/api/manage/reservations/list.phpreservations:read

Returns the reservation list for your golf club. Default: 20 per page (max 100).

ParameterTypeRequiredDescription
statusintegerOptionalFilter by status code (see table below)
date_from / date_tostringOptionalFilter by play date (YYYY-MM-DD)
searchstringOptionalKeyword search on booker name, email, or phone
pageintegerOptionalPage number (default: 1)
per_pageintegerOptionalItems per page (default: 20, max: 100)
Request example
GET /api/manage/reservations/list.php?date_from=2026-07-01&date_to=2026-07-31&page=1 HTTP/1.1
Host: en.govigolf.com
X-API-Key: YOUR_API_KEY
Response data fields
FieldTypeDescription
reservationsarrayArray of reservation objects (see below)
pagination.pageintegerCurrent page
pagination.per_pageintegerItems per page
pagination.total_countintegerTotal count
pagination.total_pagesintegerTotal pages
pagination.has_nextbooleanHas next page
pagination.has_prevbooleanHas previous page
reservations element fields
FieldTypeDescription
idintegerReservation ID
course_namestringCourse name
customer_namestringBooker name
customer_emailstringBooker email
customer_phonestringBooker phone
tee_datestringPlay date (YYYY-MM-DD)
tee_timestringTee time (HH:MM)
player_countintegerNumber of players
total_amountintegerTotal amount (VND)
statusstringStatus string (see table below)
status_codeintegerStatus code (0–3, 9)
sourcestringBooking source
remarkstringRemark
created_atstringCreated at
Status code reference
0 = pending_payment / 1 = reserved / 2 = cancelled / 3 = completed / 9 = cancelled (legacy)
GET/api/manage/reservations/detail.phpreservations:read

Returns reservation details including companion information.

ParameterTypeRequiredDescription
reservation_idintegerRequiredReservation ID (legacy id also accepted)
Response data.reservation fields
FieldTypeDescription
idintegerReservation ID
course_namestringCourse name
plan_namestring|nullPlan name
customer_namestringBooker name
customer_emailstringBooker email
customer_phonestringBooker phone
tee_datestringPlay date (YYYY-MM-DD)
tee_timestringTee time (HH:MM)
player_countintegerNumber of players
total_amountintegerTotal amount (VND)
remarkstringRemark
optionsobject|nullOption information
statusstringStatus string (same code reference as list)
status_codeintegerStatus code (0–3, 9)
sourcestringBooking source
external_refstring|nullExternal reference key
created_atstringCreated at
updated_atstringUpdated at
attendeesarrayCompanion list. Each element: {id, name, email, phone}
POST/api/manage/reservations/update-status.phpreservations:write

Updates the reservation status. status=9 is treated as a cancellation and restores slot inventory. Cancelled reservations cannot be moved to another status (409).

ParameterTypeRequiredDescription
reservation_idintegerRequiredReservation ID
statusintegerRequiredNew status code (0–3, 9)
memostringOptionalChange memo (appended to remark)
Request example
POST /api/manage/reservations/update-status.php HTTP/1.1
Host: en.govigolf.com
X-API-Key: YOUR_API_KEY
Content-Type: application/json

{ "reservation_id": 123, "status": 1, "memo": "Confirmed" }
Response data fields
FieldTypeDescription
reservation_idintegerID of the updated reservation
old_statusstringPrevious status string
new_statusstringNew status string

Management: Tee time slots

GET/api/manage/tee-times/list.phptee_times:read

Returns the tee time slot list for the specified date.

ParameterTypeRequiredDescription
datestringRequiredTarget date (YYYY-MM-DD)
course_idintegerOptionalFilter by course
Response data fields
FieldTypeDescription
datestringTarget date
countintegerNumber of slots returned
slotsarrayArray of slot objects (see below)
slots element fields
FieldTypeDescription
idintegerSlot ID (= slot_id)
course_idintegerCourse ID
course_namestringCourse name
tee_timestringTee time (HH:MM)
total_slotsintegerTotal slots
available_slotsintegerAvailable slots
booked_slotsintegerBooked slots (= total - available)
statusstringopen / closed / maintenance
allow_joinbooleanJoin (shared booking) allowed
plan_idinteger|nullAssociated plan ID
plan_namestring|nullPlan name
POST/api/manage/tee-times/update.phptee_times:write

Updates a single tee time slot. Returns 400 if available_slots after update would be outside the range 0–total_slots.

ParameterTypeRequiredDescription
slot_idintegerRequiredTee time slot ID
total_slotsintegerOptionalTotal slots (1 or more)
available_slotsintegerOptionalAvailable slots (0 or more, ≤ total_slots)
statusstringOptionalopen / closed / maintenance
allow_joinbooleanOptionalAllow join
golf_club_plan_idinteger|nullOptionalAssociated plan ID (null to unlink; must belong to your golf club)
Response data fields
FieldTypeDescription
slot_idintegerID of the updated slot
updatedbooleantrue
POST/api/manage/tee-times/bulk-update.phptee_times:write

Updates multiple tee time slots in one request (max 200). If any slot fails validation it is skipped and the details are returned in errors; other slots are still updated.

ParameterTypeRequiredDescription
slotsarrayRequiredArray of slots to update (max 200)
slots element fields
FieldTypeRequiredDescription
slot_idintegerRequiredTee time slot ID
total_slotsintegerOptionalTotal slots
available_slotsintegerOptionalAvailable slots
statusstringOptionalopen / closed / maintenance
allow_joinbooleanOptionalAllow join
Request example
POST /api/manage/tee-times/bulk-update.php HTTP/1.1
Host: en.govigolf.com
X-API-Key: YOUR_API_KEY
Content-Type: application/json

{ "slots": [ { "slot_id": 501, "available_slots": 0, "status": "closed" }, { "slot_id": 502, "available_slots": 2 } ] }
Response data fields
FieldTypeDescription
updated_countintegerNumber of successfully updated slots
error_countintegerNumber of skipped items
errorsarrayArray of error detail messages

Management: Notifications

GET/api/manage/notifications/list.phpnotifications:read

Returns the notification list in descending order of creation date.

ParameterTypeRequiredDescription
pageintegerOptionalPage number (default: 1)
per_pageintegerOptionalItems per page (default: 20, max: 100)
unread_onlyintegerOptional1 to return unread only
Response data fields
FieldTypeDescription
notificationsarrayArray of notification objects (see below)
paginationobjectPagination info (same format as reservation list)
notifications element fields
FieldTypeDescription
idintegerNotification ID
typestringNotification type (e.g. reservation.created)
reserve_idinteger|nullAssociated reservation ID
titlestringNotification title
bodystringNotification body
is_readbooleanRead flag
created_atstringCreated at
POST/api/manage/notifications/mark-read.phpnotifications:write

Marks notifications as read. Either notification_ids or all is required.

ParameterTypeRequiredDescription
notification_idsarrayOne requiredArray of notification IDs to mark read (integer[])
allbooleanOne requiredtrue to mark all as read
Response data fields
FieldTypeDescription
updated_countintegerNumber of notifications marked as read
GET/api/manage/notifications/unread-count.phpnotifications:read

Returns the number of unread notifications (no parameters).

Response data fields
FieldTypeDescription
unread_countintegerNumber of unread notifications

Management: Settings

GET/api/manage/settings/get.phpsettings:read

Retrieves golf club settings. Returns all settings as { key: value } if key is omitted.

ParameterTypeRequiredDescription
keystringOptionalReturn only this key if specified; all keys if omitted
Response data fields (single key)
FieldTypeDescription
keystringSetting key
valuestring|nullSetting value (null if not set)
Response data fields (all keys)
FieldTypeDescription
countintegerTotal number of setting keys
settingsobjectObject in { "key": "value", ... } format
POST/api/manage/settings/update.phpsettings:write

Updates golf club settings (UPSERT). Multiple keys can be updated at once.

ParameterTypeRequiredDescription
settingsobjectRequiredSettings object in { "key": "value", ... } format
Request example
POST /api/manage/settings/update.php HTTP/1.1
Host: en.govigolf.com
X-API-Key: YOUR_API_KEY
Content-Type: application/json

{ "settings": { "auto_confirm": "1", "cancel_deadline_days": "3" } }
Response data fields
FieldTypeDescription
updated_countintegerNumber of setting keys updated
settingsobjectUpdated settings as { "key": "value", ... }

Management: Reports

GET/api/manage/reports/summary.phpreports:read

Returns an aggregate summary of reservation activity. Default period: current month.

ParameterTypeRequiredDescription
date_from / date_tostringOptionalPeriod (YYYY-MM-DD; default: first to last day of current month)
group_bystringOptionaldate (by day) / course (by course) / status (by status). Default: date
Response data fields
FieldTypeDescription
period.from / period.tostringAggregation period
summary.total_reservationsintegerTotal reservation count
summary.pending_countintegerPending count (not confirmed or cancelled)
summary.confirmed_countintegerConfirmed count
summary.cancelled_countintegerCancelled count
summary.completed_countintegerCompleted count
summary.total_playersintegerTotal players
summary.total_revenueintegerTotal revenue (VND; excludes cancellations)
summary.avg_amountintegerAverage amount per reservation (VND; excludes cancellations)
breakdownarrayGroup breakdown array (see below)
breakdown element fields
FieldTypeDescription
date / course_name / statusstringKey name varies depending on group_by
reservation_countintegerReservation count
player_countintegerTotal players
revenueintegerTotal revenue (VND; excludes cancellations)
GET/api/manage/reports/export.phpreports:read

Exports reservation data as CSV. Response is text/csv (not a JSON envelope; UTF-8 BOM CSV file).

ParameterTypeRequiredDescription
date_from / date_tostringOptionalPeriod (YYYY-MM-DD; default: current month)
statusintegerOptionalFilter by status code
Request example
GET /api/manage/reports/export.php?date_from=2026-07-01&date_to=2026-07-31 HTTP/1.1
Host: en.govigolf.com
X-API-Key: YOUR_API_KEY
CSV columns
ColumnDescription
Reservation IDGOVIGO reservation ID
CourseCourse name
Booker nameCustomer name
EmailCustomer email
PhoneCustomer phone
Play dateYYYY-MM-DD
TimeHH:MM
PlayersNumber of players
AmountTotal amount (VND)
StatusStatus label
SourceBooking source
RemarkRemark text
Created atCreation date/time