Для сервиса — JSON API
Те же числа отдаёт обычный HTTP-запрос. Один запрос — одна конфигурация: модель, память, состояние. Ключей нет, регистрации нет, платить не надо.
https://trofey.app/api/v1
База — адрес ниже. Пять эндпойнтов, все GET, все с Access-Control-Allow-Origin: *, так что ходить можно прямо из браузера.
С этого начинается интеграция · GET /models
Название модели совпадает полностью. Поэтому первый вызов — этот: он отдаёт наши точные строки и количество конфигураций у каждой, без цен. q ищет подстрокой и регистр не важен; без q приедет вся категория.
curl -s -G "https://trofey.app/api/v1/models" \ --data-urlencode "q=iphone 13"{ "attribution": "Trofey — https://trofey.app . Free to use; credit Trofey and link the page the number is published on.", "category": "phones", "code": null, "count": 4, "currency": "UAH", "definition": "market_price_uah = медіана цін живих оголошень позиції за останні 14 днів; рахується лише за наявності щонайменше 8 живих оголошень", "license": "https://trofey.app/terms/", "method": "https://trofey.app/methodology/", "models": [ {"brand": "iPhone", "configurations": 4, "model": "iPhone 13"}, {"brand": "iPhone", "configurations": 4, "model": "iPhone 13 Pro"}, {"brand": "iPhone", "configurations": 4, "model": "iPhone 13 Pro Max"}, {"brand": "iPhone", "configurations": 2, "model": "iPhone 13 mini"} ], "ok": true, "query": "iphone 13", "source": "https://trofey.app/analytics/phones/", "updated": "2026-10-13"}
«iPhone 16 Pro» и «iPhone 16 Pro Max» — разные телефоны с разными ценами. Именно поэтому совпадение полное, и именно поэтому этот вызов есть. Подстрокой мы ищем только здесь: ошибиться в выборе стоит ещё одного вызова, а подстрока внутри поиска цены стоила бы опубликованного неверного ответа. Пустой результат несёт reason: производителя, которого мы не публикуем, простую опечатку, название линейки и модель из другой категории видно отдельно, потому что действия из них противоположные. В последнем случае рядом едет try_category — то же поле, что и у /configurations, и соседнюю категорию мы спрашиваем тем же поиском, так что неточное название её тоже находит. Ближайшие названия в этой категории приезжают отдельным полем did_you_mean — но никогда вместе с try_category: ответ несёт ровно один следующий шаг, а не два противоположных. Это правило любого отказа с try_category, а не одного вызова — /configurations и /price ведут себя так же.
brand — это линейка, а не производитель. Все девять значений, которые мы публикуем: iPhone, Samsung, Redmi, POCO, Xiaomi, Google Pixel, Apple iPad, Samsung Galaxy Tab, Lenovo. То есть iPhone, а не Apple; Redmi и POCO отдельно от Xiaomi; Samsung в планшетах под другим именем, чем в телефонах. Так задумано: на этом поле стоят страницы брендов и адреса, и именно так люди ищут. Если нужен производитель — его понимает поиск: q=Apple отдаёт 50 моделей под brand=iPhone, q=Xiaomi — 108 под тремя линейками. Поля manufacturer нет.
Цена одной конфигурации · GET /price
Параметры: model (обязательный, совпадает полностью), storage_gb (целое число), condition — used или new, category (по умолчанию phones).
curl -s -G "https://trofey.app/api/v1/price" \ --data-urlencode "model=iPhone 13" \ -d storage_gb=128 \ -d condition=used{ "above_range": 29, "attribution": "Trofey — https://trofey.app . Free to use; credit Trofey and link the page the number is published on.", "below_range": 3, "brand": "iPhone", "category": "phones", "cheapest_live_uah": 4500, "code": null, "condition": "used", "currency": "UAH", "dearest_live_uah": 32000, "definition": "market_price_uah = медіана цін живих оголошень позиції за останні 14 днів; рахується лише за наявності щонайменше 8 живих оголошень", "finds_14d": 189, "license": "https://trofey.app/terms/", "live_listings": 1199, "market_price_uah": 12500, "method": "https://trofey.app/methodology/", "model": "iPhone 13", "ok": true, "price_range_uah": [ 7000, 17099 ], "slug": "iphone-13-128-used", "source": "https://trofey.app/analytics/phones/", "source_page": "https://trofey.app/analytics/phones/iphone-13-128-used/", "storage_gb": 128, "typical_spread_uah": 1000, "updated": "2026-10-13", "watch_price_credits_per_day": 32}
Полключа — это полответа, и на него мы не отвечаем. Если переданного достаточно, чтобы остался ровно один вариант, приедет цена. Если вариантов остаётся несколько, мы не угадываем, а спрашиваем назад:
curl -s -G "https://trofey.app/api/v1/price" \ --data-urlencode "model=iPhone 13"{ "ok": false, "code": "ambiguous_configuration", "error": "ambiguous configuration", "model": "iPhone 13", "category": "phones", "choose_from": [ {"storage_gb": 128, "condition": "new"}, {"storage_gb": 128, "condition": "used"}, {"storage_gb": 256, "condition": "used"}, {"storage_gb": 512, "condition": "used"} ], "see": "https://trofey.app/api/v1/configurations?model=iPhone%2013&category=phones", "updated": "2026-10-13", "currency": "UAH", "definition": "market_price_uah = медіана цін живих оголошень позиції за останні 14 днів; рахується лише за наявності щонайменше 8 живих оголошень", "method": "https://trofey.app/methodology/", "license": "https://trofey.app/terms/", "source": "https://trofey.app/analytics/phones/", "attribution": "Trofey — https://trofey.app . Free to use; credit Trofey and link the page the number is published on."}В адресах внутри ответов значения percent-encoded: %20 — это пробел. Так строго правильно для машины, которая их разбирает. В терминале удобнее не кодировать руками, а передавать значения через --data-urlencode, как в примерах выше.
Чего мы не мерили — у того нет цены, а не нулевая цена. В ответе «не найдено» нет ни одного числового поля: market_price_uah: 0 прочитался бы следующим графиком как «телефон ничего не стоит», а подставленная оценка выглядела бы точно как измерение.
curl -s -G "https://trofey.app/api/v1/price" \ --data-urlencode "model=Nokia 3310"{ "attribution": "Trofey — https://trofey.app . Free to use; credit Trofey and link the page the number is published on.", "category": "phones", "code": "unknown_model", "found": false, "model": "Nokia 3310", "model_known": false, "ok": false, "reason": "No published configuration matches, and the model name is not one Trofey publishes in this category. Names are matched in full — call `models` (MCP) or GET /models to see the exact strings. Trofey publishes a price only where it measured one; it does not estimate on request.", "source": "https://trofey.app/analytics/phones/", "updated": "2026-10-13"}
Все конфигурации одной модели · GET /configurations
То же, что показывает страница модели. model тут тоже обязателен и тоже совпадает полностью — нет такого значения, которое отдало бы чужую модель, тем более все.
curl -s -G "https://trofey.app/api/v1/configurations" \ --data-urlencode "model=iPhone 13"{ "attribution": "Trofey — https://trofey.app . Free to use; credit Trofey and link the page the number is published on.", "category": "phones", "code": null, "configurations": [ {"above_range": 0, "below_range": 1, "brand": "iPhone", "cheapest_live_uah": 8000, "condition": "new", "dearest_live_uah": 27000, "finds_14d": 2, "live_listings": 23, "market_price_uah": 15400, "model": "iPhone 13", "price_range_uah": [10000, 27000], "slug": "iphone-13-128-new", "source_page": "https://trofey.app/analytics/phones/iphone-13-128-new/", "storage_gb": 128, "typical_spread_uah": 3200, "watch_price_credits_per_day": 1}, {"above_range": 29, "below_range": 3, "brand": "iPhone", "cheapest_live_uah": 4500, "condition": "used", "dearest_live_uah": 32000, "finds_14d": 189, "live_listings": 1199, "market_price_uah": 12500, "model": "iPhone 13", "price_range_uah": [7000, 17099], "slug": "iphone-13-128-used", "source_page": "https://trofey.app/analytics/phones/iphone-13-128-used/", "storage_gb": 128, "typical_spread_uah": 1000, "watch_price_credits_per_day": 32}, {"above_range": 3, "below_range": 1, "brand": "iPhone", "cheapest_live_uah": 6500, "condition": "used", "dearest_live_uah": 35500, "finds_14d": 35, "live_listings": 223, "market_price_uah": 14700, "model": "iPhone 13", "price_range_uah": [9000, 20000], "slug": "iphone-13-256-used", "source_page": "https://trofey.app/analytics/phones/iphone-13-256-used/", "storage_gb": 256, "typical_spread_uah": 1700, "watch_price_credits_per_day": 9}, {"above_range": 1, "below_range": 0, "brand": "iPhone", "cheapest_live_uah": 10000, "condition": "used", "dearest_live_uah": 27000, "finds_14d": 3, "live_listings": 17, "market_price_uah": 15500, "model": "iPhone 13", "price_range_uah": [10000, 20000], "slug": "iphone-13-512-used", "source_page": "https://trofey.app/analytics/phones/iphone-13-512-used/", "storage_gb": 512, "typical_spread_uah": 1999, "watch_price_credits_per_day": 1} ], "currency": "UAH", "definition": "market_price_uah = медіана цін живих оголошень позиції за останні 14 днів; рахується лише за наявності щонайменше 8 живих оголошень", "license": "https://trofey.app/terms/", "method": "https://trofey.app/methodology/", "model": "iPhone 13", "ok": true, "query": "iPhone 13", "source": "https://trofey.app/analytics/phones/", "updated": "2026-10-13"}
Та же цена по дням · GET /price-history
Второй вопрос после «сколько стоит» — дешевеет оно или дорожает, и одно число на него не отвечает. Это та же линия, что на странице позиции: до 31 точки, по одной на день.
curl -s -G "https://trofey.app/api/v1/price-history" \ --data-urlencode "model=iPhone 13" \ -d storage_gb=128 \ -d condition=used \ -d days=7{ "attribution": "Trofey — https://trofey.app . Free to use; credit Trofey and link the page the number is published on.", "category": "phones", "change_pct": 0.0, "change_uah": 0, "code": null, "condition": "used", "currency": "UAH", "days": 7, "definition": "market_price_uah = медіана цін живих оголошень позиції за останні 14 днів; рахується лише за наявності щонайменше 8 живих оголошень", "first_point": "2026-10-07", "history_updated": "2026-10-13", "last_point": "2026-10-13", "license": "https://trofey.app/terms/", "live_listings": 1199, "market_price_uah": 12500, "method": "https://trofey.app/methodology/", "model": "iPhone 13", "ok": true, "price_history": [ {"date": "2026-10-07", "market_price_uah": 12500}, {"date": "2026-10-08", "market_price_uah": 12500}, {"date": "2026-10-09", "market_price_uah": 12500}, {"date": "2026-10-10", "market_price_uah": 12500}, {"date": "2026-10-11", "market_price_uah": 12500}, {"date": "2026-10-12", "market_price_uah": 12500}, {"date": "2026-10-13", "market_price_uah": 12500} ], "published_delay_days": 0, "slug": "iphone-13-128-used", "source": "https://trofey.app/analytics/phones/", "source_page": "https://trofey.app/analytics/phones/iphone-13-128-used/", "storage_gb": 128, "updated": "2026-10-13", "window_from": "2026-10-07", "window_to": "2026-10-13"}
Без days приедет весь опубликованный месяц — большего не существует. change_uah считается по вернувшимся точкам. days — это календарные дни, как и в /find-history: window_from и window_to — то, что спросили, а first_point и last_point — дни, на которых у линии действительно есть точки. Потолок — 31 день здесь и 30 в /find-history: разница — день сборки, который у линии цен уже есть. Попросишь больше — приедет requested_days рядом с тем days, что вернулся. Эта линия идёт на день дальше находок, и обе говорят об этом в published_delay_days.
Где на самом деле стоят объявления · GET /price-distribution
price_range_uah в /price — это не самое дешёвое и самое дорогое объявление, а границы гистограммы, и часть лотов стоит вне их. Сколько именно — говорят below_range и above_range в том же ответе. Это та же гистограмма, что на странице позиции: от четырёх до восьми полос между теми же границами.
curl -s -G "https://trofey.app/api/v1/price-distribution" \ --data-urlencode "model=iPhone 13" \ -d storage_gb=128 \ -d condition=used{ "above_range": 29, "attribution": "Trofey — https://trofey.app . Free to use; credit Trofey and link the page the number is published on.", "below_range": 3, "bins": [ {"from_uah": 7000, "listings": 13, "share_pct": 1.1, "to_uah": 8262}, {"from_uah": 8262, "listings": 50, "share_pct": 4.2, "to_uah": 9524}, {"from_uah": 9524, "listings": 118, "share_pct": 9.8, "to_uah": 10787}, {"from_uah": 10787, "listings": 316, "share_pct": 26.4, "to_uah": 12049}, {"from_uah": 12049, "listings": 347, "share_pct": 28.9, "to_uah": 13311}, {"from_uah": 13311, "listings": 188, "share_pct": 15.7, "to_uah": 14574}, {"from_uah": 14574, "listings": 91, "share_pct": 7.6, "to_uah": 15836}, {"from_uah": 15836, "listings": 44, "share_pct": 3.7, "to_uah": 17099} ], "category": "phones", "code": null, "condition": "used", "currency": "UAH", "definition": "market_price_uah = медіана цін живих оголошень позиції за останні 14 днів; рахується лише за наявності щонайменше 8 живих оголошень", "history_updated": "2026-10-13", "in_range_listings": 1167, "license": "https://trofey.app/terms/", "live_listings": 1199, "market_price_uah": 12500, "method": "https://trofey.app/methodology/", "model": "iPhone 13", "ok": true, "range_uah": [ 7000, 17099 ], "slug": "iphone-13-128-used", "source": "https://trofey.app/analytics/phones/", "source_page": "https://trofey.app/analytics/phones/iphone-13-128-used/", "storage_gb": 128, "unverified_listings": 0, "updated": "2026-10-13"}
below_range и above_range — объявления вне полос: без них полосы в сумме меньше live_listings. in_range_listings — сумма самих полос, то есть то, чего процентам не хватает до сотни: вместе эти три числа и дают live_listings. Распределение есть лишь от восьми живых объявлений — тот же порог, что и у цены.
А самое дешёвое и самое дорогое объявление, которые действительно есть, — это cheapest_live_uah и dearest_live_uah в том же ответе. Именно их стоит называть, когда спрашивают «от скольки». Границы гистограммы — тоже цены живых объявлений, но не крайних: это самое дешёвое и самое дорогое из тех, что помещаются в шкалу. На большинстве позиций нижняя граница совпадает с самым дешёвым лотом, верхняя с самым дорогим — меньше чем на половине, а весь рынок позиции помещается в график лишь примерно на трети. Там, где что-то осталось вне шкалы, оно осталось далеко: обычно на десятки процентов ниже границы.
Сколько находок было каждый день · GET /find-history
Количества за день, и ничего больше: лента отдельных лотов платная и доставляется в канал аккаунта. Это finds_14d во времени — разница между «шесть находок» и «шесть за одно утро» видна только здесь.
curl -s -G "https://trofey.app/api/v1/find-history" \ --data-urlencode "model=iPhone 13" \ -d storage_gb=128 \ -d condition=used \ -d days=7{ "attribution": "Trofey — https://trofey.app . Free to use; credit Trofey and link the page the number is published on.", "category": "phones", "code": null, "condition": "used", "currency": "UAH", "days": 7, "days_with_finds": 7, "definition": "market_price_uah = медіана цін живих оголошень позиції за останні 14 днів; рахується лише за наявності щонайменше 8 живих оголошень", "find_history": [ {"date": "2026-10-06", "finds": 12}, {"date": "2026-10-07", "finds": 10}, {"date": "2026-10-08", "finds": 11}, {"date": "2026-10-09", "finds": 13}, {"date": "2026-10-10", "finds": 14}, {"date": "2026-10-11", "finds": 12}, {"date": "2026-10-12", "finds": 11} ], "finds_14d": 189, "finds_total": 83, "first_find": "2026-10-06", "history_updated": "2026-10-13", "last_find": "2026-10-12", "license": "https://trofey.app/terms/", "live_listings": 1199, "method": "https://trofey.app/methodology/", "model": "iPhone 13", "ok": true, "published_delay_days": 1, "slug": "iphone-13-128-used", "source": "https://trofey.app/analytics/phones/", "source_page": "https://trofey.app/analytics/phones/iphone-13-128-used/", "storage_gb": 128, "updated": "2026-10-13", "window_from": "2026-10-06", "window_to": "2026-10-12"}
В строке ровно два поля: date и finds — ни ссылки, ни заголовка, ни цены. Дни без находок отсутствуют, а не нулевые.
Нормальная ли эта цена · GET /price-check
Главный вопрос, и он ничего нового не публикует: та же арифметика, что в карточке бота. Без него — три вызова и деление руками.
curl -s -G "https://trofey.app/api/v1/price-check" \ --data-urlencode "model=iPhone 13" \ -d storage_gb=128 \ -d condition=used \ -d price_uah=11250{ "above_every_live_listing": false, "attribution": "Trofey — https://trofey.app . Free to use; credit Trofey and link the page the number is published on.", "below_every_live_listing": false, "category": "phones", "cheaper_listings_at_least": 184, "cheaper_listings_at_most": 500, "cheaper_share_at_least_pct": 15.3, "cheapest_live_uah": 4500, "code": null, "condition": "used", "currency": "UAH", "dearest_live_uah": 32000, "definition": "market_price_uah = медіана цін живих оголошень позиції за останні 14 днів; рахується лише за наявності щонайменше 8 живих оголошень", "diff_vs_market_pct": -10.0, "diff_vs_market_uah": -1250, "discount_vs_market_pct": 10.0, "discount_vs_market_uah": 1250, "history_updated": "2026-10-13", "license": "https://trofey.app/terms/", "live_listings": 1199, "market_price_uah": 12500, "method": "https://trofey.app/methodology/", "model": "iPhone 13", "ok": true, "price_bin": { "from_uah": 10787, "listings": 316, "to_uah": 12049 }, "quoted_uah": 11250, "range_uah": [ 7000, 17099 ], "slug": "iphone-13-128-used", "source": "https://trofey.app/analytics/phones/", "source_page": "https://trofey.app/analytics/phones/iphone-13-128-used/", "spreads_from_market": 1.2, "storage_gb": 128, "typical_spread_uah": 1000, "updated": "2026-10-13", "verdict": "below_market", "verdict_basis": "typical_spread"}
diff_vs_market_uah и diff_vs_market_pct — названная цена минус рыночная: плюс значит дороже рынка, минус — дешевле. discount_vs_market_* — то же число с обратным знаком; оно остаётся в ответе для старых клиентов как минимум до 2027-01-01, но устарело: цена выше рынка читается там как отрицательная скидка. В MCP его уже нет.
Вердикт меряется прежде всего разбросом самой позиции, а не процентом от медианы: typical_spread_uah — это насколько обычное объявление этой конфигурации отстоит от рыночной цены, и половина живых лотов лежит внутри него. spreads_from_market говорит, на сколько таких разбросов отошла названная цена. Один и тот же процент — разные вещи на разных позициях: «на 20% дешевле» на широком рынке это обычное объявление, а на узком — дешевле почти всего. Под разбросом лежит одна абсолютная граница: 45% от медианы — это far_below_market на любом рынке, потому что после такой скидки она перестаёт выглядеть выгодой и начинает выглядеть причиной. Сам verdict — одно из пяти: far_below_market, below_market, about_market, above_market, far_above_market. А verdict_basis говорит, какая мерка ответила: typical_spread, percent_floor, percent_ceiling (зеркало подпола: там, где разброс позиции слипся, три разброса бывают скидкой в один процент) или percent_of_market — последняя там, где разброс никогда не считался и отвечает сама процентная лестница.cheaper_listings_at_least — нижняя граница, не перцентиль: полоса с названной ценой не делится и едет как price_bin, а cheaper_listings_at_most — потолок вместе с ней. Когда below_every_live_listing — true, более дешёвых живых объявлений нет вообще, а above_every_live_listing говорит то же самое про верх. Оба читаются из самой дешёвой и самой дорогой живой цены, и границы с ними согласованы: цена дороже самого дешёвого объявления имеет под собой как минимум его, а цена не выше самого дорогого не может иметь под собой все. И это не совет: мы говорим, где стоит число, а батарею и царапины видит лишь тот, кто держит телефон.
Что эта служба отдаёт и что ограничивает · GET /info
Один вызов вместо чтения этой страницы: что мы публикуем, сколько это стоит (ничего), под какой лицензией, чего тут осознанно нет — и единственный лимит на всей поверхности. Поля: limits, licence, transports, not_available.
Какая это модель · восемь цифр · GET /device
Первые восемь цифр IMEI — это TAC, то есть модель, а не аппарат. Отдаёт brand, model, as_of — и published_as: тот же аппарат под названием, которое публикуем мы, готовым для запроса цены. Именно здесь цепочка «сфотографировал коробку → точное название → цена» и замыкается: в реестре стоит GALAXY A21, у нас — Galaxy A21s, и это разные телефоны за разные деньги, так что поля два, а не одно. Если цены на этот аппарат у нас нет, published_as пустое. did_you_mean появляется только тогда, когда мы публикуем что-то близкое — ту же модель с суффиксом или линейку, которую открывает название, — и чаще всего его нет вовсе, потому что близкого аппарата в нашем каталоге нет. Восемь цифр, не пятнадцать — кому нужна только модель, тот не обязан присылать весь номер.
Числится ли телефон в розыске · GET /imei-check
Полные пятнадцать цифр против реестра утерянных и украденных, который мы переопубликовываем, плюс аппарат из того же TAC. Поля: reported, status, listed_on, checksum_ok, as_of, и imei_tail вместо самого номера — ответ не повторяет его целиком. published_as приезжает и здесь: то же наше название аппарата, что и в /device.
reported: false — это «номера нет в ЭТОМ реестре», а не гарантия про телефон. Скажите это человеку, который сейчас платит за аппарат. checksum_ok: false обычно означает опечатку, но поиск всё равно выполняется: шестая часть записей самого реестра не проходит собственную контрольную цифру. Если реестр недоступен, придёт error: "registry unavailable" — и это тоже не чистый телефон. Это единственные два вызова с лимитом: 120 в минуту на вызывающего, потому что они единственные тут не являются закешированным файлом.
Что мы вообще меряем · GET /categories
Счётчики и даты, и никогда — сами позиции. Это вызов «покрыт ли мой товар», а не способ забрать всё одним запросом. Если категория утром не собралась, она просто не приедет в список — остальное работает.
curl -s "https://trofey.app/api/v1/categories"{ "attribution": "Trofey — https://trofey.app . Free to use; credit Trofey and link the page the number is published on.", "categories": [ {"category": "phones", "configurations": 543, "currency": "UAH", "definition": "market_price_uah = медіана цін живих оголошень позиції за останні 14 днів; рахується лише за наявності щонайменше 8 живих оголошень", "license": "https://trofey.app/terms/", "method": "https://trofey.app/methodology/", "page": "https://trofey.app/analytics/phones/", "updated": "2026-10-13"}, {"category": "tablets", "configurations": 88, "currency": "UAH", "definition": "market_price_uah = медіана цін живих оголошень позиції за останні 14 днів; рахується лише за наявності щонайменше 8 живих оголошень", "license": "https://trofey.app/terms/", "method": "https://trofey.app/methodology/", "page": "https://trofey.app/analytics/tablets/", "updated": "2026-10-13"} ], "code": null, "ok": true, "source": "https://trofey.app/"}
Живой и за какой день · GET /health
«Живой» — не самый интересный вопрос: процесс, отдающий недельный файл, тоже живой. Поэтому здесь сразу даты. Этот ответ не кешируется нигде.
curl -s "https://trofey.app/api/v1/health"{ "code": null, "ok": true, "source": "https://trofey.app/", "updated": { "phones": "2026-10-13", "tablets": "2026-10-13" }}
Ошибки
Каждый ответ несёт ok. Если он false, рядом стоит code — одно слово из короткого закрытого перечня, одинакового в HTTP и в MCP. Ветвись именно по нему, а не по тексту error: текст может стать точнее, код — нет. error, found и статус HTTP остаются как были. В MCP статуса нет, поэтому там отказ ещё и помечен isError: true, и тело приезжает то же. Исключения — три ответа о нашем покрытии: unknown_model, not_measured и no_series. Это не сбой, а правдивый ответ «этого мы не меряем». Полный перечень кодов отдаёт /info.
400 · missing_argument · нет model{ "ok": false, "code": "missing_argument", "error": "model is required", "example": "https://trofey.app/api/v1/price?model=iPhone%2013&storage_gb=128"}400 · bad_argument · storage_gb не число{ "ok": false, "code": "bad_argument", "error": "storage_gb must be an integer"}400 · unknown_condition · condition не из нашего перечня{ "ok": false, "code": "unknown_condition", "error": "unknown condition", "condition": "refurbished", "category": "phones", "published": [ "new", "used" ]}400 · ambiguous_configuration · вариантов остаётся несколько{ "ok": false, "code": "ambiguous_configuration", "error": "ambiguous configuration", "model": "iPhone 13", "category": "phones", "choose_from": [ {"storage_gb": 128, "condition": "new"}, {"storage_gb": 128, "condition": "used"}, {"storage_gb": 256, "condition": "used"}, {"storage_gb": 512, "condition": "used"} ], "see": "https://trofey.app/api/v1/configurations?model=iPhone%2013&category=phones", "updated": "2026-10-13", "currency": "UAH", "definition": "market_price_uah = медіана цін живих оголошень позиції за останні 14 днів; рахується лише за наявності щонайменше 8 живих оголошень", "method": "https://trofey.app/methodology/", "license": "https://trofey.app/terms/", "source": "https://trofey.app/analytics/phones/", "attribution": "Trofey — https://trofey.app . Free to use; credit Trofey and link the page the number is published on."}404 · unknown_category · такую категорию мы не публикуем{ "ok": false, "code": "unknown_category", "error": "unknown category", "category": "cars", "published": [ "phones", "tablets" ]}404 · unknown_model / not_measured · такую конфигурацию мы не мерили{ "attribution": "Trofey — https://trofey.app . Free to use; credit Trofey and link the page the number is published on.", "category": "phones", "code": "unknown_model", "found": false, "model": "Nokia 3310", "model_known": false, "ok": false, "reason": "No published configuration matches, and the model name is not one Trofey publishes in this category. Names are matched in full — call `models` (MCP) or GET /models to see the exact strings. Trofey publishes a price only where it measured one; it does not estimate on request.", "source": "https://trofey.app/analytics/phones/", "updated": "2026-10-13"}503 · unavailable · файл не читается прямо сейчас{ "ok": false, "code": "unavailable", "error": "data unavailable", "category": "phones"}Ошибки не кешируются нигде (Cache-Control: no-store): ошибка — про этот запрос. И storage_gb=128gb — это 400, а не молчаливое игнорирование параметра: выброшенный фильтр дал бы ответ о другой конфигурации, и ты бы об этом не узнал. По той же причине один и тот же параметр, присланный дважды, тоже 400: у двух разных значений одного имени нет правила, которое сказало бы, какое из них наше. Неизвестный параметр при этом толерируется и может повторяться — кеш-бастер &_cb= остаётся рабочим.
Кеш и вежливый клиент
Успешный ответ едет с public, max-age=3600, stale-while-revalidate=86400 и с ETag, посчитанным из байтов самого ответа. Вежливый клиент шлёт назад If-None-Match и получает 304 без тела, держит свою копию час и опрашивает нас раз в сутки: между утренними сборками не меняется ничего. Лимита, который тебя остановит, нет — именно поэтому это твоё дело, а не наше.
Числа пересчитываются каждый день, и каждый ответ говорит, за какой день он посчитан — чтобы вчерашнее число не выглядело как сегодняшнее.
Что мы просим взамен
Одно: назови Trofey и поставь ссылку на страницу, где число опубликовано. Страница уже приехала к тебе вместе с числом — это поле source_page. Условия — поле license, как считается число — поле method. Просьба едет в каждом ответе полем attribution, а не только здесь.
Вопросы и ответы
Сколько запросов можно делать?
Цены — без лимита: они приходят из файлов, которые сайт публикует раз в день и которые лежат в кеше на краю сети, так что повторный вопрос ничего не стоит. Лимит есть только на проверку IMEI — 120 запросов в минуту.
Как часто обновляются числа?
Раз в сутки. Каждый ответ несёт поле с днём расчёта — ориентируйся на него, а не на день, когда ты сделал запрос.
Можно ли использовать эти данные у себя?
Да, бесплатно. Условие одно: указать Trofey и сослаться на страницу, где число опубликовано. Ссылка на лицензию приходит в каждом ответе.