Skip to Content

Boekingswidget SDK

Bouw je eigen boekingsflow op je website met de JavaScript-SDK van Online boeken, of roep de publieke widget-API rechtstreeks aan.

Laatst bijgewerkt op

De gewone widget zet je met één script-tag op je site: zie Online boeken via je website. Wil je de boekingsflow zelf tekenen, met een eigen kalender, eigen accommodatietegels en een eigen afrekenpagina, dan gebruik je de boekingswidget-SDK. Die praat met dezelfde publieke API als de widget: beschikbaarheid, prijzen, extra's, kortingscodes en het aanmaken van de boeking komen uit Tillor, de opmaak is van jou.

Laden

<script src="https://tillor.eu/booking-sdk.js"></script>
<script>
  const booking = Tillor.booking({
    orgId: "org_abc123",
    widgetKey: "bwk_xxx",
    locale: "nl",
  });
</script>
OptieVerplichtUitleg
orgIdjaJe organisatie-ID, zoals op de integratiepagina Online boeken
widgetKeyjaDe publieke widgetsleutel (bwk_…) van dezelfde pagina
appUrlneeWaar Tillor draait; standaard de oorsprong waar booking-sdk.js vandaan komt
localeneeTaal van namen en meldingen; standaard de taal van de browser
dataLayerneefalse om events niet naar window.dataLayer / gtag te sturen (standaard true)

De sleutel is publiek

De widgetsleutel staat in de browser, net als bij de widget. Hij geeft alleen toegang tot wat een bezoeker toch al mag: beschikbaarheid, prijzen en het aanmaken van een boeking. Beperk hem met Toegestane domeinen op de integratiepagina; aanroepen vanaf een andere site krijgen dan een 403. Per bezoeker gelden 120 leesaanroepen en 10 boekingen per minuut.

Voor TypeScript staat er een declaratiebestand naast het script: booking-sdk.d.ts.

Methodes

Alle methodes geven een Promise terug en gooien een Tillor.BookingError bij een fout (zie Fouten). Datums zijn altijd yyyy-MM-dd in de kalender van het park.

MethodeBeschrijving
getConfig()Naam, logo, boekingsmodus (request of instant), valuta, tijdzone, regels (minimale vooruitboektijd, voorschot, toeristenbelasting, welke gastgegevens verplicht zijn), de accommodaties en de extra's
getHolidays(from, to)School- en feestdagen van het land van het park in die periode
getAvailability({ from, to, terrainTypeId? })Per accommodatietype en per nacht: hoeveel eenheden vrij zijn, de nachtprijs en of de nacht gesloten is. Ook getAvailability(from, to, terrainTypeId?)
quote(input)Prijst een verblijf zoals de widget: nachten, toeslagen per persoon, extra's, toeristenbelasting en kortingscode. Geeft issues wanneer een regel het verblijf blokkeert en alternatives wanneer het volzet is
createBooking(input, { redirect? })Maakt de boeking aan. Bij Direct boeken komt er een checkoutUrl (Mollie) terug; met redirect: true stuurt de SDK de bezoeker daar meteen heen
getBooking(reference, manageToken)Status, verblijf, prijs, factuur en betaallink van een boeking; beide waarden komen uit createBooking
requestCancellation(reference, manageToken, reason?)Vraagt annulering aan; je team bevestigt in Tillor
on(event, handler)Luistert naar een tillor_booking_*-event of "*"; geeft een functie terug die weer afmeldt
track(event, data)Stuurt zelf een event, bijvoorbeeld wanneer de bezoeker data kiest in jouw kalender
dates.addDays(date, n), dates.nightsBetween(in, out), dates.today(timeZone)Datumhulpjes zonder tijdzoneverrassingen

Invoer van quote en createBooking

{
  terrainTypeId: "tty_chalet",          // id uit getConfig().accommodations
  checkIn: "2026-07-10",
  checkOut: "2026-07-17",
  party: { adults: 2, children: 1, toddlers: 0, animals: 0 },
  extras: [{ extraId: "bk_extra_linnen", quantity: 3 }],   // optioneel
  partySegments: [],                    // optioneel: ander gezelschap voor een deel van het verblijf
  promoCode: "ZOMER10",                 // optioneel
}

createBooking vraagt daarbovenop:

VeldUitleg
guestfirstName, lastName, email; phone wanneer config.requirePhone aanstaat; address, zipCode, city, country wanneer config.askAddress aanstaat
licensePlatesKentekens, als config.askLicensePlates aanstaat
acceptTermsMoet true zijn
expectedTotalHet total van de laatste quote. Is de prijs intussen veranderd, dan weigert Tillor de boeking: vraag een nieuwe prijsopgave en toon die aan de gast
note, consentToMarketing, returnUrlOptioneel. returnUrl is waar Mollie de gast na het betalen heen stuurt; standaard de boekingspagina van Tillor
idempotencyKeyOptioneel; de SDK maakt er zelf een, zodat een dubbele klik nooit twee boekingen maakt

Het antwoord bevat bookingReference, manageToken, manageUrl (de boekingspagina van de gast), status, checkoutUrl (alleen bij Direct boeken) en holdExpiresAt.

Events

De SDK stuurt dezelfde events als de widget, naar je on-handlers en standaard ook naar window.dataLayer (Google Tag Manager) en gtag (GA4).

EventWie stuurt hetGegevens
tillor_booking_viewde SDK, bij de eerste getConfig()mode
tillor_booking_select_datesjij, via trackcheckIn, checkOut, nights
tillor_booking_select_accommodationjij, via trackterrainTypeId
tillor_booking_begin_checkoutjij, via trackterrainTypeId, total
tillor_booking_request_sentde SDK, na createBooking in de modus aanvraagreference, status
tillor_booking_payment_startedde SDK, na createBooking in de modus direct boekenreference, status
booking.on("*", (data, name) => console.log(name, data));
booking.track("tillor_booking_select_dates", { checkIn, checkOut, nights: 7 });

Voorbeeld: beschikbaarheid en prijs tonen

Een pagina met accommodatietegels, een datumkeuze en een prijsopgave die live meerekent. Geen framework, alleen de SDK.

<div id="accommodations"></div>
<label>Aankomst <input id="check-in" type="date" /></label>
<label>Vertrek <input id="check-out" type="date" /></label>
<label>Volwassenen <input id="adults" type="number" min="1" value="2" /></label>
<pre id="quote"></pre>

<script src="https://tillor.eu/booking-sdk.js"></script>
<script>
  const booking = Tillor.booking({ orgId: "org_abc123", widgetKey: "bwk_xxx", locale: "nl" });
  const state = { terrainTypeId: null, config: null };

  const money = (amount) =>
    new Intl.NumberFormat("nl", { style: "currency", currency: state.config.currency }).format(amount);

  async function start() {
    state.config = await booking.getConfig();
    const today = booking.dates.today(state.config.timeZone);
    document.getElementById("check-in").value = booking.dates.addDays(today, 14);
    document.getElementById("check-out").value = booking.dates.addDays(today, 17);

    const list = document.getElementById("accommodations");
    for (const accommodation of state.config.accommodations) {
      const button = document.createElement("button");
      button.textContent = `${accommodation.name} · vanaf ${money(accommodation.fromPricePerNight ?? 0)} per nacht`;
      button.addEventListener("click", () => {
        state.terrainTypeId = accommodation.id;
        booking.track("tillor_booking_select_accommodation", { terrainTypeId: accommodation.id });
        refresh();
      });
      list.appendChild(button);
    }
  }

  async function refresh() {
    const checkIn = document.getElementById("check-in").value;
    const checkOut = document.getElementById("check-out").value;
    const adults = Number(document.getElementById("adults").value);
    const output = document.getElementById("quote");
    if (!state.terrainTypeId || !checkIn || !checkOut) return;

    try {
      const quote = await booking.quote({
        terrainTypeId: state.terrainTypeId,
        checkIn,
        checkOut,
        party: { adults },
      });
      if (!quote.available) {
        output.textContent = `Volzet. Vrij: ${quote.alternatives.map((a) => `${a.checkIn} → ${a.checkOut}`).join(", ")}`;
        return;
      }
      if (!quote.valid) {
        output.textContent = `Niet mogelijk: ${quote.issues.map((issue) => issue.code).join(", ")}`;
        return;
      }
      output.textContent = quote.lines
        .map((line) => `${line.label ?? line.kind}: ${money(line.total)}`)
        .concat(`Totaal: ${money(quote.total)}`)
        .join("\n");
    } catch (error) {
      output.textContent = error.message;
    }
  }

  for (const id of ["check-in", "check-out", "adults"]) {
    document.getElementById(id).addEventListener("change", refresh);
  }
  start();
</script>

Een boeking maak je daarna met de gastgegevens uit je eigen formulier:

const result = await booking.createBooking(
  {
    terrainTypeId: state.terrainTypeId,
    checkIn,
    checkOut,
    party: { adults },
    guest: { firstName: "Jan", lastName: "Janssens", email: "jan@voorbeeld.be", phone: "+32 470 12 34 56" },
    acceptTerms: true,
    expectedTotal: quote.total,
  },
  { redirect: true }, // bij Direct boeken meteen naar Mollie
);
// Bij een aanvraag: toon result.manageUrl, de boekingspagina van de gast

Fouten

Elke mislukte aanroep gooit een Tillor.BookingError met status, code, message en, bij een 400, issues per veld.

StatuscodeBetekenis
400BAD_REQUESTOngeldige invoer (issues zegt welk veld), of een prijs die niet meer klopt
401UNAUTHORIZEDVerkeerde widgetsleutel, of Online boeken staat uit
403FORBIDDENDe website staat niet bij de toegestane domeinen
429TOO_MANY_REQUESTSTe veel aanroepen van deze bezoeker; retryAfter zegt hoelang wachten
0NETWORKTillor was niet bereikbaar
try {
  await booking.quote(input);
} catch (error) {
  if (error instanceof Tillor.BookingError && error.status === 400) {
    console.log(error.issues); // [{ field: "checkOut", message: "checkOut must be after checkIn" }]
  }
}

Zonder de SDK

De SDK is een dunne laag over de publieke widget-API. Vanuit een andere taal of een server roep je dezelfde endpoints aan met de header X-Tillor-Booking-Widget-Key. Stuur ook een Origin- of Referer-header van een toegestaan domein wanneer Toegestane domeinen ingesteld staat.

MethodeEndpoint
GET/api/orgs/{orgId}/booking/widget/config?locale=nl
GET/api/orgs/{orgId}/booking/widget/holidays?from=…&to=…&locale=nl
GET/api/orgs/{orgId}/booking/widget/availability?from=…&to=…&terrainTypeId=…
POST/api/orgs/{orgId}/booking/widget/quote
POST/api/orgs/{orgId}/booking/widget/reservations
GET/api/orgs/{orgId}/booking/widget/reservations/{bookingReference}?manageToken=…
POST/api/orgs/{orgId}/booking/widget/reservations/{bookingReference}/cancellation-request
POST https://tillor.eu/api/orgs/org_abc123/booking/widget/quote
X-Tillor-Booking-Widget-Key: bwk_xxx
Content-Type: application/json

{ "terrainTypeId": "tty_chalet", "checkIn": "2026-07-10", "checkOut": "2026-07-17", "party": { "adults": 2 } }

Zie ook

Was deze pagina nuttig?

Op deze pagina