5.13: Webhooks

In this section, we will guide you through the process of receiving real-time event notifications from the Golfdigg OTA API. When a subscribed event occurs, we will send an HTTP POST request to your registered endpoint URL.


5.13.1: Registering Your Webhook Endpoint

Webhook registration is currently handled manually. To register your endpoint URL, please contact Golfdigg support with the following information:

  • endpointUrl — The URL of your server that will receive webhook event POST requests.
  • secret — A secret key of your choice, used to verify the authenticity of incoming webhook requests.

Note: Self-service webhook configuration via the admin web portal is planned for a future release.


5.13.2: Webhook Payload Format

When an event occurs, we will send an HTTP POST request to your registered endpointUrl with the following payload structure:

interface WebhookPayload<T> {
  eventId: string;    // Unique identifier for the event
  eventType: string;  // Type of the event (e.g., payment_success)
  createdAt: string;  // ISO 8601 timestamp of when the event was created
  data: T;            // Event-specific data object
}
FieldTypeDescription
eventIdstringUnique identifier for this webhook event.
eventTypestringThe type of event that triggered this webhook.
createdAtstringISO 8601 timestamp of when the event was created.
dataobjectThe event payload. Structure varies by event type.

5.13.3: Webhook Request Headers

Each webhook request sent to your endpoint will include the following custom headers for verification purposes:

HeaderDescription
X-Ota-Event-IdThe unique identifier of the event, matching the eventId field in the payload.
X-Ota-Event-SigHMAC signature of the payload using your secret. Use this to verify the request integrity.
X-Ota-TimestampUnix timestamp of when the request was sent. Use this to guard against replay attacks.

Header Example:

X-Ota-Event-Id: payment_success_1780486622603299709
X-Ota-Event-Sig: e9ab4f74354451a993723b16dffd85face14078ecca21b0bbb7b22fc50e43fba
X-Ota-Timestamp: 1780486622

5.13.4: Event Types

payment_success

Triggered when an order has been successfully paid. The data field contains the full order details.

Data Model (OrderModelDto):

FieldTypeDescription
idstringUnique identifier of the order.
statusstringCurrent status of the order (e.g., PAID).
txNostringTransaction number for the order.
agencyIdstringIdentifier of the agency associated with the order.
agencyNamestringName of the agency.
slotIdstringIdentifier of the tee time slot.
courseIdstringIdentifier of the golf course.
courseNamestringName of the golf course.
walletIdstringIdentifier of the wallet used for the order.
customerNamestringName of the customer.
customerEmailstringEmail of the customer.
customerMobilestringMobile number of the customer.
customerIdstringIdentifier of the customer, if available.
amountint64Total amount of the order.
priceAfterDiscountint64Final price after any discounts applied.
reserveIdstringIdentifier of the associated reservation.
reserveobjectReservation details. See reserve model below.
golfReserveobjectGolf-specific booking units (golfer, cart, caddie counts).
additionGolferstring[]List of additional golfer identifiers, if any.
paymentLinkstringPayment link URL, if applicable. May be null.
createdAtstringISO 8601 timestamp of when the order was created.
updatedAtstringISO 8601 timestamp of when the order was last updated.

5.13.5: Payload Example (payment_success)

{
  "eventId": "payment_success_1780486622603299709",
  "eventType": "payment_success",
  "createdAt": "2026-06-03T18:37:02.603318985+07:00",
  "data": {
    "id": "6a201150faa1002654967b93",
    "status": "PAID",
    "txNo": "ORDER-2026-06-03-802488541",
    "agencyId": "68806539e318929087752315",
    "agencyName": "Fang",
    "slotId": "6a1d3bc8e4b07bcc9a2c785c",
    "courseId": "5c9c8252ef0ab53dcf12e8d2",
    "courseName": "331 GOLF CLUB-testtt",
    "walletId": "68806539e318929087752316",
    "customerName": "testApi-pay",
    "customerEmail": "testApi-pay",
    "customerMobile": "testApi-pay",
    "customerId": "",
    "amount": 360000,
    "priceAfterDiscount": 360000,
    "reserveId": "6a201150e4b0581f4a1b2660",
    "reserve": {
      "id": "6a201150e4b0581f4a1b2660",
      "code": "G260603-00004",
      "status": "BOOKING",
      "golf": {
        "slotTime": 1780452000000,
        "slotTimeString": "2026-06-03T09:00:00+0700",
        "persons": 3,
        "carts": 3,
        "caddies": 3
      }
    },
    "golfReserve": {
      "golfer": 3,
      "cart": 3,
      "caddie": 3
    },
    "additionGolfer": null,
    "paymentLink": null,
    "createdAt": "2026-06-03T11:34:40.712Z",
    "updatedAt": "2026-06-03T11:34:40.712Z"
  }
}

5.13.6: Verifying Webhook Signatures

To ensure that incoming webhook requests are genuinely from Golfdigg, you should verify the X-Ota-Event-Sig header using your registered secret. The signature is an HMAC-SHA256 hash of the raw request body signed with your secret key.

Verification Example (Node.js):

const crypto = require("crypto");

function verifyWebhookSignature(rawBody, secret, signature) {
  const expectedSig = crypto
    .createHmac("sha256", secret)
    .update(rawBody)
    .digest("hex");
  return expectedSig === signature;
}

Note: Always use the raw request body (before JSON parsing) when computing the signature. Parsing and re-serializing the JSON may alter the byte order and cause signature verification to fail.


5.13.7: Responding to Webhook Events

Your endpoint must return an HTTP 2xx status code to acknowledge receipt of the webhook. If we do not receive a successful response, the delivery may be retried.

  • Respond quickly — perform any heavy processing asynchronously.
  • Return 200 OK as soon as the payload is received and validated.