Skip to content
DBAI

Case study · Owner-operated short-term rental

We didn't just build a website. We built the systems that run the rental.

The Sunset House is a two-bedroom, two-bath rental in north San Diego County, booked on its own site, on Airbnb and on Vrbo. This is not a client engagement: the property's operator is part of the team that built these systems. We built the booking site, the nightly job that prices it, the app its cleaning staff sign off in, and the portal for a guest's deposit hold. The booking site carries DBAI's credit in its theme and footer.

What follows is what is running, what is still in build, and how each part works. One n8n workflow is live, and it is described down to its guard rails.

Project
The Sunset House · the-sunset-house.com
Industry
Short-term rental · north San Diego County
Context
An owner-operated rental, not a client engagement. Booking site, channel and pricing wiring, one nightly n8n job, a staff app and a deposit portal.
booking channels live

3

direct, Airbnb and Vrbo · listings checked November 10, 2026

nights compared with the pricing engine

366

at go-live, September 1, 2026, and again after the September 3 repair

rate accuracy

100%

zero price mismatches in either comparison · 366 of 366 nights

mobile page weight, approximate

4.07 → 2.44 MB

homepage · recorded September 1, 2026

the-sunset-house.com

The Sunset House homepage: a welcome headline over a living-room photo, with a Book the House form for check-in, check-out and guests built into the page.
the-sunset-house.com, captured November 10, 2026. The booking form is part of the page, not an embedded widget from a channel manager.

Visit the-sunset-house.com (opens in a new tab)

The challenge

Three channels, one calendar, one price.

One house is sold in three places. Each place has to agree on which nights are free and what a night costs, and the direct site's price calendar is not written by the channel manager. A business that sells the same thing in more than one place will recognize the problem.

  1. 01

    A price calendar outside the pricing engine's path

    PriceLabs prices the listing, and the listing is keyed to Lodgify. The direct site keeps its own price calendar inside the booking theme, outside that path. Until September 1, 2026, no scheduled job connected the two.

  2. 02

    A deposit taken at check-in

    From June 2026 the security deposit was moved offline, to check-in, and the booking site's order page said so. It was a manual step, outside the booking flow.

  3. 03

    A turnover that has to leave a record

    Each turnover produces facts the operator needs: what was cleaned, what is missing or damaged, what is running low. The app they are recorded in runs in English and Spanish.

  4. 04

    A homepage too heavy for a phone

    On September 1, 2026 the homepage weighed about 4.07 MB on mobile. Most of that was six background photos sent at desktop size to every device.

The stack

What it runs on.

Six layers, top to bottom, each listed with what is in it. Names are the ones in the real stack.

  1. Guest-facing: the direct site (WordPress, WPRentals, a child theme credited to DBAI, WooCommerce checkout, Cloudflare in front as checked November 10, 2026), plus the Airbnb and Vrbo listings.
  2. Channels: Lodgify is the channel manager for the Airbnb and Vrbo listings, as recorded on September 1, 2026; a scheduled iCal import brings booked dates into the site calendar.
  3. Pricing: PriceLabs, with a minimum-price floor; its listing is keyed to Lodgify.
  4. Automation: n8n. Nightly rate sync, live. Failure alert, wired; fired once on record, September 3, 2026. Deposit text reminders, in build.
  5. Payments and deposits: Stripe for card payments at checkout (went live June 19, 2026) and for the deposit hold; the deposit portal on Next.js, Vercel and Neon Postgres; Twilio for one-time sign-in codes.
  6. Operations: one staff app for cleaning checklists and inventory counts, live, on Next.js, Prisma and Postgres.
  • WordPress
  • WPRentals
  • WooCommerce
  • Stripe
  • Cloudflare
  • Lodgify
  • PriceLabs
  • Airbnb
  • Vrbo
  • n8n
  • Next.js
  • Vercel
  • Neon
  • Twilio

Product names and marks belong to their owners. They describe the stack and imply no partnership or endorsement.

The booking site

Built to take the booking itself.

The site is not a brochure that hands off to a marketplace. A guest picks dates, sees the calendar and checks out on the property's own domain.

Platform

WordPress with the WPRentals booking theme and a child theme credited to DBAI in its own header. The booking form sits on the listing page and on the homepage, and hands off to a WooCommerce checkout. There is no channel-manager widget in the page: the listing's page source contains no reference to Lodgify, checked November 10, 2026.

In June 2026 the cart and checkout were moved back to classic WooCommerce and given booking-specific formatting, and card payments went live through Stripe on June 19, 2026.

Speed, twice

The first pass was the network. On June 20, 2026 the domain moved behind Cloudflare. DNS lookups that people had reported taking around ten seconds resolved in about 30 milliseconds.

The second pass was the page. By September the first response arrived quickly and the page still felt slow on a phone, so we measured the whole page instead of the first response. Six background photos were going out at desktop size to every device, and the page builder's lazy-loading skipped them because they sat in moving background layers. We generated tablet and mobile versions and wired them in. On a phone those six backgrounds went from 2,446 KB to 945 KB. Mobile page weight went from about 4.07 MB to about 2.44 MB, roughly 40% lighter, as recorded on September 1, 2026.

A tour, room by room

A photo tour page walks the house in order: 12 sections and 45 photos when it shipped on September 1, 2026. The site states its own position on price there: "Booking direct here is always our best rate."

The rules, on the listing

The listing carries its own details and rules block: cancellation terms, and no smoking, no pets, no parties. A guest can read it before starting a booking.

the-sunset-house.com

The listing page with its Book Now panel open on a two-month date picker, showing the direct site's own date picker for choosing a stay.
The listing's own date picker, captured November 10, 2026. Choosing dates here starts a booking on the direct site.

the-sunset-house.com

The foot of the listing's Property Details block, with its cancellation terms, and the Terms and Conditions block, with smoking, pets and parties struck out.
Details and rules as the listing publishes them, captured November 10, 2026.
The Sunset House logo: a bronze half-sun over horizon lines with roof lines at left, beside the property name in serif capitals.
The property's horizontal lockup, an SVG at five to one, as the site header uses it.

Channels and pricing

One pricing engine. Two paths to three channels.

PriceLabs sets the nightly rate. The rate then has to arrive in three places, and it does not travel the same road to all of them.

  1. The PriceLabs listing is keyed to Lodgify; that connection is the vendors' own and we have not inspected it. Lodgify is the channel manager for the Airbnb and Vrbo listings, as recorded on September 1, 2026.
  2. Separately, an n8n job reads a year of nightly rates and the minimum price from PriceLabs every day at 5:00 a.m. Pacific and writes them into the direct site's calendar.
  3. Booked dates reach the direct site from the channel side by scheduled iCal import.

The marketplace path. Lodgify is the channel manager: the tool that keeps one listing in step across marketplaces. A build note of September 1, 2026 records the Airbnb and Vrbo listings as children of the Lodgify listing in the pricing engine, and as of November 9, 2026 Vrbo reservations reach the operator's reservation records through Lodgify. The PriceLabs listing is keyed to Lodgify. That connection belongs to the two vendors. We did not build it, and our records show how it is keyed, not the rate push inside it.

The direct path. The direct site takes bookings natively, so the nightly rate in its calendar is the rate a direct booking is priced on. That calendar lives inside the booking theme, where the channel manager does not write. So we built the second path: a nightly job in n8n, a workflow automation tool, reads PriceLabs and writes the site's calendar directly. It writes the recommended price, rounded to a whole number, and adds nothing on the way.

Availability. Booked dates reach the site calendar from the channel side by scheduled iCal import, the shared-calendar format. The pricing job does not touch availability.

The automation

One job, every night at 5:00 a.m.

One n8n workflow is live for the property. It rewrites live prices on a site that takes real bookings, so most of its design is about what happens when something is wrong.

  1. Every day at 5:00 a.m. Pacific the job starts and loads its settings: the listing, a 365-day window, and dry run explicitly off.
  2. Rates branch: read a year of nightly prices from PriceLabs; stop if the source reports an error, the data is more than two days old or fewer than 30 nights come back; otherwise write the site's price calendar in one write.
  3. "From" price branch: read the minimum price from PriceLabs; check it is a number inside a set range; write it so the listing card tracks the floor.
  4. Each network step is tried up to three times.
  5. When a run fails, a second workflow diagnoses the cause in plain language and emails the operator. The calendar keeps its last good prices.

What it does.

Every day at 5:00 a.m. Pacific, an n8n workflow asks PriceLabs for a year of nightly rates and writes them into the site's price calendar. A second branch reads the minimum-price setting from PriceLabs and writes it as the "from" price on the listing card, so that headline tracks the floor rather than the cheapest night that happens to be coming up.

When it refuses.

The job stops before writing if PriceLabs reports an error, if the pricing data was last refreshed more than two days ago, or if fewer than 30 priced nights come back. The minimum price has to be a real number inside a set range. Every network step is tried up to three times. The two-day check exists because a pricing service can answer successfully with data that has stopped updating, and every other signal would look healthy.

On the site side.

The job writes through code of our own on the site, installed so that a stray click in the admin does not switch it off. It fails closed: a request that does not explicitly ask for a live write is treated as a dry run and writes nothing.

What we fixed before it ran.

The first draft of the integration had five defects, and four of them failed silently. One would have reported a complete success while writing nothing. The largest: the theme's built-in price writer is made to save one pricing period per request, so a year of nights could not go through it in one call. We rewrote the write to build the whole year in memory and save once. That write went from failing at 60 seconds to finishing in 1.6.

How we knew it worked.

We did not trust the job's own report. Before the first live write we proved the job's date keys matched the theme's own, because a mismatch would have written prices to the wrong dates, then snapshotted the existing prices and wrote a one-command restore. After the write, we compared the site against PriceLabs night by night: 366 nights, zero mismatches, on September 1, 2026.

When it fails.

A second workflow is wired to the job as its error handler. When a run fails, it turns the error into a plain-language diagnosis and emails the operator. It names the likely cause: a wrong listing reference, pricing sync switched off at the source, rejected credentials, stale data, too few nights, a timeout on the site, or theme functions not loaded. It also states the consequence. The calendar keeps its last good prices, so a failed night means selling at stale rates, not selling at zero. It reports a run that fails. It cannot report a run that never starts.

The one outage on record.

The job failed on the two mornings after go-live, September 2 and 3. Two saved credentials in n8n had been filled in wrongly, so the pricing service never received its key. The alert that reached the operator on September 3 was for the second failed run; the record does not establish why no alert was seen for the first. With the credentials corrected, the next run completed and wrote nothing: the job's own dry-run setting was still on, a second fault. The site treats anything short of an explicit instruction to go live as a rehearsal. With the setting cleared, the run was checked against a fresh PriceLabs pull: 366 nights, zero mismatches, and the "from" price confirmed written. Two nights of stale rates, repaired and re-verified on the morning of September 3.

The run record.

n8n keeps recent executions, not all of them. The 30 it held on November 10, 2026, one per day from October 12, all finished without error. That is n8n's own run status, not a check of the site; the night-by-night comparisons above are from September. Earlier runs are no longer retained, so we do not quote them. No failed run is retained in that window, so the alert has had nothing to report in it. The published workflow has not been edited since the September 3 repair, and the schedule held at 5:00 a.m. Pacific through the November clock change.

  • Nightly rate sync

    Live

    Since September 1, 2026. Writes a year of PriceLabs rates and the "from" price into the direct site every day at 5:00 a.m. Pacific.

    100% rate accuracy in both comparisons · 366 of 366 nights · September 1 and September 3, 2026

  • Failure alert

    Wired · fired once on record

    Wired to the rate sync as its error handler. Built to email the operator a diagnosis and the consequence when a run fails.

    Fired on record once, September 3, 2026 · not exercised since: no failed run in the retained window, October 12 to November 10, 2026

  • Deposit text reminders

    In build

    Two text reminders about the deposit hold are drafted in n8n and switched off. Neither has been published and neither has run. No guest has received a reminder from either.

    Each draft sends at most one message per booking, re-checks the reservation or the hold immediately before sending, and is set not to keep guest phone numbers in its run history.

    They stay off until delivery has been tested end to end.

The staff app

An ops tool built for the property. Not the other way around.

One app covers the turnover: the cleaning checklist and the inventory count are the same report. It is built for this one property, loaded with this house's rooms and this house's items.

Live

Who it is for.

Cleaning staff. It installs as a web app, runs in English or Spanish, and gives each member of staff their own sign-in.

What a report is.

A member of staff starts a checklist by hand. It runs in four steps: an electronics check, a kitchen inventory, consumables, then the cleaning tasks room by room. An unfinished checklist can be resumed. The last screen summarizes what is missing or damaged, which counts did not match, what is low and which tasks are open, and it will not submit without a signature. The submission is timestamped.

What it counts.

Electronics are marked present, missing or damaged. Kitchen items are counted against an expected number. Consumables are marked full, low or empty, and can be flagged for reorder. Staff can add notes and attach photos to a report.

What the operator gets.

Signed reports, a shortage report with damage photos, a reorder queue of everything flagged, and an archive that exports to CSV. The operator also manages the staff list, the item lists and the reference photos staff work from.

What it does not do.

Nothing triggers it. No booking, checkout time or automation opens a checklist, and the app has no inbound integration. The reorder queue is a list, not an alert.

The record.

It is built on Next.js, Prisma and Postgres. The repository's history, as copied on August 6, 2026, runs from March 13 to July 2, 2026, ending with fixes from a code review, and a May 2026 planning record names it as the live single-property app. Its deployment was responding when we checked on November 10, 2026, and the operator confirms it is live and in use.

The deposit portal

A hold, not a charge.

The deposit now has a portal: a Next.js app on Vercel built to place a card authorization through Stripe and to show the arrival details only once the hold is confirmed.

Portal
Livesince November 9, 2026 · guest orders placed through it
Release and capture
the operator's step, by hand · not built into the portal
Text reminders
In buildnot sending

The hold.

The portal is built to place a card authorization that is held, not collected, normally $1,000. No payment is taken when it is placed.

Signing in.

A guest is meant to sign in with an identity tied to the booking: a one-time code sent by text, or a sign-in through an account they already have, depending on how the stay was booked. Delivery of that code to a guest's own phone had not been tested in production as of November 9, 2026. The booking lookup is built to give the same answer whether or not a booking is found. Which stays use the portal follows each booking channel's own rules.

What stays locked.

Arrival details stay hidden until the reservation has a confirmed, active hold. Access details are stored encrypted, under versioned keys, so a key can be rotated without losing older records.

What gets recorded.

The terms and the damage fee chart are published as immutable versions, and each acceptance records the version and a hash of the text the guest agreed to. Actions land in an audit log that the database itself refuses to update or delete. Stripe's webhooks, the messages it sends back about a payment, are de-duplicated by event id, so a replayed event is processed once.

Expiry.

Card authorizations expire. The portal is built to read the expiry from Stripe rather than calculate it, and to place a renewal's new hold before the old one is canceled.

Where reservations come from.

The portal reads reservations, read-only, from the operator's reservation records, which import them from Lodgify and from the booking site. It is wired to report deposit status back.

Add-ons.

The same portal also offers add-ons for a stay, such as early check-in and late check-out.

What is not automated.

Release and capture. They are not built into the portal, and nothing does either on a timer. They are left to the operator to do by hand after checkout.

What this page can and cannot show.

The portal went live on November 9, 2026, and the operator confirms guest orders have been placed through it since. The evidence behind this section is its design; a Stripe test-mode run on a preview deployment that day, covering a declined card, a successful hold, a bank verification challenge, a renewal and a replayed webhook; and checks on the production launch, where the live webhook endpoint accepted a signed, harmless live-mode event and rejected unsigned and test-mode ones. The portal also refuses objects and events from the other Stripe mode, test or live.

The numbers

What was measured, and when.

These figures are properties of the build and its checks, with the date each was taken where it has one. They are not business results.

booking channels live

3

direct, Airbnb and Vrbo · listings checked November 10, 2026

n8n workflow live

1

the nightly rate sync · two reminder workflows in build · as of November 10, 2026

nights compared with PriceLabs

366

at go-live September 1, 2026, and again after the September 3 repair

rate accuracy

100%

zero price mismatches in either comparison · 366 of 366 nights

mobile page weight, approximate

4.07 → 2.44 MB

homepage, about 40% lighter · recorded September 1, 2026

languages in the staff app

2

English and Spanish

How it connects

How it all connects.

Every arrow below is a connection our records show. The connections among PriceLabs, Lodgify, Airbnb and Vrbo are the vendors' own and are drawn as recorded, not inspected. Dashed arrows are in build. The deposit arrows are built and live. The map is not a complete inventory: it draws the parts this page describes.

  1. A guest books on the direct site, on Airbnb or on Vrbo.
  2. The direct site takes card payment through Stripe at checkout.
  3. The PriceLabs listing is keyed to Lodgify; that connection is the vendors' own and we have not inspected it. Lodgify is the channel manager for the Airbnb and Vrbo listings, as recorded on September 1, 2026.
  4. Booked dates reach the direct site from the channel side by scheduled iCal import.
  5. Every day at 5:00 a.m. Pacific an n8n job reads a year of rates and the minimum price from PriceLabs and writes the direct site's price calendar and "from" price.
  6. If a run fails, an alert workflow emails the operator the cause and the consequence.
  7. The operator's reservation records import reservations from Lodgify and from the direct site.
  8. The deposit portal reads those reservations read-only and is wired to report deposit status back.
  9. A guest signs in to the portal, accepts the terms and authorizes a hold through Stripe; Stripe's webhooks are de-duplicated.
  10. Once the hold is confirmed the portal shows the guest the arrival details.
  11. Release or capture after checkout is the operator's to do by hand; the portal does not do it.
  12. In build, not sending: the portal is wired to hand deposit-hold events to a text-reminder workflow that is switched off.
  13. Cleaning staff start a checklist in the staff app by hand and sign the report; the operator reads the signed reports, the shortage report, the reorder queue and the export.
  14. We found no connection from n8n to the staff app, and none from a booking to a cleaning task.
Staff start each checklist by hand. We looked for a connection from n8n, or from a booking, to the staff app and found none.

Build record

The build, by date.

Dates from commits, deploy records and session notes. The records give dates, not a complete account of time spent, so this page states dates and no durations.

  1. February – March 2026

    Booking site rebuild

    A time note from that period records the rebuild as the main focus from early February to early March.

  2. March 2026

    Staff app begins

    First commit of the staff app on March 13.

  3. May 2026

    Staff app fills out

    Early May: damage photos in the shortage report, reference photos, staff management and the CSV archive. A planning record that month names it as the live single-property app.

  4. June 2026

    Checkout, payments, network

    Cart and checkout moved back to classic WooCommerce. Stripe card payments live on June 19. Domain moved behind Cloudflare on June 20.

  5. July 2026

    Staff app review

    Fixes from a code review, July 2. The last code change in the copy we read.

  6. September 2026

    Pricing job live

    September 1: the nightly rate sync goes live and is verified at 366 nights, zero mismatches; the failure alert is added the same day. The mobile page-weight cut and the photo tour ship that day too. September 2 and 3: the one recorded outage, two failed runs, repaired on the morning of September 3.

  7. November 2026

    Deposit portal

    The portal goes live on November 9 with the add-ons store. Two text reminders were drafted the same day and remain in build.

This study reports the systems as built and their recorded status. It makes no claim about bookings, revenue or occupancy.

Next

Your business deserves the same treatment.

Bring us the operation, not just the website. We map what runs it, build the parts that are missing, and tell you plainly which parts are live.