Przejdź do treści
StayPark Suite · Pomoc
StayPark Suite · Pomoc
Zamknij menu
Szukaj w pomocy Ctrl K
Wprowadzenie Przewodniki Panel - obsługa Portal i aplikacje Wdrożenie i konfiguracja Integracje i API Nowości
API aplikacji mobilnej klienta

API aplikacji mobilnej klienta

Marka w nagłówku, logowanie kodem i hasłem, konto, zgody i e-paragony, tryb gościa, sekcje marki, Idempotency-Key, punkty, nagrody, zamówienia, sklep, bilety i kod klienta w API aplikacji klienta.

Integrator

Zaktualizowano 2 listopada 2026

Na tej stronie
Podświetlone słowa z wyszukiwania: ()

API aplikacji mobilnej (/api/mobile-app/v1, wersja 1.4) to portal klienta marki bez przeglądarki. Aplikacja dostaje te same dane i te same decyzje co portal: te same ceny, rabaty, odmowy i komunikaty. Ten przewodnik opisuje logowanie, konto, tryb gościa, ochronę przed podwójnym wykonaniem, punkty i nagrody, zamówienia, sklep, bilety i kod klienta. Treści marketingowe i cele przycisków opisuje osobny artykuł: Treści i cele przycisków. Pola i przykłady operacji są w mobile-app.yaml, w panelu pod /help/api/mobile-app (gdzie ją znaleźć).

Marka w każdym żądaniu

Każde żądanie poza health i version niesie markę w nagłówku X-Brand-Slug (albo X-Brand-UUID). Nieznana marka daje 400 BRAND_NOT_FOUND, marka nieaktywna 403 BRAND_INACTIVE, a marka z wyłączonym portalem 403 PORTAL_DISABLED.

Na starcie pobierz GET brand/config - wygląd marki, kontakt, sposoby logowania i stan sekcji (features). Sekcje marka włącza tymi samymi przełącznikami co w portalu: rewards, orders, profiles, contractors, shop (domyślnie wyłączony; wymaga też sprzedaży w kanale aplikacji); loyalty oznacza aktywny program lojalnościowy. Operacja z wyłączonej sekcji daje 403 FEATURE_DISABLED z polem error.feature. Ukryj wtedy tę część aplikacji. Dokumenty marki pobierzesz jako HTML z GET brand/documents/{type}: terms (regulamin), privacy (polityka prywatności), e_receipts (Regulamin e-paragonów).

GET version (bez marki i tokenu) podaje api_version - wersję kontraktu z pliku OpenAPI - i features, czyli sekcje, które obsługuje serwer. O sekcjach marki decyduje brand/config, nie version. Pola min_app_version, latest_app_version i update_required są dziś stałe. GET health zwraca stan usługi.

Logowanie

Zgody marketingowe przy rejestracji zapisują się tylko z wartością true i tylko wtedy, gdy marka pokazuje zgody marketingowe.

Token Sanctum jest ważny 90 dni (expires_at) i związany z marką, dla której go wydano. POST auth/refresh kasuje bieżący token i wydaje nowy tej samej marki; identyfikator urządzenia i klucz kodu offline przechodzą na nowy token. POST auth/logout kasuje token i unieważnia klucz kodu offline urządzenia. GET auth/me zwraca zalogowanego klienta. Nagłówek innej marki daje 403 BRAND_MISMATCH, a stary token bez przypisanej marki - 401 REAUTH_REQUIRED (zaloguj ponownie).

Każda operacja zwraca wyłącznie dane właściciela tokenu w marce tokenu. Cudzy zasób albo zasób innej marki daje 404 NOT_FOUND, a nie 403 - API nie zdradza, że taki zasób istnieje.

Urządzenia

device_id z logowania opisuje urządzenie na liście GET devices i jest na niej pokazywany jako nazwa urządzenia (bez niego - losowy identyfikator). device_name jest dziś przyjmowane, ale nie jest zapisywane. device_id to inny identyfikator niż X-Device-Id używany przy pomiarze treści gościa - nie łącz ich.

  • GET devices - zalogowane urządzenia konta we wszystkich markach (bez wygasłych), od ostatnio używanego; is_current oznacza bieżące, brand_slug - markę tokenu.
  • DELETE devices/{id} - odłącza urządzenie (token i klucz kodu offline). Bieżącego nie odłączysz (409 CANNOT_REVOKE_CURRENT) - użyj POST auth/logout. Token cudzy albo spoza aplikacji klienta daje 404.
  • POST devices/revoke-all - odłącza pozostałe urządzenia bieżącej marki; urządzenia w aplikacjach innych marek zostają.

Konto, hasło i zgody

  • GET account zwraca dane konta, PATCH account zmienia imię, nazwisko, e-mail i telefon (pominięte pole zostaje). Telefon innego konta daje 409 PHONE_EXISTS, zajęty e-mail - 422 VALIDATION_ERROR, a próba usunięcia naraz e-maila i telefonu - 400 IDENTIFIER_REQUIRED.
  • POST account/password ustawia pierwsze hasło (password, password_confirmation, co najmniej 8 znaków); konto z hasłem dostaje 409 PASSWORD_ALREADY_SET. PUT account/password zmienia hasło (current_password, password, password_confirmation); konto bez hasła - 409 PASSWORD_NOT_SET, złe aktualne hasło - 400 INVALID_PASSWORD, po 5 błędnych próbach na konto (albo 20 na adres IP) w 15 minut - 429 TOO_MANY_REQUESTS. Marka bez haseł daje w obu 403 FORBIDDEN.
  • Ustawienie albo zmiana hasła wylogowuje pozostałe urządzenia klienta we wszystkich markach i unieważnia ich klucze kodu offline (other_devices_logged_out w odpowiedzi). Bieżący token i jego klucz zostają. Nieudana próba niczego nie wylogowuje.
  • DELETE account dezaktywuje konto po potwierdzeniu hasłem (password) albo kodem (confirmation_code). Kod zamów przez POST auth/request-code - przychodzi na e-mail konta, a bez e-maila na telefon. Złe hasło daje 400 INVALID_PASSWORD, zły kod - 400 INVALID_CONFIRMATION_CODE. Dezaktywacja kasuje tokeny i klucze kodu offline.
  • GET account/consents zwraca zgody marketingowe (email, sms, phone, push), PUT account/consents je zmienia (pominięty kanał bez zmian). Marka bez zgód marketingowych daje w GET enabled: false i pustą listę, a w PUT - 403 FORBIDDEN.
Konto pracownika

Klient, który jest też pracownikiem z dostępem do panelu, loguje się w aplikacji tym samym kontem. E-mail, telefon i hasło są wtedy danymi logowania do panelu, więc aplikacja ich nie zmienia: zmiana e-maila albo telefonu daje 403 STAFF_ACCOUNT_CONTACT_LOCKED, a ustawienie lub zmiana hasła i dezaktywacja konta - 403 STAFF_ACCOUNT_LOCKED. Imię i nazwisko takie konto zmienia normalnie. Dane kontaktowe zmienia administrator w panelu, a hasło pracownik zmienia w panelu.

E-paragony i sprzeciw wobec profilowania

E-paragony. GET account/e-receipts zwraca stan przełącznika „Chcę otrzymywać e-paragony” w marce tokenu. Włączony przełącznik znaczy, że na kasie w lokalizacji klient dostaje domyślnie e-paragon na e-mail konta (address_masked); przy zakupach na odległość e-paragon przychodzi zawsze.

  1. Pobierz GET account/e-receipts. Gdy available = false, marka nie wskazała Regulaminu e-paragonów - ukryj przełącznik.
  2. Gdy blocker_code nie jest pusty, pokaż powód (EMAIL_REQUIRED - konto bez e-maila, E_RECEIPT_REGULATION_MISSING).
  3. Gdy regulation.accepted = false, pokaż regulamin (regulation.document_path = brand/documents/e_receipts) i pole akceptacji.
  4. Wyślij PUT account/e-receipts z enabled: true i accept_regulation_version = regulation.version_hash. Wyłączenie (enabled: false) działa od razu.

Brak akceptacji bieżącej wersji regulaminu daje 422 E_RECEIPT_TERMS_NOT_ACCEPTED, konto bez e-maila - 422 EMAIL_REQUIRED. Akceptacja trafia do rejestru akceptacji z kanałem „W aplikacji mobilnej”.

Sprzeciw wobec profilowania. GET account/profiling-objection zwraca stan przełącznika „nie profiluj” z gotowymi tekstami label i description (te same co w portalu). PUT account/profiling-objection z objected: true zgłasza sprzeciw, a z false go wycofuje - od razu. Klient ze sprzeciwem nie trafia do grup odbiorców wybieranych na podstawie zachowania ani do automatów reagujących na zachowanie. Zgody na wiadomości działają dalej. Ta operacja działa zawsze, niezależnie od ustawień portalu marki.

Profile osób i dane do faktury

  • account/profiles (sekcja profiles) - osoby klienta, np. dzieci: lista z type_options i gender_options, dodanie, karta, zmiana (PATCH; pominięte pole bez zmian, pusty napis = brak wartości), usunięcie.
  • account/contractors (sekcja contractors) - nabywcy do faktury, domyślny pierwszy. buyer_type = company (domyślnie, gdy podano NIP) albo person. NIP, REGON i KRS system sprowadza do cyfr. NIP jest unikalny wśród nabywców klienta. Pierwszy nabywca zostaje domyślnym, POST account/contractors/{uuid}/default zmienia domyślnego, a po usunięciu domyślnego jego miejsce zajmuje następny.

Tryb gościa

Bez tokenu działają: brand/config, brand/documents/{type}, treści (content*, news*) i zdarzenia treści. Aplikacja może więc pokazać ekran startowy przed logowaniem. Gdy wysyłasz Authorization, obowiązują wszystkie reguły tokenu - zły token daje błąd, a nie widok gościa. Przebieg trybu gościa i powrót do celu po logowaniu: Treści i cele przycisków.

Idempotency-Key

Operacje zmieniające stan przyjmują nagłówek Idempotency-Key (8-64 znaki A-Z a-z 0-9 _ - : ., np. UUID wygenerowany przy otwarciu okna potwierdzenia).

Nagłówek Operacje
wymagany POST rewards/{uuid}/redeem, POST shop/checkout, POST shop/orders/{uuid}/pay, POST ticket-entitlements/claim
opcjonalny POST account/profiles, POST account/contractors, POST customer-code/offline-key, POST shop/cart/items, POST shop/orders/{uuid}/return-request
  • To samo żądanie z tym samym kluczem w ciągu 24 godzin dostaje pierwszą odpowiedź jeszcze raz, z nagłówkiem Idempotent-Replayed: true. Nic nie dzieje się drugi raz.
  • Ten sam klucz z inną ścieżką albo treścią daje 409 IDEMPOTENCY_KEY_REUSED. Równoległe żądanie z tym samym kluczem daje 409 IDEMPOTENCY_IN_PROGRESS (po 10 sekundach oczekiwania). Brak wymaganego nagłówka daje 400 IDEMPOTENCY_KEY_REQUIRED, zły format - 400 INVALID_IDEMPOTENCY_KEY.
  • Serwer pamięta odpowiedzi 2xx i 4xx, także odmowę. Po zmianie danych przez klienta wyślij nowy klucz. Odpowiedzi 5xx i 429 nie są pamiętane - ponów z tym samym kluczem.
  • Odbiór nagrody i złożenie zamówienia w sklepie są dodatkowo zabezpieczone w bazie: ten sam klucz to zawsze to samo zamówienie, także po upływie 24 godzin.

Limity żądań

Trasy zalogowanego klienta liczą żądania osobno dla konta i dla grupy operacji. Limit grupy i limit operacji obowiązują razem, więc wiąże niższy.

Operacje Limit trasy na minutę Limit w operacji
auth/request-code, auth/login 30 limity kodów i haseł jak w portalu (jako 400)
auth/verify-code 60 błędne próby kodu jak w portalu (jako 400)
auth/register 10 -
auth/logout, auth/refresh, auth/me, account, account/password, account/consents, devices/*, loyalty* 120 PUT account/password: 5 błędnych prób na konto i 20 na IP w 15 minut
account/e-receipts, account/profiling-objection odczyt 60, zmiana 20 -
customer-code 60 -
customer-code/offline-key odczyt 30, wydanie i unieważnienie po 10 -
account/profiles/*, account/contractors/* 60 -
rewards/*, orders/*, shop/*, ticket-entitlements/* 120 -
POST rewards/{uuid}/redeem 20 10 prób odbioru na konto
dokumenty PDF zamówień i zakupów 30 -
koszyk (shop/cart/items*, DELETE shop/cart) 60 -
kody rabatowe w koszyku 20 10 prób kodu w 10 minut na konto i na IP, wspólnie z portalem
POST shop/checkout, POST shop/orders/{uuid}/pay 10 starty płatności (SHOP_TOO_MANY_ATTEMPTS)
POST shop/orders/{uuid}/return-request 5 -
POST ticket-entitlements/claim 10 5 prób na minutę na konto i na IP, wspólnie z portalem
PATCH ticket-entitlements/{uuid}/visit-date 20 -
online-payments/{uuid} 60 refresh=1 pyta bramkę najwyżej raz na minutę
treści i aktualności / zdarzenia treści 120 / 240 -

Bez limitu trasy są health, version i brand/*. Cztery trasy logowania (auth/request-code, auth/verify-code, auth/register, auth/login) liczą żądania na adres IP, każda własnym licznikiem - żądania auth/login nie zużywają limitu auth/register. Treści i zdarzenia gościa też liczą się na adres IP. Limit trasy daje 429 HTTP_ERROR, limit prób w operacji - 429 TOO_MANY_REQUESTS z error.retry_after; oba z nagłówkiem Retry-After. Nieoczekiwany błąd serwera daje 500 SERVER_ERROR w zwykłej kopercie.

Punkty i nagrody

  • GET loyalty - saldo, poziom i postęp do następnego, punkty wygasające i opis programu. Bez aktywnego programu: enabled: false. GET loyalty/transactions (filtry type, direction, date_from, date_to) i GET loyalty/transactions/{uuid} - historia punktów (sekcja loyalty).
  • GET rewards (sekcja rewards) - nagrody dostępne dla poziomu klienta: bez ograniczenia poziomu albo z poziomem nie wyższym niż poziom klienta. can_redeem i refusal_reason to podpowiedź; wiążąco sprawdza dopiero odbiór. Filtry: search, category, affordable, featured, sort. Kategorie: GET rewards/categories.
  • POST rewards/{uuid}/redeem z Idempotency-Key - punkty schodzą od razu. Nagroda z promocją wydaje jednorazowy kod NAG… (QR ASIK1:<kod>), ważny code_valid_days dni. Nagroda wymagająca zatwierdzenia dostaje status awaiting_approval, a kod przychodzi po zatwierdzeniu. 201 to nowy odbiór, 200 - ten sam klucz ponownie. Odmowa daje 422 REDEMPTION_REFUSED z powodem w message. Klient nie anuluje odbioru.
  • GET rewards/redemptions (status: active, awaiting, history, all) - moje nagrody i kody. Kod po terminie ma status expired i nie pokazuje coupon_code. Kod zarezerwowany na otwartym rachunku kasy (12 godzin) albo w zamówieniu ma available: false i reservation - nie pokazuj go jako dostępnego.

Zamówienia i płatności online

GET orders (sekcja orders, filtr status) i GET orders/{uuid} pokazują zamówienia klienta w marce - tylko do odczytu. Karta zamówienia niesie pozycje z terminem, miejscem, opcjami i stanem realizacji, wpłaty i zwroty, płatność online w toku, stan rezygnacji (cancellation.state; samej rezygnacji w aplikacji nie ma) i dokumenty z download_path.

Dokument Operacja
potwierdzenie zamówienia (nie dla anulowanego) GET orders/{uuid}/documents/confirmation
faktura (tylko gotowa) GET orders/{uuid}/documents/invoices/{invoiceUuid}
regulamin pozycji ścieżka z documents.regulations[].download_path

Dokumenty przychodzą jako PDF z nagłówkiem Cache-Control: no-store. Pola e-paragonu w documents (receipt_delivery, receipt_address_masked, receipt_delivery_message, receipt_delivery_blocker) mówią, jak klient dostanie paragon za wpłatę. receipt_delivery_blocker oznacza brak e-maila - wpłaty online system wtedy nie przyjmie.

GET online-payments/{uuid} zwraca stan płatności online: state = processing, paid, late, cancelled albo failed, z odsyłaczem do zamówienia (order_uuid) albo zakupu w sklepie (shop_order_uuid). Parametr refresh=1 pyta bramkę płatności, najwyżej raz na minutę.

Sklep

Sklep działa, gdy marka go włączyła i sprzedaje w kanale aplikacji (features.shop). Koszyk jest jeden na klienta w marce i wspólny z portalem; ceny przelicza się przy każdym pobraniu koszyka.

Zakup w sklepie marki
  1. Katalog GET shop/localizations, shop/categories, shop/products, karta produktu.
  2. Koszyk POST shop/cart/items, kody rabatowe POST shop/cart/coupons.
  3. Złożenie GET shop/checkout (regulaminy, dokument), potem POST shop/checkout z Idempotency-Key.
  4. PayU Otwórz payment.redirect_url; powrót na payment.continue_url.
  5. Stan i bilety GET online-payments/{uuid}, potem GET ticket-entitlements.
  • Kilka lokalizacji. Marka może sprzedawać w kilku lokalizacjach, każda z własnym katalogiem i cenami. Zapamiętaj wybór klienta i wysyłaj localization_uuid w katalogu, na karcie produktu i przy dodaniu do koszyka. Lokalizacja spoza listy daje 422 LOCALIZATION_NOT_AVAILABLE.
  • Jeden operator w koszyku. Koszyk może łączyć produkty kilku lokalizacji, ale jednego operatora. Produkt innego operatora daje 422 SHOP_OTHER_OPERATOR - klient kończy zakup albo czyści koszyk (DELETE shop/cart). Zamówienie to jedna płatność i jeden dokument w lokalizacji fiskalizującej (fiscal_localization), a bilet działa w lokalizacji pozycji, z której go kupiono.
  • Koszyk. PATCH shop/cart/items/{uuid} zmienia ilość (0 usuwa pozycję), DELETE shop/cart/items/{uuid} usuwa pozycję, DELETE shop/cart/coupons/{code} zdejmuje kod. W koszyku działa kod rabatowy albo kod nagrody.
  • Regulaminy. POST shop/checkout wymaga akceptacji bieżących wersji wszystkich regulaminów z GET shop/checkout (version_hash). Brak akceptacji daje 422 SHOP_TERMS_NOT_ACCEPTED z listą required_regulations.
  • Powrót z PayU to adres https ekranu stanu płatności portalu. Aplikacja rozpoznaje go w przeglądarce w aplikacji - linków uniwersalnych nie ma.
  • Odmowy mają kod w error.code i nazwę pola w error.field; kwoty i powody są te same co w portalu. Lista: Kody błędów.

Po zakupie GET shop/orders (filtr status) pokazuje zakupy, a karta zakupu - pozycje, dokument (e-paragon albo faktura z download_path), bilety, płatność i prośbę o zwrot. Gdy płatność się nie udała, ponów ją przez POST shop/orders/{uuid}/pay z Idempotency-Key - trwająca próba jest wznawiana z tym samym redirect_url. Fakturę pobierzesz jako PDF z GET shop/orders/{uuid}/documents/invoices/{invoiceUuid}. Prośbę o zwrot niewykorzystanych biletów bez dnia wizyty (do 14 dni od zapłaty) złożysz przez POST shop/orders/{uuid}/return-request z ticket_uuids - zwrot wykonuje obsługa.

Bilety

GET ticket-entitlements (status: active, history, all) zwraca bilety klienta z każdego kanału sprzedaży: ze sklepu, z kasy, z panelu. Działa także przy wyłączonym sklepie. Karta biletu niesie kod QR do pokazania przy wejściu (scan_payload, postać ASIW1:<kod>), instrukcję, wejścia i lokalizacje, w których bilet działa (redeemable_localizations; pusto - każda lokalizacja operatora).

  • Dodaj bilet kodem: POST ticket-entitlements/claim z code (W…, z myślnikami albo bez, albo ASIW1:…) i Idempotency-Key. Tak trafia na konto bilet na okaziciela tej marki, np. z wydruku kasy. Kod nieznany i kod innej marki dają ten sam 422 TICKET_NOT_FOUND. Limit prób jest wspólny z portalem.
  • Zmiana dnia wizyty: PATCH ticket-entitlements/{uuid}/visit-date z visit_date, tylko dla aktywnego biletu z ważnością na dzień wizyty, bez wejść, przed dniem wizyty i w zakresie visit_date_change.min-max. Inna cena na nowy dzień daje 422 VISIT_DATE_PRICE_DIFFERS - zmianę wykona obsługa. Klient dostaje e-mail.

Kod klienta

Kasa i bramka rozpoznają klienta po kodzie QR ASI1:<customer_uuid>:<kod>; kod ma 8 cyfr i zmienia się co 30 sekund. Online aplikacja pobiera go z GET customer-code. Bez internetu liczy go sama z klucza urządzenia:

  1. Po zalogowaniu wyślij POST customer-code/offline-key. Sekret (secret, 64 znaki) jest tylko w tej odpowiedzi - zapisz go w Keychain albo Android Keystore.
  2. Licz kod z sekretu i bieżącego czasu (HMAC-SHA256 jak w RFC 4226, krok 30 s). Algorytm krok po kroku jest w dokumentacji referencyjnej, w sekcji „Kod klienta offline”.
  3. Sprawdzaj GET customer-code/offline-key - mówi tylko, czy klucz jest aktywny, bez sekretu.

Ponowne POST unieważnia poprzedni klucz urządzenia. Konto ma najwyżej 10 aktywnych kluczy - wydanie kolejnego unieważnia najstarszy. Klucz wydaje się tylko tokenowi urządzenia, inaczej 403 FORBIDDEN. Klucz przestaje działać po DELETE customer-code/offline-key, wylogowaniu, odłączeniu urządzenia, usunięciu konta, wygaśnięciu tokenu i zmianie hasła na innym urządzeniu. Zmiana hasła w portalu klienta wylogowuje wszystkie urządzenia aplikacji we wszystkich markach. Urządzenie, które samo zmieniło hasło w aplikacji, zachowuje token i klucz. Kody zeskanowane przed unieważnieniem nadal przechodzą. Zegar telefonu powinien być synchronizowany (tolerancja 30 sekund).

Powiązane

Brak wyników