Example booking form
This example lists the venue’s spaces, slots and packages, checks availability for the selected date, shows a price quote and sends a booking request. It uses plain HTML and JavaScript with no libraries.
Replace kvw_yourKey with the venue’s website key, and make sure the website that hosts the page is listed on the key.
<form id="booking"> <label>Space <select id="space" required></select></label> <label>Date <input id="date" type="date" required /></label> <label>Slot and package <select id="package" required></select></label> <p id="quote"></p>
<label>Name <input id="name" required /></label> <label>Email <input id="email" type="email" required /></label> <label>Phone <input id="phone" /></label> <label>Company <input id="company" /></label> <label>Message <textarea id="message"></textarea></label>
<!-- Spam protection: hidden from visitors, always empty. --> <input id="website" name="website" tabindex="-1" autocomplete="off" style="position:absolute;left:-10000px" aria-hidden="true" />
<button type="submit">Send booking request</button> <p id="result" role="status"></p></form>
<script> const API = 'https://api.kisum.io/venues/public/v1/sites/kvw_yourKey'; const $ = (id) => document.getElementById(id); let currency = 'USD';
async function call(path, body) { const response = await fetch(API + path, body ? { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body) } : undefined); const json = await response.json(); if (!json.success) throw Object.assign(new Error(json.error.message), { code: json.error.code, status: response.status }); return json.data; }
const WHOLE_UNIT_CURRENCIES = ['IDR', 'JPY', 'KRW', 'VND', 'CLP', 'ISK', 'UGX'];
function money(amountCents) { const digits = WHOLE_UNIT_CURRENCIES.includes(currency) ? 0 : new Intl.NumberFormat('en', { style: 'currency', currency }).resolvedOptions().maximumFractionDigits; return new Intl.NumberFormat('en', { style: 'currency', currency, minimumFractionDigits: digits, maximumFractionDigits: digits }) .format(amountCents / 10 ** digits); }
async function loadSpaces() { currency = (await call('/venue')).currency; const spaces = await call('/spaces'); $('space').innerHTML = spaces.map((s) => `<option value="${s.id}">${s.name}</option>`).join(''); }
async function loadPackages() { const spaceId = $('space').value; const date = $('date').value; if (!spaceId || !date) return;
const [slots, days] = await Promise.all([ call(`/spaces/${spaceId}/slots`), call(`/spaces/${spaceId}/availability?from=${date}&to=${date}`), ]); const free = new Set((days[0]?.slots ?? []).filter((s) => s.free).map((s) => s.slotId));
$('package').innerHTML = slots .filter((slot) => free.has(slot.id)) .flatMap((slot) => slot.packages.map((p) => `<option value="${slot.id}|${p.id}">${slot.name} (${slot.startTime} to ${slot.endTime}): ${p.name}, ${money(p.hireFeeCents)} before tax</option>`)) .join(''); $('quote').textContent = $('package').value ? '' : 'No slots are available on this date.'; if ($('package').value) await showQuote(); }
function selection() { const [slotId, packageId] = $('package').value.split('|'); return { spaceId: $('space').value, slotId, packageId, date: $('date').value }; }
async function showQuote() { const quote = await call('/quote', selection()); $('quote').textContent = `Total: ${money(quote.totalCents)} (tax ${money(quote.taxCents)})`; }
$('space').addEventListener('change', loadPackages); $('date').addEventListener('change', loadPackages); $('package').addEventListener('change', showQuote);
$('booking').addEventListener('submit', async (event) => { event.preventDefault(); try { const receipt = await call('/booking-requests', { ...selection(), guest: { name: $('name').value, email: $('email').value, phone: $('phone').value, company: $('company').value }, message: $('message').value, website: $('website').value, }); $('result').textContent = `Request sent. Your reference is ${receipt.reference}. The venue will contact you.`; } catch (error) { $('result').textContent = error.status === 409 ? 'This date is no longer available. Select another date.' : error.message; } });
loadSpaces();</script>In production, escape values from the API before inserting them into HTML, and add your own styles and error handling.