Booking request forms.
Restaurants, clinics, salons and rentals often take bookings as a request first and confirm by email. FormRoute delivers each request to you from your own domain, so the conversation starts in your inbox.Who it's for.
- Restaurants, cafés and venues taking table or event requests.
- Salons, studios, practices and tutors taking appointment requests.
- Holiday rentals and guides taking date requests.
Fields to set up.
Add them in FormRoute with these names, so the form and its settings match.| Field name | Label | Required | Max length | Note |
|---|---|---|---|---|
name | Name | Yes | 120 | |
email | Yes | 254 | To confirm the booking. | |
phone | Phone | No | 40 | |
date | Preferred date | Yes | 10 | type="date" gives a date picker and sends YYYY-MM-DD. |
time | Preferred time | No | 5 | type="time" sends HH:MM. |
people | Number of people | No | 3 | Or the service, for appointments. |
notes | Notes | No | 2000 | Allergies, accessibility, special requests. |
The form.
Your own markup, plus the script that sends it.<form id="contact-form">
<label>Name <input name="name" required maxlength="120"></label>
<label>Email <input name="email" type="email" required maxlength="254"></label>
<label>Phone <input name="phone" type="tel" maxlength="40"></label>
<label>Preferred date <input name="date" type="date" required></label>
<label>Preferred time <input name="time" type="time"></label>
<label>Number of people <input name="people" type="number" min="1" max="999"></label>
<label>Notes <textarea name="notes" maxlength="2000"></textarea></label>
<!-- Honeypot: hidden from people, must stay empty -->
<div aria-hidden="true" style="position:absolute;left:-10000px">
<label>Leave this empty <input name="hp" tabindex="-1" autocomplete="off"></label>
</div>
<button type="submit">Request a booking</button>
<p id="contact-status" role="status"></p>
</form><script>
const ENDPOINT = "https://form-route.com/api/v1/send";
const SITE_KEY = "fr_your_site_key"; // from your FormRoute account
const form = document.querySelector("#contact-form");
const status = document.querySelector("#contact-status");
const shownAt = Date.now();
form.addEventListener("submit", async (event) => {
event.preventDefault();
const data = new FormData(form);
const button = form.querySelector("button[type=submit]");
button.disabled = true;
status.textContent = "Sending…";
try {
const response = await fetch(ENDPOINT, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
siteKey: SITE_KEY,
t: Date.now() - shownAt, // ms since the form was shown
hp: data.get("hp") ?? "", // honeypot, empty for people
name: data.get("name"),
email: data.get("email"),
phone: data.get("phone"),
date: data.get("date"),
time: data.get("time"),
people: data.get("people"),
notes: data.get("notes"),
}),
});
if (response.ok) {
form.reset();
status.textContent = "Thanks, your message was sent.";
} else {
status.textContent = "Sorry, that didn't go through. Please try again.";
}
} catch {
status.textContent = "Sorry, that didn't go through. Please try again.";
} finally {
button.disabled = false;
}
});
</script>Replace fr_your_site_key with the site key from your account. Using a framework or site builder? The platform guides show where the code goes.
Good to know.
Call it a request. FormRoute delivers the request; it doesn't check availability or confirm the booking. Say so on the button and in your reply.
Let the browser help. Date and time inputs give visitors a picker and send the value in a fixed format you can read at a glance.
Reply from your domain. The request arrives from your own address, so your confirmation can continue in the same thread.
Not for: Calendars, availability or payments: FormRoute is not a booking system. Pair it with your own process for confirming requests.