Synchronizacja statusów ogłoszeń i zamówień

Jeśli przechowujesz swoje ogłoszenia OLX we własnym systemie, musisz wiedzieć, kiedy zmienia się ich status w OLX - na przykład gdy ogłoszenie staje się aktywne po moderacji, wygasa lub zostaje usunięte. Z tego artykułu dowiesz się, jak być na bieżąco, pytając OLX wyłącznie o ogłoszenia, które się zmieniły, zamiast raz po raz pobierać całą bazę ogłoszeń.


1. Popularne podejście: pobieranie wszystkiego

Wiele integracji synchronizuje statusy w ten sposób: co kilka minut przegląda strona po stronie wyniki GET /api/partner/adverts, pobiera każde ogłoszenie (również nieaktywne) i porównuje je z własnymi danymi.

To działa, ale niemal cała ta praca idzie na marne. Większość Twoich ogłoszeń nie zmieniła się od ostatniego sprawdzenia, a mimo to każde uruchomienie pobiera je wszystkie od nowa.

Przykład poglądowy

Wyobraź sobie, że masz 5000 ogłoszeń i otrzymujesz 100 ogłoszeń na stronę. Jedno pełne sprawdzenie wymaga 50 zapytań. Jeśli powtarzasz je co 5 minut, daje to 600 zapytań na godzinę - nawet jeśli w tym czasie zmieniło się tylko 20 Twoich ogłoszeń. Liczby są przykładowe i służą jedynie zilustrowaniu problemu.

Pobieranie wszystkiego oznacza dla Ciebie:

  • długie synchronizacje, które obciążają Twoje serwery,
  • dużą ilość danych do pobrania, zapisania i porównania,
  • większe ryzyko przekroczenia limitów zapytań (zobacz Częste pytania),
  • późne wykrywanie zmian, ponieważ pełne sprawdzenie dużej bazy ogłoszeń zajmuje sporo czasu.

Niepotrzebnie obciąża to również OLX, który musi w kółko udostępniać te same, niezmienione ogłoszenia.


2. Lepsze podejście: kanał zmian ogłoszeń

Zamiast prosić „daj mi wszystkie moje ogłoszenia”, zapytaj: „które z moich ogłoszeń zmieniły się od ostatniego sprawdzenia?”. Właśnie na to pytanie odpowiada kanał zmian ogłoszeń:

GET /api/partner/status/adverts

Kanał zwraca wyłącznie identyfikatory ogłoszeń, które się zmieniły, zaczynając od najstarszej zmiany. Dla każdego identyfikatora pobierasz aktualne ogłoszenie za pomocą GET /api/partner/adverts/{advertId} i aktualizujesz jego status w swoim systemie. Jeśli nic się nie zmieniło, otrzymujesz pustą listę - jedno małe zapytanie i gotowe.

To tak jak ze skrzynką pocztową: nie czytasz ponownie wszystkich e-maili, żeby sprawdzić, co nowego - patrzysz tylko na nowe wiadomości.


3. Przed i po

Na tym samym przykładzie co powyżej (dane poglądowe: 5000 ogłoszeń sprawdzanych co 5 minut, 20 ogłoszeń zmienionych w ciągu godziny):

Pobieranie wszystkiego Kanał zmian ogłoszeń
Zapytania na godzinę 600 12 zapytań do kanału + 20 zapytań o ogłoszenia
Co pobierasz Wszystkie 5000 ogłoszeń, 12 razy Krótką listę identyfikatorów i 20 zmienionych ogłoszeń
Gdy nic się nie zmieniło Mimo to pełne pobieranie Jedno zapytanie z pustą listą
Praca po Twojej stronie Porównanie każdego ogłoszenia Aktualizacja tylko zmienionych ogłoszeń

4. Jak działa kanał zmian

Zapytanie do kanału przyjmuje następujące parametry:

Parametr Wymagany Opis
since Tak Moment, od którego chcesz odczytać zmiany, podany jako data w formacie ISO-8601 ze strefą czasową, na przykład 2026-05-11T10:00:00Z. Otrzymujesz zmiany zarejestrowane ściśle po tym momencie. Wysyłaj tę samą wartość w każdym kolejnym zapytaniu.
cursor Nie Wartość nextCursor z poprzedniej odpowiedzi. Wskazuje kanałowi miejsce, w którym zakończył się poprzedni odczyt. Pomiń ten parametr tylko wtedy, gdy zaczynasz odczyt od momentu since.
limit Nie Maksymalna liczba identyfikatorów na jednej stronie. Domyślnie 100; wartości powyżej 1000 są traktowane jak 1000.

Każda odpowiedź zawiera te same trzy pola:

  • data - identyfikatory ogłoszeń, które się zmieniły, zaczynając od najstarszej zmiany. Lista jest pusta, gdy nic się nie zmieniło.
  • hasMore - true, gdy na następnej stronie czekają kolejne zmiany.
  • nextCursor - Twoja zakładka. Jest zawsze obecny, nawet gdy pole data jest puste.

Pełny opis znajdziesz w dokumentacji API.


5. Synchronizacja krok po kroku

Krok 1: Rozpocznij odczyt kanału

Masz już swoje ogłoszenia w systemie, na przykład dzięki jednorazowemu pełnemu pobraniu. Jako since użyj momentu tuż przed rozpoczęciem tego pobierania, aby nie przeoczyć żadnej zmiany. Wyślij zapytanie bez kursora:

curl -H "Authorization: Bearer " \
  -H "Version: 2.0" \
  "https://www.olx.pl/api/partner/status/adverts?since=2026-05-11T10:00:00Z"
{
  "data": ["1024578390", "1024578412"],
  "hasMore": true,
  "nextCursor": "MXwyMDI2LTA1LTExVDEwOjA0OjEyLjMzMVp8MTAyNDU3ODQxMg"
}

Krok 2: Odczytaj pozostałe strony

Dopóki hasMore ma wartość true, wysyłaj to samo since razem z otrzymanym nextCursor przekazanym jako cursor:

curl -H "Authorization: Bearer " \
  -H "Version: 2.0" \
  "https://www.olx.pl/api/partner/status/adverts?since=2026-05-11T10:00:00Z&cursor=MXwyMDI2LTA1LTExVDEwOjA0OjEyLjMzMVp8MTAyNDU3ODQxMg"
{
  "data": ["1024578455"],
  "hasMore": false,
  "nextCursor": "MXwyMDI2LTA1LTExVDEwOjA1OjAxLjEwMlp8MTAyNDU3ODQ1NQ"
}

Krok 3: Pobierz tylko zmienione ogłoszenia

Dla każdego identyfikatora z data pobierz aktualne ogłoszenie i zaktualizuj jego status w swoim systemie:

curl -H "Authorization: Bearer " \
  -H "Version: 2.0" \
  "https://www.olx.pl/api/partner/adverts/1024578390"
{
  "data": {
    "id": 1024578390,
    "status": "active",
    ...
  }
}

Krok 4: Sprawdzaj zmiany regularnie

Gdy hasMore ma wartość false, Twoje dane są aktualne. Zapisz ostatni nextCursor. Przy następnym sprawdzeniu wyślij go jako cursor (razem z tym samym since). Jeśli w międzyczasie nic się nie zmieniło, otrzymasz pustą listę - mimo to zapisz nowy nextCursor:

{
  "data": [],
  "hasMore": false,
  "nextCursor": "MXwyMDI2LTA1LTExVDEwOjA1OjAxLjEwMlp8MTAyNDU3ODQ1NQ"
}

Cała pętla w pseudokodzie

since  = load("since")    # the moment your full download started
cursor = load("cursor")   # empty on the very first run

every few minutes:
    repeat:
        page = GET /api/partner/status/adverts?since=since&cursor=cursor
        for each advertId in page.data:
            ad = GET /api/partner/adverts/advertId
            save the status of advertId in your system as ad.status
        cursor = page.nextCursor
        save("cursor", cursor)
    until page.hasMore is false

6. Praktyczne wskazówki

  • Zapisuj zakładkę po każdej stronie. Przechowuj since i ostatni nextCursor w miejscu, które przetrwa restart, na przykład w bazie danych. Po przerwie lub awarii wznowisz odczyt dokładnie tam, gdzie został przerwany - niczego nie przeoczysz i niczego nie przetworzysz dwa razy.
  • Używaj kursora w niezmienionej postaci. Nie odczytuj, nie skracaj i nie twórz samodzielnie wartości kursora - zawsze odsyłaj dokładnie otrzymaną wartość.
  • Pusta lista to dobra wiadomość. Oznacza, że nic się nie zmieniło. Mimo to zapisz nextCursor z tej odpowiedzi.
  • Zmiany pojawiają się z niewielkim opóźnieniem. Zmiana staje się widoczna w kanale kilka sekund po jej wystąpieniu, więc bardzo świeża zmiana może pojawić się dopiero przy kolejnym sprawdzeniu.
  • Dobierz odpowiedni rozmiar strony. Mniejszy limit oznacza mniejsze odpowiedzi; większy pomaga szybciej nadrobić zaległości po dłuższej przerwie.
  • Obsługa błędów. Odpowiedź 400 z kodem validation_error oznacza, że zapytanie zawiera błąd - pole message wskazuje, którego parametru on dotyczy. Popraw zapytanie, zamiast wysyłać je ponownie bez zmian. Jeśli kursor zostanie odrzucony, zacznij od nowa, wysyłając tylko since z momentem ostatniej udanej synchronizacji.

7. Najważniejsze wnioski

  • Nie pobieraj całej bazy ogłoszeń tylko po to, żeby znaleźć kilka, które się zmieniły.
  • Zapytaj kanał zmian, które ogłoszenia się zmieniły, a następnie pobierz tylko te ogłoszenia.
  • Zapisuj nextCursor po każdej stronie - to Twoja zakładka.
  • Pusta lista oznacza brak zmian - jedno małe zapytanie zamiast pełnego pobierania.

To samo podejście możesz zastosować do zamówień - zobacz kanał zmian zamówień. W przyszłości dołączą kolejne obiekty.