SimphonyPOS DataStream (Oracle Simphony)
Written by AI, not reviewed by a human. Please apply the written-by-ai-not-reviewed label. The contract below comes from Oracle's published documentation — no live Simphony account has been exercised.
Integrates Oracle Simphony as a NexSigns DataStream source, so a Digital Menu Board can bind to a property's live menu.
Source name |
|
Vendor API | Simphony Configuration and Content API ("ccapi") — not Transaction Services |
Docs | REST endpoints; auth is documented separately under Transaction Services Gen 2 and applies to all Oracle Restaurants APIs |
Status | CODE COMPLETE, UNVERIFIED LIVE |
Why this one is different
Simphony is the only one of the fourteen POS sources whose native data model is already "item with sizes". A menu item master is the logical item ("Coffee") and owns up to 64 definitions ("Small", "Medium", "Large"), each with its own price records. Every other source needs a heuristic to guess which modifier group represents size; Simphony needs none, and sizes come out in the operator's own defSequenceNum order — Small before Medium before Large, not alphabetical.
It also has the most intricate authentication of the six, and the one most likely to cause an operational incident if handled carelessly. See Authentication below.
Configuration
Handed to the customer verbatim in the Data Streams "Add" dialog:
{
"DataSource": "SimphonyPOS",
"Version": "1.0",
"Host": "<Replace Simphony Host e.g. https://xxxxx-ohsim.oracleindustry.com>",
"OrgShortName": "<Replace Organization Short Name>",
"Username": "<Replace API Account Username>",
"Password": "<Replace API Account Password>",
"ClientID": "<Replace OAuth Client ID>",
"HierUnitID": "<Replace Hierarchy Unit ID>",
"Locale": "en-US",
"PriceSequenceNum": 1,
"PriceDecimalPlaces": 2,
"Currency": "",
"IncludeConsumerContent": true
}Field | Meaning |
|---|---|
| Every Simphony customer is on their own Oracle host. A pasted value with or without the scheme, and with or without a trailing path, is normalized down to the origin. |
| The organization short name, sent on the sign-in step. |
| The Simphony API account. The password is never written to the refresh log, event log, an exception message or a query string — not even as a fingerprint. |
| The OAuth 2.0 client identifier Oracle issued. Logged only as |
| Scopes every read to one property. Numeric. Blank is legal and returns the whole enterprise — on a multi-property customer that is both slow and wrong for a single board. |
| Which language to take from Simphony's name maps. Default |
| Which menu level's price to show. |
| The Configuration API exposes no currency code on any menu resource, so decimals are configured rather than derived. |
| Display only. Nothing in the price path reads it. |
| Prefer the guest-facing |
A helper endpoint lists the property's category structure so a customer can see what the board's grouping will look like before building a design:
GET /api/nexsigns/DataStreams/GetSimphonyPOSAvailableFamilyGroupList?DataStreamGUID=...It is keyed on DataStreamGUID rather than taking credentials as parameters, so no secret ever rides in a query string.
Authentication
Simphony locks an API account for 30 minutes after repeated failed sign-ins, and API account passwords expire every 60 days. The integration caches its token for 14 days specifically so the password crosses the wire as rarely as possible. Do not "simplify" the token caching away, and do not debug a credential problem by retrying in a loop.
Three steps, OpenID Connect with PKCE:
GET /oidc-provider/v1/oauth2/authorize— establishes the session cookie.POST /oidc-provider/v1/oauth2/signin— username + password + orgname. Answers with the authorization code in a JSON body rather than by redirecting. That is what makes the whole flow drivable from a server with no browser.POST /oidc-provider/v1/oauth2/token— code + PKCE verifier, returns the tokens.
Three things are load-bearing and easy to lose:
The cookie jar. Step 2 only succeeds while carrying the cookies step 1 set.
RestClientOptions.CookieContainerdoes not exist in RestSharp 109 — the version this solution is pinned to; it arrived in 110 — so the cookies are relayed by hand, with a parser tolerant enough to survive severalSet-Cookievalues merged into one header. Do not restore aCookieContainerwithout upgrading the package for every other consumer in the solution.Redirects must not be followed. The target is
apiaccount://callback, a custom scheme no HTTP stack can navigate to.The bearer is the
id_token, not theaccess_token. Oracle's own documentation says the access token is unused by Restaurants APIs. Picking the wrong one produces a 401 on every call with nothing to indicate why.
Token lifetimes: id_token 14 days, refresh_token 28 days. The integration renews 7 days early via the refresh grant — no password involved — and only falls back to a full sign-in if that fails. Both tokens live in DataStream.TempIntegratorData, scoped by client ID + host + username so changing any of the three invalidates the cache.
API contract
Every read is a POST. That is not a mistake in the code — Oracle models reads as POST bodies (getMenuItems, getMenuItemPrices, …) so that searchCriteria, includeAll and the paging fields have somewhere to live.
Call | Supplies |
|---|---|
| parent category names |
| the board's categories, plus consumer names/descriptions and images |
| the logical items — name, |
| the sizes — names, descriptions, images, |
| one price record per definition per menu level |
Paging is offset/limit with an authoritative hasMore flag; 500 rows per page, capped at 20 pages per resource. includeAll: "detailed" is sent because "basic" omits every extended value and would leave a board with names and prices only.
Prices are decimal major units — 8.49 means eight dollars forty-nine. No division anywhere. (That matches NCRPOS and RevelPOS, and is the opposite of SquarePOS, CloverPOS and PARPOS.)
How the menu is normalized
{
"source": "SimphonyPOS", "schema_version": 1,
"host": "...", "hier_unit_id": "1012", "location_name": "",
"locale": "en-US", "price_sequence_num": 1,
"currency": "", "price_decimal_places": 2,
"categories": [ { "id", "name", "description", "parent_id", "parent_name",
"sort_order", "image" } ],
"items": [ { "id", "name", "description", "object_num", "category_ids": [],
"image", "thumbnail", "alt_text", "dietary_labels", "prep_time",
"sold_out",
"variations": [ { "id", "name", "definition_id",
"def_sequence_num", "price_amount",
"menu_level", "sold_out", "is_default",
"source" } ] } ]
}Notable projection rules:
Categories are family groups with their major group as the parent, rendered in the picker as "Major Group / Family Group".
The item's name, description and image come from the first DEFINITION, not the master. That is where Simphony actually keeps them — a master carries only a name and its group references — so reading them off the master would leave every board row without a picture or a description.
A master with no definition at this hierarchy unit is dropped. It is a shell inherited from a higher level and is not sellable here.
When a definition has no price for the configured
PriceSequenceNum, the lowest sequence it does have is used rather than an arbitrary one.Images are chosen by lowest
imageIndexso the choice does not depend on array order — the change-detection hash runs over this document.
Data fields available in the Smart Menu Editor
Name, Definition Name (Size), Price, Description, Image URL, Thumbnail URL, Image Alt Text, Object Number, Dietary Labels, Prep Time, Menu Level, Definition Sequence, Inventory Status, Item ID, Currency.
Inventory Status always reads "available". The Configuration and Content API is exactly that — configuration — and carries no availability, 86 list or stock count on any menu resource. The field is implemented rather than omitted so a design carried over from ToastPOS or CloverPOS keeps working.
No calories. Nutrition lives on Simphony's separate nutrient sets, which the menu resources only reference by object number and which this integration does not fetch. A calories binding resolves to a blank, not an error token.
Multi-property designs
A binding records the item's objectNum and name into its fallback key. That is the right choice for a chain: menuItemMasterId is a surrogate that differs per property, whereas objectNum is the number the operator assigns and, in an enterprise configured top-down, is identical everywhere. So one design authored at one property resolves correctly at the others.
Troubleshooting
Symptom | Likely cause |
|---|---|
"signin was rejected" | Wrong username / password / org short name — or the account is locked for 30 minutes after earlier failures, or the password has hit its 60-day expiry. Reset it via the Reporting and Analytics portal. |
"the token response carried no id_token" | The client ID is wrong, or the OAuth client is not configured for the authorization-code + PKCE flow. |
Sync succeeds but keeps zero items |
|
Every price resolves |
|
Paging exceeded the budget |
|
Names in the wrong language |
|
Known gaps
No availability of any kind (see above).
No nutrition / calories.
Condiments, combo meals and menu item groups are fetched by neither the sync nor the projection — only masters, definitions, prices and the two group levels.
location_nameis projected as a blank pending a hierarchy-unit lookup.No webhook — the menu refreshes on the hourly interval.
Verification status
Done: builds clean (0 errors); the editor partial parsed with the real Razor engine (0 parser errors) and verified pure ASCII; every contract above traced to Oracle's published documentation.
Not done: no live Simphony call; no offline assertion harness; no end-to-end walkthrough in the running app.
Attempt Simphony end to end early. Of the six integrations this is the one with the most argued-from-documentation surface — the PKCE sign-in, the hand-rolled cookie relay and the id_token-not-access_token choice are all unverified against a real host. Budget for the 30-minute account lockout while debugging.