# Channex integration guideline
This is the canonical implementation and operations guide for Zapazime's multi-property Channex PMS integration. It covers architecture, configuration, property onboarding, two-way synchronization, certification, monitoring, failure recovery, and production rollout.
## Scope and ownership
Zapazime uses one centrally managed Channex account for all participating companies and properties. The API credential is platform-owned and must never be entered or displayed in company-admin screens.
The identity mapping is:
| Zapazime | Channex | Meaning |
|---|---|---|
| `Company` | Account/organisation context | Tenant ownership in Zapazime; not a separate Channex credential |
| `Venue` | Property | One sellable accommodation property |
| `VenueObjectType` | Room Type | Stable, venue-scoped pool of equivalent inventory |
| `VenueObject` | Physical room | An individually assignable unit inside a room-type pool; never mapped as a Channex Room Type |
| `RatePlan` | Rate Plan | A sellable price and restriction policy for one room type |
| `Booking` | Booking | Local reservation created or updated from a Channex booking revision |
Mapping physical `VenueObject` records directly to Channex Room Types is prohibited because it duplicates pooled inventory and creates overbooking risk.
## Architecture
The integration is a modular Laravel monolith. Small gateway services under `App\Services\Channex` correspond to Channex APIs, while orchestration, persistence, and retries live in application services and queued jobs.
| API/domain | Zapazime component | Responsibility |
|---|---|---|
| Shared transport | `ChannexClient` | Authentication, environment guard, JSON, timeouts, retries, pagination, normalized exceptions |
| Properties | `PropertiesService` | Property discovery, creation, and updates |
| Room Types | `RoomTypesService` | Pooled room-type creation and updates |
| Rate Plans | `RatePlansService` | Rate-plan creation and updates |
| Availability and Restrictions | `AriService` | Availability plus rate/restriction delivery |
| Booking Revisions | `BookingRevisionsService` | Account-wide feed and acknowledgement |
| Webhooks | `WebhooksService` | Registration, update, test, and disable operations |
| Property onboarding | `VenueOnboardingService` | Validation and ordered creation of remote mappings |
| Full inventory | `InitialAriSyncService` | 500-day snapshot and nightly reconciliation payloads |
| Incremental inventory | `AriOutboxService` | Transactional/coalesced ARI delivery |
| Incoming reservations | `BookingRevisionIngestService`, `BookingImporterService` | Secure, idempotent import and physical-room assignment |
| Lifecycle | `PropertyLifecycleService` | Approval, activation, pause, and safe disconnect |
See [Channex multi-property integration architecture](CHANNEX_INTEGRATION_ARCHITECTURE.md) for lower-level design rationale.
## Environment and secrets
Staging and production use different credentials and independent mapping records. Configure secrets only in the deployment secret store:
```dotenv
CHANNEX_ENABLED=true
CHANNEX_ENVIRONMENT=staging
CHANNEX_BASE_URL=https://staging.channex.io/api/v1
CHANNEX_STAGING_API_KEY=<secret>
CHANNEX_PRODUCTION_API_KEY=<secret>
CHANNEX_WEBHOOK_SECRET=<at-least-32-random-characters>
CHANNEX_ALERT_EMAIL=operations@example.com
QUEUE_CONNECTION=database
CACHE_STORE=database
DB_QUEUE_RETRY_AFTER=660
```
Use `CHANNEX_ENVIRONMENT=production` with `https://app.channex.io/api/v1` for production. The HTTP client and `channex:doctor` reject an environment/host mismatch. `CHANNEX_API_KEY` remains available as an explicit deployment override, but environment-specific keys are preferred.
Never commit, log, render, or copy API keys into tickets and documentation. Rotate any credential disclosed through chat, email, logs, screenshots, or source control.
## Database model
The integration uses dedicated tables:
- `channex_property_mappings`: one record per Venue and environment, remote property ID, lifecycle state, approval/activation timestamps, sync timestamps, metadata, and last error.
- `channex_room_type_mappings`: one local `VenueObjectType` mapping per property/environment, remote room-type ID, status, metadata, and errors.
- `channex_rate_plan_mappings`: one local `RatePlan` mapping per property/environment, linked room mapping, remote rate-plan ID, status, metadata, and errors.
- `channex_sync_outbox`: coalesced incremental ARI operations with date range, payload hash, attempts, delivery state, and errors.
- `channex_booking_revisions`: encrypted/sanitized inbound revisions with processing and acknowledgement state.
- `channex_certification_runs`: scenario request, response, Channex task IDs, and pass/fail evidence.
Core booking-room pivot data retains room-specific dates, amount/currency, Channex rate plan, OTA room identity, occupancy, guests, daily breakdown, taxes, services, and non-sensitive metadata.
## Property onboarding
Open **Company Admin → Channex**, verify the environment badge, and onboard one property at a time:
1. Run **Test Channex connection**.
2. Open the Venue and satisfy every readiness check.
3. Create/verify stable `VenueObjectType` pools and assign every physical `VenueObject` to one pool.
4. Create OTA-enabled `RatePlan` records and assign each to a room type.
5. Select **Prepare mappings**.
6. Synchronize the Property.
7. Synchronize Room Types and verify each pooled room count.
8. Synchronize Rate Plans and verify occupancy, currency, price, and restrictions.
9. Preview and send the 500-day initial ARI snapshot.
10. Register and test the booking webhook using a public HTTPS `APP_URL`.
11. Complete staging certification. In production, record the formal Channex approval.
12. Select **Activate** only after all checks pass.
Creating/synchronizing remote records does not automatically activate two-way synchronization.
## Property lifecycle
| State | Outbound ARI | Booking feed | Intended use |
|---|---:|---:|---|
| `draft` | Off | Account feed still polled | Mapping and validation |
| `live` | On | On | Normal two-way operation |
| `paused` | Off | On | Stop local outbound updates while still protecting against lost OTA bookings |
| `disconnecting` | Controlled closure only | On | Zero inventory/stop-sell is being delivered |
| `disconnected` | Off | Account feed still polled | Property is closed to new OTA sales through this integration |
Activation requires a remote property, synchronized active room/rate mappings, a successful full ARI sync no older than 26 hours, and a registered booking webhook. Production also requires `approved_at`.
**Pause is not a channel closure.** It leaves the last remote availability in place. Use **Safe disconnect** to send zero availability and stop-sell across the 500-day horizon, then disable the property webhook. Remote entity deletion is deliberately not automatic.
## Outbound synchronization
Availability is calculated from the physical rooms belonging to each `VenueObjectType`. Confirmed/checked-in bookings, room-specific booking dates, room blocks, maintenance, and out-of-order status reduce the pool.
Changes to bookings, room blocks, rooms, room types, rates, seasons, day modifiers, and restrictions enqueue an incremental outbox record. Changes are coalesced per property for approximately 30 seconds. Availability and restrictions are sent separately.
Reliability controls include:
- local per-property rate limiting for availability and restriction requests;
- one-minute cooldown after remote HTTP 429 or 5xx responses;
- serialized per-property queue jobs;
- retry/backoff for transient errors;
- payload-size protection below 10 MB;
- nightly, isolated 500-day reconciliation jobs staggered between properties;
- Channex warnings treated as visible delivery failures rather than silent success.
## Inbound booking synchronization
The webhook is a low-latency signal, not the booking payload authority. After validating `X-Zapazime-Channex-Secret`, Zapazime responds quickly and queues an account-wide Booking Revisions Feed poll. A scheduled poll every 15 minutes provides recovery if a webhook is missed.
For every revision Zapazime:
1. Resolves the remote property in the current environment.
2. Stores the sanitized revision idempotently by revision ID.
3. Removes guarantee/card data before persistence or logging.
4. Processes revisions oldest-first.
5. Locks candidate physical rooms and imports the booking transactionally.
6. Creates, modifies, or cancels the same local booking by OTA identity.
7. Persists room-level dates and financial/occupancy details.
8. Enqueues availability updates for affected old and new ranges.
9. Acknowledges the revision only after the local transaction commits.
Unmapped properties/room types and allocation failures remain visible and unacknowledged for operator recovery. The account feed remains active for paused properties because ignoring a sold OTA reservation is less safe than importing it.
## Runtime processes
Run database-backed queue and cache stores in multi-instance deployments. Deploy with:
```bash
php artisan migrate --force
php artisan optimize:clear
php artisan channex:doctor --live
php artisan channex:health
```
Supervise these processes continuously:
```bash
php artisan queue:work --queue=channex,default --tries=5 --timeout=600
php artisan schedule:work
```
The scheduler runs booking-feed recovery and health checks every 15 minutes and full reconciliation nightly. If the platform uses cron, invoke `php artisan schedule:run` once per minute instead of `schedule:work`.
## Monitoring and recovery
The company-admin property page displays pending/failed ARI deliveries, unacknowledged/failed booking revisions, webhook status, recent revisions, mapping state, and last full sync.
`php artisan channex:health` fails when it detects missing integration tables, failed/stale ARI work, old unacknowledged revisions, or stale/missing full synchronization for live properties. When `CHANNEX_ALERT_EMAIL` is configured, identical failures are deduplicated and one recovery notification is sent after health returns to normal.
Recovery order:
1. Do not acknowledge or delete failed inbound revisions manually.
2. Correct the local property/room/rate mapping or inventory problem.
3. Use **Retry** for the booking revision or **Retry failed ARI**.
4. Confirm the queue worker is consuming the `channex` queue.
5. Run `channex:health`, then inspect application and failed-job logs.
6. Perform a controlled full reconciliation if remote inventory remains inconsistent.
## Certification and go-live
Use the property **Certification workspace** for official scenarios 1–14. Scenarios 1–10 are hard-locked to the staging host and retain exact request/response evidence and Channex task IDs. Scenario 11 verifies create/modify/cancel/ack lifecycle. Scenarios 12–14 record the required implementation declarations.
Use the official Booking.com staging helper:
```bash
php artisan channex:test-booking --accounts
php artisan channex:test-booking <unique_id> --expect=new --wait=300
php artisan channex:test-booking <unique_id> --expect=modified --wait=300
php artisan channex:test-booking <unique_id> --expect=cancelled --wait=300
```
The production gate requires:
- all PMS certification scenarios completed and evidence retained;
- Channex approval recorded;
- new production credential stored and previously exposed keys revoked;
- production property/room/rate IDs independently mapped;
- HTTPS webhook registered and successfully tested;
- queue, scheduler, database cache, alerts, and failed-job monitoring operational;
- no stale ARI or unacknowledged booking failures;
- a single-property production pilot before wider activation.
See [Channex staging test runbook](CHANNEX_STAGING_TEST_RUNBOOK.md) for the detailed certification procedure.
## Official references
- [Start an integration](https://channex.io/start-integration)
- [Channex API documentation](https://docs.channex.io/api-v.1-documentation)
- [PMS certification tests](https://docs.channex.io/api-v.1-documentation/pms-certification-tests)
- [Booking revisions collection](https://docs.channex.io/api-v.1-documentation/bookings-collection)
- [Rate limits](https://docs.channex.io/api-v.1-documentation/rate-limits)
- [Booking.com test accounts](https://docs.channex.io/guides/test-account-for-booking.com)