Getting startedNotifications (webhooks)

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 service endpoint when asynchronous events occur. Notifications are not "bundled"; they are sent as they occur. 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.

To enable notifications, you must create and configure a callback configuration and then subscribe to events types (the full procedure is provided below). The callback configuration and its subscriptions are collectively referred to as the "notification profile". One profile is used for all lodging partners.

Currently, the following event types are supported:

  • Property status:
    • PropertyStatusMinRequirementMissing - Sent after a property is created with the minimum required information (address, name, type, location, and defaultLocale).
    • PropertyStatusChanged - Sent when a property becomes active or inactive.
  • Messaging:
    • MessageThreadCreated - Indicates that a new message thread has been created when a reservation is created.
    • MessageReceived - Indicates that a traveler or partner sent a message.
    • MessageAttributesUpdated - Indicates that a message's status changed, as it moves through moderation.
  • Reviews:
    • GuestReviewSubmitted - Sent when a traveler leaves a review.
    • ReviewsApproved - Sent when the traveler review is approved.
    • ReviewsManagementResponseApproved - Sent when a partner's review response is approved.
    • ReviewsManagementResponseRejected - Sent when a partner's review response is rejected.

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 notifications as follows (as defined by our retry policy):

  • Property status: every hour for seven days
  • Messaging events: every hour for one day
  • Reviews events: every 25 seconds, up to 50 retry attempts

Implementation details

  • If multiple GraphQL capabilities are implemented, you may want to create multiple callback configurations (one callback URL is specified per configuration) and then you can subscribe to specific event types. For example, you could create one callback configuration for property status events and one for reviews events. (The notification profile comprises all callback configurations and their subscriptions.)
  • When creating an HTTPS service endpoint (callback URL):
    • It must return HTTP status code 200 after successful receipt of notifications.
    • Downstream processing of events must occur asynchronously.
    • Your endpoint must use Transport Layer Security (TLS) 1.2 or 1.3, to provide over-the-wire encryption (HTTPS).
    • Be sure to allow for comma-delimiting hashes in the HTTP headers of notifications (complete details below).
  • Before enabling notifications, share your callback URLs with your TRM and wait for confirmation.

Overview of queries and mutations

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, partner email address, 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. Note that the new secret must be used to validate notifications immediately after a refresh is performed.
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.
undeliveredNotifications queryRetrieves any undelivered notifications for a given event type. This mutation is helpful in restoring notifications after connectivity issues.

Enabling notifications

The following is an overview of the process to enable notifications. Before beginning, share your callback URLs with your TRM and wait for confirmation before completing these steps. Then, be sure to complete the steps for each callback configuration, if implementing more than one callback service endpoint (URL).

  1. Generate an API key that you can use when registering your callback URL.

  2. Create an HTTPS service endpoint (callback URL) on your local server, and then deploy your 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 successful receipt of the notification. Downstream processing of the event must occur asynchronously. (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.)
    • Your endpoint must use Transport Layer Security (TLS) 1.2 or 1.3, to provide over-the-wire encryption (HTTPS).
  3. Create a callback configuration using the createNotificationCallbackConfig mutation. Input to this mutation includes the callback URL, API key, partner email address, and request timeout value. This also registers your callback URL and creates the notification profile if it does not exist.

    Note: Immediately after registering the callback URL, we send a GET request to your endpoint, to check connectivity from the Expedia network and verify whether the URL is whitelisted. This is issued once and can be ignored.

    When creating the callback configuration, the API generates a secret along with its expiration date and time, which are returned in the mutation response. 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. You can determine when it will expire using the secretExpirationDateTime field; we recommend that you renew the secret at least 30 days before the expiry date. If the secret expires, notifications fail to be sent for active subscriptions, though we attempt to retry sending them (according to the retry policy for the event type). If the secret is refreshed during these retry attempts, notifications are sent successfully. After the secret is refreshed, you have up to three days to replace the old secret (as specified when refreshing the secret).

    The following is passed in the HTTP headers of the notification:

    • API key.
    • Timestamp, in epoch time.
    • Signature, in this format: sha256=hash(timestamp.notification_payload), which is a Base64-encoded HMAC-SHA256 hash of the timestamp and notification payload using the secret as the key. If the old secret is still active, the format is sha256=hash(timestamp.notification_payload) with newSecret,hash(timestamp.notification_payload) with oldSecret. Note that you must code for comma-delimiting hashes in both cases.

    Here is an example of the headers for a MessageAttributesUpdated notification:

    "transactionId": "11111111-1111-11ec-97a3-5d06cc689918" 
    "api-key": "apiKey" 
    "x-eg-notification-timestamp": "1674149042995" 
    "x-eg-notification-signature-v2": "sha256=hash(1732710561482.{"event_name":"MessageAttributesUpdated","creation_time":"2024-11-28T10:27:18.212Z","notification_id":"53c7cb70-d772-4ddd-ad04-b1fcae1620c8","payload":{"property_id":"11840519","message_thread_id":"46c35257-1e78-45c0-a64d-cc5fae75d007","message_id":"20aeeade-0bf4-48f2-8c8b-9cda524551a9","from_role":"SUPPLIER","reservation_id":"368177214","message_attributes":[{"attribute":"reviewStatus","value":"ACCEPTED"}]}}, WUsM9s+yTDln9AfZVVAY+g==)"
    
  4. Subscribe to event types using the subscribeNotificationEventType mutation. You can use the notificationEventTypes query to retrieve the list of available event types.

  5. 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

Notification payloads

This section provides format and examples of each payload type.

Property status payloads

This section provides a description of the payload attributes and examples of each event type.

AttributeDescription
event_nameEvent name value.
creation_timeUTC timestamp when event occurred.
notification_idNotification ID.
property_idExpedia property ID. Child attribute of payload.
property_active_statusBoolean indicating whether the property is active. Child attribute of payload.
checkpointsArray of advertisers (partners); name and status (whether it's been satisfied) are provided for each advertiser.
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}

Messaging payloads

This section provides a description of the payload attributes and examples of each event type.

AttributeDescription
event_nameEvent name value.
creation_timeUTC timestamp when the message was created (including retries).
notification_idNotification ID.
property_idExpedia property ID. Child attribute of payload.
message_thread_idMessage thread ID. Child attribute of payload.
message_idMessage ID. Child attribute of payload.
message_typeMessage type; refer to Message types for the list of possible values. Child attribute of payload.
from_roleSender. Child attribute of payload. Possible values include TRAVELER and SUPPLIER.
reservation_idExpedia reservation ID. Child attribute of payload. Present if associated with a message or message thread.
message_attributesArray of attribute child attributes, which each include name and value. Currently, only the reviewStatus message attribute is supported, which indicates the review status of the message. Possible values include IN_REVIEW, ACCEPTED, and BLOCKED. message_attributes is a child attribute of payload.
1{
2 "event_name": "MessageThreadCreated",
3 "notification_id": "63376d68-651a-11ed-9022-0242ac120442",
4 "creation_time": "2023-01-10T17:13:36.140Z",
5 "payload": {
6 "property_id": "15239779",
7 "message_thread_id": "63676d68-651a-11ed-9022-0242ac120432",
8 "reservation_id": "63676d68-651a-11ed-9022-0242ac120882"
9 }
10}

Reviews payloads

This section provides a description of the payload attributes and examples of each event type.

AttributeDescription
event_nameEvent name value.
creation_timeUTC timestamp when the event occurred.
notification_idNotification ID.
property_idExpedia property ID. Child attribute of payload.
eg_reservation_idExpedia reservation ID. Child attribute of payload.
supplier_reservation_idProperty manager's reservation ID. Child attribute of payload.
review_idReview ID. Child attribute of payload.
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 contactEmail: "partner@email.com"
8 }
9 ) {
10 callbackConfig {
11 id
12 callbackUrl
13 secretExpirationDateTime
14 requestTimeoutSeconds
15 contactEmail
16 }
17 secret
18 }
19}

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:

1 query {
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}
19```json
20{
21 "data": {
22 "subscribeNotificationEventType": {
23 "eventType": "GuestReviewSubmitted",
24 "callbackConfig": {
25 "id": "074af31e-c583-4bab-9636-aa79a76221a4",
26 "callbackUrl": "https://callbackUrl.com",
27 "requestTimeoutSeconds": 60,
28 "secretExpirationDateTime": "2024-05-18T15:52:40"
29 }
30 }
31 }
32}

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 contactEmail
9 }
10 subscriptions{
11 product
12 eventTypeSubscriptions {
13 eventType
14 callbackConfig {
15 id
16 }
17 }
18 }
19 }
20}

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 keepExistingSecretActive: true
6 })
7 {
8 callbackConfigId
9 secret
10 secretExpirationDateTime
11 previousSecretExpirationDateTime
12 }
13}

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 contactEmail: "partner@company.com"
7 })
8 {
9 callbackConfig {
10 id
11 callbackUrl
12 secretExpirationDateTime
13 requestTimeoutSeconds
14 contactEmail
15 }
16 }
17}