Avalik API ja broneerimisvidin
Public API & embeddable widget. Asenda näidetes APP oma rakenduse domeeniga ja uks-maja oma asukoha lühinimega (slug).
OpenAPI 3.1: /api/openapi.json · Reference
Üldist / Base URL
Baas-URL: https://APP/api/v1/{venue}/, kus {venue} on asukoha slug.
- HTTPS on kohustuslik; kasuta alati
https://aadressi. - CORS: kõik lõpp-punktid vastavad päistega
Access-Control-Allow-Origin: *, meetodid GET, POST, OPTIONS, päis Content-Type. Brauserist saab API-d otse kutsuda igalt domeenilt. - Rate limit (IP kohta, token bucket):
catalog,rooms,availability120 päringut minutis;estimate60 minutis;requests10 päringut minutis. Ületamisel vastus 429{"error":"rate_limited"}. - Summad on sentides (
*Cents). Kellaajad on asukoha ajavööndis (venue.timezone). - Isikuandmeid ei tagastata kunagi. Vastused sisaldavad ainult kataloogi, vabu aegu ja hinnaarvutust; kliendi andmeid (nimi, e-post, telefon) saab ainult saata (
requests), mitte lugeda. Kui asukoht ei näita hindu avalikult, on hinnaväljad tühjad /null.
GET /catalog
Asukoha avalik kataloog: ruumid, broneeringutüübid, sündmusetüübid ja lisateenused (ainult aktiivsed). Vahemälu 60 s.
| Parameeter | Kohustuslik | Kirjeldus |
|---|
curl "https://APP/api/v1/uks-maja/catalog"{
"venue": { "name": "Üks Maja", "slug": "uks-maja", "currency": "EUR", "vatRate": 0.24,
"pricesIncludeVat": false, "showPrices": true, "startStepMinutes": 30,
"minBookingMinutes": 60, "maxBookingMinutes": 1440, "timezone": "Europe/Tallinn" },
"rooms": [ { "id": "…", "name": "Saal", "description": "…", "capacity": 80, "areaM2": 120,
"equipment": [], "restrictions": null, "openHours": {} } ],
"bookingTypes": [ { "id": "…", "code": "private", "name": "…", "description": "…", "terms": "…",
"collectsCompany": false, "allowsPublicEvent": true } ],
"eventTypes": [ { "id": "…", "name": "Sünnipäev", "bookingTypeIds": ["…"] } ],
"extras": [ { "id": "…", "name": "Heli", "description": null, "unit": "per_booking",
"amountCents": 5000, "bookingTypeIds": null } ]
}GET /rooms
Ainult ruumide nimekiri (sama kuju mis catalog.rooms).
curl "https://APP/api/v1/uks-maja/rooms"{ "rooms": [ { "id": "…", "name": "Saal", "capacity": 80, "areaM2": 120, "…": "…" } ] }GET /availability
Vabad algusajad ühe päeva kohta ruumide kaupa. commonStarts on ajad, mil kõik valitud ruumid on korraga vabad.
| Parameeter | Kohustuslik | Kirjeldus |
|---|---|---|
| date | jah | YYYY-MM-DD |
| duration | jah | Kestus minutites, täisarv 15 kuni 20160 |
| rooms | jah* | Ruumi id-d komadega eraldatud. *Pole vaja, kui wholeHouse=1 |
| wholeHouse | ei | 0 või 1; 1 = kõik aktiivsed ruumid |
| eventTypeId | ei | Sündmusetüübi id (võib mõjutada konflikte) |
curl "https://APP/api/v1/uks-maja/availability?date=2026-11-20&duration=180&rooms=ROOM_ID_1,ROOM_ID_2"{
"date": "2026-11-20",
"rooms": [
{ "roomId": "ROOM_ID_1", "freeStarts": ["10:00", "10:30", "18:00"] },
{ "roomId": "ROOM_ID_2", "freeStarts": ["10:00", "18:00"] }
],
"commonStarts": ["10:00", "18:00"]
}POST /estimate
Hinnaarvutus ja saadavuse kontroll, midagi ei salvestata. JSON keha on sama mis requests, ilma customer väljata.
| Parameeter | Kohustuslik | Kirjeldus |
|---|---|---|
| bookingTypeId | jah | Broneeringutüübi id |
| eventTypeId | ei | Sündmusetüübi id |
| date | jah | YYYY-MM-DD |
| endDate | ei | YYYY-MM-DD, kui lõpp on teisel päeval |
| startTime / endTime | jah | HH:MM (lõpp võib olla 24:00) |
| roomIds | jah* | Ruumi id-de massiiv. *Pole vaja, kui wholeHouse=true |
| wholeHouse | ei | boolean, vaikimisi false |
| guests | jah | Täisarv 1 kuni 10000 |
| extras | ei | [{ extraId, quantity }] |
| title, description, message | ei | Tekst (title kuni 200, teised kuni 4000 märki) |
| isPublicEvent | ei | boolean |
| locale | ei | Kliendi keel: et | en | ru | lv | lt (pakkumise leht ja e-kirjad kasutavad seda) |
curl -X POST "https://APP/api/v1/uks-maja/estimate" \
-H "Content-Type: application/json" \
-d '{
"bookingTypeId": "…",
"date": "2026-11-20",
"startTime": "18:00",
"endTime": "22:00",
"roomIds": ["…"],
"guests": 40,
"extras": [{ "extraId": "…", "quantity": 1 }]
}'{
"available": true,
"problems": [],
"lines": [ { "label": "Saal", "quantity": 4, "unit": "hour", "unitPriceCents": 6000, "totalCents": 24000 } ],
"netCents": 24000,
"vatCents": 5760,
"grossCents": 29760,
"needsManualPrice": false,
"flags": []
}needsManualPrice: true tähendab, et lõpliku hinna annab pakkumine. problems sisaldab {code, message, field}.
POST /requests
Saadab uue broneeringutaotluse. Ei kinnita kunagi automaatselt, personal vaatab taotluse üle ja saadab pakkumise. Keha nagu estimate pluss kohustuslik customer. Valikuline päringuparameeter ?source=widget märgib allika vidinaks (muidu api).
| Parameeter | Kohustuslik | Kirjeldus |
|---|---|---|
| customer.name | jah | 2 kuni 200 märki |
| customer.email | jah | Kehtiv e-posti aadress |
| customer.phone | ei | Kuni 40 märki |
| customer.company | ei | Ettevõtte nimi |
| customer.regCode | ei | Registrikood |
| customer.newsletterConsent | ei | boolean, vaikimisi false |
curl -X POST "https://APP/api/v1/uks-maja/requests?source=widget" \
-H "Content-Type: application/json" \
-d '{
"bookingTypeId": "…",
"date": "2026-11-20",
"startTime": "18:00",
"endTime": "22:00",
"roomIds": ["…"],
"guests": 40,
"customer": { "name": "Mari Maasikas", "email": "mari@example.ee", "newsletterConsent": false }
}'HTTP 201
{ "bookingNumber": "UM-2026-0042", "estimate": { "…": "sama kuju mis /estimate" } }Staatused: 201 loodud; 400 valideerimisviga; 409 aeg pole vaba; 404 tundmatu asukoht; 429 rate limit.
GET /testimonials
Kliendikommentaarid, mida klient on pärast sündmust lubanud avalikult näidata (kuni 50 uusimat, uuemad ees). Iga kirje: eesnimi + perekonnanime algustäht (name), hinne 0–10 (score), kuu (month, YYYY-MM) ja kommentaar. E-posti, broneeringut ega muid isikuandmeid ei tagastata. Vahemälu 60 s; rate limit nagu catalog (120 minutis).
curl "https://APP/api/v1/uks-maja/testimonials"{ "testimonials": [ { "name": "Anna T.", "score": 10, "month": "2026-10", "comment": "Suurepärane õhtu!" } ] }POST /waitlist
Liitub ootenimekirjaga, kui valitud ruumid ja aeg on hõivatud (requests vastas 409). Keha on sama mis requestspluss kohustuslik waitlistConsent: true (kliendi nõusolek, et talle kirjutatakse, kui aeg vabaneb). Ei broneeri midagi. Kui aeg vabaneb (broneering tühistati, hoidmine aegus, pakkumisest loobuti), saab vanim ootaja e-kirja lingiga /w/{token}, mis kehtib venue seades waitlist_offer_hours (vaikimisi 24 h). Kinnitamisel tekib tavaline broneeringutaotlus; kui ta ei vasta, pakutakse aega järgmisele. Sama rate limit mis requests (10 päringut minutis).
curl -X POST "https://APP/api/v1/uks-maja/waitlist" \
-H "Content-Type: application/json" \
-d '{
"bookingTypeId": "…",
"date": "2026-11-20",
"startTime": "18:00",
"endTime": "22:00",
"roomIds": ["…"],
"guests": 40,
"customer": { "name": "Mari Maasikas", "email": "mari@example.ee", "phone": "+3725551234" },
"waitlistConsent": true
}'HTTP 201
{ "ok": true }Staatused: 201 liitutud; 400 valideerimisviga (sh puuduv waitlistConsent); 404 tundmatu asukoht; 409 aeg on vaba (saada tavaline päring); 429 rate limit.
Connect anything (Zapier, Make, n8n)
Kaks viisi andmete liigutamiseks Zapieri, Make'i, n8n-i või oma skripti: webhookid (me saadame sündmuse, kui midagi juhtub) ja võtmega REST API (te loete andmeid ise). Zapieri ega Make'i jaoks pole avaldatud eraldi rakendust: kasutage nende üldist "Webhooks" / "HTTP" moodulit allolevalt juhendilt. API on saadaval Venue ja Pro paketis, webhookid Pro paketis.
1. API-võtme loomine
Admin → Integratsioonid → API-võtmed → anna võtmele nimi, vali õigused (bookings:read, customers:read) ja vajuta "Loo võti". Võti (vb_live_…, arenduskeskkonnas vb_test_…) näidatakse ainult üks kord; serveris hoitakse vaid selle räsi. Tühistatud võti lakkab kohe töötamast. Ühel asukohal võib olla kuni 20 aktiivset võtit.
2. REST lõpp-punktid
Baas-URL https://APP/api/v1/rest/ (võti tuvastab asukoha, slugi pole vaja). Autentimine: Authorization: Bearer <võti>. Kõik päringud on GET ja ainult lugemiseks; vastused on no-store.
| Lõpp-punkt | Õigus | Kirjeldus |
|---|---|---|
| GET /me | mis tahes võti | Asukoht ja võtme õigused. Sobib Zapieri autentimise testiks. |
| GET /bookings | bookings:read | Broneeringud, uuemad ees. |
| GET /bookings/{id} | bookings:read | Üks broneering. |
| GET /customers | customers:read | Kliendid, uuemad ees. |
| GET /customers/{id} | customers:read | Üks klient. |
curl "https://APP/api/v1/rest/me" -H "Authorization: Bearer vb_live_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"{
"venue": { "id": "…", "name": "Üks Maja", "slug": "uks-maja", "timezone": "Europe/Tallinn", "currency": "EUR" },
"key": { "id": "…", "name": "Zapier: Google Sheet", "scopes": ["bookings:read", "customers:read"] }
}Broneeringute filtrid (kõik valikulised):
| Parameeter | Kohustuslik | Kirjeldus |
|---|---|---|
| status | ei | Üks või mitu komaga eraldatud staatust: new_request, quote_drafting, awaiting_staff, quote_sent, awaiting_customer, confirmed, cancelled, completed |
| updated_since | ei | ISO 8601; ainult broneeringud, mida on muudetud sellest ajast (updated_at >= …) |
| from / to | ei | ISO 8601 kuupäev või kellaaeg (UTC); algusaeg starts_at >= from ja < to |
| sort | ei | created_at (vaikimisi) või updated_at; alati uuemad ees. Muudatuste jälgimiseks kasuta sort=updated_at |
| limit | ei | 1 kuni 100, vaikimisi 25 |
| cursor | ei | Eelmise vastuse next_cursor |
curl "https://APP/api/v1/rest/bookings?status=confirmed&updated_since=2026-11-01T00:00:00Z&limit=25" \
-H "Authorization: Bearer $VENUE_API_KEY"{
"data": [
{
"id": "6f1c…", "number": "B-2026-00042", "status": "confirmed",
"starts_at": "2026-11-20T16:00:00.000Z", "ends_at": "2026-11-20T20:00:00.000Z",
"guests": 40, "whole_house": false,
"rooms": [ { "id": "…", "name": "Saal" } ],
"customer_id": "9a2d…", "total_gross_cents": 29760, "currency": "EUR",
"created_at": "2026-11-02T08:15:00.000Z", "updated_at": "2026-11-05T12:00:00.000Z"
}
],
"next_cursor": "WyJjcmVhdGVkX2F0IiwiMjAyNi0xMS0wMlQwODoxNTowMC4wMDAwMDBaIiwiNmYxYy4uLiJd"
}Broneeringu väljad: id, number, status, starts_at, ends_at, guests, whole_house, rooms[], customer_id, total_gross_cents, currency, created_at, updated_at. total_gross_cents on aktsepteeritud pakkumise summa sentides koos käibemaksuga (null, kuni pakkumist pole aktsepteeritud).
Kliendid: id, name, email, phone, company, created_at, erased. Kliendil pole updated_at välja, seega kliente sorteeritakse loomise järgi ja updated_since neil puudub. GDPR-i alusel kustutatud kliendil on erased: true ja nimi, e-post, telefon ning ettevõte null.
Lehitsemine / Pagination
Vastus on { "data": [...], "next_cursor": "..." }. Kui next_cursor ei ole null, kutsu sama päring uuesti parameetriga cursor. Kursor on läbipaistmatu: ära tõlgenda ega muuda seda, ja kasuta sama sort väärtust. Lehitsemine on stabiilne: uued kirjed ei nihuta juba nähtud lehti.
curl "https://APP/api/v1/rest/bookings?limit=25&cursor=WyJjcmVhdGVkX2F0Ii4uLl0" -H "Authorization: Bearer $VENUE_API_KEY"Rate limit ja vead
60 päringut minutis võtme kohta. Iga vastus sisaldab X-RateLimit-Limit, X-RateLimit-Remaining ja X-RateLimit-Reset (UNIX-sekundid, millal limiit on täielikult taastunud). Ületamisel tuleb 429 ja Retry-After (sekundites).
| Staatus | Tähendus | |
|---|---|---|
| 401 unauthorized | Võti puudub, on vigane või tühistatud | |
| 403 insufficient_scope | Võtmel puudub vajalik õigus | |
| 403 api_not_available | Asukoha pakett ei sisalda API-t või on tasuta periood läbi | |
| 400 invalid_parameter | Vigane filter, limit või cursor; message ütleb, milline | |
| 404 not_found | Kirjet pole selles asukohas | |
| 429 rate_limited | Liiga palju päringuid |
HTTP/1.1 401 Unauthorized
{ "error": "unauthorized", "message": "Invalid or revoked API key." }HTTP/1.1 429 Too Many Requests
Retry-After: 12
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1793000000
{ "error": "rate_limited", "message": "Rate limit exceeded: 60 requests per minute per key." }3. Webhookid
Admin → Integratsioonid → Webhookid lisab aadressi ja sündmused ning näitab allkirjastamise saladuse üks kord (webhookid on Pro paketis). Sündmused: booking.confirmed, booking.cancelled, booking.changed, request.created. Sisu sisaldab ainult id-sid, numbrit, aega ja staatust, kliendi andmeid mitte (need saab vajadusel REST API-st, customer_id kaudu).
POST https://hooks.zapier.com/hooks/catch/123456/abcdef/
content-type: application/json
x-venue-event: booking.confirmed
x-venue-delivery: 3b1f6c0e-6a8e-4c0e-9d52-0d1f6c7a1b11
x-venue-signature: sha256=9f2c…
{
"event": "booking.confirmed",
"occurred_at": "2026-11-05T12:00:03.120Z",
"data": {
"bookingId": "6f1c…", "number": "B-2026-00042", "status": "confirmed",
"startsAt": "2026-11-20T16:00:00.000Z", "endsAt": "2026-11-20T20:00:00.000Z", "guests": 40
}
}x-venue-signature: sha256=<hex>on keha toorbaitide HMAC-SHA256 saladusega. Kontrolli seda enne sisu usaldamist.x-venue-deliveryon saatmise unikaalne id; kordused kasutavad sama id-d ja sama keha, nii saad topeltsaatmised ära tunda.x-venue-eventon sündmuse nimi. Vasta 2xx staatusega 5 sekundi jooksul. Ümbersuunamisi (3xx) ei järgita ja need loetakse ebaõnnestunuks.- Kordused: ebaõnnestunud saatmist (mitte-2xx, ajalõpp, viga) korratakse 1 min, 5 min, 30 min, 2 h ja 12 h pärast. Pärast kuuendat katset märgitakse see "dead". Admin → Integratsioonid → Webhooki saatmislogi näitab viimast 100 saatmist (30 päeva), saadetud sisu ja nuppu "Proovi uuesti".
const crypto = require("node:crypto");
// rawBody: the request body exactly as received (a Buffer or string), NOT re-serialised JSON
function verify(rawBody, signatureHeader, secret) {
const expected = "sha256=" + crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
const a = Buffer.from(expected);
const b = Buffer.from(signatureHeader || "");
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
// Express: app.post("/hook", express.raw({ type: "application/json" }), (req, res) => {
// if (!verify(req.body, req.get("x-venue-signature"), process.env.WEBHOOK_SECRET)) return res.sendStatus(401);
// const delivery = req.get("x-venue-delivery"); // skip if you have already processed this id
// res.sendStatus(200);
// });Retsept: kinnitatud broneering → Google Sheeti rida (Zapier)
- Zapieris loo Zap, trigger: Webhooks by Zapier → Catch Hook. Kopeeri antud URL.
- Lisa URL Integratsioonide lehel webhookina, vali ainult
booking.confirmed. Salvesta saladus. - Tee Zapieris Test trigger: kinnita testbroneering, et Zapier saaks näidissisu.
- Action: Google Sheets → Create Spreadsheet Row; vii veergudesse
data.number,data.startsAt,data.guests. - Kliendi nime/e-posti vajadusel: lisa samm Webhooks by Zapier → Custom Request (GET
/api/v1/rest/bookings/{data.bookingId}ja/customers/{customer_id}, päisAuthorization: Bearer …).
Zapier ei kontrolli allkirja ise; kui see on oluline, lisa vahele Code by Zapier samm ülaltoodud kontrolliga.
Retsept: Make (Custom webhook)
- Make'is lisa moodul Webhooks → Custom webhook, loo uus webhook ja kopeeri URL.
- Lisa URL Integratsioonide lehel webhookina ja vali sündmused. Käivita Run once ja tekita sündmus, et Make õpiks struktuuri.
- Pärast seda saad kasutada välju
data.number,data.statusjne järgmistes moodulites. - Andmete lugemiseks: HTTP → Make a request, URL
https://APP/api/v1/rest/bookings, päisAuthorization: Bearer <võti>, parse response = jah; tulemusedata[]massiivi saab itereerida. n8n-is sama: HTTP Request sõlm.
Veaformaat / Errors
HTTP 400 { "problems": [ { "code": "invalid", "message": "…", "field": "guests" } ] }
HTTP 400 { "error": "invalid", "problems": ["date: Invalid"] } // availability
HTTP 404 { "error": "not_found" }
HTTP 409 { "problems": [ { "code": "not_available", "message": "Valitud aeg ei ole vaba", "field": "time" } ] }
HTTP 429 { "error": "rate_limited" }Vead on alati JSON. Kontrolli esmalt HTTP staatust, seejärel error või problems[].
WordPress
WordPressile on pistikprogramm (lühikood [venue_booking] ja plokk). Vidin v2 näitab vormi, vabade kuupäevade kalendrit või ruumide nimekirja (data-mode="form|calendar|rooms|events"), laeb alles siis, kui külastaja selleni kerib, ja võtab värvid CSS-muutujatest --vb-primary, --vb-radius, --vb-bg, --vb-text, --vb-font:
<div data-venue-booking data-venue="uks-maja" data-mode="calendar" data-lang="et"
style="--vb-primary:#0f766e;--vb-radius:12px"></div>
<script src="https://APP/widget.js" async></script>Vidin (iframe)
Lisa lehele "Custom HTML" plokk ja kleebi sinna:
<script src="https://APP/widget.js"
data-venue="uks-maja"
data-lang="et"
async></script>Valikuline data-target="#element-id" paigutab vormi etteantud elementi. Vidin kohandab kõrgust automaatselt ja töötab ühel lehel mitu korda. Pärast taotluse saatmist tekib iframe elemendil sündmus venuebooking:submitted (detail.number on broneeringu number):
document.addEventListener("venuebooking:submitted", function (e) {
console.log("Taotlus saadetud, number:", e.detail.number);
});Google Tag Manageri jaoks lisa skripti sildile data-datalayer="1": siis lisatakse window.dataLayer massiivi sündmus { event: "venue_booking_submitted", booking_number }. Meie vidin ise jälgimisskripte ei laadi; nõusoleku ja edasise töötluse otsustab teie oma tag manager.
Vabade aegade päring PHP-s
<?php
$res = wp_remote_get( add_query_arg( array(
'date' => '2026-11-20',
'duration' => 180,
'rooms' => 'ROOM_ID_1',
), 'https://APP/api/v1/uks-maja/availability' ), array( 'timeout' => 10 ) );
if ( ! is_wp_error( $res ) && 200 === wp_remote_retrieve_response_code( $res ) ) {
$data = json_decode( wp_remote_retrieve_body( $res ), true );
$starts = $data['commonStarts']; // nt ["10:00", "18:00"]
}Saabuv e-kiri / Inbound email
Taotlusi saab saata ka e-kirjaga. Kui kirja tekst järgib allolevat vormi, tõlgendatakse see otse (ilma tehisaruta). Rea võti on enne koolonit; suur- ja väiketähti ei eristata. Kohustuslikud on Kuupäev ja Algus. Kuupäev kujul AAAA-KK-PP, kellaaeg HH:MM, loetelud komaga eraldatud.
Tüüp: private
Sündmus: Sünnipäev
Kuupäev: 2026-11-20
Algus: 18:00
Lõpp: 22:00
Osalejaid: 40
Ruumid: Saal, Köök
Lisateenused: Heli
Ettevõte: Näide OÜ
Telefon: +372 5555 5555
Pealkiri: Mari 30
Sõnum: Soovime ka kohvilauda.Puuduvate väljade korral märgitakse taotlus mittetäielikuks ja personal täiendab selle käsitsi.