Przejdź do treści

Zasady ogólne komunikacji

Dokument opisuje reguły wspólne dla całego API partnerskiego. Pozostałe dokumenty opisują poszczególne moduły i zakładają, że te zasady są znane.

Adresy

Wszystkie ścieżki zaczynają się od /partner/v1
Dokumentacja interaktywna /partner-api (Swagger UI), /partner-api-json (OpenAPI)
Socket.IO (czat) ten sam host, szczegóły w dokumentacji czatu

Adresy środowiska testowego i produkcyjnego przekażemy razem z poświadczeniami.

Swagger partnerski zawiera wyłącznie endpointy udostępnione integracji i pozwala przejść pełny przebieg bez pisania kodu: po wpisaniu poświadczeń w „Authorize" są one zapamiętywane między odświeżeniami strony.

Nagłówki

Nagłówek Wymagany Znaczenie
x-client-id zawsze identyfikator integracji
x-api-key zawsze klucz integracji
x-user-id prawie zawsze użytkownik końcowy, w którego imieniu działa żądanie
x-language nie język odpowiedzi

Klucz nigdy nie powinien opuścić backendu partnera. Całe REST API jest pomyślane jako komunikacja serwer–serwer; z przeglądarki nawiązywane jest wyłącznie połączenie Socket.IO, uwierzytelniane osobnym, krótkożyciowym tokenem.

x-user-id

Identyfikator zwracany przez POST /partner/v1/users przy zakładaniu konta. To on rozstrzyga, czyje dane są odczytywane i modyfikowane — nie ma innego mechanizmu sesji.

Wyjątki, w których nagłówek nie jest potrzebny: POST /partner/v1/users (użytkownik jeszcze nie istnieje) oraz endpointy słownikowe niezwiązane z użytkownikiem.

Podanie identyfikatora spoza własnej integracji kończy się 401 — użytkownicy jednej integracji są dla drugiej niewidoczni.

x-language

Dopuszczalne wartości: pl i en.

Nagłówek Użyty język
pominięty albo pusty język zapisany na profilu użytkownika, a w jego braku en
pl albo en ta wartość; wielkość liter bez znaczenia (PL działa jak pl)
cokolwiek innego en — bez zaglądania w profil

Ostatni wiersz bywa mylący: literówka w nagłówku nie kończy się błędem ani powrotem do języka użytkownika, tylko cichym przełączeniem całego interfejsu na angielski. Jeśli partner nie wysyła świadomie konkretnego języka, najbezpieczniej jest nagłówek pominąć i zdać się na profil.

Język profilu pochodzi z konfiguracji integracji i jest wspólny dla wszystkich jej użytkowników — szczegóły w dokumentacji użytkowników.

Język steruje wyłącznie treściami słownikowymi — nazwami ras, chorób, zabiegów, opisami triażu. Dane wprowadzone przez użytkownika wracają zawsze tak, jak je zapisano.

Jeden słownik jest wyjątkiem: nazwy leków są polskie niezależnie od języka — szczegóły w dokumentacji leków.

Uprawnienia

System partnera jest źródłem prawdy co do tego, kto ma prawo korzystać z usługi. My sprawdzamy dwie rzeczy:

  1. czy x-user-id należy do tej integracji,
  2. czy zasób, którego dotyczy żądanie, należy do tego użytkownika.

Drugi punkt dotyczy każdego zasobu — zwierzaka, wizyty, leku, prediagnozy, konwersacji. Odwołanie się do cudzego kończy się 403 albo 404, nawet przy poprawnym kluczu.

Subskrypcji nie sprawdzamy. Użytkownik założony przez integrację ma pełny i bezterminowy dostęp do uzgodnionego zakresu; decyzja, czy może z niego korzystać, należy do partnera.

Format odpowiedzi

Odpowiedzi to czysty JSON, bez koperty — obiekt zasobu albo obiekt z nazwanym polem, zależnie od endpointu. Nie ma wspólnego opakowania w rodzaju { data: … }.

Błędy mają jeden kształt:

{ "statusCode": 403, "message": "errors::access_denied", "error": "Forbidden" }

message bywa kluczem tłumaczenia (postać errors::…) — to identyfikator komunikatu w naszym systemie, nie tekst dla użytkownika. Treść komunikatu należy do partnera; do rozpoznania sytuacji służy statusCode i sam klucz.

Przy błędach walidacji message jest tablicą opisów pól:

{ "statusCode": 400,
  "message": ["date should not be empty", "treatAsWrapper must be a boolean value"],
  "error": "Bad Request" }

Kody

Kod Znaczenie
400 błąd walidacji ciała lub parametrów
401 brak lub nieprawidłowe poświadczenia, albo nieznany x-user-id
403 zasób nie należy do tego użytkownika
404 zasób nie istnieje albo nie należy do wskazanego rodzica
409 konflikt — dziś wyłącznie zajęty numer mikroczipa
422 żądanie poprawne, ale niewykonalne przy obecnym stanie danych — np. wyliczenie diety dla nieuzupełnionego profilu
500 błąd po naszej stronie; prosimy o zgłoszenie z czasem i treścią żądania

Pole nieznane w ciele żądania kończy się 400, a nie cichym pominięciem:

{ "statusCode": 400,
  "message": ["property treatAsWraper should not exist"],
  "error": "Bad Request" }

Robimy to celowo — literówka w nazwie pola inaczej wyglądałaby jak poprawne żądanie, którego skutek po prostu nie nastąpił.

Stronicowanie

Nie ma jednego wzorca — moduły powstawały w różnym czasie i zachowujemy ich istniejące kontrakty:

Wzorzec Gdzie Uwagi
page + take listy zwierzaków page liczone od zera, w odpowiedzi total
skip + take pielęgnacja w odpowiedzi count
cursor + take oś czasu, czat koniec listy to nextCursor: null

take ma na listach sufit 100 i własną wartość domyślną w każdym module. Wartość większa jest cicho przycinana do sufitu, nie powoduje błędu.

Wyjątkiem jest słownik leków (GET /pets/medicines-list), który domyślnie zwraca wszystkie pozycje — jest pomyślany jako dane do podpowiadarki, nie jako lista do przeglądania. Szczegóły w dokumentacji leków.

Daty i godziny

  • daty przyjmujemy w obu postaciach: YYYY-MM-DD albo pełne ISO 8601 (2026-09-04T00:00:00.000Z). Sama data jest rozumiana jako północ UTC, więc przy strefach na wschód od UTC warto przesyłać pełny znacznik czasu, gdy liczy się konkretny dzień lokalny
  • w odpowiedziach daty wracają zawsze w pełnym ISO 8601
  • godziny w ciele żądań i odpowiedziach modułów medycznych to tekst "HH:MM"
  • wyjątek: oś czasu, gdzie hour i minute są liczbami — szczegóły w jej dokumentacji

Wersjonowanie

Ścieżki zawierają v1. Zmiany niezgodne wstecz trafią do nowej wersji, a sposób wygaszania poprzedniej ustalimy wspólnie. Zmiany zgodne wstecz — nowe pola w odpowiedziach, nowe endpointy, nowe wartości pól opcjonalnych — mogą pojawić się w v1 bez uprzedzenia, dlatego prosimy o tolerancyjne parsowanie: nieznane pole w odpowiedzi nie powinno psuć integracji.

Zdarzenia przychodzące

Wszystko, co dzieje się po naszej stronie bez udziału partnera — odpowiedź weterynarza, przypomnienie, ankieta po wizycie — dociera webhookiem. Nie wysyłamy użytkownikom partnera naszych maili, powiadomień ani pushy. Szczegóły w dokumentacji webhooków.

Zalecana kolejność wdrożenia

1. POST /partner/v1/users                       → id użytkownika, zapisywane u partnera
2. GET  /partner/v1/pets/pets-profile-relations → słowniki do formularza
3. POST /partner/v1/pets                        → pierwszy zwierzak
4. dalej moduły w dowolnej kolejności: żywienie, prediagnoza, książeczka zdrowia, czat
5. odbiór webhooków