{
  "openapi": "3.1.0",
  "info": {
    "title": "LoviSchet API v1",
    "version": "1.0.0",
    "description": "Актуальный публичный API для внешних интеграций.\nКонтракт отражает текущее runtime-поведение `/api/v1/*`.\n"
  },
  "servers": [
    {
      "url": "/",
      "description": "Current origin"
    }
  ],
  "tags": [
    {
      "name": "API v1"
    }
  ],
  "security": [
    {
      "ApiKeyHeader": []
    },
    {
      "BearerAuth": []
    },
    {
      "ApiKeyQuery": []
    }
  ],
  "paths": {
    "/api/openapi.yaml": {
      "get": {
        "tags": [
          "API v1"
        ],
        "summary": "Машинно-читаемая спецификация API v1",
        "responses": {
          "200": {
            "description": "YAML спецификация",
            "content": {
              "application/yaml": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/api/openapi.json": {
      "get": {
        "tags": [
          "API v1"
        ],
        "summary": "JSON-спецификация API v1",
        "responses": {
          "200": {
            "description": "JSON спецификация",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/ref/catalog": {
      "get": {
        "tags": [
          "API v1"
        ],
        "summary": "Справочники команды",
        "description": "Возвращает справочники и enum-значения для активной команды API-ключа.",
        "responses": {
          "200": {
            "description": "Успешный ответ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CatalogResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitError"
          }
        }
      }
    },
    "/api/v1/invoices": {
      "get": {
        "tags": [
          "API v1"
        ],
        "summary": "Список документов команды",
        "parameters": [
          {
            "in": "query",
            "name": "q",
            "schema": {
              "type": "string"
            },
            "description": "Текстовый поиск"
          },
          {
            "in": "query",
            "name": "date_from",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "in": "query",
            "name": "date_to",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "in": "query",
            "name": "limit",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 50
            }
          },
          {
            "in": "query",
            "name": "offset",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Успешный ответ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvoiceListResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitError"
          }
        }
      },
      "post": {
        "tags": [
          "API v1"
        ],
        "summary": "Создать документ",
        "description": "Поддерживает два формата тела:\n1. корневой объект документа\n2. объект с полем `invoice`\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateInvoiceRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Документ создан",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreateUpdateInvoiceResponse"
                }
              }
            }
          },
          "207": {
            "description": "Документ сохранен, часть писем не отправлена",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreateUpdateInvoiceResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestError"
          },
          "401": {
            "$ref": "#/components/responses/AuthError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "409": {
            "$ref": "#/components/responses/ConflictError"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLargeError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitError"
          }
        }
      }
    },
    "/api/v1/invoices/{invoice_public_id}": {
      "get": {
        "tags": [
          "API v1"
        ],
        "summary": "Карточка документа",
        "parameters": [
          {
            "in": "path",
            "name": "invoice_public_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Успешный ответ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvoiceDetailResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitError"
          }
        }
      },
      "put": {
        "tags": [
          "API v1"
        ],
        "summary": "Полностью обновить документ",
        "description": "Partial update не поддерживается. Для PUT требуется полный объект в поле `invoice`.",
        "parameters": [
          {
            "in": "path",
            "name": "invoice_public_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateInvoiceRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Документ обновлен",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreateUpdateInvoiceResponse"
                }
              }
            }
          },
          "207": {
            "description": "Документ обновлен, часть писем не отправлена",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreateUpdateInvoiceResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestError"
          },
          "401": {
            "$ref": "#/components/responses/AuthError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "409": {
            "$ref": "#/components/responses/ConflictError"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLargeError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitError"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKeyHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "x-api-key"
      },
      "ApiKeyQuery": {
        "type": "apiKey",
        "in": "query",
        "name": "api_key"
      },
      "BearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "API key"
      }
    },
    "responses": {
      "AuthError": {
        "description": "Ошибка авторизации API",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/AuthErrorResponse"
            }
          }
        }
      },
      "ForbiddenError": {
        "description": "Ошибка scope/tenant/seller",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "BadRequestError": {
        "description": "Неверный запрос",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "NotFoundError": {
        "description": "Счет не найден",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "ConflictError": {
        "description": "Конфликт данных или ограничение операций",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "PayloadTooLargeError": {
        "description": "Слишком большой JSON payload",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "RateLimitError": {
        "description": "Превышен rate limit",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/RateLimitErrorResponse"
            }
          }
        }
      }
    },
    "schemas": {
      "CatalogResponse": {
        "type": "object",
        "required": [
          "ok",
          "organizations",
          "bank_accounts",
          "managers",
          "signers",
          "enums"
        ],
        "properties": {
          "ok": {
            "type": "boolean",
            "const": true
          },
          "organizations": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "bank_accounts": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "managers": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "signers": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "enums": {
            "type": "object",
            "additionalProperties": true
          }
        }
      },
      "InvoiceListResponse": {
        "type": "object",
        "required": [
          "ok",
          "total",
          "items"
        ],
        "properties": {
          "ok": {
            "type": "boolean",
            "const": true
          },
          "total": {
            "type": "integer"
          },
          "demo_mode": {
            "type": "boolean"
          },
          "demo_guids": {
            "type": "object",
            "additionalProperties": true
          },
          "items": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          }
        }
      },
      "InvoiceDetailResponse": {
        "type": "object",
        "required": [
          "ok",
          "public_id",
          "invoice_url",
          "portal_view_url",
          "portal_edit_url",
          "share_links",
          "status",
          "validation",
          "metadata",
          "invoice"
        ],
        "properties": {
          "ok": {
            "type": "boolean",
            "const": true
          },
          "public_id": {
            "type": "string"
          },
          "document_public_id": {
            "type": "string"
          },
          "document_kind": {
            "type": "string"
          },
          "demo_mode": {
            "type": "boolean"
          },
          "demo_guids": {
            "type": "object",
            "additionalProperties": true
          },
          "document_url": {
            "type": "string"
          },
          "invoice_url": {
            "type": "string"
          },
          "portal_view_url": {
            "type": "string"
          },
          "portal_document_view_url": {
            "type": "string"
          },
          "portal_edit_url": {
            "type": "string"
          },
          "portal_document_edit_url": {
            "type": "string"
          },
          "share_links": {
            "$ref": "#/components/schemas/ShareLinks"
          },
          "status": {
            "$ref": "#/components/schemas/InvoiceStatus"
          },
          "validation": {
            "type": "object",
            "additionalProperties": true
          },
          "metadata": {
            "$ref": "#/components/schemas/InvoiceMetadata"
          },
          "invoice": {
            "type": "object",
            "additionalProperties": true
          }
        }
      },
      "CreateUpdateInvoiceResponse": {
        "allOf": [
          {
            "$ref": "#/components/schemas/InvoiceDetailResponse"
          },
          {
            "type": "object",
            "required": [
              "document",
              "notifications",
              "share_gate",
              "api",
              "totals",
              "qr"
            ],
            "properties": {
              "notifications": {
                "$ref": "#/components/schemas/Notifications"
              },
              "share_gate": {
                "$ref": "#/components/schemas/ShareGateSummary"
              },
              "api": {
                "$ref": "#/components/schemas/ApiWriteMeta"
              },
              "totals": {
                "$ref": "#/components/schemas/InvoiceTotalsSummary"
              },
              "qr": {
                "$ref": "#/components/schemas/InvoiceQrSummary"
              },
              "document": {
                "$ref": "#/components/schemas/DocumentSummary"
              }
            }
          }
        ]
      },
      "CreateInvoiceRequest": {
        "type": "object",
        "description": "Либо корневой invoice-объект, либо envelope с полем `invoice`.\nМедиа через внешний API не принимаются. Поля с URL/base64 изображений должны отсутствовать.\n",
        "properties": {
          "actor_login": {
            "type": "string"
          },
          "notify_recipients": {
            "type": "boolean"
          },
          "send_notifications": {
            "type": "boolean"
          },
          "invoice": {
            "$ref": "#/components/schemas/InvoicePayload"
          }
        },
        "additionalProperties": true
      },
      "UpdateInvoiceRequest": {
        "type": "object",
        "description": "Полное обновление документа.\nМедиа через внешний API не принимаются. Поля с URL/base64 изображений должны отсутствовать.\n",
        "properties": {
          "actor_login": {
            "type": "string"
          },
          "notify_recipients": {
            "type": "boolean"
          },
          "send_notifications": {
            "type": "boolean"
          },
          "partial_update": {
            "type": "boolean",
            "description": "Не поддерживается. Приведет к `400 partial_update_not_supported`."
          },
          "patch": {
            "type": "boolean",
            "description": "Не поддерживается. Приведет к `400 partial_update_not_supported`."
          },
          "invoice": {
            "$ref": "#/components/schemas/InvoicePayload"
          }
        },
        "additionalProperties": true,
        "required": [
          "invoice"
        ]
      },
      "InvoicePayload": {
        "type": "object",
        "description": "Полезная нагрузка документа.\nМедиа-поля через внешний API запрещены. Не передавайте логотипы, печати, факсимиле и QR-изображения в JSON.\n",
        "required": [
          "number",
          "date",
          "currency",
          "seller",
          "buyer",
          "items"
        ],
        "properties": {
          "public_id": {
            "type": "string"
          },
          "number": {
            "type": "string"
          },
          "date": {
            "type": "string",
            "format": "date"
          },
          "currency": {
            "type": "string",
            "enum": [
              "RUB",
              "USD",
              "EUR",
              "CNY",
              "KZT",
              "BYN"
            ]
          },
          "invoice_direction": {
            "type": "string",
            "enum": [
              "incoming",
              "outgoing"
            ]
          },
          "seller": {
            "$ref": "#/components/schemas/Party"
          },
          "buyer": {
            "$ref": "#/components/schemas/Party"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/InvoiceItem"
            }
          }
        },
        "additionalProperties": true,
        "x-prohibited-fields": [
          "seller_logo_url",
          "seller_stamp_url",
          "payment_qr_url",
          "signers[].facsimile_url",
          "manager.contact_qr_url",
          "buyer_contact.contact_qr_url"
        ]
      },
      "Party": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "inn": {
            "type": "string"
          },
          "email": {
            "type": "string"
          }
        },
        "additionalProperties": true
      },
      "InvoiceItem": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "qty": {
            "type": "number"
          },
          "unit": {
            "type": "string"
          },
          "price": {
            "type": "number"
          },
          "vat_pct": {
            "type": "number"
          }
        },
        "additionalProperties": true
      },
      "ShareLinks": {
        "type": "object",
        "properties": {
          "colleague_url": {
            "type": "string"
          },
          "colleague_document_url": {
            "type": "string"
          },
          "buyer_url": {
            "type": "string"
          },
          "buyer_document_url": {
            "type": "string"
          },
          "recipients": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ShareRecipientLink"
            }
          }
        }
      },
      "InvoiceStatus": {
        "type": "object",
        "properties": {
          "seller_status": {
            "type": "string"
          },
          "seller_status_label": {
            "type": "string"
          },
          "buyer_status": {
            "type": "string"
          },
          "buyer_status_label": {
            "type": "string"
          },
          "service_status": {
            "type": "string"
          },
          "service_status_label": {
            "type": "string"
          },
          "service_status_reason": {
            "type": "string"
          }
        }
      },
      "InvoiceMetadata": {
        "type": "object",
        "properties": {
          "public_id": {
            "type": "string"
          },
          "document_public_id": {
            "type": "string"
          },
          "document_kind": {
            "type": "string"
          },
          "kind_version": {
            "type": "string"
          },
          "kind_ordinal": {
            "type": "integer"
          },
          "sort_order": {
            "type": "integer"
          },
          "document_title": {
            "type": "string"
          },
          "title_is_custom": {
            "type": "boolean"
          },
          "package_public_id": {
            "type": "string"
          },
          "legacy_invoice_public_id": {
            "type": "string"
          },
          "source_type": {
            "type": "string"
          },
          "editor_mode": {
            "type": "string"
          },
          "information_system": {
            "type": "string"
          },
          "created_at": {
            "type": "string"
          },
          "created_by_login": {
            "type": "string"
          },
          "last_modified_at": {
            "type": "string"
          },
          "last_modified_by_login": {
            "type": "string"
          },
          "seller_edo_id": {
            "type": "string"
          },
          "buyer_edo_id": {
            "type": "string"
          },
          "public_share_enabled": {
            "type": "boolean"
          },
          "api_key_id": {
            "type": "integer"
          },
          "api_key_name": {
            "type": "string"
          },
          "api_request_host": {
            "type": "string"
          },
          "api_created_at": {
            "type": "string"
          },
          "api_updated_at": {
            "type": "string"
          },
          "status": {
            "$ref": "#/components/schemas/InvoiceStatus"
          },
          "validation": {
            "type": "object",
            "additionalProperties": true
          },
          "notifications": {
            "type": "object",
            "additionalProperties": true
          },
          "api_recipients": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ApiRecipient"
            }
          },
          "links": {
            "$ref": "#/components/schemas/InvoiceLinks"
          }
        }
      },
      "Notifications": {
        "type": "object",
        "properties": {
          "document_public_id": {
            "type": "string"
          },
          "document_kind": {
            "type": "string"
          },
          "planned_count": {
            "type": "integer"
          },
          "sent_count": {
            "type": "integer"
          },
          "failed_count": {
            "type": "integer"
          },
          "sent_to": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "failed": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/NotificationFailure"
            }
          },
          "blocked_by_service_gate": {
            "type": "boolean"
          },
          "block_reason": {
            "type": "string"
          },
          "mail_runtime": {
            "type": "object",
            "additionalProperties": true
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "required": [
          "ok",
          "error"
        ],
        "properties": {
          "ok": {
            "type": "boolean",
            "const": false
          },
          "error": {
            "type": "string"
          },
          "document_public_id": {
            "type": "string"
          },
          "document_kind": {
            "type": "string"
          },
          "details": {
            "type": "string"
          },
          "missing_fields": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "demo_public_id": {
            "type": "string"
          }
        }
      },
      "AuthErrorResponse": {
        "allOf": [
          {
            "$ref": "#/components/schemas/ErrorResponse"
          },
          {
            "type": "object",
            "properties": {
              "error": {
                "type": "string",
                "enum": [
                  "unauthorized"
                ]
              },
              "code": {
                "type": "string",
                "enum": [
                  "api_key_missing",
                  "api_key_invalid",
                  "api_key_inactive",
                  "api_key_over_tariff_limit"
                ]
              }
            }
          }
        ]
      },
      "RateLimitErrorResponse": {
        "allOf": [
          {
            "$ref": "#/components/schemas/ErrorResponse"
          },
          {
            "type": "object",
            "properties": {
              "error": {
                "type": "string",
                "enum": [
                  "rate_limited"
                ]
              },
              "code": {
                "type": "string"
              },
              "retry_after_sec": {
                "type": "integer"
              }
            }
          }
        ]
      },
      "ShareRecipientLink": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "position": {
            "type": "string"
          },
          "contact_id": {
            "type": "integer",
            "nullable": true
          },
          "url": {
            "type": "string"
          },
          "document_url": {
            "type": "string"
          }
        },
        "additionalProperties": true
      },
      "DocumentSummary": {
        "type": "object",
        "properties": {
          "public_id": {
            "type": "string"
          },
          "document_public_id": {
            "type": "string"
          },
          "document_kind": {
            "type": "string"
          },
          "kind_version": {
            "type": "string"
          },
          "kind_ordinal": {
            "type": "integer"
          },
          "sort_order": {
            "type": "integer"
          },
          "document_title": {
            "type": "string"
          },
          "title_is_custom": {
            "type": "boolean"
          },
          "package_public_id": {
            "type": "string"
          },
          "legacy_invoice_public_id": {
            "type": "string"
          }
        }
      },
      "DocumentContext": {
        "type": "object",
        "properties": {
          "document_public_id": {
            "type": "string"
          },
          "document_kind": {
            "type": "string"
          }
        }
      },
      "ShareGateSummary": {
        "allOf": [
          {
            "$ref": "#/components/schemas/DocumentContext"
          },
          {
            "type": "object",
            "additionalProperties": true
          }
        ]
      },
      "ApiWriteMeta": {
        "allOf": [
          {
            "$ref": "#/components/schemas/DocumentContext"
          },
          {
            "type": "object",
            "properties": {
              "key_id": {
                "type": "integer"
              },
              "key_name": {
                "type": "string"
              }
            },
            "additionalProperties": true
          }
        ]
      },
      "InvoiceTotalsSummary": {
        "allOf": [
          {
            "$ref": "#/components/schemas/DocumentContext"
          },
          {
            "type": "object",
            "properties": {
              "subtotal": {
                "type": "number"
              },
              "vat_total": {
                "type": "number"
              },
              "total": {
                "type": "number"
              },
              "currency": {
                "type": "string"
              }
            },
            "additionalProperties": true
          }
        ]
      },
      "InvoiceQrSummary": {
        "allOf": [
          {
            "$ref": "#/components/schemas/DocumentContext"
          },
          {
            "type": "object",
            "properties": {
              "enabled": {
                "type": "boolean"
              },
              "url": {
                "type": "string"
              },
              "payload": {
                "type": "string"
              }
            },
            "additionalProperties": true
          }
        ]
      },
      "NotificationFailure": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string"
          },
          "error": {
            "type": "string"
          }
        },
        "additionalProperties": true
      },
      "ApiRecipient": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "position": {
            "type": "string"
          },
          "contact_id": {
            "type": "integer",
            "nullable": true
          },
          "buyer_invoice_url": {
            "type": "string"
          },
          "buyer_document_url": {
            "type": "string"
          }
        },
        "additionalProperties": true
      },
      "InvoiceLinks": {
        "type": "object",
        "properties": {
          "share_url": {
            "type": "string"
          },
          "document_url": {
            "type": "string"
          },
          "portal_view_url": {
            "type": "string"
          },
          "portal_document_view_url": {
            "type": "string"
          },
          "portal_edit_url": {
            "type": "string"
          },
          "portal_document_edit_url": {
            "type": "string"
          }
        },
        "additionalProperties": true
      }
    }
  }
}
