Guide
Property systems
The five property-system connectors, the three port contracts they implement, how a deployment picks its reservation source, and what the Amadeus sales and catering connector is still missing.
Guest Intelli reaches into a property's existing systems in exactly three places: it looks a reservation up, it posts a charge, and it opens a check. Each of those is one small interface. Five vendor connectors implement them.
What each connector does
| Vendor | Reservation lookup | Folio posting | F&B check |
|---|---|---|---|
| Sabre SynXis Property Hub | yes | no | no |
| Oracle OPERA Cloud (OHIP) | yes | yes | no |
| Stayntouch Connect v2 | yes | yes | no |
| Hapi | yes | no | no |
| Oracle MICROS Simphony | no | no | yes |
SynXis is the CRS side of the house. A guest types a booking code the core has never seen, the SynXis connector looks it up live, and if the reservation is active the guest is recognized like any other. This is a read-only connection. Guest Intelli never writes anything back to SynXis, and it looks up one reservation at a time, only on a code the core does not already hold.
OPERA Cloud does both jobs. It can serve as the reservation source for a property whose system of record is the PMS rather than the CRS, and it is the folio sink: when a staff member completes a request in Hotel Operator, the value of that request posts as a single charge to the guest's folio. It posts one thing and only that. No reservation writes, no profile writes, no refunds, no voids, no transfers. If the post fails, the guest's request still completes and the charge needs posting by hand that one time.
Stayntouch covers the same two roles for properties on Connect v2, with a configured charge code carrying the posting.
Hapi is a normalization layer sitting between PMSs and downstream consumers,
so it appears here as a reservation source only. There is no Hapi folio route in
this build, which matters: a Hapi-sourced stay whose request completes under the
auto folio router gets a deliberate folio_skipped event rather than a
failure.
Simphony is the point of sale. When a dining request completes and a POS sink is configured, the core opens one check in the restaurant's revenue center and stamps the check reference on the booking row.
The port contracts
All five connectors implement interfaces defined in core/src/ports.ts. The core
knows nothing about any vendor beyond these three shapes.
TS
interface ReservationSource {
findByBookingCode(code: string): Promise<StaySeed | null>;
}
interface FolioSink {
postCharge(input: {
external_ref: string; booking_code: string; source_system: string;
amount_usd: number; reference: string; description: string;
}): Promise<{ posting_ref: string }>;
}
interface PosSink {
openCheck(input: {
booking_code: string; confirmation_code: string;
venue: string; party_size: number; amount_usd: number;
}): Promise<{ check_ref: string }>;
}
A StaySeed is the flat set of fields a vendor lookup has to produce:
booking_code, guest_first_name, room, tier, party_size,
arrival_date, departure_date, source_system, external_ref. Tier mapping
from a vendor's own loyalty vocabulary happens inside the connector, never in
the core.
stay-sync.ts turns a seed into a stay row. It derives stay_id as stay- plus
the lowercased booking code, inserts with INSERT OR IGNORE, sets origin to
live, and leaves analytics_consent, recognized_at, and session_token
null. A vendor lookup never counts as consent and never counts as recognition on
its own.
integration-routing.ts holds the two wrappers that make multiple vendors work
together. createChainSource tries each configured source in order and returns
the first hit. A source that throws is skipped, logged, and recorded as a
source_unreachable event, never fatal, so one dead vendor cannot take
recognition down. createRoutingFolioSink picks the sink by the stay's own
source_system. A stay from a system with no folio route throws the sentinel
folio_unrouted, and the completion path turns that into a folio_skipped
event rather than an outage.
openings-sources.ts sits alongside these but belongs to the federation side. See
Federated services.
Choosing sources at deploy time
Selection is entirely environment-driven, read at startup in core/src/main.ts.
Names only below. Never commit values.
| Variable | Meaning |
|---|---|
GI_RESERVATION_SOURCE | Comma-separated list of fixtures, synxis, opera, stayntouch, hapi. Default fixtures. Order is the chain order. fixtures cannot be combined with a vendor, and the process exits with one line if you try. |
GI_FOLIO_SINK | none (default), opera, or auto. auto routes by the stay's source system: OPERA and SynXis stays post to OPERA through a confirmation-number crosswalk, Stayntouch stays post to Stayntouch when its five variables are all set. |
GI_POS_SINK | none (default) or simphony. |
SYNXIS_BASE_URL, SYNXIS_CLIENT_ID, SYNXIS_CLIENT_SECRET, SYNXIS_HOTEL_ID | SynXis credentials. All four required when SynXis is selected. |
OPERA_BASE_URL, OPERA_CLIENT_ID, OPERA_CLIENT_SECRET, OPERA_APP_KEY, OPERA_HOTEL_ID | OHIP credentials. OHIP needs the app key on every business call in addition to the bearer token. |
STAYNTOUCH_BASE_URL, STAYNTOUCH_CLIENT_ID, STAYNTOUCH_CLIENT_SECRET, STAYNTOUCH_HOTEL_ID, STAYNTOUCH_CHARGE_CODE_ID | Stayntouch credentials plus the charge code postings are booked against. |
HAPI_BASE_URL, HAPI_CLIENT_ID, HAPI_CLIENT_SECRET | Hapi credentials. |
SIMPHONY_BASE_URL, SIMPHONY_TOKEN, SIMPHONY_ORG, SIMPHONY_LOC, SIMPHONY_RVC | Simphony endpoint, bearer token, organization short name, location reference, revenue center reference. |
Startup checks the whole set for a selected vendor at once and exits naming
every variable that is missing, rather than letting a connector fail later with a
confusing runtime error. The auto folio router is the one exception: an
incomplete Stayntouch environment disables that route and logs a line instead of
exiting.
Note that core/src/config.ts reads only the property config file
(config/solara-cove.json) and holds no environment logic. All of the above is
read in main.ts.
What "connected" means in this build
This build talks to vendor sandboxes, not production tenants. Each sandbox under
integrations/mock-* is built from that vendor's own public reference, and each
one ships a per-route fidelity table in its README marking every wire detail as
doc-derived, inferred, simplified, or mock-only. The SynXis and OPERA credentials
sheets in docs/integrations/ carry the certification checklists: the places a
guess needs confirming against a real tenant before a property goes live. Open
items there include SynXis's single-reservation lookup path, the expires_in
unit on its token, and the confirmation-number crosswalk OPERA's folio sink
depends on. None of the five connectors is enrolled in its vendor's partner
program yet.
Amadeus Sales & Event Management
Amadeus Sales & Event Management is the group sales and catering system most full-service hotels run their blocks, banquets, and events on. There is no connector for it and no sandbox for it in the kit. The socket exists, the plug does not.
The reason is documentation access. Every other vendor here is mocked from a public reference with a fidelity table behind it. Amadeus publishes no such reference: its developer portal lists product names with no API documentation and routes every request through a sales contact. The only public traces of its interfaces are third-party integration notes. A sandbox built from those would be a sandbox of hearsay, and a fidelity table reading "inferred from somebody else's help desk" is worse than saying the docs are gated.
The port contract already fits the work. Group blocks and rooming lists map onto
the chain reservation source exactly as Stayntouch and Hapi do, one
findByBookingCode per guest with source_system: 'amadeus' and the folio router
deciding where charges land. Event and banquet bookings map onto the same
PosSink pattern Simphony proved. A block arriving with a known code could
pre-seed a shared group plan so a wedding party lands with its plan already
standing. What is needed from Amadeus is one conversation and two artifacts: API
documentation access for the Sales & Event Management APIs and a sandbox
credential. With those, the connector is the same shape as the five already
built.