11 November 2026 · 3 min read
Mirror the API you depend on.
Why the Luminous site reads from its own Postgres copy of Hostaway instead of calling it on every page view, and how webhooks and small scheduled jobs keep that copy honest.
Most of what a rental website shows belongs to someone else. The listings, photos, calendars, prices and reviews on Luminous live in Hostaway, the property management system the team runs their business on. The obvious way to build the site is to ask Hostaway for everything, every time a page loads.
I didn't, and it's the decision I'd defend first in that whole project.
The problem with asking live
A page that calls a third-party API on every view inherits all of that API's bad days. It is as slow as their slowest response and as available as their least available minute. It is also rate-limited by someone who has never seen your traffic: a search engine crawling forty listing pages, or a newsletter going out, can burn through a request budget meant for the team's own tools.
And a search page that filters by dates, bedrooms and guests would need to ask about every listing's calendar to answer one question.
Keep a copy, treat it as a cache
Instead, the site keeps its own copy of what it needs in Postgres: listings, a calendar per listing, reservations and reviews. Every page reads from that copy. A page view never waits on Hostaway, and search becomes a normal database query.
The copy is a cache, not a second source of truth. Hostaway stays the owner. The site never edits a listing locally and hopes it sticks; when the team changes something from the admin console, the change is written to Hostaway first and mirrored back.
Two ways to stay fresh
A cache is only as good as how it stays current. This one uses two mechanisms, because each covers the other's weakness.
Webhooks for what changes often. When a reservation is created or changed in Hostaway, it calls the site, and the copy updates within seconds. Webhooks can repeat, so each one is recorded by a hash of its contents and processed once, no matter how many times it arrives.
Scheduled jobs for everything else, and as a safety net. Calendars, listings and reservations are re-synced on a schedule, from every few minutes to once a day depending on how quickly each kind of data really changes. If a webhook is ever lost, the next sync quietly corrects it.
The jobs are deliberately small. Each one syncs one kind of data, so it finishes well inside the time limit of a serverless function, and one slow sync can't hold up the others.
Be a polite client
The sync jobs are the only part of the system that talks to Hostaway in bulk, so they are the part that has to behave. They share a small client that limits how many requests run at once, spaces them out, and backs off when the API says slow down. The rest of the code never calls the API directly; it can't accidentally start a stampede.
Where it bends
A mirror has a cost: for a short time the copy can be behind. For browsing that's fine. For booking it isn't, which is why availability at checkout adds the site's own in-flight bookings on top of the mirrored calendar (I wrote about that in Never sell the same night twice).
It's also more moving parts than "just call the API". The trade is worth it when the API isn't yours, the pages are, and the people visiting them shouldn't feel the difference.
The short version
- Read from a copy you control; write to the system that owns the data.
- Keep the copy fresh twice over: events for speed, schedules for certainty.
- Put one polite client between you and the API, and route everything through it.