Build a booking website in v0 with the Opencals agent skills

Stanislav TyshchenkoTutorial6 min readSep 26, 2026
A v0 prompt box reading 'Build a booking site for my padel club that takes real bookings' under the Lovable, v0 and Base44 logos, with the opencals-build-booking-site skill attached

v0 writes the kind of code I'd write by hand: a Next.js app, server components, a clean lib/ folder. That makes it a good fit for a booking site, as long as it knows which API it's talking to. Left to guess, it invents one: slots from a hard-coded array, bookings as rows in a database, no hold on the slot while someone types their card number.

The fix is two agent skills. They're plain Markdown files that tell v0 exactly how the Opencals booking API and SDK work, with the real method names, the order of calls, and the mistakes to avoid. v0 supports skills from skills.sh, so setting it up is mostly one attachment and one environment variable.

Attach the two Opencals skills from skills.sh (letsopencals/skills) in the v0 prompt bar, add your storefront key as OPENCALS_API_KEY, and describe the business. v0 builds a Next.js site on the Opencals SDK: real services, live availability, a cart that holds the slot, and Stripe checkout into your own account.

The two skills, and why there are two

The skills live in a public, MIT-licensed repo: github.com/letsopencals/skills. The same files work in Claude Code, Cursor, Codex and Gemini CLI, so whatever v0 learns from them carries over if you take the code elsewhere.

  • opencals-build-booking-site is the workflow. It works out what kind of business this is (people's time, like a salon or clinic; things, like courts and rooms; or classes with capacity), picks the matching booking flow, and knows the four open-source templates it can borrow from.
  • opencals-storefront-api is the ground truth. Every SDK service and method, the availability → cart → appointment → checkout sequence, discounts, customer accounts, reschedule and cancel, and rate limits.

They're split on purpose. The build skill decides what to make; the API skill makes sure each call is shaped correctly. Attach both, or v0 has the plan without the exact method names.

Step 1: a storefront key

In the Opencals dashboard, go to Settings → API Keys and create a storefront key. It starts with sfk_. If you don't have a store yet, create one free and add a service with a schedule first. A new store is a free development store with Stripe in test mode, which is what you want while building.

Leave the key's allowed origins empty. The site calls Opencals from its server functions, which send no Origin header, and a key with an allowlist rejects those requests with 401 Origin not allowed.

Step 2: attach the skills in v0

In the v0 prompt bar, open the skills menu (typing / in the composer brings it up) and add the Opencals skills from skills.sh. Search for this repo:

text
letsopencals/skills

Attach both opencals-build-booking-site and opencals-storefront-api. Save them to your personal or team scope, and they're one click away in every new chat.

Working outside v0 as well? The same repo installs into any agent that reads skills with one command:

bash
npx skills add letsopencals/skills

And in Claude Code, as a plugin:

bash
/plugin marketplace add letsopencals/skills /plugin install opencals@opencals

Step 3: add the key as an environment variable

The generated code reads the key from the environment and only uses it on the server, so it never ships to the browser. v0 asks for missing environment variables above the composer when the code needs them; you can also add them to the project's environment variables yourself.

Environment variables

Required

Value: your sfk_ storefront key

OPENCALS_API_KEY

Optional

Value: https://api.opencals.com (the default)

OPENCALS_API_URL

If v0 adds sign-in

Value: any long random string, e.g. the output of openssl rand -base64 32

AUTH_SECRET

Step 4: describe the business, not the booking system

The skills already cover how booking works. What they can't know is who's booking what, so spend the prompt on that:

text
Build a booking website for Ridge Padel, a six-court padel club in Valencia. Use the Opencals skills. Players pick a date and see every court against time in one grid, then choose 60 or 90 minutes. Coached group sessions are bookable separately, with spots left shown. Dark, sporty, one electric-lime accent. Pages: home, book a court, coaching, checkout, confirmation.

Leave out the services, prices and opening hours. v0 fetches them from your store, so when you add a court or change a price in the Opencals dashboard, the site follows without another prompt.

The build skill is where the business type pays off. For the padel club above, it steers v0 toward a courts × time grid with a length picker, the shape of the VOLT template, instead of a salon-style "pick a service, pick a staff member" form. A clinic gets a department-first flow; a salon gets services and stylists.

What v0 generates

A standard Next.js app with @opencals/storefront-sdk initialised once on the server:

ts
// lib/opencals.ts import { setupOpencals } from '@opencals/storefront-sdk'; setupOpencals({ baseUrl: process.env.OPENCALS_API_URL ?? 'https://api.opencals.com', apiKey: process.env.OPENCALS_API_KEY, });

After that, it's service classes: ProductService.getCurrentAvailabilities for slots, CartService.createOrGet to hold them, AppointmentService.create to book, and CheckoutService.start → saveCustomer → submit to pay. Card payments use Stripe's payment form in the page with the details Opencals returns at checkout, so there's no Stripe secret key in the project; the money goes to the Stripe account connected to your store.

Because it's ordinary Next.js, the code isn't tied to v0. Push it to GitHub and keep going in Cursor or Claude Code with the same skills installed.

Where v0 needs a second pass

v0 writes new code every run. The skills make it right far more often, not every time. The mistake worth checking first: the times on screen are off by your timezone offset. Slot times from the API are UTC, and occasionally the generated picker shows them raw. The skill says so explicitly, and a one-line follow-up ("slot times are UTC, show them in the store's timezone") fixes it.

Then run one booking end to end in the v0 preview:

  1. Services and prices match your Opencals dashboard.
  2. Days without availability are disabled; times are in local time.
  3. Book, pay with Stripe's test card 4242 4242 4242 4242, and land on a confirmation with an order number.
  4. The booking shows up in your Opencals dashboard and the confirmation email arrives.

When that passes, publish from v0 to Vercel, switch your Opencals store to production to take real payments, and add your domain.

Setting up a different builder? There are guides for Lovable and Base44, and the overview is in build a booking website with AI.

Frequently Asked Questions

Early Access — 3 Months Free

Ready to transform your service business?

Join 150+ businesses already using Opencals. Get 3 months completely free with all features unlocked.

No credit card required
Setup in 10 minutes
Cancel anytime