Streaming API (push)

Overview of Event Consumption via the Streaming API

When partners or customers consume business event data from OPERA Cloud, they can choose which events an application will receive. These are the events to which the application subscribes.

A partner or customer can subscribe to business events from a specific environment, but approval from the environment owner is required.

For more information on streaming, read our blog post.

The following resources can help you get started with the streaming API:

Customer Approval for Partners

A customer Developer Portal user can only approve the sending of business events for hotels to which they have access.

Customers can log in to the Developer Portal and do the following:
  • See a list of the partners who are requesting to consume events.

  • View a list of events a partner is consuming and see from which hotels and environments the partner is consuming these events.

  • Approve event consumption for one or many hotels in the requested environment.

Note:

In the following circumstances, the event subscription will automatically be approved.

  • Partners consuming business events from the partner sandbox.

  • Partners consuming business events from their dedicated non production environment.

  • Customers consuming business events from their own non production environment.

  • Customers consuming business events from their own production environment.

Customer - Enabling Streaming

To get started with their first environment, customers must purchase the OHIP Premium Remote Assistance SKU (B93152) to engage with Oracle Professional Services.

For subsequent environments, customers must raise a technical SR. The Technical SR must include the following details, which are found on the customer's Environments card in the OHIP developer portal:
  • Customer Name — The customer’s name can be found on the hotelier's Environments card in the OHIP developer portal and appears before the brackets on the card.

  • Customer Chain — The customer chain to be accessed. This can be found on the hotelier's Environments card in the OHIP developer portal and appears after the brackets on the card.

  • Environment Name — This can be found on the hotelier's Environments card in the OHIP developer portal and appears in brackets on the card.

  • Shared Security Domain — This is the URL via which the integration user for the hotelier's environment was created.

Note:

Streaming is enabled at the chain level, so once enabled for a chain, you do not need to enable it at the hotel level.

Partner - Enabling Streaming

Partners can initiate their testing in the partner sandbox environment. To gain access, request this in the partner Slack community. Partners should complete a successful streaming test by confirming that their code correctly receives Business Events and does not encounter errors either from OHIP or from downstream systems. This is not an Oracle validation, but a necessary assurance for both the partner and the hotelier before the partner accesses a hotelier's environment.

Following a successful streaming test, partners must open a Technical SR if they wish to get a customer environment UAT or Production environment enabled for streaming. The Technical SR must include the following details, which are found on the customer's Environments card in the OHIP developer portal:
  • Customer Name — The customer’s name can be found on the hotelier's Environments card in the OHIP developer portal and appears before the brackets on the card.

  • Customer Chain — The customer chain to be accessed. This can be found on the hotelier's Environments card in the OHIP developer portal and appears after the brackets on the card.

  • Environment Name — This can be found on the hotelier's Environments card in the OHIP developer portal and appears in brackets on the card.

  • Shared Security Domain —This is the URL via which the integration user for the hotelier's environment was created.

Note:

Streaming is enabled at the chain level, so once enabled for a chain, you do not need to enable it at the hotel level.

Partners must also ensure approvals have been obtained for the events they have configured on the customer environment. Customers can grant access to consume events within their developer portal.

Working with Events in the Developer Portal

Prerequisites for Consuming Events

  • You must first add an OPERA environment from which to consume events before adding and subscribing to events.

  • The OPERA environment must either have streaming enabled (see Streaming API) or have polling configured (see Configuring the Polling Subscription).

For information on working with business events in OPERA Cloud, refer to the Configuring Business Events topic in the OPERA Cloud User Guide. This topic also provides a list of business events and data elements.

Creating a Template of Events for an Application

The event template represents the list of events a given integration will use. When subscribing to consume events from a given OPERA environment, the template is a faster way to ensure the correct list of events is subscribed.

Before subscribing to consume events from a given OPERA environment, you must first create a template for the integration.

The template can be edited at any time. For example, your integration might change, and it now needs to consumer more events or fewer events.

Note:

Changes made on the template do not affect existing subscriptions to OPERA environments but will take effect when subscribing to new OPERA environments.

To configure the template events, complete the following steps:
  1. Open the Developer Portal and click the Applications tab.

  2. Search for and click an application to open it.

  3. Click the Events tab.

  4. Click Add Event to Template and complete the following information:
    1. Category: Select a category for the event, such as Reservation.

    2. Event: Select an event for the category, such as Check In.

      Note:

      To remove an event from the template, click the Remove link.

  5. Click Add to add the event to the template.

  6. Repeat these steps to add additional events to the template.

Once you have configured all the events your integration requires, click the Subscribed tab and choose any OPERA environment(s) from which to consume these events.

Subscribing to Events

A partner can subscribe to business events from a customer. Subscriptions to business events are specific to each application.

Use the Subscribe tab to subscribe to the list of events that you added on the Template tab.
  1. Open the Developer Portal and click the Applications tab.

  2. Search for and click an application to open it.

  3. Click the Events tab.

  4. Click the Subscribed tab.

  5. Click the Subscribe link.

  6. Select an Environment and click Subscribe.

  7. As a customer subscribing to events from your environment, select which hotels will consume the events.

The subscribed to event will be in a ‘Pending Approval’ status.

Note:

Only OPERA environments enabled for streaming appear in the list of environments.

Unsubscribing from Events

Once events are approved, you can unsubscribe from them as needed.

Note:

Unsubscribing from events on the Subscribe tab does not affect the events that appear on the Template tab. Also, changes made to events on the Template tab do not affect event subscriptions.

  1. Open the Developer Portal and click the Applications tab.

  2. Search for and click an application to open it.

  3. Click the Events tab.

  4. Click the Subscribed tab.

  5. Under Event Subscriptions, locate the event and click the green arrow to expand it and then click Unsubscribe.

Approving Events

A customer with Developer Portal access can approve the consumption of events from a specific environment. The customer can approve a partner's request to consume events before any events are sent to the partner. This enables customers to protect their data.

  1. Open the Developer Portal and click the Applications tab.

  2. Search for and click an application to open it.

  3. Click the Partner Applications tab.

    Note:

    Applications with pending event subscriptions appear with a red ribbon icon on the application card.

  4. Click an application with a pending event to open it.

  5. Click the Events tab.

  6. Click Next to proceed with approval.

  7. Select the properties for the event subscription and click Next.

  8. Click Approve.

The event status changes to ‘In Progress’ and then to ‘Approved’ status. The partner can see this status in the Developer Portal.

Rejecting Events

  1. Open the Developer Portal and click the Applications tab.

  2. Search for and click an application to open it.

  3. Click the Partner Applications tab.

  4. Click an application with a pending event to open it.

  5. Click the Events tab.

  6. Click Reject to reject the subscription.

    The event status changes to ‘In Progress’ and then to ‘Rejected’ status. The partner can see this status in the Developer Portal.

Revoking Events

As a customer, if you no longer want a partner to consume events from your chain, deselect all hotels on the partner's application:
  1. Open the Developer Portal and click the Applications tab.

  2. Search for and click an application to open it.

  3. Click the Partner Applications tab.

  4. Click an application with a pending event to open it.

  5. Click the Events tab.

  6. Click Edit next to the list of hotels.

  7. Deselect all the hotels.

  8. Click Save.

Adding Events to Existing Subscription

To add events to an existing approved subscription:
  1. Add the events on the Template tab (see the ‘Creating a Template of Events for an Application’ procedure above).

  2. Subscribe again to consume events from the same environment (see the ‘Subscribing to Events’ procedure above).

Adding Hotels to an Existing Subscription

A customer with Developer Portal access can adjust an existing approved subscription to consume events from different hotels.
  1. Open the customer or partner application.

  2. Go to the Events tab.

  3. Click Edit next to the list of hotels.

  4. Select the hotels that can consume the events.

  5. Click Save.

Broken Connections

To avoid missing messages, you should keep the WebSocket connected. However, interrupted connections do occur, so OHIP retains a record of the last message sent to each connection as well as up to 7 days of messages. If the WebSocket gets disconnected, reconnect as described in the Authentication message. OHIP will then send any messages that have occurred since the disconnection occurred. For example:

Note:

OHIP holds the last offset for 24 hours only. If you do not reconnect within 24 hours, you must send the offset in the subscribe message that reflects the last offset you received.

Table 12-1 How the Streaming API works around broken connections

Oracle Hospitality System Emits Offset OHIP Sends Partner Offset Partner Receives Offset

191

191

191

192

192

192

193

193

193

194

Connection broken

195

Connection broken

196

Connection broken

194

195

196

Connection re-established

194

195

196

197

197

197

If the WebSocket remains disconnected for over 7 days, this might result in missed messages. Refer to the following table for examples.

Table 12-2 How the Streaming API stores and replays 7 days of events

Day Oracle Hospitality System Emits Offset OHIP Sends Partner Offset Partner Receives Offset

1

191

191

191

1

192

192

192

1

193

193

193

2

194 to 317

Connection disconnected for day 1

3

318 to 520

Connection disconnected for day 2

4

521 to 701

Connection disconnected for day 3

5

702 to 929

Connection disconnected for day 4

6

930 to 1027

Connection disconnected for day 5

7

1028 to 1240

Connection disconnected for day 6

8

1241 to 1403

Connection disconnected for day 7

9

1404 to 1581

Connection disconnected for day 8

10

1582 to 1826

Connection disconnected for day 9

11

521 to 1826

Connection re-established

521 to 1826

11

1827

1827

1827

In this example, messages 194 to 521 are missed and it is not possible to replay them.

Replaying Messages

Note:

If you use the ‘offsetType’ parameter in the subscribe message, then events that occurred before that parameter was used are not included in any message replay.

The OHIP schema includes the metadata attribute "offset," which is the message number.

To replay messages already received, specify the offset value following the chainCode. For example in Postman:

{
   "id": "1",
   "type": "subscribe",
   "payload": {
         "variables": {},
         "extensions": {},
         "operationName": null,
               "query": "subscription { newEvent(input: { chainCode: \"<CHAIN CODE>\" offset: \"<OFFSET>\" } ) { metadata { offset } moduleName eventName detail { oldValue newValue elementName } } }"
   }
}

In GraphiQL add the offset parameter after the chainCode. For example:

subscription{
  newEvent(input:{chainCode: \"<CHAIN CODE>\" offset: \"<OFFSET>\"}) {
    moduleName
    eventName 
    detail{
      newValue
      oldValue
      elementName
    }         
    metadata{
      offset
      uniqueEventId 
    }
  }
}         

OHIP sends event 193 and all events that occurred after event 193.

As noted in Broken Connections, if offset 193 was emitted more than 7 days ago, OHIP will return all messages emitted since 7 days ago. This is because OHIP retains events for only 7 days.

Retrieving the Latest Message

To retrieve only the latest message, use the "offsetType" parameter and specify the value as "highest." For example:

{
   "id": "1",
   "type": "subscribe",
   "payload": {
         "variables": {},
         "extensions": {},
         "operationName": null,
               "query": "subscription { newEvent(input: { chainCode: \"<CHAIN CODE>\" offsetType: \"highest\" } ) { metadata { offset } moduleName eventName detail { oldValue newValue elementName } } }"
   }
}

Streaming Scenario

Imagine the following scenario: A stream has produced 10 events over the previous 24 hours. A consumer has connected and consumed events 0 to 6 inclusive, and then disconnected again.

While the consumer is disconnected, events 7 to 10 occur.

If the consumer connects again without specifying an offset, then events 7 to 10 are sent to the caller followed by subsequent events.

If the consumer connects again and specifies an offset of 3, then events 3 to 10 are sent to the caller followed by subsequent events.

If the consumer connects with the offsetType highest, then only event 10 is sent, followed by subsequent events.


This figure shows earliest to the latest events in an event stream.

Therefore, only use the offsetType highest if you have no interest in historic events because you will no longer receive them. Similarly, you can never maintain the sequence of events if you use offsetType highest.

A good use case for offsetType highest is when a resource is changing rapidly, and you are only interested in the last state of the resource.

Note:

Do not use offsetType highest if you must synchronize an external system with OPERA Cloud as it would get (and remain) out of sync.

Interpreting the Event

Determining Changes

Three key fields are used to determine what has changed:
  • elementName

  • oldValue

  • newValue

New Records

When receiving the record of a new Reservation, the payload will include the following for each field in the Reservation:

{
   "elementName": "First Name",
   "newValue": "NewFirstName"
   "oldValue": null
}

Note:

For the polling API, the "oldValue" will not be in the payload.

Updated Records

The following scenarios reflect when a record is updated and a field is changed:

  1. If a field was blank before the update,

    The polling API returns:

    {
       "dataElement": "First Name",
       "newValue": "NewFirstName",
    }
    

    The streaming API returns:

    {
       "elementName": "First Name",
       "newValue": "NewFirstName",
       "oldValue": ""
    }
    
  2. If the field is updated with a blank value,

    The polling API returns:

    {
       "dataElement": "First Name",
       "oldValue": "TheOldFirstNameValue"
    }

    The streaming API returns:

    {
       "elementName": "First Name",
       "newValue": "",
       "oldValue": "OldFirstName"
    }
  3. If the field was not changed during this event,

    The polling API returns:

    {
       "elementName": "First Name",
       "newValue": "MyFirstName",
       "oldValue": "MyFirstName"
    }
    By default, the streaming API returns the same fields. However, if the "delta" input variable is set to true, the streaming API returns only fields whose value has changed. In this scenario, the elementName "First Name" would not be sent by the streaming API.

Removed Fields

If a field has been removed, this is reflected as:

{
   "elementName": "First Name",
   "oldValue": "OldFirstNameValue"
}

Retrieving Unchanged Fields

As you can see in Updated records, if a field remains unchanged neither the "oldValue" nor "newValue" is sent. To retrieve the current (unchanged) value, make a GET call to the resource using the "primaryKey" field that is sent in the event payload. For example, if the event is UPDATE RESERVATION, the primaryKey will be a reservationId, so the full resource can be obtained using the getReservation API.

Comparing the Event Payload from Polling and Streaming APIs

Polling API Business Event payload

{
    "businessEventData": [
        {
            "businessEvent": {
                "header": {
                    "moduleName": "Reservation",
                    "actionType": "NEW RESERVATION",
                    "actionId": "1234567",
                    "primaryKey": "987654",
                    "publisherId": "15951",
                    "createdDateTime": "2021-06-03 16:45:48.0",
                    "hotelId": "ABC123"
                },
                "detail": [                    {
                        "dataElement": "FIRST NAME"
                    },
                    {
                        "dataElement": "CONFIRMATION NO",
                        "newValue": "123456789"
                    }
                ]
            },
            "businessEventId": {
                "id": "1234567"
            }
        }
    ]
}

Streaming API Business Event payload

{
  "data": {
    "newEvent": {
      "metadata": {
        "offset": 100,
        "uniqueEventId": "0ed06ced-843e-4e35-86ec-e2564cf495ee"
      },
      "moduleName": "Reservation",
      "eventName": "NEW RESERVATION",
      "primaryKey": "123456",
      "timestamp": "2021-06-03 16:45:48.000",
      "hotelId": "ABC123",
      "publisherId": "15951",
      "actionInstanceId": "222222",
      "detail": [
        {
          "newValue": "NewFirstNameValue",
          "oldValue": "",
          "elementName": "FIRST NAME",
          "scopeFrom": "",
          "scopeTo": "",
          "elementType": null,
          "elementRole": null,
          "elementSequence": null
        },
        {
          "newValue": "123456789",
          "oldValue": "",
          "elementName": "CONFIRMATION NO",
          "scopeFrom": "",
          "scopeTo": "",
          "elementType": null,
          "elementRole": null,
          "elementSequence": null
        }
      ]
    }
  }
}

Table 12-3 Comparing Fields in the Polling and Streaming APIs

Section Field Name in Polling Section Field Name in Streaming Use

Header

moduleName

Event Header

moduleName

Grouping of events, useful guide to which API to use if unchanged data are needed.

Header

actionType

Event Header

eventName

Name of the event that occurred.

Header

actionId

Number of the event emitted from OPERA.

Event Header

actionInstanceId

Number of the event emitted from OPERA.

Header

primaryKey

Event Header

primaryKey

OPERA internal ID of the resource on which the event occurred. For example, an UPDATE RESERVATION event occurs on a reservation resource, so the primaryKey is the reservationId.

Header

parentActionId

Header

publisherId

Event Header

publisherId

User reference Id of the user who created the transaction in OPERA.

Header

createdDateTime

Event Header

timestamp

Date and time the event occurred.

Header

hotelId

Event Header

hotelId

OPERA internal Id of the hotel in which the event occurred.

Subscription

chainCode

OPERA Shared Security Domain organization code within which the event occurred.

Metadata

offset

Offset number of the event emitted from OHIP.

Metadata

uniqueEventId

Unique identifier for the event emitted from OHIP.

Detail

dataElement

Detail

elementName

Name of the field that changed.

Detail

oldValue

Detail

oldValue

Old value of the field that changed (see notes in the ‘Determining Changes’ section)

Detail

newValue

Detail

newValue

New value of the field that changed (see notes in the ‘Determining Changes’ section)

Detail

scopeFrom

Detail

scopeFrom

Beginning of the data range for which the business event is valid. For example, if a rate code or rate amount is different for different stay dates and the rate is updated, the scopeFrom determines the start of the stay date range that was updated.

Detail

scopeTo

Detail

scopeTo

End of the data range for which the business event is valid. For example, if a rate code or rate amount is different for different stay dates and the rate is updated, the scopeTo determines the end of the stay date range that was updated.

Errors

All errors result in the connection being broken and require the below fixes before connecting again.

Table 12-4 Potential Streaming API Errors and Fixes

Error Returned How does this Happen? How to Fix Error Type

429 Too Many Requests

Sending more than 150 requests to upgrade to WebSocket and sending the requests within 2 minutes from the same application.

Retry after 2 minutes.

HTTP

499

The client disconnected before the server was able to send a response to the initial HTTP upgrade, so the WebSocket was not opened.

Ensure your calling architecture is leaving the connection open long enough for the server to reply.

HTTP

1000 Normal Closure

The WebSocket was disconnected by the caller

Reconnect from the Authentication message.

WebSocket

1001 Going Away: Going away

Maintenance by Oracle

Reconnect from the Authentication message.

WebSocket

1006 Abnormal Closure: Abnormal Closure

Connection broken

Wait 4 seconds and then reconnect from the Authentication message.

WebSocket

Error: Unexpected server response: 400

Incorrect key or URL

  • Check the sha256 hash of the application key is correct.

  • Check that the application key is subscribed to consume events and that the event subscription is approved.

  • Check the URL matches the environment listed in the Developer Portal.

  • Check that the environment is Streaming Enabled.

HTTP

4400 Error: Bad Request - Invalid GraphQL Subscription

Invalid field in subscription message

  • Check the response body which includes details of the invalid field. For example, "Cannot query field XYZ on type ABC" or "Value for <FIELD> is invalid - Expected ABC to match pattern ZYZ."

  • Check that the fields in the subscription request match the OHIP schema Github link.

  • Reconnect from the Authentication message.

WebSocket

4401 Error: Unauthorised - Invalid credentials

Invalid credentials sent in the Authentication message

  • Check you are sending the application key, not the sha256 hash of the application key.

  • Check that the application is subscribed to consume events and that the event subscription is approved.

  • Check that the oAuth token is valid and current.

WebSocket

4403 Error: Forbidden - You are not authorized to access this resource

Invalid chainCode in subscription message

  • Check that the chain code in the subscription message matches the chain code being accessed. This is the value at the start of the integration that the user sent to obtain the oAuth token.

  • Check that streaming is enabled for the environment you are accessing

  • Reconnect from the Authentication message.

WebSocket

4406 Error: Subprotocol not acceptable

Failing to include the WebSocket protocol header.

Include the header "Sec-WebSocket-Protocol: graphql-transport-ws"

WebSocket

4408 Error: Disconnect

Connection initialization time out

Send the Authentication message within 5 seconds of opening the connection.

WebSocket

4409 Too Many Requests

More than one client or process is trying to consume events from the same gateway using the same application key and chain code.

This often happens in the following circumstances:
  1. When consuming events in code and in Postman/GraphiQL.

  2. Where multiple developers are trying to consume events from a single application.

  3. Where an application has spawned additional threads all consuming events from the same gateway, application key, and chain code.

  4. When disconnecting without sending the Complete message.

Ensure that only one client or process consumes events from a given gateway using a given application key and chain code.

Ensure that you send the Complete message before disconnecting from the WebSocket.

WebSocket

4429 Error: Too Many Requests

Resending the subscription message when the connection is already open

Resending the connection_init message when the connection is already open

The WebSocket connection is already open, so it cannot be reopened. Look for the connection_ack message and do not resend connection_init if you have received a connection_ack.

WebSocket

4500 Server Error - No configuration found. If this problem persists, contact Oracle Customer Support at the Customer Support Portal.

A Subscribe message was sent but either there are no events subscribed for this application, or the subscription is not approved by the environment owner.

Check that the application is subscribed to events and shows as approved for that environment.

WebSocket

4500 Unable to find configuration between Application, Chain, and Environment. Please ensure your application has access. If this problem persists, contact Oracle Customer Support at the Customer Support Portal.

A piece of internal configuration might be missing.

Ensure your application is approved to consume events and that the URL you are calling is a streaming enabled gateway. If the problem persists, contact Oracle Customer Support at the Customer Support Portal.

WebSocket

4500 Internal Server Error received 6 minutes after sending the subscribe message.

When subscribing, the consuming application should wait up to 6 minutes before receiving any events. If the subscription is valid and an internal issue has occurred, this message is received 6 minutes after sending the subscribe message.

Reconnect and send the Authentication message and then send the Subscription message.

WebSocket

4501 Socket closed with error 4501 Not Supported Environment for subscriptions

Connecting to an environment that does not support streaming Business Events.

Ensure the environment shows as "Streaming Enabled" on the Environments tab of the developer portal. Streaming Business Events from OPERA requires a minimum of OPERA Cloud version 22.3.0.1.

WebSocket

4504 Socket closed with error 4504 Service Timeout

This error occurs when the OCI Streaming Service goes down for more than 30 seconds.

Try again after 15 seconds. If this problem persists, contact Oracle Customer Support at the Customer Support Portal.

Websocket