fns-receipt-service/public/openapi.json
romantarkin ab50066400 fix
2026-06-12 22:58:09 +05:00

1264 lines
31 KiB
JSON
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{
"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": "Нет доступа"
}
}
}
}
}
}