Channel Manager (Channex)
The Channex integration distributes our catalogue to OTAs through the Channex channel manager. Unlike the Staah and Livbnb integrations — which pull rates and inventory into our database — Channex is a push integration: we mirror our catalogue up into Channex, push availability and rates, and receive bookings back.
It lives in the admin-api module under com.elivaas.pms and is driven by manual admin endpoints.
Entity Mapping
| Our entity | Channex entity |
|---|---|
Listing (lst_…) | Property |
Property (prop_…) | Room Type (+ one primary Rate Plan) |
Inventory (per property/date) | Availability (ARI) |
ChannelRate (per property/date) | Restriction / rate (ARI) |
| Channex Booking | Stored raw and acknowledged |
A single listing becomes one Channex property; each of the listing's properties becomes a room type with a primary rate plan underneath it.
How It Works
Admin onboards a listing (channelId=chnl_X)
│
ChannexSyncService.onboardListing(listingId, channelId)
│ Resolve per-channel credentials from channels.channel_config
│
├─ Create/update Channex PROPERTY ← Listing
│ store channex_property.channex_property_id
│
├─ For each property:
│ Create/update ROOM TYPE ← Property
│ Create/update RATE PLAN (primary)
│ store channex_room_type.{room_type_id, rate_plan_id}
│
└─ Register a booking WEBHOOK (idempotent)
store channex_property.channex_webhook_id
Admin pushes ARI
│
ChannexSyncService.pushAri(listingId, channelId, from, to)
├─ Inventory → POST /availability (keyed by room_type_id)
└─ ChannelRate → POST /restrictions (keyed by rate_plan_id)
Channex sends a booking
│
POST /api/channex/webhook?channelId=chnl_X
└─ ChannexBookingService: fetch full booking → persist raw → ack
Stored Mappings
Channex UUIDs are persisted so subsequent syncs update in place rather than creating duplicates. Three tables back the integration (migration 047-add-channex-tables.sql):
| Table | Grain | Holds |
|---|---|---|
channex_property | one row per onboarded listing | channex_property_id, channex_webhook_id, status, last error/sync |
channex_room_type | one row per property | channex_room_type_id, channex_rate_plan_id, status |
channex_booking | one row per inbound booking | raw payload, status (RECEIVED/ACKED/FAILED) |
Each mapping row carries a status (PENDING / SYNCED / FAILED) and a last_error, so a partial sync is visible per entity.
Configuration
Credentials are stored per channel in the channels.channel_config JSONB column, so multiple Channex accounts and environments can coexist:
| Field | Meaning |
|---|---|
channexApiKey | Account API key, sent as the user-api-key header |
channexEnvironment | STAGING (default) → staging.channex.io, PRODUCTION → secure.channex.io |
channexGroupId | Channex group UUID a created property is associated with |
channexWebhookSecret | Optional shared secret for verifying inbound webhooks |
The webhook callback host is set with the channex.webhook.base-url application property; the registered callback URL embeds ?channelId= so the receiver can resolve the right credentials.
See Catalogue Mapping, Availability & Rates, and Bookings & Webhooks.