If you keep your OLX ads in your own system, you need to know when their status changes on OLX - for example when an ad becomes active after moderation, expires or is removed. This article shows how to stay up to date by asking OLX only about the ads that changed, instead of downloading your whole inventory again and again.
1. The common approach: downloading everything
Many integrations keep statuses in sync like this: every few minutes they page through GET /api/partner/adverts, download every ad (including inactive ones) and compare each of them with their own records.
It works, but almost all of this work is wasted. Most of your ads did not change since the last check, yet every run downloads all of them again.
Example only
Imagine you have 5,000 ads and receive 100 ads per page. One full check takes 50 requests. Repeated every 5 minutes, that is 600 requests per hour - even if only 20 of your ads changed during that hour. These numbers are made up to illustrate the idea.
Downloading everything costs you:
- long sync runs that keep your servers busy,
- a lot of data to download, store and compare,
- a higher risk of reaching request limits (see FAQ),
- changes noticed late, because a full check of a large inventory takes time.
It also puts unnecessary load on OLX, which has to serve the same unchanged ads over and over again.
2. The better approach: the ad change feed
Instead of asking "give me all my ads", ask "which of my ads changed since my last check?". This is exactly what the ad change feed answers:
GET /api/partner/status/adverts
The feed returns only the IDs of the ads that changed, oldest change first. For each ID you fetch the current ad with GET /api/partner/adverts/{advertId} and update its status in your system. If nothing changed, you get an empty list - one small request and you are done.
Think of it like your mailbox: you do not reread every e-mail to find out what is new - you look at the new ones only.
3. Before and after
Using the same example as above (example only: 5,000 ads, checked every 5 minutes, 20 ads changed within an hour):
| Downloading everything | Ad change feed | |
|---|---|---|
| Requests per hour | 600 | 12 feed requests + 20 ad requests |
| What you download | All 5,000 ads, 12 times | A short list of IDs and the 20 changed ads |
| When nothing changed | Still a full download | One request with an empty list |
| Work on your side | Compare every ad | Update only the changed ads |
4. How the feed works
A request to the feed takes the following parameters:
| Parameter | Required | Description |
|---|---|---|
since |
Yes | The moment from which you want to read changes, as an ISO-8601 date with a timezone, for example 2026-05-11T10:00:00Z. You get changes recorded strictly after this moment. Send the same value on every follow-up request. |
cursor |
No | The nextCursor value from your previous response. It tells the feed where you stopped. Leave it out only when you start reading from since. |
limit |
No | The largest number of IDs on one page. Defaults to 100; values above 1000 are treated as 1000. |
Every response has the same three fields:
data- the IDs of the ads that changed, oldest change first. Empty when nothing changed.hasMore-truewhen more changes are waiting on the next page.nextCursor- your bookmark. It is always present, even whendatais empty.
For the full reference see the API documentation.
5. Syncing step by step
Step 1: Start reading the feed
You already have your ads in your system, for example from one full download. Use the moment just before that download started as since, so that no change is missed. Send it without a cursor:
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"
}
Step 2: Read the remaining pages
While hasMore is true, send the same since together with the nextCursor you received as 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"
}
Step 3: Fetch only the changed ads
For every ID from data, get the current ad and update its status in your system:
curl -H "Authorization: Bearer" \ -H "Version: 2.0" \ "https://www.olx.pl/api/partner/adverts/1024578390"
{
"data": {
"id": 1024578390,
"status": "active",
...
}
}
Step 4: Keep polling
When hasMore is false, you are up to date. Save the last nextCursor. On your next check, send it as cursor (together with the same since). If nothing changed in the meantime, you get an empty list - keep the new nextCursor anyway:
{
"data": [],
"hasMore": false,
"nextCursor": "MXwyMDI2LTA1LTExVDEwOjA1OjAxLjEwMlp8MTAyNDU3ODQ1NQ"
}
The whole loop in pseudo-code
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. Practical tips
- Save your bookmark after every page. Store
sinceand the latestnextCursorsomewhere that survives restarts, for example in your database. After a break or a failure you continue exactly where you stopped - nothing is missed and nothing is processed twice. - Use the cursor as it is. Do not read, shorten or build cursor values yourself - always send back exactly what you received.
- An empty list is good news. It means nothing changed. Still save the
nextCursorfrom that response. - Changes appear with a short delay. A change becomes visible in the feed a few seconds after it happens, so a very recent change may only show up on your next check.
- Choose the page size that suits you. A smaller
limitkeeps responses small; a bigger one helps you catch up faster after a longer break. - Handling errors. A
400response withvalidation_errormeans something is wrong with the request - themessagefield tells you which parameter. Fix the request instead of sending it again unchanged. If your cursor is rejected, start again withsinceonly, using the moment of your last successful sync.
7. Key takeaways
- Do not download your whole inventory just to find the few ads that changed.
- Ask the ad change feed which ads changed, then fetch only those ads.
- Save
nextCursorafter every page - it is your bookmark. - An empty list means nothing changed - one small request instead of a full download.
The same approach is available for orders - see the orders change feed. More objects will follow in the future.