Пустой ratings
Это валидный ответ: сейчас нет оценки, которую можно достоверно опубликовать. Скрывайте блок или показывайте нейтральный текст; не подставляйте 0.
Публичный JSON API
Прежний API v1 возвращает оценки карточек и логотипы без изменений. Дополнительный API v2 даёт оценки всей сети по площадкам, количество оценок и до трёх отзывов с 5★ на площадку — после отдельного разрешения владельца.
Для владельца компании
URL создаётся отдельно для каждой компании. Его не нужно составлять вручную или дополнять ключом.
Войдите в ReputeScan и выберите нужную компанию.
Пункт доступен владельцу компании и администратору в меню кабинета.
Передайте готовый адрес разработчику вместе с этой инструкцией. Для чтения не нужны cookie, Bearer-токен или доступ в кабинет.
Для разработчика
Сделайте обычный GET-запрос по выданному URL. Публичный endpoint поддерживает CORS для GET и OPTIONS.
https://reputescan.ru/api/v1/public/company-ratings/rpf_REPLACE_WITH_YOUR_PUBLIC_IDcurl --request GET \
--header "Accept: application/json" \
"https://reputescan.ru/api/v1/public/company-ratings/rpf_REPLACE_WITH_YOUR_PUBLIC_ID"Контракт API v1
Всегда показывайте rating вместе с rating_scale: отдельные источники могут использовать разные шкалы. Не рассчитывайте на порядок элементов и не объединяйте строки только по platform_slug — у одной площадки могут быть разные филиалы.
{
"api_version": "1",
"company_name": "Example company",
"ratings": [
{
"platform_slug": "yandex_maps",
"platform_name": "Яндекс Карты",
"rating": 4.8,
"rating_scale": 5,
"profile_url": "https://yandex.ru/maps/org/example/123",
"logo_url": "https://reputescan.ru/marketing/platforms/yandex-maps.svg",
"location": {
"name": "Основная точка",
"city": "Москва"
},
"updated_at": "2026-10-20T12:00:00Z"
}
],
"updated_at": "2026-10-20T12:00:00Z"
}| Поле | Тип | Описание |
|---|---|---|
api_version | string | Версия контракта; сейчас всегда «1». |
company_name | string | Публичное название компании. |
ratings | array | Список доступных оценок. Может быть пустым. |
updated_at | string | null | Самое позднее обновление в ISO 8601 UTC; null для пустой выдачи. |
| Поле | Тип | Описание |
|---|---|---|
platform_slug | string | Стабильный машинный код площадки. |
platform_name | string | Название площадки для интерфейса. |
rating | number | Актуальная подтверждённая оценка. |
rating_scale | number | Максимум шкалы, например 5 или 10. |
profile_url | string | null | Безопасная публичная ссылка на карточку. Если null, карточку не делайте кликабельной. |
logo_url | string | null | Локальный логотип или нейтральный бейдж ReputeScan. Для всех текущих поддерживаемых площадок URL заполнен; всё равно предусмотрите fallback. |
location | object | null | Филиал: nullable name и city. null означает оценку без отдельной точки. |
updated_at | string | Время наблюдения этой оценки в ISO 8601 UTC. |
Изображения имеют разные пропорции — используйте object-fit: contain. Для части источников возвращаются нейтральные идентификационные бейджи ReputeScan, а не заявление об официальном партнёрстве площадки.
API v2 · widget
В кабинете «API для сайта» включите «Публиковать количество оценок» и/или «Публиковать до 3 отзывов с 5★» и сохраните. Используйте дополнительный URL с /widget. Старый URL и его ответ v1 остаются прежними. Без хотя бы одного разрешения v2 возвращает 404. Замена ссылки сбрасывает разрешения, отключение отзывает обе версии.
https://reputescan.ru/api/v1/public/company-ratings/rpf_REPLACE_WITH_YOUR_PUBLIC_ID/widget{
"api_version": "2",
"company_name": "Example company",
"total_rating_count": null,
"known_rating_count": 120,
"rating_count_complete": false,
"platforms": [
{
"platform_slug": "yandex_maps",
"platform_name": "Яндекс Карты",
"logo_url": "https://reputescan.ru/marketing/platforms/yandex-maps.svg",
"rating": 4.8,
"rating_scale": 5,
"rating_method": "unweighted_listing_mean",
"listing_count": 2,
"rating_count": null,
"known_rating_count": 120,
"rating_count_complete": false,
"reviews": [
{
"author": "Example author",
"text": "An example of a saved five-star review.",
"rating": 5,
"rating_scale": 5,
"published_at": null,
"published_date": "2026-10-20",
"source_url": null,
"profile_url": "https://yandex.ru/maps/org/example/123",
"location": {
"name": "Основная точка",
"city": "Москва"
}
}
]
}
],
"updated_at": "2026-10-25T12:00:00Z"
}| Поле | Тип | Описание |
|---|---|---|
api_version | string | Всегда «2». company_name и updated_at имеют прежний смысл. |
total_rating_count | number | null | Сумма оценок всей сети на всех включённых площадках, только когда все количества известны. null — данные неполные или публикация выключена, не ноль. |
known_rating_count | number | Сумма только известных количеств. При rating_count_complete=false не подписывайте её как итог всей сети. При выключенной публикации 0 — отсутствие раскрытых данных, не измеренный ноль. |
rating_count_complete | boolean | Полнота именно количества; это не доказательство полноты всех отзывов в базе. |
platforms | array | Одна строка на площадку: platform_slug, platform_name, logo_url, listing_count, rating, rating_scale, rating_method, rating_count, known_rating_count, rating_count_complete, reviews. |
platforms[].rating | number | null | Среднее арифметическое доступных оценок карточек после приведения к /5. Без весов по количеству; rating_method=unweighted_listing_mean, rating_scale=5. Это расчёт ReputeScan, не официальная сетевая оценка площадки. Неизвестная оценка — null. |
platforms[].rating_count | number | null | Сумма оценок карточек этой площадки при известном количестве каждой; те же правила known_rating_count/completeness. Это оценки, не уникальные люди и не количество текстовых отзывов. |
platforms[].reviews | array | От 0 до 3 сохранённых полных отзывов с оценкой ровно 5/5, сначала новые, на всю площадку сети, а не по 3 на филиал. При выключенной публикации — []. Нехватка не заполняется выдуманными отзывами или 4★. |
reviews[] | object | author: string|null, text: string, rating:5, rating_scale:5, published_at:string|null (ISO timestamp), published_date:string|null (календарная дата без выдуманного времени), source_url:string|null (сам отзыв), profile_url:string|null (карточка), location: прежний nullable филиал/город. Нельзя выдавать profile_url за прямую ссылку на отзыв. |
Сохраните код как /reviews-widget.js. Сама карточка не кликабельна: переход вынесен в отдельную ссылку «Читать оригинал отзыва» и появляется только при source_url. Данные вставляются через textContent, не innerHTML. Пример не повторяет запросы и не делает polling; для 429 действуют правила ниже.
<p id="rating-total" aria-live="polite"></p>
<div id="network-ratings" aria-live="polite"></div>
<section id="five-star-reviews" class="review-carousel" aria-label="Five-star reviews" tabindex="0"></section>
<script type="module" src="/reviews-widget.js"></script>const API_URL = "https://reputescan.ru/api/v1/public/company-ratings/rpf_REPLACE_WITH_YOUR_PUBLIC_ID/widget";
const scores = document.querySelector("#network-ratings");
const carousel = document.querySelector("#five-star-reviews");
const total = document.querySelector("#rating-total");
const safeLink = (value) => {
try {
const url = new URL(value);
return ["http:", "https:"].includes(url.protocol) && !url.username && !url.password ? url.href : null;
} catch { return null; }
};
try {
const response = await fetch(API_URL, { headers: { Accept: "application/json" } });
if (!response.ok) throw new Error("Widget API: " + response.status);
const data = await response.json();
// null means unknown or not published, not zero.
total.textContent = data.total_rating_count !== null
? "Всего оценок: " + data.total_rating_count
: data.known_rating_count > 0
? "Известно оценок (неполные данные): " + data.known_rating_count
: "";
scores.replaceChildren();
carousel.replaceChildren();
for (const platform of data.platforms) {
const score = document.createElement("p");
score.textContent = platform.platform_name + ": " + (platform.rating === null
? "Оценка недоступна"
: platform.rating + " / " + platform.rating_scale);
scores.append(score);
for (const review of platform.reviews) {
const card = document.createElement("article");
card.className = "review-slide";
const title = document.createElement("h3");
title.textContent = platform.platform_name + " · 5 / 5";
const author = document.createElement("p");
author.textContent = review.author || "Автор отзыва";
const text = document.createElement("p");
text.textContent = review.text;
const date = document.createElement("small");
date.textContent = review.published_date || review.published_at || "";
card.append(title, author, text, date);
const href = safeLink(review.source_url);
if (href) {
const link = document.createElement("a");
link.href = href;
link.target = "_blank";
link.rel = "noopener noreferrer";
link.textContent = "Читать оригинал отзыва";
// Only this link is clickable, not the swipable card.
card.append(link);
}
carousel.append(card);
}
}
} catch (error) {
console.error(error);
scores.textContent = "Оценки временно недоступны.";
carousel.replaceChildren();
total.textContent = "";
}.review-carousel { display: flex; gap: 16px; overflow-x: auto; scroll-snap-type: x mandatory; padding: 12px 0; }
.review-slide { flex: 0 0 min(85vw, 360px); scroll-snap-align: start; border: 1px solid #e2e8f1; border-radius: 12px; padding: 20px; overflow-wrap: anywhere; }
.review-slide a { display: inline-block; padding: 12px 0; }
.review-slide p { white-space: pre-wrap; }Без библиотек
Добавьте контейнер, сохраните JavaScript как /ratings.js, подключите стили и замените API_URL на ссылку из кабинета. type=module запускает код после разбора HTML. Пример создаёт DOM-элементы безопасно, не вставляет данные через innerHTML и убирает изображение, если логотип не загрузился.
<div id="reputescan-ratings" aria-live="polite"></div>
<script type="module" src="/ratings.js"></script>const API_URL =
"https://reputescan.ru/api/v1/public/company-ratings/rpf_REPLACE_WITH_YOUR_PUBLIC_ID";
const root = document.querySelector("#reputescan-ratings");
function createRatingCard(source) {
const card = document.createElement(source.profile_url ? "a" : "article");
card.className = "rating-card";
if (source.profile_url) {
card.href = source.profile_url;
card.target = "_blank";
card.rel = "noopener noreferrer";
}
if (source.logo_url) {
const logo = document.createElement("img");
logo.src = source.logo_url;
logo.alt = "";
logo.width = 88;
logo.height = 36;
logo.addEventListener("error", () => logo.remove(), { once: true });
card.append(logo);
}
const name = document.createElement("span");
name.textContent = source.platform_name;
const score = document.createElement("strong");
score.textContent = `${source.rating} / ${source.rating_scale}`;
card.append(name, score);
const location = [source.location?.name, source.location?.city]
.filter(Boolean)
.join(", ");
if (location) {
const place = document.createElement("small");
place.textContent = location;
card.append(place);
}
return card;
}
async function loadRatings() {
root.textContent = "Загружаем оценки…";
try {
const response = await fetch(API_URL, {
headers: { Accept: "application/json" },
});
if (response.status === 429) {
const seconds = response.headers.get("Retry-After") || "60";
throw new Error(`Слишком много запросов. Повторите через ${seconds} сек.`);
}
if (!response.ok) throw new Error(`API вернул ${response.status}`);
const data = await response.json();
if (!data.ratings.length) {
root.textContent = "Актуальные оценки скоро появятся.";
return;
}
root.replaceChildren(...data.ratings.map(createRatingCard));
} catch (error) {
console.error(error);
root.textContent = "Не удалось загрузить оценки.";
}
}
loadRatings();.rating-card {
display: grid;
grid-template-columns: 96px 1fr auto;
align-items: center;
gap: 12px;
padding: 14px;
border: 1px solid #e2e8f1;
border-radius: 12px;
color: #172640;
text-decoration: none;
}
.rating-card img {
width: 88px;
height: 36px;
object-fit: contain;
}
.rating-card small {
grid-column: 2 / -1;
color: #53627a;
}Надёжная интеграция
Блок оценок не должен ломать основную страницу сайта. Покажите спокойное резервное состояние и оставьте повторную попытку следующей загрузке страницы.
Это валидный ответ: сейчас нет оценки, которую можно достоверно опубликовать. Скрывайте блок или показывайте нейтральный текст; не подставляйте 0.
API отключён, ссылка заменена или URL неверен. Запросите у владельца новую ссылку из кабинета.
Пример автоматически не повторяет запрос. Если добавляете повтор на сервере, используйте Retry-After; в cross-origin JavaScript этот заголовок может быть недоступен, поэтому задайте паузу не менее 60 секунд.
Не показывайте устаревшие данные как свежие. Сохраните интерфейс сайта рабочим и повторите позже.
Лимиты защищают доступность API и не являются авторизацией. Не добавляйте URL в публичный репозиторий как секрет: это именно отзываемая публичная ссылка для чтения.
Да, для всех текущих поддерживаемых источников logo_url заполнен. Там, где официальный знак нельзя использовать без отдельного разрешения, ReputeScan отдаёт нейтральный локальный бейдж с названием источника. Оставьте визуальный fallback на случай нового источника или временной ошибки изображения.
API сохраняет родную шкалу площадки. Всегда выводите «rating / rating_scale» или нормализуйте значение у себя осознанно.
У компании может быть несколько филиалов и отдельная карточка площадки для каждого из них. Используйте location и не удаляйте строки только из-за одинакового platform_slug.
API показывает последний достоверный снимок, доступный в ReputeScan. Точное время есть в updated_at у каждой строки и на верхнем уровне ответа. GET-запрос сам не запускает новый сбор.
Да, через дополнительный /widget API v2 после отдельного разрешения владельца: количество оценок и до трёх полных отзывов ровно с 5/5 на каждую площадку. Прежний v1 остаётся rating-only; его URL и формат не меняются.
Готово к подключению
Постоянный адрес инструкции: reputescan.ru/docs/ratings-api