Предварителни условия
- Медията създава акаунт за всеки офис на ЕРА, който ще ползва услугата. Всеки акаунт се удостоверява с token, който медията предоставя на ЕРА при създаването на офис акаунта. Този token е и паролата на акаунта на офиса.
- Към този акаунт трябва да има линк, от който медията чете текущия статус на офертите за дадения офис. Линкът се предоставя от ЕРА. Формат:
https://publisher.era.bg/media/{media_name}/{office_name} - Медията предоставя на ЕРА route за нотификация, към който ЕРА прави POST заявка за да уведоми медията, че трябва да започне импорт/синхронизация на офертите за съответния офис, като подава token, удостоверяващ офиса. Този token е предоставен в т. 1. и ще бъде получен в хедърите на заявката, като API-KEY:
'Content-Type' => 'application/json', 'API-KEY' => {token} - Медията предоставя на ЕРА максимален брой изображения (
image_limit) за една оферта. Системата на ЕРА ще конфигурира лимита според стойността, предоставена от медията, и ще отрязва излишните изображения до този лимит при генериране наoutput.xml.
Процедура по синхронизация
- ЕРА изпраща нотификация към медията чрез предоставения от медията route, че информацията за конкретен офис е обновена.
- Медията прочита файла на офиса:
https://publisher.era.bg/media/{media_name}/{office_name}и синхронизира информацията. - Медията изпраща статус на операцията на линка, посочен в полето
<result_url>наoutput.xml.
Точка за достъп до output.xml
- Публичен URL по шаблон:
https://publisher.era.bg/media/{media_name}/{office_name} - Файлът се генерира от системата и се обновява при налични промени за офиса.
- При грешка в предходен импорт системата пази маркер (
started.lock) и може да отложи следващото стартиране до приключване.
Формат на output.xml
- Кодиране: UTF-8
- XML декларация:
<?xml version="1.0" encoding="UTF-8"?> - Коренов елемент:
feed - Структура (в този ред):
updated– дата и час на генериране (формат: YYYY-MM-DD hh:mm:ss, локално време).agency_uid– уникален идентификатор на офиса. В момента се попълва с телефонния номер на офиса.agency_name– име на офиса.agency_phone– телефон на офиса.agency_email– имейл на офиса.result_url– абсолютен URL (HTTP/HTTPS), на който медията трябва да изпрати резултата от импорта/синхронизацията за този офис.Brokers– масив с нула или повече брокери, които са активни в момента.offers– масив с нула или повече оферти, които са активни в момента. Ако от масива с оферти липсват оферти, които са текущо публикувани, то системата автоматично ще ги направи непубликувани/архивирани. Този масив с оферти трябва да съдържа само офертите, които искате да са публикувани.
Пример:
XML
<?xml version="1.0" encoding="UTF-8"?>
<feed>
<updated>2024-10-07 11:47:22</updated>
<agency_uid>+359896523887</agency_uid>
<agency_name>Решение</agency_name>
<agency_phone>+359896523887</agency_phone>
<agency_email>reshenie@era.bg</agency_email>
<result_url>https://publisher.era.bg/media/{media}/callback/{officeId}</result_url>
<Brokers>
<Broker>
<BrokerName>Румяна Илиева</BrokerName>
<BrokerID>22329</BrokerID>
<BrokerPhone>0897975071</BrokerPhone>
<BrokerEmail>rilieva@era.bg</BrokerEmail>
</Broker>
</Brokers>
<offers>
<offer>
<last_update>2024-10-07</last_update>
<offer_uid>155174</offer_uid>
<description>…</description>
<images>http://…/p1.jpg,http://…/p2.jpg</images>
<price>36500</price>
<surface>1098</surface>
<currency>eur</currency>
<category>продажби</category>
<subcategory>ПАРЦЕЛ</subcategory>
<internal_id>15975</internal_id>
<building_condition></building_condition>
<furnished></furnished>
<heating_ids></heating_ids>
<rooms_count></rooms_count>
<bedroom_count>0</bedroom_count>
<broker_id>0896523887</broker_id>
<offer_code>5700097</offer_code>
<surface_parcel>1098</surface_parcel>
<floor>0</floor>
<parking_ids></parking_ids>
<balcony_count>0</balcony_count>
<bath_count>0</bath_count>
<Exclusive>1</Exclusive>
</offer>
</offers>
</feed>
Полета в feed
updated(string) – време на генериране. Формат: YYYY-MM-DD hh:mm:ss.agency_uid(string) – уникален идентификатор на офиса. В текущата имплементация е телефонен номер на офиса.agency_name(string) – име на офиса.agency_phone(string) – телефон на офиса (E.164 препоръчителен формат).agency_email(string) – валиден имейл адрес.result_url(URL) – абсолютен URL за обратна връзка. Динамично се генерира и включва идентификатор на офиса и името на медията.
Секция Brokers
- Масив за 0..N брокера. Когато няма брокери, елементът все пак присъства, но може да е празен.
- Елемент
Brokerсъдържа:BrokerName(string)BrokerID(string|int)BrokerPhone(string)BrokerEmail(string)
- Забележка: Секцията се композира от валидни XML фрагменти; невалидни фрагменти се пропускат.
Секция offers
- Масив за 0..N оферти. Когато няма оферти, елементът присъства, но може да е празен.
- Елемент
offerвключва често срещани полета:last_update(datetime) – YYYY-MM-DD hh:mm:ssoffer_uid(int)description(string)images(string) – абсолютни URL-и, разделени с ; (до зададения image_limit)price(number),surface(number),currency(enum),category(enum),subcategory(enum)internal_id(int)- и др.:
building_condition,furnished,heating_ids,rooms_count,bedroom_count,broker_id,offer_code,surface_parcel,floor,parking_ids,balcony_count,bath_count,Exclusive
- Невалидни XML фрагменти за единични оферти се пропускат.
Допустими стойности (offers)
last_update: формат YYYY-MM-DD hh:mm:ss.offer_uid: уникален и стабилен във времето.offer_code: референтен код.description: текст.images: множество абсолютни URL адреси, разделени с ;.price,surface,surface_parcel: цели числа.currency(enum): едно от [eur,лв.]; от 01.01.2026 – самоeur.category(enum): [продажби,наеми].subcategory(enum): „СТАЯ“, „1-СТАЕН“, „2-СТАЕН“, „3-СТАЕН“, „4-СТАЕН“, „МНОГОСТАЕН“, „МЕЗОНЕТ“, „ОФИС“, „АТЕЛИЕ“, „АТЕЛИЕ, ТАВАН“, „ТАВАН“, „ГАРСОНИЕРА ЛУКС“, „ГАРСОНИЕРА“, „ЕТАЖ ОТ КЪЩА“, „КЪЩА“, „ВИЛА“, „МАГАЗИН“, „ЗАВЕДЕНИЕ“, „СКЛАД“, „ГАРАЖ“, „ПРОМ. ПОМЕЩЕНИЕ“, „ХОТЕЛ“, „ПАРЦЕЛ“, „ЗЕМЕДЕЛСКА ЗЕМЯ“, „СГРАДИ“, „ЗАТВОРЕН КОМПЛЕКС“.internal_id: стойност от колоната internal_id на geo_db.csv.construction_type(enum): [епк, панел, тухла, гредоред, метална конструкция].floor,floorAll,rooms_count,bedroom_count,balcony_count,bath_count: цели числа.building_condition(enum): [Completed, UnderConstruction, PreConstruction, SemiCompleted, NotCompleted].build_year: дата YYYY-MM-DD.furnished(enum): една стойност от [14 (С обзавеждане), 23 (Без обзавеждане), 65 (Частично обзавеждане)].heating_ids: една или повече стойности от [18 (Камина), 35 (Климатик), 44 (Ток), 46 (Локално парно), 80 (Отопление)], разделени със запетая.parking_ids: една или повече стойности от [52 (С гараж), 93 (С паркинг)], разделени със запетая.exterior_ids: една или повече стойности от [10 (Асфалтиран), 42 (Има асансьор)], разделени със запетая.new_construction(enum): 0 или 1.land_category(enum): 0..10.parcel_in_regulation(enum): True или False.broker_id: номер – трябва да съвпада сBrokerIDотBrokers.youTube_link,virtual_panorama_link: URL.Exclusive(enum): 0 или 1.
Ограничения и технически бележки
- Кодиране: UTF-8.
- Валидност на XML: Системата валидира, че
output.xmlе добре формиран; при грешка файлът не се публикува. - Максимален брой изображения: определя се от медията; системата отрязва излишните до зададения лимит.
- Часови прозорци за пускане: изпълнение само в разрешен часови диапазон (конфигурируем).
Callback към ЕРА: result_url
- Полето
result_urlуказва крайна точка, на която медията изпраща резултат от процеса на импорт. - Адресът е абсолютен и съдържа идентификатор на офиса и името на медията.
- HTTP метод: POST
- Content-Type: application/json
- Формат на тялото: JSON, валидиран от UniversalProcessPublishedStatus:
logResult: масив от низове (индекс 0 – обобщение) – requiredlogOffers: масив от обекти – required; всеки обект включва:errors: масив от низове (може да е празен)offerSourceData: обект сoffer_uid(низ, required)
JSON
{
"logResult": ["Import completed with 3 offers processed."],
"logOffers": [
{
"errors": [],
"offerSourceData": {"offer_uid": "155174"}
},
{
"errors": ["Missing price", "Invalid currency"],
"offerSourceData": {"offer_uid": "155175"}
}
]
}
Грешки при импорт в медията
Медията връща статус на result_url (POST, JSON). Препоръчителни HTTP кодове:
- 200 OK – импортът е изпълнен; в
logResult[0]има обобщение, а вlogOffers– детайли по офертите. - 400 Bad Request – JSON невалиден/липсващо поле.
- 401/403 – неуспешна автентикация/авторизация (невалиден токен/подпис).
- 409 Conflict – конфликтно състояние (напр. дублиран процес).
- 413 Payload Too Large – надхвърлен допустим размер.
- 415 Unsupported Media Type – грешен Content-Type (изисква се
application/json). - 422 Unprocessable Entity – семантични грешки (невалидни стойности по полета); включете подробности в
errors. - 429 Too Many Requests – ограничение на скоростта.
- 500/503 – временна вътрешна/инфраструктурна грешка; опитайте отново с backoff.
Препоръки за устойчивост
- Частичен провал: отбелязвайте конкретните оферти с грешки в
logOffers[*].errors, но връщайте 200 ако процесът глобално е успешен. - Ограничаване на изображенията до
image_limit; излишните се игнорират.
Сигурност
- Използвайте само HTTPS за всички крайни точки.
- Идентификация на офис/медия чрез токен; пазете го поверително и го подменяйте при инциденти.
- Препоръчително: подписване на заявки (напр. HMAC-SHA256 над тялото + timestamp) и валидиране в двете посоки.
- Ограничете достъпа до
result_urlчрез IP allowlist и/или rate limiting. - Валидация на входа:
Content-Type: application/json, максимални размери на тяло и полета. - Политика за съхранение: пазете логове за одит за разумен период, след което ги анонимизирайте/изтрийте според политиките ви.
Версиониране и съвместимост
- Стабилни идентификатори:
offer_uid,BrokerID,internal_id. - Депрeкации: валутата
лв.се премахва на 01.01.2026 – приемайте самоeurслед тази дата. - Добавяне на нови полета се прави по backward-compatible модел (неизвестните полета се игнорират).
Често задавани въпроси
- Какво става при липсващи изображения? –
imagesможе да е празно; импортът не трябва да се проваля. - Можем ли да извикаме импорт без нотификация? – Да, при наличие на нов
output.xml, но спазвайте rate limiting.
Контакти и поддръжка
- Оперативни въпроси за интеграция: вашият контакт в ЕРА.
- Инциденти в продукция: уведомете поддръжката и предоставете timestamp,
office_name,media_name, примерниoffer_uid.
История на промените
- 1.0 (2025-09-02): Първоначална версия на документацията, включваща формат на фийда, синхронизация и callback.
- 1.1 (2025-09-12): Промяна на линка на точка за достъп до output.xml от
https://publisher.era.bg/{media_name}/{office_name}/output.xmlнаhttps://publisher.era.bg/media/{media_name}/{office_name} - 1.2 (2025-10-22): Поясняване на употребата на ендпойнта за стартиране на импорт