Feed
Feed - це механізм синхронізації даних, який надає доступ до переліку основних сутностей системи Prozorro (тендери, контракти, плани, фреймворки тощо).
Feed є основним інструментом для інтеграції з системою Prozorro, дозволяючи отримувати актуальні дані та відстежувати зміни в режимі реального часу.
Доступні Feed ендпоінти
У системі Prozorro доступні наступні feed ендпоінти:
/tenders- перелік тендерів/contracts- перелік контрактів/plans- перелік планів закупівель/frameworks- перелік фреймворків/submissions- перелік подань/qualifications- перелік кваліфікацій/agreements- перелік угод
Приклад запиту:
GET /tenders?descending=1&limit=2 HTTP/1.1
Структура відповіді
Кожен feed ендпоінт повертає JSON відповідь наступної структури:
{
"data": [
{
"id": "82caff5150214ad2b43aa583f7fabcae",
"dateModified": "2026-01-10T12:52:00.068344+02:00"
},
{
"id": "8e57141320ec463abf6d82c1497702fc",
"dateModified": "2026-01-09T16:40:51.220780+02:00"
}
],
"next_page": {
"offset": "1767969651.246.1.4325efbb2409185921e764a90ea1cb93",
"path": "/api/2.5/tenders?limit=2&descending=1&offset=1767969651.246.1.4325efbb2409185921e764a90ea1cb93",
"uri": "https://lb-api-sandbox-2.prozorro.gov.ua/api/2.5/tenders?limit=2&descending=1&offset=1767969651.246.1.4325efbb2409185921e764a90ea1cb93"
},
"prev_page": {
"offset": "1768042320.082.1.5142ecd8a327509ce0580c5133be68f6",
"path": "/api/2.5/tenders?limit=2&offset=1768042320.082.1.5142ecd8a327509ce0580c5133be68f6",
"uri": "https://lb-api-sandbox-2.prozorro.gov.ua/api/2.5/tenders?limit=2&offset=1768042320.082.1.5142ecd8a327509ce0580c5133be68f6"
}
}
Поля відповіді:
data: масив об’єктів з мінімальною інформацією (за замовчуванням
idтаdateModified)next_page: інформація про наступну сторінку
prev_page: інформація про попередню сторінку
Сортування за часом модифікації
Feed ендпоінти автоматично сортувати об’єкти за часом модифікації, використовуючи внутрішнє поле public_modified. Це поле містить Unix timestamp (в секундах) і автоматично оновлюється при будь-якій зміні об’єкта.
Важливо: Сортування відбувається за полем public_modified, а не за dateModified. Це забезпечує стабільність пагінації та коректну обробку об’єктів з однаковим часом модифікації.
За замовчуванням (без параметра descending) об’єкти сортируються від старіших до новіших (за зростанням public_modified).
Параметри запиту
offset
Курсор для пагінації. Використовується для отримання наступної або попередньої сторінки результатів.
Формат: {timestamp}.{skip_len}.{skip_hash}
timestamp: Unix timestamp - час модифікації останнього об’єкта з попередньої сторінки
skip_len: кількість об’єктів з однаковим timestamp, які вже були показані
skip_hash: MD5 хеш від посортованих ID об’єктів з однаковим timestamp
Приклад: 1696888800.0.2.c9e589b703dacf9b5ed4833357465084
Для отримання наступної сторінки використовуйте значення offset з поля next_page.offset або просто перейдіть за посиланням next_page.uri що містить значення offset.
limit
Кількість об’єктів на сторінці.
За замовчуванням: 100
Максимум: 1000
Мінімум: 1
Якщо вказано більше 1000, автоматично обмежується до 1000
Приклад: /tenders?limit=500
descending
Сортування в зворотному порядку (від новіших до старіших).
Якщо параметр присутній (будь-яке значення) - сортування від новіших до старіших
Якщо параметр відсутній - сортування від старіших до новіших (за замовчуванням)
Приклад: /tenders?descending=1
mode
Фільтр за режимом об’єктів (тестові або реальні).
test: тільки тестові об’єкти
_all_: всі об’єкти
Якщо не вказано: тільки не тестові об’єкти
Приклади:
/tenders?mode=test- тільки тестові тендери/tenders?mode=_all_- всі тендери/tenders- тільки не тестові тендери (за замовчуванням)
opt_fields
Додаткові поля, які потрібно включити в відповідь.
За замовчуванням feed ендпоінти повертають тільки id та dateModified. Параметр opt_fields дозволяє додати додаткові поля до відповіді.
Детальний перелік доступних полів для feed та детальних ендпоінтів дивіться в Опціональні поля (opt_fields).
Дозволені поля залежать від типу ресурсу, але завжди доступні:
public_modified- Unix timestamp часу модифікації (в секундах)
Поля розділяються комою: opt_fields=public_modified,dateCreated
Приклади:
/tenders?opt_fields=status/tenders?opt_fields=dateCreated,procuringEntity/tenders?opt_fields=public_modified
Важливо про opt_fields=public_modified:
Поле public_modified містить Unix timestamp в секундах і використовується системою для внутрішнього сортування. Воно може бути корисним для:
Точного визначення часу модифікації об’єкта
Реалізації власної логіки синхронізації
Порівняння часу модифікації різних об’єктів
Збереження точки синхронізації для подальшого використання
Приклад відповіді з opt_fields=public_modified:
{
"data": [
{
"id": "82caff5150214ad2b43aa583f7fabcae",
"dateModified": "2023-10-10T01:00:00+03:00",
"public_modified": 1696888800.123
}
],
"next_page": {
"offset": "1696888800.123.0.abc...",
"uri": "..."
}
}
Поле public_modified також можна отримати в детальних ендпоінтах через параметр opt_fields.
Приклад:
GET /tenders/82caff5150214ad2b43aa583f7fabcae?opt_fields=public_modified HTTP/1.1
Пагінація
Feed ендпоінти використовують курсорну пагінацію на основі поля public_modified. Це забезпечує стабільність пагінації навіть при одночасних змінах об’єктів у системі.
Як працює пагінація:
Перший запит: Отримайте першу сторінку без параметра
offsetНаступні сторінки: Перейдіть за посиланням
next_page.uriПопередні сторінки: Перейдіть за посиланням
prev_page.uri
Важливо про напрямок пагінації:
next_page: рухає вас у напрямку поточного сортування
prev_page: рухає вас у зворотному напрямку від поточного сортування, але змінює напрямок сортування
Наприклад:
- Якщо ви використовуєте
descending=1(від новіших до старіших), то: next_page(зdescending=1) дасть вам старіші об’єктиprev_page(безdescending=1) - це “розворот”, дасть новіші об’єкти, і тепер наступні запити треба робити зnext_page(без descending) для отримання новіших об’єктів
- Якщо ви використовуєте
- Якщо ви не використовуєте
descending(від старіших до новіших), то: next_page(без descending) дасть вам новіші об’єктиprev_page(зdescending=1) - це “розворот”, дасть старіші об’єкти, і тепер наступні запити треба робити зnext_page(з descending) для отримання старіших об’єктів
- Якщо ви не використовуєте
Стратегії синхронізації
Forward Sync: Синхронізація з початку (старіші об’єкти) до кінця (новіші об’єкти)
Для синхронізації всіх даних з початку до поточного моменту:
- Крок 1: Ініціалізація
Виконайте перший запит без параметрів (сортування від старіших до новіших)
Отримайте першу сторінку результатів
- Крок 2: Ітерація по сторінках
Перейдіть за посиланням
next_page.uriдля отримання наступної сторінкиКожна наступна сторінка містить новіші об’єкти
Повторюйте до отримання порожнього списку в
data
- Крок 3: Визначення завершення
Якщо відповідь містить порожній список в
data, це означає, що всі існуючі об’єкти були прочитані
- Крок 4: Подальші дії
Зупиніть синхронізацію, або
Продовжуйте читати оновлення в режимі реального часу, очікуючи появи нових об’єктів
При читанні оновлень в режимі реального часу рекомендується додати затримку між запитами при отриманні порожніх відповідей
Backward Sync: Синхронізація від кінця (найновіші об’єкти) до початку (старіші об’єкти)
Для отримання найновіших об’єктів першими:
- Крок 1: Ініціалізація
Виконайте перший запит з
descending=1(сортування від новіших до старіших)Отримайте першу сторінку результатів з найновішими об’єктами
- Крок 2: Ітерація по сторінках
Перейдіть за посиланням
next_page.uriдля отримання наступної сторінкиКожна наступна сторінка містить старіші об’єкти
Повторюйте до зникнення поля
next_page
- Крок 3: Визначення завершення
Якщо у відповіді відсутнє поле
next_page, це означає, що всі об’єкти були прочитані
- Крок 4: Завершення
Зупиніть синхронізацію
Forward/Backward Sync: Двонаправлена синхронізація
Для синхронізації в обох напрямках (вперед і назад) та моніторингу нових змін:
- Крок 1: Ініціалізація
Виконайте перший запит з
descending=1(сортування від новіших до старіших)Отримайте першу сторінку результатів
- Крок 2: Backward Sync: Рух назад (читання старих даних від новіших до старіших)
Перейдіть за посиланням
next_page.uriдля отримання наступної сторінкиКожна наступна сторінка містить старіші об’єкти
Повторюйте до зникнення поля
next_pageЯкщо у відповіді відсутнє поле
next_page, це означає, що всі об’єкти були прочитаніЗупиніть синхронізацію
- Крок 3: Forward Sync: Рух вперед (читання нових даних в режимі реального часу)
Перейдіть за посиланням
prev_page.uriдля “розвороту” (він автоматично знімаєdescending=1)Перейдіть за посиланням
next_page.uriдля отримання наступної сторінкиКожна наступна сторінка містить новіші об’єкти
Якщо відповідь містить порожній список в
data, це означає, що всі існуючі об’єкти були прочитаніПродовжуйте читати оновлення в режимі реального часу, очікуючи появи нових об’єктів
При читанні оновлень в режимі реального часу рекомендується додати затримку між запитами при отриманні порожніх відповідей
Отримання повної інформації про об’єкт
Feed ендпоінти повертають тільки мінімальну інформацію про об’єкти. Для отримання повної інформації про конкретний об’єкт використовуйте детальний ендпоінт:
GET /tenders/64e93250be76435397e8c992ed4214d1 HTTP/1.1
Приклад робочого процесу:
Отримайте список об’єктів через feed ендпоінт
Витягніть
idз кожного об’єктаВикористайте
idдля отримання повної інформації через детальний ендпоінт
Затримка появи нових об’єктів у фіді (watermark)
Об’єкти у фіді з’являються з невеликою затримкою після їхнього збереження в базі даних.
Це навмисна поведінка, що захищає від race condition: при паралельних записах MongoDB фіксує час операції на її початку, а не в момент коміту. Через це два об’єкти, збережені майже одночасно, можуть з’явитися в БД у неочікуваному порядку. Без затримки crawler міг би пропустити деякі об’єкти назавжди.
Поточне значення затримки: ~1 секунда.
Практичний ефект:
Forward feed (без
descending): об’єкти з’являються з затримкою ~1 секунда. Якщо ваш crawler досяг кінця і отримав порожню відповідь — нові об’єкти з’являться за ~1 секунду. При типовій паузі між запитами затримка непомітна.Descending без offset (перша сторінка): також застосовується затримка ~1 секунда. Це критично для коректної двонаправленої синхронізації (backward→forward): offset з першої descending-сторінки гарантовано старіший за 1 секунду, тому використання його як стартової точки для подальшого forward sync не призведе до пропуску об’єктів.
Descending з offset (пагінація по历史nich даних): затримка не застосовується — читаються вже закомічені старі записи.
Warning
Backward→forward sync: якщо ви реалізуєте двонаправлену синхронізацію
(спочатку descending, потім forward), використовуйте offset з першої
descending-сторінки як стартову точку для forward sync без жодних коректувань.
Затримка на першій descending-сторінці вже гарантує, що жоден об’єкт не буде
пропущений при переході на forward.
See also
Гарантія порядку в API фіді — детальний технічний опис race condition, реалізації watermark та альтернативних підходів (для розробників).
Обмеження та рекомендації
Обмеження швидкості запитів
На публічних ендпоінтах діє обмеження швидкості запитів: 140 запитів на секунду (r/s).
Максимальний ліміт сторінки
Максимальна кількість об’єктів на сторінку: 1000.
Рекомендація: Використовуйте значення limit від 100 до 500 для оптимального балансу між кількістю запитів та обсягом даних.
Фільтрація об’єктів
Автоматично застосовуються наступні фільтри:
Тільки публічні об’єкти (статус не
draft)Фільтр за
mode(тестові/реальні об’єкти)
Об’єкти зі статусами draft не відображаються в feed, навіть якщо вони публічні.