Getting startedNotifications

Intro to notifications

Note: If you are interested in this feature, contact your Technical Relationship Manager before implementing it.

The notification service (also referred to as "webhooks") enables us to push real-time notifications to your app when asynchronous events occur. To enable webhooks, a webhooks profile is created and configured (one profile is used for all lodging partners). HTTPS is used to send these notifications to your app as a JSON payload. You can then use these notifications to execute actions in your system.

Currently, the following notifications are supported:

  • Property status:
    • PropertyStatusMinRequirementMissing
    • PropertyStatusChanged
  • Reviews:
    • GuestReviewSubmitted
    • ReviewsApproved
    • ReviewsManagementResponseApproved
    • ReviewsManagementResponseRejected

If multiple GraphQL capabilities are implemented, you may want to create multiple callback URLs where notifications are sent. For example, you could create one for property status events and one for reviews events.

Here is an overview of the queries and mutations available to you to implement notifications:

Mutation or query nameDescription
createNotificationCallbackConfig mutationCreates the callback configuration for the partner account, including the callback URL (where notification events are sent when they occur), API key, and request timeout value. If your notification profile does not exist, this mutation will create the profile, too.
updateNotificationCallbackConfig mutationUpdates the callback configuration, including the callback URL, API key, and request timeout value.
refreshNotificationCallbackConfigSecret mutationRefreshes the secret of the callback configuration.
deleteNotificationCallbackConfig mutationDeletes a callback configuration using the callback ID.
sendTestNotification mutationSends a test notification using the specified event type and payload. The notification is sent to the configured callback URL.
subscribeNotificationEventType mutationSubscribes a callback configuration to notifications (by event type).
unsubscribeNotificationEventType mutationUnsubscribes from event types.
updateNotificationEventTypeSubscription mutationUpdates the callback ID associated with the registered event type.
notificationProfile queryRetrieves the partner profile.
notificationEventTypes queryRetrieves all available event types.

Enabling notifications

The following is an overview of the process to enable notifications. You must share your callback URLs with your TRM and wait for confirmation before completing these steps. Also, be sure to complete the steps for each callback URL, if implementing more than one.

  1. Generate an API key that you can use when registering your callback URL. Our team then generates a secret along with the expiration date and time of the secret. You can use the secret to validate the signature of payloads when you receive notifications from the webhooks service. By default, the secret is valid for one year (no notification is sent when the secret expires; you can determine when it will expire using the secretExpirationDateTime field).

    The API key and signature are passed in the HTTP headers of the notification. The timestamp is in epoch time. The signature is a Base64 encoded HMAC-SHA256 hash created using the timestamp and notification payload as the text string and using the secret as the key. The format of the string is timestamp.payload (period is the delimiter), where payload is the full payload of the notification.

    Here is an example of the headers:

    “transactionId”: “11111111-1111-11ec-97a3-5d06cc689918" 
    “api-key”: “apiKey” 
    “x-eg-notification-timestamp”: “1674149042995" 
    “x-eg-notification-signature”: “sha256=3VmZm10hD3/HUEStwf+BsTLP7/csgtECzIj0Ap8BYiY=” 
    
  2. Create a webhook endpoint as an HTTPS endpoint (callback URL) on your local server, and then deploy your webhook endpoint so that it’s a publicly accessible HTTPS URL. The URL must be able to accept a notification payload, and it must return HTTP status code 200 after successfully receiving the notification, even if there is an error in the downstream processing. (If you subscribe to notifications before the callback URL can accept traffic, our retry logic will generate unnecessary errors in our monitoring reports. If you do not return status code 200, we continue to resend the notification to your server as per retry policy.)

  3. Register your callback URL and subscribe to events using these mutations:

    • createNotificationCallbackConfig mutation, which creates the callback configuration, including the callback URL, API key, and request timeout value (this also creates the notification profile if it does not exist)
    • subscribeNotificationEventType mutation, to subscribe to event types (you can use the notificationEventTypes query to retrieve the list of available event types)

    Additional mutations and queries are available.

  4. Verify the authenticity of requests (to make sure the requests are from Expedia) by

    • Verifying the API key provided in the request header
    • Confirming the security hash that you generate is same as what we send along with the payload

In the event that you have issues receiving a webhook notification (because of a database failure, network outage, unavailable callback URL, and so on), we attempt to resend the notification every 25 seconds, up to 50 retry attempts (as defined by our retry policy).

Notification payloads

This section provides format and examples of each payload type.

Property status payloads

Format:

1{
2 "event_name": "<event_name_value>",
3 "creation_time": "<UTC_timestamp>",
4 "notification_id": "<notification_id>",
5 "payload": {
6 "property_id": "<expedia_property_id>",
7 "property_active_status": <boolean>, \\for PropertyStatusChanged only
8 "checkpoints": [
9 {
10 "name": "<checkpoint_name>",
11 "status": "<boolean>"
12 },
13
14 ]
15 }
16}

Examples:

1{
2 "event_name": "PropertyStatusMinRequirementMissing",
3 "creation_time": "2023-09-26T07:50:51.726Z",
4 "notification_id": "8c7ffeec-5eb6-4cd7-8557-0f6d9290f359",
5 "payload": {
6 "property_id": "71888474",
7 "checkpoints": [
8 {
9 "name": "HasImages",
10 "status": "false"
11 },
12 {
13 "name": "HasRates",
14 "status": "false"
15 },
16 {
17 "name": "HasBookingType",
18 "status": "false"
19 },
20 {
21 "name": "HasCancellationPolicy",
22 "status": "false"
23 },
24 {
25 "name": "HasHouseRules",
26 "status": "false"
27 },
28 {
29 "name": "HasCheckInCheckOut",
30 "status": "false"
31 },
32 {
33 "name": "HasPropertyDetails",
34 "status": "false"
35 },
36 {
37 "name": "HasPropertyDescription",
38 "status": "false"
39 },
40 {
41 "name": "HasBathroom",
42 "status": "false"
43 },
44 {
45 "name": "HasMaxOccupancy",
46 "status": "false"
47 },
48 {
49 "name": "HasPropertyType",
50 "status": "false"
51 }
52 ]
53 }
54}

Reviews payloads

Format:

1{
2 "event_name": "<event_name_value>",
3 "creation_time": "<UTC_timestamp>",
4 "notification_id": "<notification_id>",
5 "payload": {
6 "property_id": "<expedia_property_id>",
7 "eg_reservation_id": "<expedia_reservation_id>", \\when a traveler submits a review
8 "supplier_reservation_id": "<supplier_reservation_id", \\when a traveler submits a review
9 "review_id": "<review_id>"
10 }
11}

Examples:

1{
2 "event_name": "GuestReviewSubmitted",
3 "creation_time": "2023-10-04T16:02:58.978Z",
4 "notification_id": "9c065ff3-7c21-4eef-be11-da11f543590c",
5 "payload": {
6 "eg_reservation_id": "5ee844ca-e753-491b-a391-be8598597259",
7 "supplier_reservation_id": "19043678",
8 "property_id": "82898394"
9 }
10}

Creating a callback configuration

This mutation creates the callback configuration, including the callback URL (where notification events are sent when they occur), API key, and request timeout value.

Here is an example:

1mutation {
2 createNotificationCallbackConfig (
3 input: {
4 callbackUrl: "https://testcallbackurl.com",
5 apiKey: "newapikey",
6 requestTimeoutSeconds: 50
7 })
8 {
9 callbackConfig {
10 id
11 callbackUrl
12 secretExpirationDateTime
13 requestTimeoutSeconds
14 }
15 secret
16 }
17}

Retrieving available event types

To determine the event types to which you can subscribe, use the notificationEventTypes query.

Note: Not all event types are applicable to conventional lodging partners at this time. Refer to each capability's overview page for the list of event types that are available for the capability.

Here is an example:

1query {
2 notificationEventTypes {
3 name
4 description
5 }
6}

Subscribing to notifications

Use the following mutation to subscribe to an event type, to receive notifications of that type when they occur. You must subscribe one at a time.

Here is an example:

1mutation {
2 subscribeNotificationEventType (
3 input: {
4 eventType: "GuestReviewSubmitted",
5 callbackConfigId: "1969081f-8380-4dbd-9a19-c26fc1747b06"
6 })
7 {
8 eventType
9 callbackConfig {
10 id
11 callbackUrl
12 requestTimeoutSeconds
13 secretExpirationDateTime
14 }
15 }
16}

Retrieving a notification profile and its subscriptions

To review your notification profile, including the callback URL(s) and event type subscriptions, use the notificationProfile query.

Here is an example:

1query {
2 notificationProfile {
3 callbackConfigs {
4 id
5 callbackUrl
6 requestTimeoutSeconds
7 secretExpirationDateTime
8 }
9 subscriptions{
10 product
11 eventTypeSubscriptions {
12 eventType
13 callbackConfig {
14 id
15 }
16 }
17 }
18 }
19}

Refreshing the secret

If the API key's secret is about to expire, you can update it using this mutation.

Here is an example:

1mutation {
2 refreshNotificationCallbackConfigSecret (
3 input: {
4 callbackConfigId: "1969081f-8380-4dbd-9a19-c26fc1747b06"
5 })
6 {
7 callbackConfigId
8 secret
9 secretExpirationDateTime
10 }
11 }
12}

Updating a callback configuration

To change an attribute of the callback configuration, such as the request timeout value, use this mutation.

Here is an example:

1mutation {
2 updateNotificationCallbackConfig (
3 input: {
4 callbackConfigId: "1969081f-8380-4dbd-9a19-c26fc1747b06",
5 requestTimeoutSeconds: 50
6 })
7 {
8 callbackConfig {
9 id
10 callbackUrl
11 secretExpirationDateTime
12 requestTimeoutSeconds
13 }
14 }
15}