Eigen widgets en de kanaal-API
Met een Eigen widget bouw je je eigen boekingservaring. Je stelt de regels in Bookingmood in, en je eigen code gebruikt de kanaal-API om beschikbaarheid op te halen en boekingen aan te nemen.
Pre-release: de kanaal-API kan nog veranderen, ook op manieren die bestaande code laten stoppen met werken, en deze pagina behandelt misschien nog niet alles. JavaScript-pakketten voor de API zijn nog niet beschikbaar. Test je integratie goed voordat je erop vertrouwt.
Een eigen widget maken
Eigen widgets zijn beschikbaar vanaf het Booking-abonnement.
Ga naar Kanalen en klik op Nieuw kanaal.
Kies Eigen widget, voer een titel in en selecteer de objecten die erbij horen.
Om boekingen aan te nemen, zet je Interactie op Boeken.
Kopieer de Publieke sleutel.
Een eigen widget heeft geen weergave-instellingen. Hij bepaalt alleen wat de API teruggeeft en toestaat: de objecten, hoe geboekte, gesloten en openstaande data worden getoond, of gasten kunnen boeken, wat er na het boeken gebeurt, of beoordelingen beschikbaar zijn en, als je wilt, een wachtwoord.
De Publieke sleutel is de ID van de widget. Die is openbaar, dus je kunt hem in een browser gebruiken. Zet nooit een Bookingmood-API-sleutel in browsercode: die zijn geheim.
Verzoeken
De basis-URL is https://www.bookingmood.com/api/public/v1. Verzoeken zijn toegestaan vanaf elke website.
const channelId = "YOUR_PUBLISHABLE_KEY";
const baseUrl = "https://www.bookingmood.com/api/public/v1";
const response = await fetch(`${baseUrl}/channels/${channelId}`);
const { availability, channel, organization, products } = await response.json();| Methode en pad | Wat het doet |
|---|---|
GET /channels/:id | Het kanaal, de organisatie en objecten ervan, en hun beschikbaarheid. Telt als een weergave van het kanaal. |
GET /channels/:id/availability | Alleen de beschikbaarheid. Voeg product_ids per object één keer toe om het tot die objecten te beperken. |
POST /channels/:id/calendars/sync | Synchroniseert de geïmporteerde kalenders van objecten. |
GET /channels/:id/reviews | Beoordelingen van een object, als het kanaal beoordelingen toont. |
GET /channels/:id/coupons | Kortingscodes op code. Voeg codes per code één keer toe. |
POST /channels/:id/coupons/verify | Controleert of een kortingscode gebruikt kan worden. |
POST /channels/:id/cart/validate | Controleert of een winkelwagen geboekt kan worden en wat die kost. |
POST /channels/:id/cart/checkout | Boekt een winkelwagen. |
POST /channels/:id/access | Wisselt het wachtwoord van het kanaal in voor een token. |
GET /bookings/:id | De status en betalingen van een boeking. |
POST /bookings/:id/pay | Haalt een betaallink op voor een openstaande boeking. |
POST /bookings/:id/cancel | Annuleert een openstaande boeking. |
Een verblijf boeken
Boekingen lopen via een winkelwagen, met daarin een of meer verblijven:
const cart = {
coupon_codes: [],
items: [
{
id: "stay-1", // Your own ID, to match results to items
product_id: "UNIT_ID",
interval: { start: "2027-03-01", end: "2027-03-08" },
occupancy: { CAPACITY_GROUP_ID: 2 },
form_values: { SERVICE_ID: "Arriving around 16:00" },
},
],
};interval: data alsYYYY-MM-DD. Een verblijf per nacht eindigt op de dag dat gasten vertrekken. Een verblijf per dag eindigt de dag na de laatste dag.occupancy: het aantal gasten per capaciteitsgroep, met de ID uitorganization.capacity_groups.form_values: de antwoorden op het boekingsformulier, met de ID uit deservicesvan het object.
1. De winkelwagen valideren
Valideer de winkelwagen voordat je een gast om gegevens of een betaling vraagt. Het resultaat laat zien of elk verblijf geboekt kan worden en wat het kost. Bedragen zijn in centen.
const response = await fetch(`${baseUrl}/channels/${channelId}/cart/validate`, {
body: JSON.stringify(cart),
headers: { "Content-Type": "application/json" },
method: "POST",
});{
"items": [
{
"availabilityMatch": true,
"id": "stay-1",
"occupancyMatch": true,
"price": {
"currency": "EUR",
"deposit": 0,
"lines": [],
"subtotal": 70000,
"tax": 6300,
"total": 76300
},
"valid": true
}
],
"valid": true
}2. Afrekenen
Stuur de winkelwagen mee, met optioneel een weergavevaluta in currency en een taal in language. Afrekenen maakt een echte boeking aan en geeft een 201-antwoord. De winkelwagen kan nog steeds worden geweigerd, omdat de beschikbaarheid kan veranderen nadat je hebt gevalideerd.
const response = await fetch(`${baseUrl}/channels/${channelId}/cart/checkout`, {
body: JSON.stringify({ cart, currency: null, language: "en-US" }),
headers: { "Content-Type": "application/json" },
method: "POST",
});
const { booking_id, payment_expiry_timestamp, payment_url, reference, secret } =
await response.json();Als payment_url niet null is, stuur je de gast daarheen om te betalen. Na het betalen gaan gasten naar wat de instelling Na boeking van de widget aangeeft.
3. Later betalen of annuleren
Gebruik de secret van de boeking als bearer-token voor de routes onder /bookings/:id. Die geeft toegang tot de status en betalingen van de boeking, zonder gegevens van de gast. Deel hem alleen met de gast die de boeking heeft gemaakt.
const response = await fetch(`${baseUrl}/bookings/${booking_id}/pay`, {
body: JSON.stringify({ language: "en-US" }),
headers: {
Authorization: `Bearer ${secret}`,
"Content-Type": "application/json",
},
method: "POST",
});
const { payment_url } = await response.json();Betalen en annuleren werken alleen zolang een boeking op de betaling wacht. Anders krijg je 409 terug met de code booking_not_pending. Een geslaagde annulering geeft 204 terug, zonder inhoud.
Kortingscodes
POST /channels/:id/coupons/verify krijgt de code, de product_ids in de winkelwagen en de al ingevoerde current_codes. Het result is een van deze waarden:
| Resultaat | Betekenis |
|---|---|
VALID | De code kan worden gebruikt. |
INVALID | De code bestaat niet of geldt niet voor deze objecten. |
STACK_NOT_ALLOWED | Een code die al is ingevoerd, kan niet met andere worden gecombineerd. |
LIMIT_REACHED | De winkelwagen heeft al 5 codes, het maximum. |
Beoordelingen
GET /channels/:id/reviews heeft een product_id nodig. Je kunt een limit van 1 tot 1000 (de standaardwaarde) toevoegen, en een order: most-recent (de standaardwaarde), highest-rating of lowest-rating.
Geïmporteerde kalenders synchroniseren
Als je objecten kalenders importeren, stuur je { "product_ids": [...] } naar POST /channels/:id/calendars/sync om ze bij te werken. Het antwoord bevat de totalen. Met Accept: application/x-ndjson krijg je in plaats daarvan een regel JSON zodra elke kalender klaar is.
Een verzoek start na 40 seconden geen nieuwe kalenders meer. Als remaining in het resultaat boven de 0 ligt, stuur je nog een verzoek.
Kanalen met een wachtwoord
Als de widget een wachtwoord heeft, geeft elk kanaalverzoek 401 terug met de code password_required, totdat de bezoeker is ingelogd:
const response = await fetch(`${baseUrl}/channels/${channelId}/access`, {
body: JSON.stringify({ password }),
headers: { "Content-Type": "application/json" },
method: "POST",
});
const { expiresAt, token } = await response.json();Stuur het token als Authorization: Bearer <token> mee met volgende verzoeken. Het is een week geldig, en expiresAt geeft die tijd in milliseconden.
Fouten en limieten
Fouten hebben een code en een message:
{
"code": "channel_not_found",
"details": null,
"hint": null,
"message": "No channel found with this ID"
}| Status | Code | Betekenis |
|---|---|---|
400 | BM400 | Het verzoek past niet bij het schema van de route. details geeft aan wat er mis is. |
400 | product_not_listed | Een object in het verzoek hoort niet bij dit kanaal. |
400 | checkout_failed | De winkelwagen kan niet worden geboekt. message geeft de reden. |
400 | password_not_set | Het kanaal heeft geen wachtwoord. |
401 | password_required | Het kanaal heeft een toegangstoken nodig. |
401 | invalid_password | Het wachtwoord is onjuist. |
403 | channel_inactive | Het abonnement van de organisatie staat dit kanaal niet toe. |
403 | channel_not_bookable | De Interactie van het kanaal staat niet op Boeken. |
403 | reviews_disabled | Het kanaal toont geen beoordelingen. |
404 | channel_not_found | Er is geen kanaal met deze ID. |
404 | booking_not_found | De boeking bestaat niet, of de secret klopt niet. |
409 | booking_not_pending | De boeking wacht niet op een betaling. |
429 | rate_limited | Te veel verzoeken. |
Per IP-adres zijn de limieten 300 verzoeken per minuut per kanaal, 60 per minuut naar de boekingsroutes en 10 per minuut om kortingscodes te controleren. Ook het aantal wachtwoordpogingen is beperkt.
Laatst gewijzigd 6 november 2026