One August afternoon a booking came in from Airbnb for four nights, in an apartment where a Booking.com guest was already staying. Our client has two apartments, a booking site we built for him, and both big channels synced through iCal. Everything showed “synced” on all three sides.
Airbnb cancelled the booking with a full refund to the guest and no penalty for the host, once we showed them what had happened. The more useful part was what we found while looking for the cause, because it is not a bug in one platform. It is how iCal works, combined with a change of our own that was reasonable and had a side effect.
In short
- iCal carries only blocked dates, and each platform reads it with a delay of hours.
- Our own change to the export made Booking.com hide its reservations, and our site read that as a cancellation.
- The fix: export depending on who is asking, a register of nights only a person can release, and a weekly report.
How iCal works, and what it does not do
iCal is a link ending in .ics that lists the dates that are taken. Each platform publishes its own link and reads the links of the others. Nothing is pushed. Each side goes and asks whenever it likes.
- Airbnb says in its help centre that it refreshes imported calendars roughly every 3 hours, with a manual refresh button and a limit on how often you can use it.
- Booking.com says on its partner page that syncing is not instant and can take up to two hours.
- iCal carries availability only. No prices, no minimum stay, no guest details.
So even when everything works, there is a window of hours in which the same night is open on two channels. That is the known risk of iCal, and for a small property it is usually acceptable. Our case was different.
What actually happened
When Booking.com exports its calendar, it leaves out the dates that were blocked because it read them from an imported calendar. That is a sensible loop protection: it does not send back to you what you sent to it. We saw it clearly in the extranet. September was red, labelled with our own site as the source, and the Booking export contained not a single September event.
A week earlier we had changed the site’s export so that it also included bookings arriving from the channels, to make it complete. From that moment we were sending Booking its own reservations back. The figure below follows one reservation around the loop, step by step.

The loop ran every 2 to 3 hours. On one apartment we counted 84 cancel-and-restore cycles in five days. Each time, the nights stayed open on Airbnb for a short while. One of those times was enough.
A second finding made the picture murkier. Booking builds the identifier of each reservation in the iCal from the date range. While the guest was already in the apartment, the range “slid” every morning (9-16, then 10-16, then 11-16), so every day showed up as a new reservation. That is why we also had duplicate entries on the site.
The change that triggered all of it was ours. We say so because it is the most useful lesson here: in a network of calendars, every change to what you export changes what the others send back to you.
What we changed
- Export depends on who is asking. The site recognises whether the request comes from Booking or from Airbnb, and does not send a channel back the days that were blocked only because of that same channel. Anything that corresponds to a real booking from the site or from another channel is always sent. On one apartment, what Booking was reading dropped from 399 events to 21.
- A booking that never unlocks by itself. Every night that any channel has ever declared booked goes into a register and stays closed until a person releases it. This proved its worth within an hour: when Airbnb cancelled the wrong booking, the nights stayed closed. Without it they would have reopened, with the Booking guest inside the apartment.
- A report someone can read. Every Monday at 08:00 the owner gets an email with the bookings per apartment, the status of each calendar and when it last refreshed. A separate email goes out the same day only if something critical happens: the same night booked on two channels, a calendar that has not refreshed for over 6 hours, or no calendar read at all within 24 hours. It also shows nights that stay closed with no booking justifying them any more, because that is lost revenue too.
After the change, Booking republished its reservation normally, and the booking on the site came back on its own without manual work.
If you run on iCal, check these
- What your Booking export contains. The calendar sync page in the extranet has an option for whether the export holds only booked dates or also blocked ones. Know which one you use.
- Where each calendar ends up. Draw it on paper: who reads whom. If A reads B and B reads A together with whatever came from C, you have a loop.
- What your system does when a booking disappears. If it cancels automatically and opens the dates, that is where the risk is. A booking vanishing from a feed does not always mean a cancellation.
- When each calendar last refreshed. Airbnb shows the time of the last update for every linked calendar. If it is old, something is not being read.
- Same-day bookings. With sync delays of hours, a booking for tonight on one channel may not reach the other in time. If you have a history of this, consider a minimum notice before arrival.
When is iCal not enough? When you have several units of the same room type, when you want prices and minimum stay to update everywhere from one place, or when you have more than two channels. Then you need an API connection, which means a channel manager, plus a booking engine on your own site that reads the same availability. We compare those options, and when each one is worth it, in a separate piece on booking engine, channel manager and PMS.
What we build for accommodation, from the booking site to channel sync, is on the Hospitality page. The channels we have connected in production are on Integrations. If you have already seen double bookings and do not know where they come from, write to us. We start from the feeds themselves, not from assumptions.
