Showing Availability and Rates in Near Real Time

Never sum daily prices yourself, never show "sold out" on failure — fetch and cache design principles

availability searchrate lookupcachingAPI rate limitsfail-safe
6 min read

Introduction

You type in "three nights from August 1st, six guests" and the site immediately tells you whether it's free and what the total comes to. On a booking site that feels completely ordinary — but behind the scenes, every one of those lookups fires a request at the channel manager.

This article covers the traps we actually fell into while building the availability and rate display, and how we got out of them. Lodging rates are far more complicated than they look, and if you build the obvious thing, the numbers will always end up wrong.

Never Calculate the Rate Yourself

Summing Daily Prices Will Always Be Wrong

The first version I built fetched daily rates and added them up. At ¥190,000 a night, three nights should be ¥570,000. Except the figure the channel manager actually quoted was nothing like that.

How to arrive at the rate
BEFORE
Summing daily rates yourself

Extra-guest fees, multi-night discounts, and minimum-stay rules never make it in, so the number drifts from the real charge

AFTER
Fetching a quote from the API in one call

The system calculates the total for "these dates, this party size" and hands it back. There's nothing left to get wrong

Lodging rates stack rule on top of rule: surcharges by party size, discounts for longer stays, seasonal pricing, minimum-stay requirements. All of that is configured inside the channel manager, and you simply cannot reproduce it from the outside by looking at daily rates.

So we switched to a quote API — hand it the stay dates and the party size, get the total back — and adopted the rule that we never do any of the arithmetic ourselves. The per-night figures shown on the calendar are indicative only and are never used for billing.

Count Guests the Same Way Everywhere

This property has a rate rule where "up to two children aged five and under stay free when sharing a bed." Which means what the screen calls "4 adults + 2 children" has to be treated as "4 guests" for pricing purposes.

The tricky part is that this conversion has to happen both when displaying and when confirming the booking. Fix only one of them and the screen says ¥570,000 while confirmation comes out at ¥600,000 — and the booking dies with a "the amount has changed" error.

So we pulled the guest-count conversion into a single function that both paths call. Don't write the same calculation in two places. It sounds obvious, but it's the kind of thing you usually only notice after something has already gone wrong.

Don't Turn "Couldn't Check" Into "Sold Out"

Four States, Not Two

Showing availability isn't a simple choice between "free" and "sold out". In practice we distinguish four states.

The most important one is the last: never, ever display "couldn't check" as "sold out". Show sold out because of a connection error and a guest gives up on dates that were actually free. Don't translate an error into an inventory status. That principle applies to plenty of other external integrations too.

When It's Sold Out, Offer an Alternative

Just saying "sold out" sends the guest straight back out the door. So when we detect a sold-out result, we automatically look for open stretches on either side of those dates and suggest them: "these dates are available."

Don't build dead ends. On a booking site, that alone moves conversion.

Living With the Cache

Cache for Exactly 60 Seconds

When the same dates get searched over and over, hitting the API each time is wasteful and pushes you toward the rate limit. So we cache search results for 60 seconds.

Lodging inventory doesn't move second by second, so information that's up to a minute stale is fine in practice. That said, right before a booking is confirmed we always bypass the cache and re-fetch. The display can be slightly stale; the moment money moves, it has to be current. That's the line we drew.

Never Forget to Clear It

The scariest thing about a cache is stale data hanging around after inventory has moved. We actually hit a bug where the screen kept saying "sold out" right after a guest came back from the payment page. Placing the hold had moved inventory, but the cache hadn't been updated.

When the cache gets refreshed
A hold was created

Inventory drops by one, so the cache is dropped immediately

A hold was released

Inventory comes back, so the cache is dropped immediately

A change notification arrived from outside

It might be an OTA booking, so drop the cache regardless of the contents

Periodic reconciliation found a difference

Drop the cache if the change affects inventory

Wrapping Up

Three things mattered most in getting availability and rates on screen.

  1. Don't calculate rates yourself — leave it to the API that returns a total, and keep daily prices as rough guidance only
  2. Don't translate errors into "sold out" — distinguish four states and be honest when you can't check
  3. Clear the cache inside the code that moves inventory — don't leave it to the caller; make forgetting structurally impossible

Holding inventory at the moment a booking is confirmed is covered in "A Booking Registration Flow That Prevents Double-Booking".