Reference
Website widget
The booking form lives on the restaurant's own website. The browser never holds an API key: it talks to a thin proxy on your server, and the proxy adds the key and forwards to the public API. The live demo runs exactly this pattern.
The proxy pattern
Browser ── POST /api/website/reservations ──▶ Your server ── POST /api/v1/... + API key ──▶ VardvikThree rules keep it safe:
- The API key lives in a server-side environment variable, never in markup or bundles.
- The proxy fixes restaurant and location ids server-side; the browser cannot choose them.
- The proxy generates the idempotency key per submission, so double-clicks cannot double-book.
Next.js proxy route
export async function POST(request: Request) {
const body = await request.json();
const response = await fetch(
`${process.env.VARDVIK_BASE_URL}/api/v1/restaurants/${process.env.VARDVIK_RESTAURANT_ID}/reservations`,
{
method: "POST",
headers: {
authorization: `Bearer ${process.env.VARDVIK_API_KEY}`,
"content-type": "application/json",
"idempotency-key": crypto.randomUUID()
},
body: JSON.stringify({
locationId: process.env.VARDVIK_LOCATION_ID,
startTime: body.startTime,
partySize: body.partySize,
guest: body.guest,
specialRequests: body.specialRequests
})
}
);
return Response.json(await response.json(), { status: response.status });
}Availability lookup
export async function GET(request: Request) {
const url = new URL(request.url);
const upstream = new URL(
`/api/v1/restaurants/${process.env.VARDVIK_RESTAURANT_ID}/availability`,
process.env.VARDVIK_BASE_URL
);
upstream.searchParams.set("locationId", process.env.VARDVIK_LOCATION_ID!);
upstream.searchParams.set("date", url.searchParams.get("date") ?? "");
upstream.searchParams.set("partySize", url.searchParams.get("partySize") ?? "2");
const response = await fetch(upstream, {
headers: { authorization: `Bearer ${process.env.VARDVIK_API_KEY}` },
cache: "no-store"
});
return Response.json(await response.json(), { status: response.status });
}The form itself
Any form works: load slots from your availability proxy, let the guest pick one, post the booking, show the publicReference as the confirmation code. Working examples ship in the repository under examples/: a plain HTML form, a React component, and the Next.js proxy above.
const response = await fetch("/api/website/reservations", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
startTime: selectedSlot,
partySize: 4,
guest: { firstName, lastName, email }
})
});
const { reservation, error } = await response.json();
if (reservation) {
show(`Confirmed. Your reference: ${reservation.publicReference}`);
}Guest self-registration
Restaurants can also link guests to a hosted registration page with a signed token, so profiles and consents are recorded without any API work on your side. See guest registration.