Контракт совместим с legacy. Авторизация приёма — заголовок api-key (per-promo). Интерактивная схема: Swagger /docs.
POST /api/receipts/qr — JSON {qrStr,userUuid,promoId?,externalId?}POST /api/widgets/receipts — form qrAsString ИЛИ photos[], userUuid,promoId?POST /api/receipts — multipart photos[] (≤5, ≤20МБ), userUuid,promoId?,externalId?POST /api/receipts/url — JSON {urls[],userUuid,promoId?}POST /api/receipts/{uuid}/photos — добавить фото к чекуPOST /api/qr — синхронный разбор QR (qrAsString или photo) → фискальный ключОтвет приёма: {status,uuid,receiptId}. Дубликат → 409.
GET /api/receipts/{uuid} (api-key) или публично GET /r/{uuid}.json. Состояния: ARRIVED → INSPECTED → REVIEWED; поля REVIEWED: approved, retailer, total, answers, rules, promoPoints, reviewers, matchedPromos, fnsReceipt, rejectReason.
Per-promo URL/метод/заголовки. Шлются ARRIVED → INSPECTED → REVIEWED (тот же payload, что в статусе, + state). Ответ бренда {externalId, meta} сохраняется. Ретраи с бэкоффом; коды 400/409/424 не повторяются; на 404 повторно шлётся ARRIVED и затем исходное событие (само-восстановление).
<script src='/widget/fnfd-widget.js'> + FnfdWidget.init({el,apiKey,promoId}). Демо: /widget/demo.