Fiqo · JSON API кроссов

Схема v1 · отдельный сервис · изоляция подписчиков · источник обязателен

Личная база + общая подтверждённая база

Поиск по бренду и артикулу

Запрос выполняется сервером клиента с API-ключом. Браузеру постоянный ключ не передаётся. Аккаунт, область ключа и подписка проверяются сервером при каждом запросе. Реальный адрес и ключ выдаются при подключении.

POST /v1/lookup
Authorization: Bearer <API_KEY>
Content-Type: application/json

{"brand":"MANN-FILTER","article":"W 67/1","supplier":"Supplier One"}
{
  "schema": "fiqo.crosses", "version": 1,
  "found": true,
  "part": {"id":"…","brandId":"…","brand":"MANN-FILTER","article":"W 67/1"},
  "crosses": [{
    "id":"…", "part":{"id":"…","brand":"DEMO","article":"DF100"},
    "relation":"replacement", "direction":"forward",
    "origin":"shared", "status":"confirmed", "priority":"high",
    "confidence":"manufacturer", "restrictions":[]
  }],
  "next": null
}

Нормализация сохраняет дефисы, косые черты, различие кириллицы/латиницы и O/0. Варианты поставщика задаются алиасами. equivalent симметричен, replacement направлен, conditional требует списка ограничений. Транзитивные замены не выводятся.

Источники и происхождение

У кросса может быть несколько независимых свидетельств. Каждое свидетельство и каждый алиас связаны с источником и импортом: кто опубликовал данные, какой API или исходный файл, версия, внешний ID строки, исходные значения и положение в файле. SHA-256 считается на исходных байтах загруженного файла.

POST /v1/sources
{"name":"Каталог производителя","kind":"file", "publisher":"Производитель",
 "externalId":"catalog-2026","scope":"private"}

POST /v1/sources/<sourceId>/artifacts?filename=crosses.csv&version=2026-10
Content-Type: application/octet-stream
<исходные байты файла>

POST /v1/sources/<sourceId>/imports
Idempotency-Key: import-2026-10-page-1
{"externalBatchId":"page-1","version":"2026-10","artifactId":"…",
 "rows":[{"externalRowId":"line-15","locator":"лист 1, строка 15",
   "from":{"brand":"BRAND A","article":"A-1"},
   "to":{"brand":"BRAND B","article":"B-2"},"relation":"replacement"}]}

Импорт возвращает HTTP 202 и ID сохраняемого задания. Результат проверяется через GET /v1/jobs/:id. Повтор внешнего ID пачки не создаёт дублей; другие данные под тем же ID отклоняются. Из API-источника нужен стабильный providerKey; URL хранится без токенов и параметров авторизации.

Общая база и согласие

useShared по умолчанию true, contribute false. Личная база используется всегда. Это две независимые настройки. Три независимых подписчика повышают приоритет кандидата, но не публикуют его. Копии одного файла, один API и одна организация не дают три независимых голоса. Проверенный администратором источник производителя сразу имеет высокий приоритет. Общую базу в первом выпуске публикует администратор.

Личные записи и исходники других клиентов не возвращаются. При отзыве согласия личные данные остаются у владельца и исключаются из общего расчёта. Публикация без оставшихся подтверждений отзывается.

Удаление источника

POST /v1/sources/<sourceId>/preview
{"operation":"delete"}

POST /v1/sources/<sourceId>/execute
Idempotency-Key: delete-source-request-1
{"confirmationToken":"<токен из предпросмотра>"}

Предпросмотр показывает свидетельства, алиасы, файлы и затронутые публикации. Токен действует 10 минут и связан с пользователем и состоянием подтверждений. Если данные изменились, нужен новый предпросмотр. Удаление и отключение выполняются транзакционно через устойчивую очередь. Другие источники не удаляются. Технические идентификаторы, история заданий и минимальный аудит сохраняются; удалённые свидетельства больше не участвуют в выдаче.

Синхронизация

GET /v1/changes?cursor=…&limit=100 возвращает изменения и явные удаления. Первый снимок постраничный; пока more=true, нужно продолжать по полученному курсору. Данные и курсор сохраняются вместе. При reset=true локальный набор заменяется. Неизвестный, чужой, устаревший курсор и изменение доступа к общей базе требуют восстановления снимка.

requiresResolveRefresh=true означает, что изменились алиасы или настройки: локальные результаты разрешения бренда/артикула нужно сбросить. Курсоры переживают перезапуск; скрытые пользовательские вкладки опрашивать не нужно.

Методы

МетодНазначение
GET/PATCH /v1/settingsОбщая база и согласие на вклад
GET/POST /v1/sourcesСписок и регистрация собственных источников
GET /v1/sources/:idИсходники, файлы, строки и алиасы владельца
POST :id/artifacts, :id/importsИсходный файл и импорт
POST :id/preview, :id/executeПредпросмотр и задание удаления/отключения
GET /v1/jobs, /v1/jobs/:idВидимая очередь и результат задания
POST /v1/lookupБренд + артикул → кроссы
PATCH /v1/overridesСкрыть конкретный кросс только у себя
GET /v1/changesКурсор изменений
GET /v1/candidates, /:idПроверка кандидатов администратором
POST /v1/publishРучная публикация с основанием
PATCH /v1/independenceСвязать подписчиков одной организации
PATCH /v1/sources/:id/trustПроверка производителя администратором

Администрирование — через доверенный серверный шлюз Fiqo. Обычный внешний ключ чтения/записи не получает административную роль. Для внешнего административного API нужна отдельная область crosses:admin в сервисе авторизации.

Ограничения первого выпуска

До 200 результатов поиска на страницу, до 2000 кроссов и 2000 алиасов в пачке, исходный файл до 10 МБ. Начальный снимок синхронизации ограничен 100 000 связей; больший экспорт требует отдельного задания экспорта. Реальные API поставщиков и форматы их файлов подключаются отдельными адаптерами: сервис сам не обходит сайты и не угадывает схему чужого файла.

Импорт таблиц · v0.2

Авторизация и подписка проверяются для рабочего пространства. Административные методы требуют роли администратора. XLSX/CSV: до 5 МБ и 5000 строк; формулы не исполняются.

POST /v1/bulk/preview — бинарный файл, X-Filename: имя в percent-encoding
POST /v1/bulk/validate — {previewId,mapping,relation,direction}
POST /v1/bulk/jobs — {previewId,mapping,sourceId?,relation?,direction?}
GET /v1/bulk/jobs
GET /v1/bulk/jobs/{id}?cursor=0
POST /v1/bulk/jobs/{id} — {action:"pause" | "retry"}

mapping: fromBrand, fromArticle, toBrand, toArticle — индексы четырёх разных колонок с нуля. relation и direction — необязательные индексы; -1 означает общее значение. Типы: analog (направленный аналог), equivalent (двусторонний), replacement (направленная замена артикула). Предпросмотр содержит headers, mapping и detection с причинами выбора. Проверьте неоднозначные колонки.

Повтор запроса с тем же предпросмотром и сопоставлением возвращает тот же ID задания. Результаты строк читаются по курсору; при more=true продолжите чтение. Сначала сохраните строки, затем курсор. После перезапуска очередь заново проверяет доступ клиента.

GET /v1/records — личные утверждения, nextCursor
POST /v1/records — {from:{brand,article},to:{brand,article},relation,hidden?,sourceId?,externalRowId?}
GET /v1/admin/moderation?status=pending
POST /v1/admin/moderation — {ids,status,reason}
GET /v1/admin/sources
POST /v1/sources/{id}/preview — {operation:"disable"}
POST /v1/admin/sources/{id} — {action:"block",confirmationToken,reason}
POST /v1/admin/sources/{id} — {action:"unblock",reason}
GET /v1/admin/history?id=...

Изменившиеся последствия блокировки делают confirmationToken недействительным. Подтверждения других источников сохраняются. Приватные свидетельства не выдаются чужим клиентам; баллы не публикуют связь автоматически.