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.
-
GraphiQL — This provides a visual playground for familiarizing yourself with the streaming API. The Connecting to the Streaming API via GraphiQL topic provides instruction on how to use this tool.
-
Postman collection — The Github and Postman Collections topic provides instruction on how to set up and use this tool.
-
Node reference implementation in TypeScript.
Customer Approval for Partners
A customer Developer Portal user can only approve the sending of business events for hotels to which they have access.
-
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.
-
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.
-
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
- Connecting to the Streaming API
- Broken Connections
- Replaying Messages
- Retrieving the Latest Message
- Interpreting the Event
- Errors
Parent topic: Business Events
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.
-
Open the Developer Portal and click the Applications tab.
-
Search for and click an application to open it.
-
Click the Events tab.
-
Click Add Event to Template and complete the following information:
-
Category: Select a category for the event, such as Reservation.
-
Event: Select an event for the category, such as Check In.
Note:
To remove an event from the template, click the Remove link.
-
-
Click Add to add the event to the template.
-
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.
-
Open the Developer Portal and click the Applications tab.
-
Search for and click an application to open it.
-
Click the Events tab.
-
Click the Subscribed tab.
-
Click the Subscribe link.
-
Select an Environment and click Subscribe.
-
As a customer subscribing to events from your environment, select which hotels will consume the events.
Note:
Only OPERA environments enabled for streaming appear in the list of environments.
Unsubscribing from Events
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.
-
Open the Developer Portal and click the Applications tab.
-
Search for and click an application to open it.
-
Click the Events tab.
-
Click the Subscribed tab.
-
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.
-
Open the Developer Portal and click the Applications tab.
-
Search for and click an application to open it.
-
Click the Partner Applications tab.
Note:
Applications with pending event subscriptions appear with a red ribbon icon on the application card.
-
Click an application with a pending event to open it.
-
Click the Events tab.
-
Click Next to proceed with approval.
-
Select the properties for the event subscription and click Next.
-
Click Approve.
Rejecting Events
-
Open the Developer Portal and click the Applications tab.
-
Search for and click an application to open it.
-
Click the Partner Applications tab.
-
Click an application with a pending event to open it.
-
Click the Events tab.
-
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
-
Open the Developer Portal and click the Applications tab.
-
Search for and click an application to open it.
-
Click the Partner Applications tab.
-
Click an application with a pending event to open it.
-
Click the Events tab.
-
Click Edit next to the list of hotels.
-
Deselect all the hotels.
-
Click Save.
Adding Events to Existing Subscription
-
Add the events on the Template tab (see the ‘Creating a Template of Events for an Application’ procedure above).
-
Subscribe again to consume events from the same environment (see the ‘Subscribing to Events’ procedure above).
Adding Hotels to an Existing Subscription
-
Open the customer or partner application.
-
Go to the Events tab.
-
Click Edit next to the list of hotels.
-
Select the hotels that can consume the events.
-
Click Save.
Parent topic: Streaming API (push)
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 |
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 |
Parent topic: Streaming API (push)
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.
Parent topic: Streaming API (push)
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.
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.
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.
Parent topic: Streaming API (push)
Interpreting the Event
Determining Changes
-
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:
- 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": "" }
-
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" }
-
If the field was not changed during this event,
The polling API returns:
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.{ "elementName": "First Name", "newValue": "MyFirstName", "oldValue": "MyFirstName" }
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
{
"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. |
Parent topic: Streaming API (push)
Errors
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 |
|
HTTP |
4400 Error: Bad Request - Invalid GraphQL Subscription |
Invalid field in subscription message |
|
WebSocket |
4401 Error: Unauthorised - Invalid credentials |
Invalid credentials sent in the Authentication message |
|
WebSocket |
4403 Error: Forbidden - You are not authorized to access this resource |
Invalid chainCode in subscription 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:
|
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 |
Parent topic: Streaming API (push)