Справочник качества
GET /api/v1/quality/vocabulary
Возвращает 12 видов, подписи параметров, безопасные форматы и точные ограничения для формы.
Доступ
Bearer API-ключ активного пространства и право runs.read. Для записи нужны ключ с записью и sites.write на выбранном сайте. Общие определения изменяет только оператор платформы с settings.manage, не внешний ключ. Сайты и история ограничены текущей командой. На агенте POST/PATCH/DELETE запрещены: определения меняются в облаке.
Параметры
| Имя | Где | Обязательно | Описание |
|---|---|---|---|
locale |
query | нет | Язык справочника, предложений и пояснений. Если не указан, учитывается cookie akmelo_locale; иначе ru. Имена полей пользователя не переводятся. |
Тело не требуется. locale=ru|en выбирает язык подписей и пояснений; без явного параметра используется cookie akmelo_locale, затем русский. Код вида и имена полей не переводятся.
Ответ 200
Пример сокращён. Числовые ID условны; полные поля описаны ниже и в скачиваемой схеме OpenAPI.
{
"kinds": [
{
"value": "field_fill_rate",
"label": "Поле заполнено",
"hint": "Сообщить, если слишком много товаров без цены.",
"skip_hint": "Нужны сохранённые записи.",
"params": [
{
"key": "field",
"label": "Поле",
"type": "field",
"required": true,
"default": ""
},
{
"key": "max_empty_percent",
"label": "Допустимо пустых, %",
"type": "number",
"min": 0,
"max": 100,
"default": 30,
"required": false
}
]
}
],
"actions": [
{
"value": "warn",
"label": "Только предупредить"
}
],
"severities": [
{
"value": "warning",
"label": "Предупреждение"
}
],
"formats": {
"url": "Полная ссылка HTTP или HTTPS",
"email": "Электронная почта",
"phone": "Телефон",
"inn": "Российский ИНН",
"gtin": "Товарный код GTIN, EAN или UPC"
}
}
| Поле | Значение |
|---|---|
kinds[] |
Стабильный value, понятные label, hint, skip_hint, next_step и схема params[] |
actions[] |
warn и mark_suspicious, с переведёнными подписями |
severities[] |
Уровни важности находок |
formats |
Подписи пяти разрешённых форматов |
Все виды и параметры
kind |
Параметры и начальные значения | Условие находки |
|---|---|---|
row_count_drop |
drop_percent=50, min_previous=10 |
Записей стало меньше начиная с указанного процента |
row_count_growth |
growth_percent=100, min_previous=10 |
Записей стало больше начиная с указанного процента |
row_count_min |
min_count=1 |
Сохранено меньше указанного количества |
invalid_share |
max_invalid_percent=50, min_items=1 |
Доля отклонённых записей выше допуска |
field_fill_rate |
field, max_empty_percent=30 |
Доля пустых значений выше допуска |
field_numeric_range |
field, min_value=0, max_value=null, max_bad_percent=5 |
Заполненное значение не число либо вне включённых границ |
field_format |
field, format=url, max_bad_percent=5 |
Заполненное значение не соответствует формату |
field_allowed_values |
field, allowed_values, max_bad_percent=5 |
Значение не входит в разрешённый список |
field_length |
field, min_length=3, max_length=null, max_bad_percent=5 |
Длина заполненной строки в символах вне включённых границ |
field_duplicate_share |
field, max_duplicate_percent=0 |
Доля повторов сверх первого выше допуска |
field_change_rate |
field, max_changed_percent=50, min_items=10 |
Доля записей с изменением поля в журнале выше допуска |
field_freshness |
field, max_age_hours=48, max_bad_percent=5 |
Дата слишком старая, неверная либо более чем на 5 минут в будущем |
field является кодом объявленного поля выбранного сайта, не его подписью. allowed_values содержит от 1 до 100 различных строк до 128 символов каждая; регистр учитывается. A, A, B означает один повтор из трёх, а не два. Изменения для JSON/collection-поля включают вложенные пути stock.warehouse.qty; пути другого поля stockroom не учитываются. Новая запись не считается изменённой.
Проценты долей находятся в пределах 0–100, drop_percent в пределах 1–100, growth_percent в пределах 1–100000. Количества целые от 1 до 1000000000. Числовые границы от -1000000000000000 до 1000000000000000; длина от 0 для минимума и от 1 для максимума до 1000000; max_age_hours от 0.25 до 87600. Точный источник ограничений для формы: kinds[].params в ответе. Учитывайте required, nullable, integer, options, min, max, default.
min_value, max_value, min_length, max_length допускают явный null, снимающий только соответствующую границу. Хотя бы одна граница пары обязательна. Остальные параметры не допускают null; пропущенное необязательное значение получает безопасное начальное значение. При PATCH переданный params заменяет набор, поэтому пропущенные необязательные границы снимаются. Числовые строки сохраняют точность; для точных дробных порогов передавайте строку, например "7.0000000000000001".
Форматы: url проверяет абсолютную HTTP/HTTPS-ссылку; email синтаксис почты; phone 10–15 цифр с допустимыми разделителями; inn российский ИНН с контрольными цифрами; gtin товарный код GTIN/EAN/UPC с контрольной цифрой. Ссылки не открываются, номера и адреса не проверяются через внешние сервисы. Произвольные регулярные выражения не принимаются.
Поведение и ограничения
Состав kinds сокращён в примере. Сервис возвращает все 12 видов. Вид выбирается по стабильному value, не по переведённой подписи. Для параметров учитывайте type, required, min, max, integer, options и default.
Правила действуют на следующие успешные полные сборы. Они не меняют старые данные и не исправляют сценарий. Проверки полей используют до 5 000 записей текущего сбора, с явной отметкой ограниченной выборки; пустые значения кроме проверки заполненности пропускаются. passed, breached, skipped различаются, а отсутствие находки не доказывает успех.
Числовые примеры сохраняют прежний контракт v1. Для публичных UUID используйте X-Identifier-Format: uuid либо тот же метод /api/v2. Это относится и к вложенным ссылкам на сайты, правила и сборы; preset_id, category_id и field остаются строковыми кодами. Форматы идентификаторов.
Если budget_truncated=true, результат пропущен с частичными измерениями. Превышение общего бюджета не считается успешно выполненной проверкой.
Покрытие и пропущенные проверки
До json_decode проверяются сложность и глубина JSON: общий предел 200000узлов и 16 МиБ оценённой распакованной структуры, не больше 4 МиБ на строку и 24уровней. Строковые скобки не считаются узлами. Дополнительно перед PDO-порцией и распаковкой проверяется свободная память PHP с резервом 8 МиБ. Новые причины пропуска: sample_structure_exceeded, sample_depth_exceeded, sample_decode_error, sample_memory_exceeded. Даже если первая строка слишком сложная, это пропуск по пределу, а не no_records. Все измерения до остановки частичные.
Проверяются только успешные полные обычные сборы. Пробные, частичные, неуспешные и отменённые сборы не проверяются. Продолжение или повтор прерванного сбора имеет skipped / continued_run. Сравнение объёма требует более раннего успешного полного сбора того же сайта и сценария, не помеченного для проверки; без него будет no_baseline, при слишком малом прошлом объёме baseline_too_small.
Счётчики объёма относятся ко всему сбору. Поля проверяются по первым 5000 действующим записям текущего сбора, по внутреннему ID. Это ограниченная выборка, не случайная оценка всего каталога. Общий предел: 32 различных поля, 100000 ячеек и 8 МиБ сырых данных; отдельное значение свыше 8 КиБ не читается в память. sample_limited, sample_size, sample_limit, budget_truncated, budget_bytes, byte_limit, cell_limit, field_limit, oversized_skipped раскрывают покрытие. При достижении общего бюджета результат skipped, причина sample_budget_exceeded, частичное измерение в observed_status не является итоговым успехом или находкой. Поля сверх лимита получают field_budget_exceeded.
Пустыми считаются null, пустая строка, строка только из пробельных символов Unicode и пустой массив. 0 и false заполнены. Только field_fill_rate считает пустоту нарушением. Другие виды исключают её из знаменателя и при отсутствии заполненных значений возвращают no_filled_values. Иные причины пропуска: no_records, field_missing, values_too_large, too_few_records, unsupported_kind, check_error. Ошибка проверки не превращает уже сохранённый успешный сбор в неуспешный.
Доли нарушают правило строго выше допуска: ровно 7 из 100 при допуске 7% проходят. Падение и рост объёма включают порог: 100 → 90 при пороге 10% вызывает находку. Сравнения точные, округляется только показанный процент. Свежесть измеряется относительно run.finished_at; дата без часового пояса считается UTC.
Подробные примеры всех 24 шаблонов и работа с интерфейсом: Качество данных. Схема параметров: справочник.
Как отправить запрос
В серверном окружении задайте BASE (адрес установки без завершающего слеша) и API_KEY. Секрет не вставляется в исходник. Подготовка клиентов и браузерный JavaScript.
curl
curl --fail-with-body -X GET "$BASE/api/v1/quality/vocabulary?locale=ru" \
-H "Authorization: Bearer $API_KEY" \
-H "Accept: application/json"
Node.js · сервер
// Node.js, сервер. Сохраните как request.mjs.
const response = await fetch(process.env.BASE + "/api/v1/quality/vocabulary?locale=ru", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.API_KEY}`,
Accept: "application/json"
},
signal: AbortSignal.timeout(120000)
});
if (!response.ok) throw new Error(`${response.status}: ${await response.text()}`);
console.log(await response.json());
Python
import json
import os
import urllib.request
import urllib.error
request = urllib.request.Request(
os.environ["BASE"] + "/api/v1/quality/vocabulary?locale=ru",
method="GET",
headers={"Authorization": "Bearer " + os.environ["API_KEY"],
"Accept": "application/json"},
)
try:
with urllib.request.urlopen(request, timeout=120) as response:
print(json.load(response))
except urllib.error.HTTPError as error:
print(error.code, error.read().decode("utf-8", errors="replace"))
raise
PHP · внешний клиент
<?php
$handle = curl_init(getenv("BASE") . "/api/v1/quality/vocabulary?locale=ru");
curl_setopt_array($handle, [
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 120,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer " . getenv("API_KEY"),
"Accept: application/json",
],
]);
$content = curl_exec($handle);
$status = curl_getinfo($handle, CURLINFO_RESPONSE_CODE);
if ($content === false) {
throw new RuntimeException(curl_error($handle));
}
curl_close($handle);
if ($status < 200 || $status >= 300) {
throw new RuntimeException("HTTP $status: $content");
}
print_r(json_decode($content, true, 512, JSON_THROW_ON_ERROR));
Go
package main
import (
"fmt"
"io"
"net/http"
"os"
"time"
)
func main() {
request, err := http.NewRequest("GET", os.Getenv("BASE") + "/api/v1/quality/vocabulary?locale=ru", nil)
if err != nil { panic(err) }
request.Header.Set("Authorization", "Bearer " + os.Getenv("API_KEY"))
request.Header.Set("Accept", "application/json")
client := &http.Client{Timeout: 120 * time.Second}
response, err := client.Do(request)
if err != nil { panic(err) }
defer response.Body.Close()
content, err := io.ReadAll(response.Body)
if err != nil { panic(err) }
if response.StatusCode < 200 || response.StatusCode >= 300 {
panic(fmt.Sprintf("HTTP %d: %s", response.StatusCode, content))
}
fmt.Println(string(content))
}
Если запрос не выполнен
401: проверьте ключ и срок. 403: права, режим чтения/записи и 2FA. 404: идентификатор и пространство. 422: поля запроса или состояние объекта. 429: подождите Retry-After. Подробно об ошибках и повторах.