{ "openapi": "3.1.0", "info": { "title": "FNS Receipt Service API", "version": "1.0.0", "description": "API сервиса создания чеков ФНС, админ-панели, настроек и диагностики." }, "servers": [ { "url": "/", "description": "Current host" } ], "tags": [ { "name": "Service", "description": "Состояние сервиса" }, { "name": "Receipts", "description": "Создание, чтение и синхронизация чеков" }, { "name": "Auth", "description": "Авторизация API и админ-панели" }, { "name": "Admin", "description": "Админские методы UI" } ], "components": { "securitySchemes": { "AdminBearer": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT", "description": "JWT из POST /admin/api/login" }, "AdminPassword": { "type": "apiKey", "in": "header", "name": "x-api-key", "description": "Значение API_PASS. Для совместимости также поддерживается x-admin-password и api_pass в JSON body." } }, "schemas": { "Health": { "type": "object", "properties": { "status": { "type": "string", "examples": [ "ok" ] } } }, "Item": { "type": "object", "required": [ "name", "price" ], "properties": { "id": { "type": "string", "examples": [ "order-1" ] }, "name": { "type": "string", "examples": [ "Услуга" ] }, "price": { "type": "number", "examples": [ 1000 ] }, "quantity": { "type": "number", "default": 1, "examples": [ 1 ] } } }, "CreateReceiptRequest": { "type": "object", "required": [ "email", "items" ], "properties": { "api_pass": { "type": "string", "description": "Legacy-доступ для внешних интеграций. В UI вместо него используется Bearer JWT." }, "email": { "type": "string", "format": "email", "examples": [ "client@example.com" ] }, "items": { "type": "array", "minItems": 1, "items": { "$ref": "#/components/schemas/Item" } }, "clientType": { "type": "string", "enum": [ "individual", "legal" ], "default": "individual", "description": "individual = физлицо 4%, legal = юрлицо 6%" } } }, "CreateReceiptResponse": { "type": "object", "properties": { "success": { "type": "boolean" }, "receiptCreated": { "type": "boolean" }, "emailSent": { "type": "boolean" }, "receiptId": { "type": "string" }, "printLink": { "type": "string", "format": "uri" }, "warning": { "type": "string" }, "technicalError": { "type": "object", "additionalProperties": true }, "clientType": { "type": "string", "enum": [ "individual", "legal" ], "description": "individual = физлицо 4%, legal = юрлицо 6%" }, "grossAmount": { "type": "number", "description": "Сумма грязными, до налога" }, "taxRate": { "type": "number", "examples": [ 0.04, 0.06 ] }, "taxAmount": { "type": "number", "description": "Сумма налога" }, "netAmount": { "type": "number", "description": "Сумма чистыми, после налога" } } }, "Receipt": { "type": "object", "properties": { "receiptId": { "type": "string" }, "email": { "type": "string" }, "amount": { "type": "number" }, "printLink": { "type": "string" }, "status": { "type": "string", "enum": [ "created", "cancelled" ] }, "emailSent": { "type": [ "boolean", "null" ] }, "createdAt": { "type": "string", "format": "date-time" }, "items": { "type": "array", "items": { "$ref": "#/components/schemas/Item" } }, "cancelled": { "type": "boolean" }, "clientType": { "type": "string", "enum": [ "individual", "legal" ], "description": "individual = физлицо 4%, legal = юрлицо 6%" }, "grossAmount": { "type": "number", "description": "Сумма грязными, до налога" }, "taxRate": { "type": "number", "examples": [ 0.04, 0.06 ] }, "taxAmount": { "type": "number", "description": "Сумма налога" }, "netAmount": { "type": "number", "description": "Сумма чистыми, после налога" } }, "additionalProperties": true }, "ReceiptListResponse": { "type": "object", "properties": { "receipts": { "type": "array", "items": { "$ref": "#/components/schemas/Receipt" } }, "pagination": { "type": "object", "properties": { "limit": { "type": "number", "examples": [ 50 ] }, "offset": { "type": "number", "examples": [ 0 ] }, "total": { "type": "number" } } }, "storage": { "type": "string", "enum": [ "redis", "file" ] } } }, "ReceiptResponse": { "type": "object", "properties": { "receipt": { "$ref": "#/components/schemas/Receipt" } } }, "ConfigItem": { "type": "object", "properties": { "key": { "type": "string" }, "value": { "type": "string" }, "configured": { "type": "boolean" }, "secret": { "type": "boolean" }, "source": { "type": "string", "enum": [ "env", "ui" ] } } }, "ErrorResponse": { "type": "object", "properties": { "error": { "type": "string" }, "technicalError": { "type": "object", "additionalProperties": true } } }, "LoginRequest": { "type": "object", "required": [ "password" ], "properties": { "password": { "type": "string", "description": "Значение API_PASS" } } }, "LoginResponse": { "type": "object", "properties": { "success": { "type": "boolean" }, "token": { "type": "string" }, "expiresAt": { "type": "number" }, "expiresIn": { "type": "number" } } }, "SyncReceiptsRequest": { "type": "object", "properties": { "month": { "type": "string", "pattern": "^\\d{4}-\\d{2}$", "examples": [ "2026-06" ], "description": "Месяц выгрузки из ФНС в формате YYYY-MM" } } }, "SyncReceiptsResponse": { "type": "object", "properties": { "success": { "type": "boolean" }, "synced": { "type": "number" }, "activeSynced": { "type": "number" }, "cancelledSynced": { "type": "number" }, "total": { "type": "number" }, "month": { "type": "string" }, "from": { "type": "string", "format": "date-time" }, "to": { "type": "string", "format": "date-time" }, "storage": { "type": "string", "enum": [ "redis", "file" ] } } } } }, "paths": { "/": { "get": { "tags": [ "Service" ], "summary": "Информация о сервисе", "responses": { "200": { "description": "Сервис доступен", "content": { "application/json": { "schema": { "type": "object", "properties": { "service": { "type": "string" }, "status": { "type": "string" } } } } } } } } }, "/health": { "get": { "tags": [ "Service" ], "summary": "Быстрая проверка состояния", "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Health" } } } } } } }, "/health/deep": { "get": { "tags": [ "Service" ], "summary": "Проверка SMTP и ФНС", "responses": { "200": { "description": "Результат диагностики", "content": { "application/json": { "schema": { "type": "object", "properties": { "status": { "type": "string" }, "connect_to_fns": { "type": "string" }, "smtp": { "type": "string" } } } } } } } } }, "/health/smtp": { "get": { "tags": [ "Service" ], "summary": "Проверка SMTP", "responses": { "200": { "description": "SMTP доступен" }, "500": { "description": "Ошибка SMTP", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } } } } }, "/api/v1/create-receipt": { "post": { "tags": [ "Receipts" ], "summary": "Создать чек в ФНС и отправить email", "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateReceiptRequest" } } } }, "responses": { "200": { "description": "Чек создан", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateReceiptResponse" } } } }, "400": { "description": "Неверные данные" }, "401": { "description": "Неверный api_pass" }, "500": { "description": "Ошибка создания чека", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } } }, "security": [ { "AdminBearer": [] }, { "AdminPassword": [] } ] } }, "/api/v1/auth/login": { "post": { "tags": [ "Auth" ], "summary": "Получить JWT для API и админ-панели", "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LoginRequest" }, "examples": { "password": { "value": { "password": "strong_api_password" } }, "legacy": { "value": { "api_pass": "strong_api_password" } } } } } }, "responses": { "200": { "description": "JWT создан", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LoginResponse" } } } }, "401": { "description": "Неверный пароль" } } } }, "/api/v1/receipts": { "get": { "tags": [ "Receipts" ], "summary": "Получить журнал чеков", "security": [ { "AdminBearer": [] }, { "AdminPassword": [] } ], "parameters": [ { "name": "limit", "in": "query", "schema": { "type": "number", "default": 50, "maximum": 200 } }, { "name": "offset", "in": "query", "schema": { "type": "number", "default": 0 } }, { "name": "status", "in": "query", "schema": { "type": "string", "enum": [ "created", "cancelled" ] } }, { "name": "clientType", "in": "query", "schema": { "type": "string", "enum": [ "individual", "legal" ] } }, { "name": "search", "in": "query", "schema": { "type": "string" }, "description": "Поиск по email, ID чека и позициям" }, { "name": "dateFrom", "in": "query", "schema": { "type": "string", "format": "date" }, "description": "Начало периода включительно, YYYY-MM-DD или ISO date-time" }, { "name": "dateTo", "in": "query", "schema": { "type": "string", "format": "date" }, "description": "Конец периода включительно, YYYY-MM-DD или ISO date-time" } ], "responses": { "200": { "description": "Список чеков", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReceiptListResponse" } } } }, "401": { "description": "Нет доступа" } } } }, "/api/v1/receipts/{receiptId}": { "get": { "tags": [ "Receipts" ], "summary": "Получить чек по ID", "security": [ { "AdminBearer": [] }, { "AdminPassword": [] } ], "parameters": [ { "name": "receiptId", "in": "path", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "Чек найден", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReceiptResponse" } } } }, "401": { "description": "Нет доступа" }, "404": { "description": "Чек не найден" } } } }, "/api/v1/receipts/sync": { "post": { "tags": [ "Receipts" ], "summary": "Синхронизировать чеки из ФНС за выбранный месяц", "security": [ { "AdminBearer": [] }, { "AdminPassword": [] } ], "requestBody": { "required": false, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SyncReceiptsRequest" } } } }, "responses": { "200": { "description": "Синхронизация выполнена", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SyncReceiptsResponse" } } } }, "401": { "description": "Нет доступа" }, "500": { "description": "Ошибка синхронизации" } } } }, "/admin/api/session": { "post": { "tags": [ "Admin" ], "summary": "Проверить пароль админ-панели", "security": [ { "AdminBearer": [] } ], "responses": { "200": { "description": "Пароль принят" }, "401": { "description": "Неверный пароль" } } } }, "/admin/api/config": { "get": { "tags": [ "Admin" ], "summary": "Получить настройки сервиса", "security": [ { "AdminBearer": [] } ], "responses": { "200": { "description": "Настройки", "content": { "application/json": { "schema": { "type": "object", "properties": { "config": { "type": "array", "items": { "$ref": "#/components/schemas/ConfigItem" } }, "files": { "type": "object", "additionalProperties": { "type": "string" } }, "storage": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "redis", "file" ] }, "receiptsKey": { "type": "string" } } } } } } } } } }, "put": { "tags": [ "Admin" ], "summary": "Обновить настройки сервиса", "security": [ { "AdminBearer": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "values": { "type": "object", "additionalProperties": { "type": "string" } } } } } } }, "responses": { "200": { "description": "Настройки сохранены" } } } }, "/admin/api/receipts": { "get": { "tags": [ "Admin" ], "summary": "Получить локальный журнал чеков и ошибок", "security": [ { "AdminBearer": [] } ], "responses": { "200": { "description": "Чеки и ошибки", "content": { "application/json": { "schema": { "type": "object", "properties": { "receipts": { "type": "array", "items": { "$ref": "#/components/schemas/Receipt" } }, "errors": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "storage": { "type": "string", "enum": [ "redis", "file" ] } } } } } } } } }, "/admin/api/receipts/sync": { "post": { "tags": [ "Admin" ], "summary": "Синхронизировать чеки из ФНС за выбранный месяц", "security": [ { "AdminBearer": [] } ], "responses": { "200": { "description": "Синхронизация выполнена", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SyncReceiptsResponse" } } } }, "500": { "description": "Ошибка синхронизации" } }, "requestBody": { "required": false, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SyncReceiptsRequest" } } } } } }, "/admin/api/fns-user": { "get": { "tags": [ "Admin" ], "summary": "Получить профиль ФНС", "security": [ { "AdminBearer": [] } ], "responses": { "200": { "description": "Профиль ФНС", "content": { "application/json": { "schema": { "type": "object", "properties": { "user": { "type": "object", "additionalProperties": true } } } } } }, "500": { "description": "Ошибка ФНС" } } } }, "/openapi.json": { "get": { "tags": [ "Service" ], "summary": "OpenAPI JSON", "responses": { "200": { "description": "Спецификация OpenAPI" } } } }, "/swagger": { "get": { "tags": [ "Service" ], "summary": "Swagger UI", "responses": { "200": { "description": "Swagger UI HTML" } } } }, "/admin/api/login": { "post": { "tags": [ "Admin" ], "summary": "Войти в админ-панель и получить JWT", "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LoginRequest" } } } }, "responses": { "200": { "description": "JWT создан", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LoginResponse" } } } }, "401": { "description": "Неверный пароль" } } } }, "/api/v1/receipts/export": { "get": { "tags": [ "Receipts" ], "summary": "Экспортировать чеки в CSV", "description": "Возвращает все чеки, подходящие под фильтры search, status, clientType, dateFrom и dateTo, без пагинации.", "security": [ { "AdminBearer": [] }, { "AdminPassword": [] } ], "parameters": [ { "name": "status", "in": "query", "schema": { "type": "string", "enum": [ "created", "cancelled" ] } }, { "name": "clientType", "in": "query", "schema": { "type": "string", "enum": [ "individual", "legal" ] } }, { "name": "search", "in": "query", "schema": { "type": "string" }, "description": "Поиск по email, ID чека и позициям" }, { "name": "dateFrom", "in": "query", "schema": { "type": "string", "format": "date" }, "description": "Начало периода включительно, YYYY-MM-DD или ISO date-time" }, { "name": "dateTo", "in": "query", "schema": { "type": "string", "format": "date" }, "description": "Конец периода включительно, YYYY-MM-DD или ISO date-time" } ], "responses": { "200": { "description": "CSV-файл с чеками", "content": { "text/csv": { "schema": { "type": "string", "format": "binary" } } } }, "400": { "description": "Неверный период экспорта" }, "401": { "description": "Нет доступа" } } } }, "/admin/api/receipts/export": { "get": { "tags": [ "Admin" ], "summary": "Экспортировать чеки в CSV для админ-панели", "security": [ { "AdminBearer": [] } ], "parameters": [ { "name": "status", "in": "query", "schema": { "type": "string", "enum": [ "created", "cancelled" ] } }, { "name": "clientType", "in": "query", "schema": { "type": "string", "enum": [ "individual", "legal" ] } }, { "name": "search", "in": "query", "schema": { "type": "string" }, "description": "Поиск по email, ID чека и позициям" }, { "name": "dateFrom", "in": "query", "schema": { "type": "string", "format": "date" }, "description": "Начало периода включительно, YYYY-MM-DD или ISO date-time" }, { "name": "dateTo", "in": "query", "schema": { "type": "string", "format": "date" }, "description": "Конец периода включительно, YYYY-MM-DD или ISO date-time" } ], "responses": { "200": { "description": "CSV-файл с чеками", "content": { "text/csv": { "schema": { "type": "string", "format": "binary" } } } }, "400": { "description": "Неверный период экспорта" }, "401": { "description": "Нет доступа" } } } } } }