> ## Documentation Index
> Fetch the complete documentation index at: https://opencals.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Bali Villa Rentals — villa booking template

> Free, open-source villa and holiday-rental website template. Next.js 15, nightly stays with fixed check-in and check-out, a calendar on live availability, per-stay extras, guest details, Stripe checkout and passwordless accounts, built on the Opencals Storefront API.

A complete villa-rental website you can clone and deploy today. Bali Villa
Rentals is the first template built around **nightly stays**: each villa is
booked by the night, from a check-in date to a check-out date, with a fixed
**check-in at 15:00 and check-out at 11:00**. Start here if you rent villas,
cabins, guest houses or rooms by the night. It runs on the same
[Storefront API](/docs/api-reference/introduction) and typed
[TypeScript SDK](/docs/guides/storefront-sdk) as [Haar](/docs/open-source/haar),
[Frisor](/docs/open-source/frisor), [Clear Care](/docs/open-source/clarity),
[VOLT](/docs/open-source/volt), [NOIR Drive](/docs/open-source/noir) and
[Fluently](/docs/open-source/fluently).

The demo brand is **Lumbung Sidemen**, ten villas in the rice fields of
Sidemen, East Bali (USD, `Asia/Makassar`). The design is warm and quiet:
limestone paper, jungle green and a single terracotta accent, with every
nightly rate shown.

<CardGroup cols={3}>
  <Card title="Live demo" icon="external-link" href="https://template-bali-villas.vercel.app">
    template-bali-villas.vercel.app
  </Card>

  <Card title="Source code" icon="github" href="https://github.com/letsopencals/template-bali-villas">
    letsopencals/template-bali-villas (MIT)
  </Card>

  <Card title="Deploy to Vercel" icon="rocket" href="https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fletsopencals%2Ftemplate-bali-villas&env=OPENCALS_API_KEY,AUTH_SECRET&envDescription=API%20key%20from%20your%20Opencals%20dashboard%20and%20a%20random%20secret%20for%20auth&project-name=bali-villas&repository-name=template-bali-villas">
    One-click deploy
  </Card>

  <Card title="Build it with AI" icon="sparkles" href="/docs/ai-agents/build-booking-site-skill">
    rentals-multi-day reference
  </Card>
</CardGroup>

<Frame caption="Bali Villa Rentals — the storefront on desktop and mobile, demo brand Lumbung Sidemen">
  <img src="https://raw.githubusercontent.com/letsopencals/template-bali-villas/main/docs/cover.png" alt="Bali Villa Rentals website template on a laptop and a phone on a villa terrace above the rice fields" />
</Frame>

<Frame caption="Homepage hero — a flyover of the valley with a price pin on every villa">
  <img src="https://raw.githubusercontent.com/letsopencals/template-bali-villas/main/docs/homepage-hero.png" alt="Bali Villa Rentals template homepage hero, an aerial view of rice terraces with nightly price pins over the villas and a date and guest search" />
</Frame>

## Nightly stays

Guests pick a villa, then a check-in and a check-out date on a calendar that
reads the villa's live availability. Booked nights are struck through, and the
calendar stops the check-out date at the next booking. Guests (adults, children,
infants), arrival time, flight number and the occasion are collected in the same
flow. Extras such as an airport transfer or a floating breakfast are added once
per stay. The total is always **nights × nightly rate + extras**, the same maths
the engine charges.

<Frame caption="Reserve — stay dates, guests and arrival details, extras and a running total">
  <img src="https://raw.githubusercontent.com/letsopencals/template-bali-villas/main/docs/reserve.png" alt="Bali Villa Rentals template reserve page with check-in and check-out dates, guest counts, arrival time, extras and a stay summary" />
</Frame>

## The stay model

This is the part worth copying even if you never ship this template. It uses
existing Opencals features only.

| Piece | How it's modelled |
| - | - |
| A villa | One staffless product in its own product pool, `duration: 86400` (one night), `allowCustomDuration: true`, `maxDuration` (21 nights in the demo), `maxAttendees: 1` |
| Check-in and check-out | `fixedTimes: true`, `fixedStartTime: "15:00:00"`, `fixedEndTime: "11:00:00"`. The API rejects a customer booking that doesn't start and end at these times |
| Availability across midnight | A continuous 24/7 schedule |
| Date picker | `getCurrentAvailabilitiesMerged` **without** `duration`; the client checks that the stay fits inside one range |
| The slot | Check-in date 15:00 → check-out date 11:00 in the schedule timezone, sent in UTC |
| Turnover day | A check-out day can be the next guest's check-in day (out at 11:00, in at 15:00) |
| Guests, arrival time, flight number, occasion | Appointment [custom attributes](/docs/changelog/custom-attributes) |
| Minimum nights | Per-villa content in the template (`lib/villa-content.ts`), checked in the calendar |
| Extras | Add-ons charged once per stay |
| Cancellation | `allowCustomerCancel` with `cancelGap` of 14 days; customers can also move their dates |

A stay at Lumbung Sidemen, check-in 14 Nov and check-out 17 Nov, becomes
`{ fromDate: '2026-11-14', fromTime: '07:00:00', toDate: '2026-11-17', toTime: '03:00:00' }`
(UTC+8): three nights, priced as three units, three × the nightly rate.

Give each villa its own product rather than a variant: variants don't block each
other, so the same villa could be booked twice.

## What's inside

<Frame caption="Villas — all ten houses, with collection filters and a search by dates and guests">
  <img src="https://raw.githubusercontent.com/letsopencals/template-bali-villas/main/docs/villas.png" alt="Bali Villa Rentals template villas page listing villas with nightly rates and collection filters" />
</Frame>

<Frame caption="Villa page — gallery, rooms and amenities next to the booking calendar">
  <img src="https://raw.githubusercontent.com/letsopencals/template-bali-villas/main/docs/villa-page.png" alt="Bali Villa Rentals template villa page for Joglo Agung with a photo gallery and a reservation card" />
</Frame>

<Frame caption="Site map — find each house on the terraces">
  <img src="https://raw.githubusercontent.com/letsopencals/template-bali-villas/main/docs/site-map.png" alt="Bali Villa Rentals template illustrated site map of the resort with each villa marked on the rice terraces" />
</Frame>

<Frame caption="My trips — the next stay with its dates, nights and arrival details">
  <img src="https://raw.githubusercontent.com/letsopencals/template-bali-villas/main/docs/account.png" alt="Bali Villa Rentals template My trips page showing the next stay at Pondok Bambu with check-in and check-out dates and night count" />
</Frame>

<Frame caption="Trip page — check-in from 15:00, check-out by 11:00, guests, extras, payment, and buttons to change dates or cancel">
  <img src="https://raw.githubusercontent.com/letsopencals/template-bali-villas/main/docs/trip.png" alt="Bali Villa Rentals template trip page with stay details, change dates and cancel buttons, payment summary and directions" />
</Frame>

<Frame caption="Mobile — the villa page at phone size">
  <img src="https://raw.githubusercontent.com/letsopencals/template-bali-villas/main/docs/mobile.png" alt="Bali Villa Rentals template villa page on a mobile screen" />
</Frame>

| Feature | Notes |
| - | - |
| Home | Video hero with villa pins and a date and guest search, the valley, a day at the resort, experiences, testimonials and FAQ |
| Villas | All ten villas with collection filters (rice barns, pool villas, family houses, signature), a search by dates and guests, and a map |
| Villa pages | Gallery, room tour, sleeping arrangements, amenities, house rules, reviews and a cancellation timeline next to the booking calendar |
| Reserve | Stay dates, guests and arrival details, per-stay extras, checkout questions, promo code, a hold countdown and Stripe payment |
| Trip-aware accounts | Check-in → check-out dates in the resort timezone, night count and guest details; customers can change dates (same number of nights) or cancel within policy |
| Passwordless accounts | 6-digit email login, one-time email links via `/link/[token]` |
| Editorial pages | Experiences, journal, about and getting there |
| Motion | Lenis smooth scrolling, a gate curtain on first visit, reveals and parallax; every effect has a reduced-motion fallback |
| SEO | Per-page metadata, Open Graph, `LodgingBusiness`, `VacationRental` and `FAQPage` structured data, `robots.txt`, `sitemap.xml` |
| Stack | Next.js 15, TypeScript, Tailwind v4, Framer Motion, `@opencals/storefront-sdk` v0.3.17 |

## Get started

<Steps>
  <Step title="Clone and install">
    ```bash theme={"theme":{"light":"github-light","dark":"github-dark-default"}}
    git clone https://github.com/letsopencals/template-bali-villas.git
    cd template-bali-villas
    npm install
    ```
  </Step>

  <Step title="Add your API key">
    Create a store in the [Opencals dashboard](https://opencals.com) and choose
    the **Bali Villa Rentals** dataset preset (category Villa resort,
    `villa_resort`). It seeds the ten villas on a 24/7 schedule with fixed
    check-in and check-out, collections, extras, checkout questions and sample
    stays. Then grab a Storefront API key (see [Authentication](/docs/authentication))
    and set `OPENCALS_API_KEY` and `AUTH_SECRET` in `.env.local`.
  </Step>

  <Step title="Run it">
    ```bash theme={"theme":{"light":"github-light","dark":"github-dark-default"}}
    npm run dev
    ```

    Your villas, rates and availability render immediately.
  </Step>

  <Step title="Deploy">
    Push to your own repo and
    [deploy to Vercel](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fletsopencals%2Ftemplate-bali-villas\&env=OPENCALS_API_KEY,AUTH_SECRET\&envDescription=API%20key%20from%20your%20Opencals%20dashboard%20and%20a%20random%20secret%20for%20auth\&project-name=bali-villas\&repository-name=template-bali-villas),
    or host anywhere Next.js runs.
  </Step>
</Steps>

<Note>
  Pages are server-rendered, so their API calls carry no browser `Origin`.
  Leave **allowed origins** empty on the key you give this template, or those
  calls are rejected.
</Note>

<Note>
  Set **Storefront Base URL** in your dashboard (Settings → API) to your
  deployed domain. Every customer link (view, reschedule, cancel, leave
  feedback) is built as `{storefrontBaseUrl}/link/{token}`, so if it still
  points at localhost those emailed links go nowhere.
</Note>

## Make it yours

MIT-licensed: rebrand it, restructure it, or use it for client work. Business
settings live in `lib/site-config.ts`: name, currency and timezone, check-in and
check-out times, the longest stay, the cancellation window, arrival times,
occasions and contact details. Per-villa rooms, story, amenities and minimum
nights are in `lib/villa-content.ts`. Every colour and font is a Tailwind v4
`@theme` token in `app/globals.css`:

```css theme={"theme":{"light":"github-light","dark":"github-dark-default"}}
@theme {
  --color-paper: #F4EEE4;       /* limestone page background */
  --color-jungle: #1F3A2E;      /* dark sections and footer */
  --color-terracotta: #B4502E;  /* the only accent */
}
```

Building a different stay or rental site with an AI agent? The
[build-booking-site skill](/docs/ai-agents/build-booking-site-skill) has a
`rentals-multi-day` reference with the full pattern, including nightly stays.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.