Salta ai contenuti

Reporting OTA bookings through Channex

Questi contenuti non sono ancora disponibili nella tua lingua.

From an OTA booking’s reservation, a front-desk member can report a guest’s no-show or an invalid card to the booking’s channel. If the guest never replaces the card, the member can then cancel the booking for that reason. GuestCraft sends each report through Channex’s Booking Reporting API. Decisions are in ADR 0032, “Reporting to the OTA”.

Everything here runs against the independent Channex simulator and injected transports. A live Channex check is still needed (see certification).

The operations and the quotes below come from Channex’s official public OpenAPI (https://openapi.channex.io/public/openapi.json, captured 2026-11-01, sha256 50d36d7e56db57ebbe2446cb45c16f8fe577976034be02ef4f350e008c3a8eaf; it declares version 0.0.0, so this guide cites operation IDs). The repository’s curated snapshot, packages/channex-simulator/src/openapi.snapshot.json, keeps the three operations’ paths, answers and schemas at that sha256, but not their operation IDs or descriptions: the quotes are the upstream spec’s.

Report Channex operation Channels Window, as Channex describes it Window GuestCraft applies (property time zone)
Invalid card POST /bookings/{id}/invalid_card (BookingOtaReports_invalidCard), empty body Booking.com “Available immediately after the reservation is made, up until midnight (00:00) on the day of check-in, in the property’s local timezone.” From the booking’s creation until 00:00 on the arrival date
Cancel over an invalid card POST /bookings/{id}/cancel_due_invalid_card (BookingOtaReports_cancelDueInvalidCard), empty body Booking.com “Available when the guest has not provided valid card details within the allowed update window after an invalid-card report: usually 24 hours; 12 hours or until 3 pm (whichever is earlier) for bookings made within 48 hours of check-in; always at least 2 hours.” From the end of the update window after GuestCraft’s own successful invalid-card report until 00:00 on the departure date
No-show POST /bookings/{id}/no_show (BookingOtaReports_noShow), body {"no_show_report": {"waived_fees": …, "penalty_amount": …}} Booking.com, Expedia “Available from 00:00 (midnight, property-local time) on the planned check-in date, up to 48 hours later, provided the reservation’s status allows modifications and the reservation is not overbooked.” From 00:00 on the arrival date for 48 elapsed hours

Each window includes its start and excludes its end. The arrival date is the earliest arrival among the rooms the booking still holds, and the departure date is the latest departure.

  • Booking creation. This is the inserted_at of the booking’s first stored new revision. When GuestCraft holds no such revision (history imported after the booking changed), the reservation’s creation time stands in. That time is later than the real one, so the invalid-card window can open late but never early.
  • No-show window across a time change. The 48 hours are elapsed hours: on a daylight-saving change the window ends at 23:00 or 01:00 local time.
  • Update window. This is GuestCraft’s reading of Channex’s sentence, to confirm at certification:
    • The window is 24 hours.
    • It is shorter only for a booking whose exact creation time is known and which was made less than 48 hours before 00:00 of the arrival date in the property’s time zone (the start of check-in, as for the no-show and invalid-card windows). The shorter window is the time until the next 15:00 in the property’s zone at or after the report, at most 12 hours and at least 2 hours.
    • When the creation time is inexact, the 24 hours open the cancellation later, never earlier.
  • When the cancellation closes. Channex documents no end for it. GuestCraft stops offering it at 00:00 on the departure date.
  • Reports made elsewhere. A report made on the channel’s extranet is invisible to GuestCraft, and so cannot open the cancellation.

The channel is the booking’s Channex ota_name, compared without case, spaces or punctuation:

  • Booking.com: BookingCom or Booking.com, the spec’s ota_name examples of a booking revision and a booking.
  • Expedia: Expedia or A-Expedia. The spec gives no ota_name example for Expedia; these two spellings are GuestCraft’s unverified assumption, to confirm against a live booking.

Any other channel, Expedia’s affiliate networks included, answers ota_report.channel_unsupported; report it on that channel’s extranet.

  • No-show. The local no-show comes first (policies): every room the booking still holds must already be recorded as a no-show, with its own fee or waiver. The web app offers Mark no-show and report, which records the local no-show first, then sends the report. If the report then fails, the local no-show stays recorded.
    • waived_fees defaults to the local outcome: true only when the no-show fees posted were waived. ADR 0032 posts no fee on an OTA booking, so the default is “not waived”: the channel’s own no-show terms apply.
    • For Expedia only, penalty_amount defaults to the no-show fees posted and not waived (none on an OTA booking today).
    • The member can change both before sending.
    • An overbooked stay is never reported, whatever its rooms’ status: it is refused before the stay status is checked, so the web app offers no Mark no-show and report for it.
  • Card reports. An invalid-card report or a cancellation over an invalid card changes nothing in GuestCraft: no local cancellation, released inventory or fee. The reservation follows the OTA’s next booking revision through booking import.
  • Penalties. They stay with the policies and the folio; reporting posts no money.

Channex has no idempotency key and no endpoint that reads a report back. GuestCraft stores one report per reservation and kind (table booking_ota_reports). A booking maps to one reservation per workspace, so this is also one report per booking and kind.

  1. In one transaction, the request checks the rules and claims the report as sending, with an audit entry and an event. A concurrent or repeated request finds the claim and answers the stored report (200) without calling Channex.
  2. The Channex call runs outside any transaction, in one 10-second attempt that is never retried. It goes to the Channex installation that verified the workspace’s key (ADR 0050). A sandbox connection whose key production verified fails closed as ota_report.property_not_linked.
  3. The outcome is committed with its audit entry and event:
    • sent: Channex answered 200. The report is never sent again, and the public reservation.ota_reported@1 webhook event is published.
    • failed: the report can be sent again. The reason is one of:
      • not_supported: 422 method_not_supported, answered as ota_report.refused_by_channel;
      • invalid_arguments: another 400 or 422, also ota_report.refused_by_channel;
      • booking_not_found: 404, also ota_report.refused_by_channel;
      • access_refused: 401 or 403, also ota_report.refused_by_channel;
      • unavailable: 429 or another answer that applied nothing, answered as 503 server.unavailable.
    • unknown: the answer was lost (network failure or timeout), or a 408, 5xx or unreadable success may follow an applied report. The answer is ota_report.outcome_unknown.

An unknown report is never sent again blindly, also not after a crash: a sending report older than two minutes reads as unknown. The member checks the channel’s extranet and records what it shows with POST …/ota_reports/{kind}/reconcile:

  • { "received": true } makes the report sent;
  • { "received": false } makes it failed (not_received), so it can be sent again.

Reconciling is audited and calls nothing upstream.

Audit entries and events carry identifiers and safe facts only: the kind, channel and computed window, the fee flags, the failure reason and the actor (Principal.credential for an integration). They never carry card data, guest data, upstream bodies or secrets.

  • GET /properties/{property_id}/reservations/{id}/ota_reports (reservations.read): each report with available, the problem a request would answer (refusal), its window, the local no-show’s fee state and the stored report.
  • POST …/ota_reports/{kind} sends it, and POST …/ota_reports/{kind}/reconcile records a checked outcome. Both need reservations.report_to_ota, which the built-in administrator and front desk roles hold, for the property.
  • Problem codes:
    • ota_report.invalid (422, field);
    • 409, in the order a request checks them: ota_report.not_ota_booking, channel_unsupported, property_not_linked, reservation_cancelled, overbooked (no-show only), stay_status_not_allowed, invalid_card_not_reported (cancellation only) and window_closed (opens_at, closes_at); then outcome_unknown, refused_by_channel (reason) and not_unknown;
    • 503 server.unavailable.
  • See the API changelog.
  • The reservation’s Policies area shows a Report to the OTA group: each report with its window in the property’s time zone, the reason it is unavailable, a confirmation, and the sent, failed or unknown state with the reconcile actions.
  • Whether the OTA acted on a report Channex accepted.
  • Reports made on the channel’s extranet.
  • The outcome of a report whose answer was lost.
  • The channel’s own no-show fee.
  • Whether a window GuestCraft computes matches the channel’s in every case: Channex does not publish the time it measures “check-in” from.

The simulator answers 422 method_not_supported for an unsupported OTA but models no window, because the OpenAPI documents no error shape for a closed one.