Skip to content

Connecting to OHIP

What you need from the OHIP Developer Portal

Section titled “What you need from the OHIP Developer Portal”

Create (or open) an application in the Oracle Hospitality Developer Portal and note, for the environment you want to use:

Value Where it goes Notes
Gateway URL OHIP_<ENV>_GATEWAY_URL For example https://<host>/. No trailing path.
Application key OHIP_<ENV>_APP_KEY Sent as x-app-key on every call.
OAuth client id and secret OHIP_<ENV>_CLIENT_ID, OHIP_<ENV>_CLIENT_SECRET Basic auth on POST /oauth/v1/tokens.
Enterprise id OHIP_<ENV>_ENTERPRISE_ID Client-credentials (“OCIM”) environments. Setting it selects the client-credentials grant.
Scope OHIP_<ENV>_SCOPE Client-credentials only. Default urn:opc:hgbu:ws:__myscopes__.
Integration user and password OHIP_<ENV>_USERNAME, OHIP_<ENV>_PASSWORD Password (“SSD”) environments only. Leave empty for client-credentials.
Hotel code OHIP_<ENV>_HOTEL_ID Sent as x-hotelid. OHIP requires it (or x-hubid) on every call, even chain-level ones.
Chain code OHIP_<ENV>_CHAIN_CODE Needed for streaming.
Hotel time zone OHIP_<ENV>_TIMEZONE Optional IANA id, default UTC.
Streaming URL OHIP_<ENV>_WEBSOCKET_URL Optional. Default wss://<gateway host>/subscriptions.

<ENV> is an upper-case environment name you choose. The rest of this README uses SANDBOX, which .env.example already contains. You can keep several sets side by side (OHIP_SANDBOX_*, OHIP_UAT_*, …) and pick one with --env.

For streaming you also need to subscribe the application to business events in the portal: open the application, then the environment, then Business Events, and select the events you want (at least reservation and profile events). Without that subscription the stream connects but delivers nothing.

Terminal window
set -a; source .env; set +a
dotnet run --project src/StayFn.Cli -- ohip ping --env sandbox --hotel "$OHIP_SANDBOX_HOTEL_ID"

This fetches a token and makes one read-only hotel call through the full StayFn pipeline. It prints token ok and the call result, and never prints secrets. A non-zero exit code means the token or the call failed. The error names the OHIP error code where one exists.

Step 2: seed a tenant that uses these credentials

Section titled “Step 2: seed a tenant that uses these credentials”
Terminal window
dotnet run --project src/StayFn.Cli -- dev seed --env sandbox --tenant "Sandbox (dev)"

This creates or updates one tenant, one environment and one default hotel. The environment stores references such as env:OHIP_SANDBOX_APP_KEY, never the values, so the host must see the same variables at run time. stayfn dev runs this seeding automatically.

With the host running (for example stayfn dev) and the dev tenant enabled:

Terminal window
curl -s -X POST http://localhost:5080/api/functions/rsv/get-reservation/invoke \
-H 'Content-Type: application/json' \
-H "X-Hotel-Id: $OHIP_SANDBOX_HOTEL_ID" \
-d '{"confirmationNumber":"<a confirmation number in that hotel>"}'

The response carries X-Invocation-Id. Open that invocation in the dashboard to see each OHIP call: operation, status, duration, retries and rate-limit waits. An unknown confirmation number returns 404 with an RFC 9457 problem body.

The reference functions you can call right away:

Function What it does
custom/ping-echo echoes its input, no OHIP call (smoke test)
rsv/get-reservation fetches a reservation by confirmation number (searchHotelReservations)
rsv/nightly-arrivals-export scheduled export of a hotel’s arrivals
rsv/sync-reservation-to-crm-stub target of the reservation.changed handler
rsv/count-arrivals counts a date’s arrivals, optionally for one room type (plain signature, {"date":"2026-10-01","roomType":"KING"})
rsv/arrivals-summary OHIP’s reported arrival total for a date (flat ctx.Ohip.Api.Rsv.SearchHotelReservationsAsync) next to the count of rsv/count-arrivals (typed client); Derived idempotency, so the same date replays
crm/search-profiles profile search (searchProfiles)
crm/upsert-profile creates or updates a guest profile (writes to OPERA)
crm/audit-profile-change target of the profile.changed handler

Handlers: reservation.changed → rsv/sync-reservation-to-crm-stub, profile.changed → crm/audit-profile-change.

  • Tokens. POST {gateway}/oauth/v1/tokens with Basic auth and x-app-key. It uses the password grant, or client credentials with scope and the enterpriseId header. Tokens are cached per environment and refreshed at the earlier of 80 % of their lifetime and exp − 2 min. Sandbox tokens live 8 hours.
  • Headers. Every call carries Authorization: Bearer …, x-app-key, x-hotelid (the request hotel, or the tenant’s default hotel for chain-level calls) and x-request-id (the StayFn correlation id).
  • Rate limits. OHIP documents about 50 requests/s per gateway, shared by all consumers, and throttles by delaying responses rather than returning 429. StayFn’s governor defaults to a token bucket of 40 with 40/s refill per app key. Each function declares its expected number of calls with [OhipBudget(n)] (default 10), and the budget is reserved before it runs. Tune it with STAYFN__Ohip__RateLimit__*.
  • Errors. OHIP error bodies (type, title, detail, o:errorCode) become OhipException. 408, 429, 5xx and network errors are transient and retried with backoff. Other 4xx errors are permanent. An empty 204 on a fetch, or a search with no match, becomes ResourceNotFoundException (404).
  • Asynchronous operations (the *async modules) use POST → 202 + Location → HEAD polling with retry-after → GET once.
  • One method per operation. ctx.Ohip.Api.<Module>.<Operation>Async (for example ctx.Ohip.Api.Crm.GetProfileAsync(profileId)) is generated from the pinned specs by tools/kiota/operations-facade: 2,843 of the 2,845 operations. It uses the same module clients as the Kiota chains, so it sends the same requests and leaves the same invocation_ohip_calls rows. Its hotelId defaults to the hotel that feeds x-hotelid. The rules and the two skipped operations are in tools/kiota/README.md.
  • Specs. The generated clients and the flat layer come from the specs pinned in tools/ohip-specs/26.3.0.0 (Oracle’s hospitality-api-docs, Swagger 2.0). tools/kiota/generate.sh regenerates both deterministically, and CI fails if the generated code drifts.

Everything above, with the evidence for each item, is in docs/adr/0002-ohip-facts.md.

Oracle’s partner sandbox is shared with other partners. Keep writes to a minimum, never load-test it, and never commit data read from it. The opt-in live tests in tests/StayFn.SandboxTests run only when the OHIP_SANDBOX_* variables are present.