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).
What GuestCraft sends
Section titled “What GuestCraft sends”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_atof the booking’s first storednewrevision. 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:
BookingComorBooking.com, the spec’sota_nameexamples of a booking revision and a booking. - Expedia:
ExpediaorA-Expedia. The spec gives noota_nameexample 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_feesdefaults 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_amountdefaults 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.
Idempotency and outcomes
Section titled “Idempotency and outcomes”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.
- 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. - 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. - The outcome is committed with its audit entry and event:
sent: Channex answered 200. The report is never sent again, and the publicreservation.ota_reported@1webhook event is published.failed: the report can be sent again. The reason is one of:not_supported: 422method_not_supported, answered asota_report.refused_by_channel;invalid_arguments: another 400 or 422, alsoota_report.refused_by_channel;booking_not_found: 404, alsoota_report.refused_by_channel;access_refused: 401 or 403, alsoota_report.refused_by_channel;unavailable: 429 or another answer that applied nothing, answered as 503server.unavailable.
unknown: the answer was lost (network failure or timeout), or a 408, 5xx or unreadable success may follow an applied report. The answer isota_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 reportsent;{ "received": false }makes itfailed(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.
API, permission and screens
Section titled “API, permission and screens”GET /properties/{property_id}/reservations/{id}/ota_reports(reservations.read): each report withavailable, 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, andPOST …/ota_reports/{kind}/reconcilerecords a checked outcome. Both needreservations.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) andwindow_closed(opens_at,closes_at); thenoutcome_unknown,refused_by_channel(reason) andnot_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.
What GuestCraft cannot know
Section titled “What GuestCraft cannot know”- 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.