Rezerwacje i dostępność
Ten przewodnik opisuje przepływ rezerwacji i reguły, które nim rządzą. Pola i parametry każdego endpointu znajdziesz w referencji API.
Przepływ
Dział zatytułowany „Przepływ”GET /v1/services— wybierz usługę.GET /v1/availability— pobierz wolne terminy usługi.POST /v1/bookings— zarezerwuj wybrany termin.GET /v1/bookings/{id}alboGET /v1/bookings— śledź stan rezerwacji.POST /v1/bookings/{id}/cancel— anuluj, jeśli trzeba.
Usługi i pracownicy
Dział zatytułowany „Usługi i pracownicy”API zwraca te same usługi, które klient widzi w widgecie organizacji: aktywne, publiczne i z co najmniej jednym aktywnym pracownikiem. Rezerwację utworzysz tylko dla usługi z tej listy — inna daje 404 not_found.
Przed rezerwacją sprawdź w usłudze:
modes—online,offlinealbo oba. Gdy usługa ma oba tryby, w rezerwacji musisz podaćmode.required_client_fields— które dane klienta są wymagane.namejest zawsze. Organizacja może wymagać teżemail,phonealbo obu.payment—none,optional,requiredalbodeposit. Dwie ostatnie wartości oznaczają płatność z góry. Zobacz Płatności online.staff_ids— pracownicy, którzy wykonują usługę.
GET /v1/staff zwraca pracowników z imieniem i listą usług, bez danych kontaktowych.
Listy usług i pracowników mają Cache-Control: private, max-age=60. Możesz je cache’ować przez minutę.
Wolne terminy
Dział zatytułowany „Wolne terminy”GET /v1/availability przyjmuje service_id, opcjonalnie staff_id oraz daty from i to (YYYY-MM-DD, obie włącznie).
tomoże być najwyżej 31 dni pofrom. Dłuższy zakres daje422 range_too_large, atoprzedfrom—422 invalid_range.- Organizacja, która chwilowo nie przyjmuje rezerwacji, zwraca
409 booking_unavailablezamiast slotów. Pusta listadataznaczy więc tylko brak wolnych terminów. - Dni w przeszłości i dni za horyzontem rezerwacji organizacji nie mają slotów. Zakres jest przycinany, a nie odrzucany.
- „Dziś” to data w strefie organizacji, nie w UTC.
- Bez
staff_iddostajesz sloty wszystkich pracowników usługi. Każdy slot mastaff_idpracownika, który go obsłuży. - Sloty uwzględniają godziny pracy, bufory, minimalne wyprzedzenie i istniejące rezerwacje — tak jak widget.
Odpowiedź to {data: [...]} bez paginacji i z Cache-Control: no-store. Wolne terminy zmieniają się z każdą rezerwacją, więc pobieraj je tuż przed pokazaniem klientowi.
W noc zmiany czasu end - start zawsze odpowiada rzeczywistemu czasowi usługi, a offset końca może różnić się od offsetu początku.
Tworzenie rezerwacji
Dział zatytułowany „Tworzenie rezerwacji”POST /v1/bookings wymaga scope’u bookings:write i nagłówka Idempotency-Key. Body:
service_id,start(z offsetem) iclientsą wymagane;staff_id— pracownik slotu; bez niego Rezeri wybierze pracownika sam;mode— gdy usługa ma oba tryby;pay_online,return_url— dla płatności online, zobacz Płatności online;terms_accepted,terms_hash,early_performance_requested— akceptacja warunków, zobacz Warunki rezerwacji;metadata— Twoje dane (niżej).
Body z nieznanym polem daje 422 unknown_field.
Co sprawdza Rezeri
Dział zatytułowany „Co sprawdza Rezeri”Rezerwacja przechodzi te same reguły co rezerwacja z widgetu:
| Sytuacja | Błąd |
|---|---|
| Usługa albo pracownik spoza oferty organizacji | 404 not_found |
Brak mode przy usłudze z dwoma trybami |
422 mode_required |
mode, którego usługa nie oferuje |
422 mode_not_supported |
| Brak wymaganego e-maila albo telefonu klienta | 422 client_email_required, 422 client_phone_required |
| Termin zajęty, w przeszłości, za blisko albo za daleko w przyszłości | 409 slot_unavailable |
| Organizacja chwilowo nie przyjmuje rezerwacji | 409 booking_unavailable |
| Wyczerpany miesięczny limit rezerwacji planu organizacji | 403 booking_limit_reached |
| Za dużo rezerwacji jednego klienta albo pracownika | 429 client_booking_limit |
start nie musi leżeć na siatce slotów, ale musi przejść wszystkie powyższe kontrole. Najpewniej rezerwować start i staff_id slotu z /v1/availability.
Po 409 slot_unavailable pobierz wolne terminy ponownie i zaproponuj klientowi inny.
Warunki rezerwacji
Dział zatytułowany „Warunki rezerwacji”Jeśli organizacja ma warunki rezerwacji albo własny regulamin, klient musi je zaakceptować w Twoim formularzu przed rezerwacją.
-
Pobierz warunki:
GET /v1/booking-terms?service_id=...&start=...(scopebookings:write;pay_online=truewybiera wariant dla płatności online). Odpowiedź maCache-Control: no-storei status200także wtedy, gdy organizacja nie ma warunków (terms: null):{ "terms": { "...": "..." }, "privacy_notice": { "...": "..." } }termsjestnull, gdy organizacja nie ma warunków do akceptacji albo gdy rezerwacja w tym terminie powstanie jako prośba, która nie blokuje terminu do decyzji usługodawcy — wtedy pomiń kolejne kroki. -
Pokaż klientowi
terms.sections(tytuły i akapity), a gdy jestterms.provider_terms— link do regulaminu organizacji (url; dla regulaminu tekstowego jest to bezwzględny adres strony). Gdyterms.requestnie jestnull, pokaż też jegolabelidescriptionjako osobną zgodę na rozpoczęcie usługi przed upływem 14 dni na odstąpienie od umowy. -
Pod formularzem pokaż klauzulę informacyjną z art. 13 RODO na podstawie
privacy_notice(nazwa, adres, NIP i e-mail administratora, czyli usługodawcy). Rezeri niczego z niej nie zapisuje i nie wymaga potwierdzenia. -
Wyślij w
POST /v1/bookings:terms_accepted: true,terms_hashz odpowiedzi orazearly_performance_requested: true, gdy klient wyraził zgodę z kroku 2 (terms.requestnie jestnull).terms_hashma najwyżej 128 znaków.
Akceptacji nie wymaga tylko prośba o rezerwację, która nie blokuje terminu do czasu decyzji usługodawcy (status pending). Rezerwacja czekająca na akceptację usługodawcy, ale blokująca termin (też pending), wymaga akceptacji warunków jak każda inna.
| Sytuacja | Błąd |
|---|---|
Brak terms_accepted: true albo terms_hash |
422 terms_required |
Brak early_performance_requested, choć terms.request nie jest null |
422 early_performance_required |
terms_hash nieaktualny — warunki się zmieniły |
409 terms_changed |
Po 409 terms_changed pobierz warunki ponownie i pokaż je klientowi. Odrzucenie przez warunki zwalnia Idempotency-Key, więc ponowienie z tym samym kluczem i poprawnymi polami utworzy rezerwację.
Odpowiedź 201 zawiera pełną rezerwację. Rezerwacja ma źródło „API” i trafia do kalendarza panelu jak każda inna. Klient końcowy dostaje standardowe powiadomienia organizacji.
API nie wymaga od klienta weryfikacji kontaktu kodem. Uwierzytelnienie klientów jest po stronie Twojego systemu.
Statusy
Dział zatytułowany „Statusy”status |
Znaczenie |
|---|---|
pending |
czeka na akceptację pracownika |
awaiting_payment |
czeka na płatność online |
accepted |
przyjęta |
cancelled |
anulowana |
completed |
zakończona |
Nieobecność klienta nie jest statusem. Zaznacza ją pole no_show_at z czasem oznaczenia albo null.
W przyszłości mogą dojść nowe statusy. Obsłuż nieznaną wartość, zamiast odrzucać odpowiedź.
Pola rezerwacji
Dział zatytułowany „Pola rezerwacji”Kilka pól wymaga komentarza:
price— uzgodniona cena jako string ("90.00") albonull.payment— stan płatności online:required,status,amount,url. Zobacz Płatności online.client.emailiclient.phonemogą byćnull— rezerwacja z panelu może mieć tylko jeden kontakt.service_idistaff_idto wartości z chwili rezerwacji. Starsza rezerwacja może wskazywać usługę albo pracownika, których nie zwraca już/v1/servicesani/v1/staff.manage_url— strona rezerwacji dla klienta końcowego.metadata— obiekt z Twoimi danymi albo{}dla rezerwacji spoza API.
Odpowiedzi z rezerwacją mają Cache-Control: no-store — zawierają dane osobowe klienta.
Metadane
Dział zatytułowany „Metadane”metadata to do 20 par klucz–wartość, które zapisujesz przy tworzeniu rezerwacji. Klucz ma do 40 znaków, wartość jest stringiem do 500 znaków. Przekroczenie limitu daje 422 validation_error.
Metadane wracają w każdej odpowiedzi z rezerwacją: przy tworzeniu, odczycie, na liście i przy anulowaniu. Użyj ich do powiązania rezerwacji z rekordem w swoim systemie, np. {"order_id": "1001"}.
Nie zapisuj w metadanych danych wrażliwych.
Lista rezerwacji
Dział zatytułowany „Lista rezerwacji”GET /v1/bookings zwraca rezerwacje organizacji posortowane po start rosnąco.
Filtry:
fromito— czas z offsetem; lista obejmuje rezerwacje zstartw przedziale[from, to). Czas bez offsetu daje422 validation_error.status— jedna z publicznych wartości statusu.staff_id— rezerwacje jednego pracownika.
Paginacja
Dział zatytułowany „Paginacja”Listy z paginacją — usługi, pracownicy, rezerwacje i endpointy webhooków — mają ten sam kształt (GET /v1/availability nie jest paginowane, zwraca same data):
{"data": [ ... ], "has_more": true, "next_cursor": "eyJrIjoi..."}Gdy has_more jest true, pobierz kolejną stronę z cursor=<next_cursor> i tymi samymi filtrami:
curl "https://api.rezeri.com/v1/bookings?from=2026-10-01T00:00:00%2B02:00&limit=50&cursor=eyJrIjoi..." \ -H "Authorization: Bearer $REZERI_API_KEY"limit przyjmuje 1–100 (domyślnie 20). Kursor jest nieprzezroczysty — nie składaj go sam. Zły kursor albo kursor z innej listy daje 422 invalid_cursor. Na ostatniej stronie has_more ma wartość false, a next_cursor — null.
Pamiętaj o %2B zamiast + w offsecie w adresie URL.
Anulowanie
Dział zatytułowany „Anulowanie”POST /v1/bookings/{id}/cancel anuluje rezerwację w imieniu klienta. Body jest opcjonalne: {"reason": "…"} (do 500 znaków).
curl -X POST https://api.rezeri.com/v1/bookings/311905c9-7a15-45c0-8b66-1dd2e8711875/cancel \ -H "Authorization: Bearer $REZERI_API_KEY" \ -H "Content-Type: application/json" \ -d '{"reason": "Klient zmienił plany"}'- Odpowiedź
200zawiera anulowaną rezerwację. - Ponowne anulowanie już anulowanej rezerwacji też daje
200. - Wizyta, która już się rozpoczęła, daje
409 cancellation_window_closed. - Rezerwacja w stanie, którego nie da się anulować (np.
completed), daje409 not_cancellable. - Zwrot płatności liczy się według zasad anulowania organizacji, tak jak przy anulowaniu przez klienta na stronie rezerwacji.
Nagłówek Idempotency-Key jest tu opcjonalny.
Przełożenie wizyty
Dział zatytułowany „Przełożenie wizyty”v1 nie ma endpointu przełożenia. Kieruj klienta na manage_url z odpowiedzi rezerwacji — tam przełoży albo anuluje wizytę sam. Zmianę zobaczysz w GET /v1/bookings/{id}.
Link do spotkania online nie jest częścią odpowiedzi. Klient znajdzie go pod manage_url.
Inna organizacja
Dział zatytułowany „Inna organizacja”Każde ID rezerwacji, usługi albo pracownika spoza organizacji klucza daje 404 not_found — w ścieżce i w body. API nie zdradza, czy taki zasób istnieje.