Skip to content

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.