{
  "openapi": "3.1.0",
  "jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
  "info": {
    "title": "Kevmi — серверный API",
    "version": "2026-10-22.12",
    "description": "Kevmi API: Telegram sign-in, sessions, merchant invoices, encrypted buyer checkout, support, notifications, applications and webhook delivery. One-time direct payments only. JSON responses use no-store. Timestamps are UTC Unix milliseconds unless stated otherwise. Live checkout uses a configured external gateway; card and bank-code fields are encrypted in the browser and decrypted only by the gateway. New charges require the latest merchant website application to be approved. Creating an invoice does not charge a buyer.",
    "x-updated-at": "2026-10-22"
  },
  "servers": [
    {
      "url": "https://kevmi.one",
      "description": "Публичный origin проекта; отдельная платформа хостинга может дополнительно ограничивать доступ."
    }
  ],
  "externalDocs": {
    "description": "Публичная документация продукта",
    "url": "https://kevmi.one/docs"
  },
  "tags": [
    {
      "name": "Service",
      "description": "Публичные сведения о состоянии."
    },
    {
      "name": "Auth",
      "description": "Регистрация и вход используют один подтверждённый сценарий Telegram."
    },
    {
      "name": "Account",
      "description": "Настройки только текущего пользователя."
    },
    {
      "name": "Payment links",
      "description": "Серверные счета текущего магазина. Цена, валюта, плательщик НДС, имя продавца и расчёт сохраняются неизменно."
    },
    {
      "name": "Checkout",
      "description": "Чтение отдельного счёта без аккаунта. Доступность оплаты проверяется отдельно."
    },
    {
      "name": "Support",
      "description": "Публичная база знаний и собственные обращения."
    },
    {
      "name": "Notifications",
      "description": "Собственный центр событий, прочтение на сайте и независимое состояние доставки Telegram."
    },
    {
      "name": "Telegram",
      "description": "Webhook бота; не платёжный webhook."
    },
    {
      "name": "Disabled payments",
      "description": "Unsupported legacy money routes and payout execution. The public checkout flow has its own documented endpoints."
    },
    {
      "name": "Merchant API",
      "description": "Scoped server-to-server invoices and immutable event history."
    },
    {
      "name": "Webhooks",
      "description": "Verified HTTPS endpoints, signed events, delivery attempts and retries."
    },
    {
      "name": "Applications",
      "description": "Authenticated website applications and individual tracking."
    },
    {
      "name": "Moderation",
      "description": "Allowlisted Telegram moderators; every decision is version-checked."
    },
    {
      "name": "Gateway events",
      "description": "Source-native gateway events are verified, then the authoritative payment is read over authenticated server transport. Merchant-facing webhooks use a separate signature and delivery queue."
    }
  ],
  "security": [],
  "x-disabled-route-prefixes": [
    "/api/payments",
    "/api/payouts",
    "/api/gateway",
    "/api/linzapay"
  ],
  "x-disabled-route-behavior": "Legacy unscoped direct-money routes and payout execution remain disabled. Authenticated /api/v1/payments creates invoices; /api/checkout/{token} exposes the separate buyer checkout flow. POST /api/gateway/webhook accepts signed gateway events.",
  "paths": {
    "/api/config": {
      "get": {
        "tags": [
          "Service"
        ],
        "operationId": "getConfig",
        "summary": "Фактическая готовность интеграций",
        "responses": {
          "200": {
            "description": "Конфигурация без секретов.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Config"
                }
              }
            }
          },
          "503": {
            "description": "Интеграция или хранилище не настроены, событие обрабатывается либо сервис недоступен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/health": {
      "get": {
        "tags": [
          "Service"
        ],
        "operationId": "getHealth",
        "summary": "Состояние API и таблиц D1",
        "description": "not_configured допускает status=ok: публичные страницы и поиск могут работать без DB. Наличие DB с недоступными таблицами даёт 503/degraded. Ответ не проверяет работоспособность Telegram или модели по сети.",
        "responses": {
          "200": {
            "description": "Хранилище ready или not_configured.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Health"
                }
              }
            }
          },
          "503": {
            "description": "D1 недоступна либо неожиданная ошибка сервиса.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/Health"
                    },
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/auth/me": {
      "get": {
        "tags": [
          "Auth"
        ],
        "operationId": "getCurrentSession",
        "summary": "Текущая сессия и CSRF",
        "security": [
          {},
          {
            "cookieSession": []
          }
        ],
        "responses": {
          "200": {
            "description": "authenticated=false без действующей сессии.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/Anonymous"
                    },
                    {
                      "$ref": "#/components/schemas/CurrentSession"
                    }
                  ]
                }
              }
            }
          },
          "503": {
            "description": "Интеграция или хранилище не настроены, событие обрабатывается либо сервис недоступен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/auth/telegram/start": {
      "post": {
        "tags": [
          "Auth"
        ],
        "operationId": "startTelegramLogin",
        "summary": "Начать вход или регистрацию",
        "description": "Создаёт challenge на 300 секунд и HttpOnly cookie browser proof; максимум 6 запусков в минуту по хешу адреса. Сравните шестизначный код на сайте и в личном чате бота.",
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "description": "Должен точно совпасть с настроенным APP_ORIGIN. Sec-Fetch-Site: cross-site отклоняется. Сервер не предоставляет CORS-доступ.",
            "schema": {
              "type": "string",
              "format": "uri"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "description": "JSON-объект. Максимум 16 384 байта. Неизвестные поля отклоняются.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EmptyObject"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Запрос входа создан; cookie proof привязывает его к исходному браузеру.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              },
              "Set-Cookie": {
                "schema": {
                  "type": "string"
                },
                "description": "Secure; HttpOnly; SameSite=Lax; Path=/. Значение сессии не доступно JavaScript. При завершении входа также удаляется cookie browser proof."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LoginChallenge"
                }
              }
            }
          },
          "400": {
            "description": "Некорректный JSON, неизвестное поле или недопустимое значение.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "403": {
            "description": "Не пройдена проверка Origin, CSRF или привязки входа к браузеру.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "413": {
            "description": "Превышен размер тела: 16 384 байта; для /api/support/ask и Telegram webhook 65 536 байт.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "REQUEST_TOO_LARGE"
            ]
          },
          "415": {
            "description": "Ожидается Content-Type: application/json.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "JSON_REQUIRED"
            ]
          },
          "429": {
            "description": "Лимит частоты превышен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "string",
                  "const": "60"
                },
                "description": "Сервер всегда возвращает 60; это не гарантирует истечение часовой квоты."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "RATE_LIMITED"
            ]
          },
          "503": {
            "description": "Интеграция или хранилище не настроены, событие обрабатывается либо сервис недоступен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/auth/telegram/complete": {
      "post": {
        "tags": [
          "Auth"
        ],
        "operationId": "completeTelegramLogin",
        "summary": "Завершить подтверждённый вход",
        "description": "Требует proof cookie из start и того же браузера. Pending возвращает 202. После подтверждения ботом запрос выдаёт одну сессию на 24 часа. Максимум 90 проверок в минуту на challenge. Значение Telegram ID из браузера не принимается.",
        "security": [
          {
            "browserProof": []
          }
        ],
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "description": "Должен точно совпасть с настроенным APP_ORIGIN. Sec-Fetch-Site: cross-site отклоняется. Сервер не предоставляет CORS-доступ.",
            "schema": {
              "type": "string",
              "format": "uri"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "description": "JSON-объект. Максимум 16 384 байта. Неизвестные поля отклоняются.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "challengeId": {
                    "type": "string",
                    "pattern": "^[A-Za-z0-9_-]{43}$"
                  }
                },
                "required": [
                  "challengeId"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Аккаунт создан/обновлён, сессия выдана.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              },
              "Set-Cookie": {
                "schema": {
                  "type": "string"
                },
                "description": "Secure; HttpOnly; SameSite=Lax; Path=/. Значение сессии не доступно JavaScript. При завершении входа также удаляется cookie browser proof."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CompletedLogin"
                }
              }
            }
          },
          "202": {
            "description": "Ожидается подтверждение в Telegram.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string",
                      "const": "pending"
                    }
                  },
                  "required": [
                    "status"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "400": {
            "description": "Некорректный JSON, неизвестное поле или недопустимое значение.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "403": {
            "description": "Не пройдена проверка Origin, CSRF или привязки входа к браузеру.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "409": {
            "description": "Запрос входа уже использован/отменён, личность ещё не подтверждена или конфликт обращения.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "CHALLENGE_UNAVAILABLE",
              "IDENTITY_INCOMPLETE",
              "TICKET_CONFLICT",
              "IDEMPOTENCY_CONFLICT",
              "LINK_CANCELLED",
              "LINK_EXPIRED",
              "LINK_UNAVAILABLE"
            ]
          },
          "410": {
            "description": "Пятиминутный запрос входа истёк.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "CHALLENGE_EXPIRED"
            ]
          },
          "413": {
            "description": "Превышен размер тела: 16 384 байта; для /api/support/ask и Telegram webhook 65 536 байт.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "REQUEST_TOO_LARGE"
            ]
          },
          "415": {
            "description": "Ожидается Content-Type: application/json.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "JSON_REQUIRED"
            ]
          },
          "429": {
            "description": "Лимит частоты превышен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "string",
                  "const": "60"
                },
                "description": "Сервер всегда возвращает 60; это не гарантирует истечение часовой квоты."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "RATE_LIMITED"
            ]
          },
          "503": {
            "description": "Интеграция или хранилище не настроены, событие обрабатывается либо сервис недоступен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/auth/logout": {
      "post": {
        "tags": [
          "Auth"
        ],
        "operationId": "logoutCurrentSession",
        "summary": "Завершить текущую сессию",
        "description": "Тело не требуется и не читается. /logout в боте отдельно завершает все сессии аккаунта.",
        "security": [
          {
            "cookieSession": [],
            "csrfToken": []
          }
        ],
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "description": "Должен точно совпасть с настроенным APP_ORIGIN. Sec-Fetch-Site: cross-site отклоняется. Сервер не предоставляет CORS-доступ.",
            "schema": {
              "type": "string",
              "format": "uri"
            }
          },
          {
            "name": "X-CSRF-Token",
            "in": "header",
            "required": true,
            "description": "Токен текущей сессии из GET /api/auth/me или успешного завершения входа.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{43}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Сессия удалена, cookie очищена.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              },
              "Set-Cookie": {
                "schema": {
                  "type": "string"
                },
                "description": "Secure; HttpOnly; SameSite=Lax; Path=/. Значение сессии не доступно JavaScript. При завершении входа также удаляется cookie browser proof."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "loggedOut": {
                      "type": "boolean",
                      "const": true
                    }
                  },
                  "required": [
                    "loggedOut"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "Нет действующей сессии; для webhook — неверный секрет.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "403": {
            "description": "Не пройдена проверка Origin, CSRF или привязки входа к браузеру.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "503": {
            "description": "Интеграция или хранилище не настроены, событие обрабатывается либо сервис недоступен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/account/settings": {
      "get": {
        "tags": [
          "Account"
        ],
        "operationId": "getAccountSettings",
        "summary": "Настройки текущего пользователя",
        "security": [
          {
            "cookieSession": []
          }
        ],
        "responses": {
          "200": {
            "description": "Публичная часть собственного профиля.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserResponse"
                }
              }
            }
          },
          "401": {
            "description": "Нет действующей сессии; для webhook — неверный секрет.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "503": {
            "description": "Интеграция или хранилище не настроены, событие обрабатывается либо сервис недоступен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      },
      "patch": {
        "tags": [
          "Account"
        ],
        "operationId": "updateAccountSettings",
        "summary": "Изменить название, плательщика НДС или уведомления",
        "description": "Все поля необязательны; частичный patch. Сервер сохраняет настройку vatPayer, но не создаёт денежную операцию. Переключатели payments/payouts не подключают платёжный шлюз.",
        "security": [
          {
            "cookieSession": [],
            "csrfToken": []
          }
        ],
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "description": "Должен точно совпасть с настроенным APP_ORIGIN. Sec-Fetch-Site: cross-site отклоняется. Сервер не предоставляет CORS-доступ.",
            "schema": {
              "type": "string",
              "format": "uri"
            }
          },
          {
            "name": "X-CSRF-Token",
            "in": "header",
            "required": true,
            "description": "Токен текущей сессии из GET /api/auth/me или успешного завершения входа.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{43}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "description": "JSON-объект. Максимум 16 384 байта. Неизвестные поля отклоняются.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SettingsPatch"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Обновлённый профиль.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserResponse"
                }
              }
            }
          },
          "400": {
            "description": "Некорректный JSON, неизвестное поле или недопустимое значение.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "401": {
            "description": "Нет действующей сессии; для webhook — неверный секрет.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "403": {
            "description": "Не пройдена проверка Origin, CSRF или привязки входа к браузеру.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "413": {
            "description": "Превышен размер тела: 16 384 байта; для /api/support/ask и Telegram webhook 65 536 байт.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "REQUEST_TOO_LARGE"
            ]
          },
          "415": {
            "description": "Ожидается Content-Type: application/json.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "JSON_REQUIRED"
            ]
          },
          "503": {
            "description": "Интеграция или хранилище не настроены, событие обрабатывается либо сервис недоступен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/support/ask": {
      "post": {
        "tags": [
          "Support"
        ],
        "operationId": "askDocumentation",
        "summary": "Ответ по всей публичной базе знаний",
        "description": "Публичный вопрос без сессии и CSRF. Переданный Origin должен совпасть с APP_ORIGIN; агенты могут не отправлять Origin. В AI-режиме сервер передаёт все опубликованные статьи, факты, каталог страниц и готовность функций. Необязательные history и pageContext используются только как недоверенный контекст вопроса. Доступа к аккаунтам, деньгам, приватным обращениям и инструментам у модели нет. При D1 действует лимит 12 вопросов/минуту по хешу адреса. Режим ai требует D1, корректной конфигурации провайдера и квоты: по умолчанию 60 генераций/час на весь сервис. Готовность конфигурации не подтверждает доступность внешнего API. Ошибка провайдера, превышение квоты или некорректный ответ возвращают search с aiUnavailable=true и HTTP 200. Без генеративной конфигурации возвращается обычный search.",
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": false,
            "description": "Должен точно совпасть с настроенным APP_ORIGIN. Sec-Fetch-Site: cross-site отклоняется. Сервер не предоставляет CORS-доступ.",
            "schema": {
              "type": "string",
              "format": "uri"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "description": "JSON-объект до 65 536 байт. Неизвестные поля отклоняются. Длины текстов проверяются после trim.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SupportQuestion"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Ответ либо найденный материал с проверенными ссылками на опубликованные статьи.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SupportAnswer"
                }
              }
            }
          },
          "400": {
            "description": "Некорректный JSON, неизвестное поле или недопустимое значение.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "403": {
            "description": "Не пройдена проверка Origin, CSRF или привязки входа к браузеру.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "413": {
            "description": "Превышен размер тела: 16 384 байта; для /api/support/ask и Telegram webhook 65 536 байт.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "REQUEST_TOO_LARGE"
            ]
          },
          "415": {
            "description": "Ожидается Content-Type: application/json.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "JSON_REQUIRED"
            ]
          },
          "429": {
            "description": "Лимит частоты превышен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "string",
                  "const": "60"
                },
                "description": "Сервер всегда возвращает 60; это не гарантирует истечение часовой квоты."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "RATE_LIMITED"
            ]
          },
          "503": {
            "description": "Интеграция или хранилище не настроены, событие обрабатывается либо сервис недоступен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/support/tickets": {
      "get": {
        "tags": [
          "Support"
        ],
        "operationId": "listOwnTickets",
        "summary": "Последние 30 собственных обращений",
        "security": [
          {
            "cookieSession": []
          }
        ],
        "responses": {
          "200": {
            "description": "По убыванию createdAt; возвращаются последние 30 записей.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "tickets": {
                      "type": "array",
                      "maxItems": 30,
                      "items": {
                        "$ref": "#/components/schemas/Ticket"
                      }
                    }
                  },
                  "required": [
                    "tickets"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "Нет действующей сессии; для webhook — неверный секрет.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "503": {
            "description": "Интеграция или хранилище не настроены, событие обрабатывается либо сервис недоступен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      },
      "post": {
        "tags": [
          "Support"
        ],
        "operationId": "createOwnTicket",
        "summary": "Сохранить обращение",
        "description": "До 6 обращений в час на пользователя, общая квота сайта и бота. Сохранение создаёт обращение в аккаунте. Используйте его номер для уточнения статуса.",
        "security": [
          {
            "cookieSession": [],
            "csrfToken": []
          }
        ],
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "description": "Должен точно совпасть с настроенным APP_ORIGIN. Sec-Fetch-Site: cross-site отклоняется. Сервер не предоставляет CORS-доступ.",
            "schema": {
              "type": "string",
              "format": "uri"
            }
          },
          {
            "name": "X-CSRF-Token",
            "in": "header",
            "required": true,
            "description": "Токен текущей сессии из GET /api/auth/me или успешного завершения входа.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{43}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "description": "JSON-объект. Максимум 16 384 байта. Неизвестные поля отклоняются.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "subject": {
                    "type": "string",
                    "minLength": 1,
                    "x-trimmedMaxLength": 120,
                    "x-trimmedMinLength": 1,
                    "description": "Пробелы по краям удаляются. Длина после удаления: 1–120 символов. Управляющие символы, кроме табуляции и перевода строки, запрещены."
                  },
                  "message": {
                    "type": "string",
                    "minLength": 5,
                    "x-trimmedMaxLength": 4000,
                    "x-trimmedMinLength": 5,
                    "description": "Пробелы по краям удаляются. Длина после удаления: 5–4000 символов. Управляющие символы, кроме табуляции и перевода строки, запрещены."
                  }
                },
                "required": [
                  "subject",
                  "message"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Обращение сохранено.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TicketResponse"
                }
              }
            }
          },
          "400": {
            "description": "Некорректный JSON, неизвестное поле или недопустимое значение.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "401": {
            "description": "Нет действующей сессии; для webhook — неверный секрет.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "403": {
            "description": "Не пройдена проверка Origin, CSRF или привязки входа к браузеру.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "409": {
            "description": "Запрос входа уже использован/отменён, личность ещё не подтверждена или конфликт обращения.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "CHALLENGE_UNAVAILABLE",
              "IDENTITY_INCOMPLETE",
              "TICKET_CONFLICT",
              "IDEMPOTENCY_CONFLICT",
              "LINK_CANCELLED",
              "LINK_EXPIRED",
              "LINK_UNAVAILABLE"
            ]
          },
          "413": {
            "description": "Превышен размер тела: 16 384 байта; для /api/support/ask и Telegram webhook 65 536 байт.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "REQUEST_TOO_LARGE"
            ]
          },
          "415": {
            "description": "Ожидается Content-Type: application/json.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "JSON_REQUIRED"
            ]
          },
          "429": {
            "description": "Лимит частоты превышен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "string",
                  "const": "60"
                },
                "description": "Сервер всегда возвращает 60; это не гарантирует истечение часовой квоты."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "RATE_LIMITED"
            ]
          },
          "503": {
            "description": "Интеграция или хранилище не настроены, событие обрабатывается либо сервис недоступен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/support/tickets/{id}": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^tkt_[a-f0-9-]{36}$"
          },
          "description": "Идентификатор собственного обращения."
        }
      ],
      "get": {
        "tags": [
          "Support"
        ],
        "operationId": "getOwnTicket",
        "summary": "Прочитать своё обращение",
        "security": [
          {
            "cookieSession": []
          }
        ],
        "responses": {
          "200": {
            "description": "Чужое и отсутствующее обращение одинаково дают 404.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TicketResponse"
                }
              }
            }
          },
          "401": {
            "description": "Нет действующей сессии; для webhook — неверный секрет.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "404": {
            "description": "Запись отсутствует, публичный token неверен или собственная запись принадлежит другому пользователю.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TICKET_NOT_FOUND",
              "LINK_NOT_FOUND"
            ]
          },
          "503": {
            "description": "Интеграция или хранилище не настроены, событие обрабатывается либо сервис недоступен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      },
      "patch": {
        "tags": [
          "Support"
        ],
        "operationId": "closeOwnTicket",
        "summary": "Закрыть своё обращение",
        "description": "Метод принимает только status=closed. Он не поддерживает повторное открытие, редактирование сообщений или отправку ответов.",
        "security": [
          {
            "cookieSession": [],
            "csrfToken": []
          }
        ],
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "description": "Должен точно совпасть с настроенным APP_ORIGIN. Sec-Fetch-Site: cross-site отклоняется. Сервер не предоставляет CORS-доступ.",
            "schema": {
              "type": "string",
              "format": "uri"
            }
          },
          {
            "name": "X-CSRF-Token",
            "in": "header",
            "required": true,
            "description": "Токен текущей сессии из GET /api/auth/me или успешного завершения входа.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{43}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "description": "JSON-объект. Максимум 16 384 байта. Неизвестные поля отклоняются.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "status": {
                    "type": "string",
                    "const": "closed"
                  }
                },
                "required": [
                  "status"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Обращение закрыто.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "closed": {
                      "type": "boolean",
                      "const": true
                    }
                  },
                  "required": [
                    "closed"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "400": {
            "description": "Некорректный JSON, неизвестное поле или недопустимое значение.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "401": {
            "description": "Нет действующей сессии; для webhook — неверный секрет.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "403": {
            "description": "Не пройдена проверка Origin, CSRF или привязки входа к браузеру.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "404": {
            "description": "Запись отсутствует, публичный token неверен или собственная запись принадлежит другому пользователю.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TICKET_NOT_FOUND",
              "LINK_NOT_FOUND"
            ]
          },
          "413": {
            "description": "Превышен размер тела: 16 384 байта; для /api/support/ask и Telegram webhook 65 536 байт.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "REQUEST_TOO_LARGE"
            ]
          },
          "415": {
            "description": "Ожидается Content-Type: application/json.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "JSON_REQUIRED"
            ]
          },
          "503": {
            "description": "Интеграция или хранилище не настроены, событие обрабатывается либо сервис недоступен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/notifications": {
      "get": {
        "tags": [
          "Notifications"
        ],
        "operationId": "listOwnNotifications",
        "summary": "Страница собственных уведомлений",
        "description": "До 30 записей: createdAt DESC, затем id DESC. Чтение списка не меняет readAt и не запускает доставку. unreadCount — общее число непрочитанных событий текущего пользователя, независимо от страницы. Поля владельца, Telegram ID и секреты не возвращаются.",
        "security": [
          {
            "cookieSession": []
          }
        ],
        "parameters": [
          {
            "name": "unread",
            "in": "query",
            "description": "1 — только непрочитанные; 0 или отсутствие — все события.",
            "schema": {
              "type": "string",
              "enum": [
                "0",
                "1"
              ],
              "default": "0"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "nextCursor предыдущего ответа. Передавайте без изменений через URLSearchParams; формат createdAt:id, createdAt — безопасное целое в миллисекундах.",
            "schema": {
              "type": "string",
              "pattern": "^\\d{1,16}:ntf_[A-Za-z0-9-]{1,80}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "События с независимыми состояниями прочтения и доставки.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotificationsPage"
                }
              }
            }
          },
          "400": {
            "description": "Некорректный JSON, неизвестное поле или недопустимое значение.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "401": {
            "description": "Нет действующей сессии; для webhook — неверный секрет.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "503": {
            "description": "Интеграция или хранилище не настроены, событие обрабатывается либо сервис недоступен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/notifications/read": {
      "patch": {
        "tags": [
          "Notifications"
        ],
        "operationId": "markOwnNotificationsRead",
        "summary": "Отметить собственные уведомления прочитанными",
        "description": "Принимается одна из двух форм: ids либо all:true вместе с before. before — дата последнего уже наблюдавшегося события; значение не должно быть позже текущего времени сервера. Более новые события сохраняются непрочитанными. Повторный запрос идемпотентен: readAt уже прочитанных записей не меняется. Чужие и отсутствующие ids не изменяются и не раскрываются. status и sentAt доставки Telegram остаются прежними.",
        "security": [
          {
            "cookieSession": [],
            "csrfToken": []
          }
        ],
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "description": "Должен точно совпасть с настроенным APP_ORIGIN. Sec-Fetch-Site: cross-site отклоняется. Сервер не предоставляет CORS-доступ.",
            "schema": {
              "type": "string",
              "format": "uri"
            }
          },
          {
            "name": "X-CSRF-Token",
            "in": "header",
            "required": true,
            "description": "Токен текущей сессии из GET /api/auth/me или успешного завершения входа.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{43}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "description": "JSON-объект. Максимум 16 384 байта. Неизвестные поля отклоняются.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReadNotifications"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Количество новых отметок, время операции и актуальный счётчик.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReadNotificationsResult"
                }
              }
            }
          },
          "400": {
            "description": "Некорректный JSON, неизвестное поле или недопустимое значение.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "401": {
            "description": "Нет действующей сессии; для webhook — неверный секрет.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "403": {
            "description": "Не пройдена проверка Origin, CSRF или привязки входа к браузеру.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "413": {
            "description": "Превышен размер тела: 16 384 байта; для /api/support/ask и Telegram webhook 65 536 байт.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "REQUEST_TOO_LARGE"
            ]
          },
          "415": {
            "description": "Ожидается Content-Type: application/json.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "JSON_REQUIRED"
            ]
          },
          "503": {
            "description": "Интеграция или хранилище не настроены, событие обрабатывается либо сервис недоступен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/notifications/test": {
      "post": {
        "tags": [
          "Notifications"
        ],
        "operationId": "testOwnNotification",
        "summary": "Отправить тестовое уведомление в свой Telegram",
        "description": "Это действие ставит сообщение в очередь и пытается отправить его. Максимум 3/час на пользователя. Тест не является уведомлением об оплате и не меняет баланс. HTTP 202 не подтверждает доставку; проверяйте список уведомлений.",
        "security": [
          {
            "cookieSession": [],
            "csrfToken": []
          }
        ],
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "description": "Должен точно совпасть с настроенным APP_ORIGIN. Sec-Fetch-Site: cross-site отклоняется. Сервер не предоставляет CORS-доступ.",
            "schema": {
              "type": "string",
              "format": "uri"
            }
          },
          {
            "name": "X-CSRF-Token",
            "in": "header",
            "required": true,
            "description": "Токен текущей сессии из GET /api/auth/me или успешного завершения входа.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{43}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "description": "JSON-объект. Максимум 16 384 байта. Неизвестные поля отклоняются.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EmptyObject"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Результат постановки в очередь.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "queued": {
                      "type": "boolean"
                    },
                    "id": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  },
                  "required": [
                    "queued"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "400": {
            "description": "Некорректный JSON, неизвестное поле или недопустимое значение.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "401": {
            "description": "Нет действующей сессии; для webhook — неверный секрет.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "403": {
            "description": "Не пройдена проверка Origin, CSRF или привязки входа к браузеру.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "413": {
            "description": "Превышен размер тела: 16 384 байта; для /api/support/ask и Telegram webhook 65 536 байт.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "REQUEST_TOO_LARGE"
            ]
          },
          "415": {
            "description": "Ожидается Content-Type: application/json.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "JSON_REQUIRED"
            ]
          },
          "429": {
            "description": "Лимит частоты превышен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "string",
                  "const": "60"
                },
                "description": "Сервер всегда возвращает 60; это не гарантирует истечение часовой квоты."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "RATE_LIMITED"
            ]
          },
          "503": {
            "description": "Интеграция или хранилище не настроены, событие обрабатывается либо сервис недоступен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/telegram/webhook": {
      "post": {
        "tags": [
          "Telegram"
        ],
        "operationId": "receiveTelegramUpdate",
        "summary": "Принять событие Telegram Bot API",
        "description": "Только секретный заголовок Telegram, без session/CSRF/Origin. Дополнительные поля Update разрешены. Обрабатываются message и callback_query, персональные действия только в private-чате подтверждённого отправителя. Прочие события пропускаются. update_id дедуплицируется; выполняющийся update даёт 503 для повтора. Это не webhook платёжного провайдера.",
        "security": [
          {
            "telegramWebhookSecret": []
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Telegram Update, максимум 65 536 байт.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TelegramUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Обработано, пропущено либо уже обработано ранее.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    }
                  },
                  "required": [
                    "ok"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "400": {
            "description": "Некорректный JSON, неизвестное поле или недопустимое значение.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "401": {
            "description": "Нет действующей сессии; для webhook — неверный секрет.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "413": {
            "description": "Превышен размер тела: 16 384 байта; для /api/support/ask и Telegram webhook 65 536 байт.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "REQUEST_TOO_LARGE"
            ]
          },
          "415": {
            "description": "Ожидается Content-Type: application/json.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "JSON_REQUIRED"
            ]
          },
          "429": {
            "description": "Лимит частоты превышен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "string",
                  "const": "60"
                },
                "description": "Сервер всегда возвращает 60; это не гарантирует истечение часовой квоты."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "RATE_LIMITED"
            ]
          },
          "502": {
            "description": "Ошибка обращения к Telegram.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TELEGRAM_UNAVAILABLE",
              "TELEGRAM_INVALID_RESPONSE",
              "TELEGRAM_RATE_LIMITED",
              "TELEGRAM_DELIVERY_FAILED"
            ]
          },
          "503": {
            "description": "Интеграция или хранилище не настроены, событие обрабатывается либо сервис недоступен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/payments": {
      "post": {
        "tags": [
          "Disabled payments"
        ],
        "operationId": "paymentsUnavailable",
        "summary": "Денежная операция отключена",
        "description": "Возвращает 503 GATEWAY_NOT_CONNECTED. Денежные операции недоступны. Тело не обрабатывается, запрос к шлюзу не выполняется.",
        "security": [],
        "responses": {
          "503": {
            "description": "Денежные операции недоступны.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "const": "GATEWAY_NOT_CONNECTED"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ],
                      "additionalProperties": false
                    }
                  },
                  "required": [
                    "error"
                  ],
                  "additionalProperties": false
                }
              }
            }
          }
        }
      }
    },
    "/api/payouts": {
      "post": {
        "tags": [
          "Disabled payments"
        ],
        "operationId": "payoutsUnavailable",
        "summary": "Денежная операция отключена",
        "description": "Возвращает 503 GATEWAY_NOT_CONNECTED. Денежные операции недоступны. Тело не обрабатывается, запрос к шлюзу не выполняется.",
        "security": [],
        "responses": {
          "503": {
            "description": "Денежные операции недоступны.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "const": "GATEWAY_NOT_CONNECTED"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ],
                      "additionalProperties": false
                    }
                  },
                  "required": [
                    "error"
                  ],
                  "additionalProperties": false
                }
              }
            }
          }
        }
      }
    },
    "/openapi.json": {
      "get": {
        "tags": [
          "Service"
        ],
        "operationId": "getOpenApi",
        "summary": "Публичный машиночитаемый контракт",
        "description": "Только чтение. Не содержит секретов, сессий, данных пользователей или рабочего контракта платёжного провайдера.",
        "responses": {
          "200": {
            "description": "Этот документ OpenAPI 3.1.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "public, max-age=300"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "openapi",
                    "info",
                    "paths"
                  ],
                  "additionalProperties": true
                }
              }
            }
          }
        }
      }
    },
    "/api/payment-links": {
      "get": {
        "tags": [
          "Payment links"
        ],
        "operationId": "listOwnPaymentLinks",
        "summary": "Список собственных ссылок",
        "security": [
          {
            "cookieSession": []
          }
        ],
        "description": "Сортировка createdAt DESC, id DESC. Публичные ссылки читаются между устройствами; доступ к списку требует аккаунт.",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 30
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "nextCursor из предыдущего ответа. Сервис использует base64 JSON [createdAt,id]; клиенту следует передавать значение без изменений через URLSearchParams."
          }
        ],
        "responses": {
          "200": {
            "description": "Страница собственных ссылок.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaymentLinksPage"
                }
              }
            }
          },
          "400": {
            "description": "Некорректный JSON, неизвестное поле или недопустимое значение.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "401": {
            "description": "Нет действующей сессии; для webhook — неверный секрет.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "503": {
            "description": "Интеграция или хранилище не настроены, событие обрабатывается либо сервис недоступен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      },
      "post": {
        "tags": [
          "Payment links"
        ],
        "operationId": "createOwnPaymentLink",
        "summary": "Создать счёт с неизменными условиями",
        "security": [
          {
            "cookieSession": [],
            "csrfToken": []
          }
        ],
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "description": "Должен точно совпасть с настроенным APP_ORIGIN. Sec-Fetch-Site: cross-site отклоняется. Сервер не предоставляет CORS-доступ.",
            "schema": {
              "type": "string",
              "format": "uri"
            }
          },
          {
            "name": "X-CSRF-Token",
            "in": "header",
            "required": true,
            "description": "Токен текущей сессии из GET /api/auth/me или успешного завершения входа.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{43}$"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{16,100}$"
            },
            "description": "Один ключ на логический запрос. Повтор с теми же каноническими полями возвращает исходную запись; другое тело с тем же ключом даёт 409."
          }
        ],
        "description": "Create an immutable invoice and immediately receive checkoutUrl; this does not charge the buyer. USD: card/Alipay; RUB: SBP; USDT: crypto. USD crypto remains accepted for compatibility but cannot be paid without a USDT invoice. Fee and VAT customer shares are independent integers from 0 to 100; current live card/Alipay supports VAT customer=100 and fee customer=0. The customer total is never silently changed. Latest website application must be approved before a new live charge. Invoice creation and its merchant event commit atomically.",
        "requestBody": {
          "required": true,
          "description": "JSON-объект. Максимум 16 384 байта. Неизвестные поля отклоняются.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePaymentLink"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Идемпотентный повтор; replayed=true.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreatePaymentLinkResponse"
                }
              }
            }
          },
          "201": {
            "description": "Счёт создан; replayed=false.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreatePaymentLinkResponse"
                }
              }
            }
          },
          "400": {
            "description": "Некорректный JSON, неизвестное поле или недопустимое значение.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "401": {
            "description": "Нет действующей сессии; для webhook — неверный секрет.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "403": {
            "description": "Не пройдена проверка Origin, CSRF или привязки входа к браузеру.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "409": {
            "description": "Запрос входа уже использован/отменён, личность ещё не подтверждена или конфликт обращения.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "CHALLENGE_UNAVAILABLE",
              "IDENTITY_INCOMPLETE",
              "TICKET_CONFLICT",
              "IDEMPOTENCY_CONFLICT",
              "LINK_CANCELLED",
              "LINK_EXPIRED",
              "LINK_UNAVAILABLE"
            ]
          },
          "413": {
            "description": "Превышен размер тела: 16 384 байта; для /api/support/ask и Telegram webhook 65 536 байт.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "REQUEST_TOO_LARGE"
            ]
          },
          "415": {
            "description": "Ожидается Content-Type: application/json.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "JSON_REQUIRED"
            ]
          },
          "429": {
            "description": "Лимит частоты превышен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "string",
                  "const": "60"
                },
                "description": "Сервер всегда возвращает 60; это не гарантирует истечение часовой квоты."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "RATE_LIMITED"
            ]
          },
          "503": {
            "description": "Интеграция или хранилище не настроены, событие обрабатывается либо сервис недоступен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/payment-links/{id}": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^lnk_[0-9a-f-]{36}$"
          },
          "description": "Идентификатор собственной ссылки; не публичный token."
        }
      ],
      "get": {
        "tags": [
          "Payment links"
        ],
        "operationId": "getOwnPaymentLink",
        "summary": "Собственная ссылка и сохранённый расчёт",
        "security": [
          {
            "cookieSession": []
          }
        ],
        "responses": {
          "200": {
            "description": "Чужой и отсутствующий ID одинаково возвращают 404.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaymentLinkResponse"
                }
              }
            }
          },
          "401": {
            "description": "Нет действующей сессии; для webhook — неверный секрет.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "404": {
            "description": "Запись отсутствует, публичный token неверен или собственная запись принадлежит другому пользователю.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TICKET_NOT_FOUND",
              "LINK_NOT_FOUND"
            ]
          },
          "503": {
            "description": "Интеграция или хранилище не настроены, событие обрабатывается либо сервис недоступен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      },
      "patch": {
        "tags": [
          "Payment links"
        ],
        "operationId": "changePaymentLinkStatus",
        "summary": "Приостановить, возобновить или отменить ссылку",
        "security": [
          {
            "cookieSession": [],
            "csrfToken": []
          }
        ],
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "description": "Должен точно совпасть с настроенным APP_ORIGIN. Sec-Fetch-Site: cross-site отклоняется. Сервер не предоставляет CORS-доступ.",
            "schema": {
              "type": "string",
              "format": "uri"
            }
          },
          {
            "name": "X-CSRF-Token",
            "in": "header",
            "required": true,
            "description": "Токен текущей сессии из GET /api/auth/me или успешного завершения входа.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{43}$"
            }
          }
        ],
        "description": "Changes only status. The update and immutable invoice.updated event commit atomically. Concurrent changes use a version check; refresh and retry on LINK_CHANGED. cancelled is terminal, expiration is never extended, and price, methods, cost shares and description stay frozen. Repeating the saved status returns the current invoice.",
        "requestBody": {
          "required": true,
          "description": "JSON-объект. Максимум 16 384 байта. Неизвестные поля отклоняются.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "status": {
                    "type": "string",
                    "enum": [
                      "active",
                      "paused",
                      "cancelled"
                    ]
                  }
                },
                "required": [
                  "status"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Актуальное состояние собственной ссылки.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaymentLinkResponse"
                }
              }
            }
          },
          "400": {
            "description": "Некорректный JSON, неизвестное поле или недопустимое значение.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "401": {
            "description": "Нет действующей сессии; для webhook — неверный секрет.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "403": {
            "description": "Не пройдена проверка Origin, CSRF или привязки входа к браузеру.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "404": {
            "description": "Запись отсутствует, публичный token неверен или собственная запись принадлежит другому пользователю.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TICKET_NOT_FOUND",
              "LINK_NOT_FOUND"
            ]
          },
          "409": {
            "description": "Запрос входа уже использован/отменён, личность ещё не подтверждена или конфликт обращения.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "CHALLENGE_UNAVAILABLE",
              "IDENTITY_INCOMPLETE",
              "TICKET_CONFLICT",
              "IDEMPOTENCY_CONFLICT",
              "LINK_CANCELLED",
              "LINK_EXPIRED",
              "LINK_UNAVAILABLE"
            ]
          },
          "413": {
            "description": "Превышен размер тела: 16 384 байта; для /api/support/ask и Telegram webhook 65 536 байт.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "REQUEST_TOO_LARGE"
            ]
          },
          "415": {
            "description": "Ожидается Content-Type: application/json.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "JSON_REQUIRED"
            ]
          },
          "503": {
            "description": "Интеграция или хранилище не настроены, событие обрабатывается либо сервис недоступен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/checkout/{token}": {
      "parameters": [
        {
          "name": "token",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{43}$"
          },
          "description": "Случайный публичный идентификатор из URL страницы оплаты. Даёт чтение только этого счёта."
        }
      ],
      "get": {
        "tags": [
          "Checkout"
        ],
        "operationId": "getPublicCheckout",
        "summary": "Публичные детали счёта для покупателя",
        "description": "Read the immutable public invoice quote and its persisted payment snapshot. method must belong to the invoice. No account is required. Does not expose owner identity, private metadata or merchant proceeds. The token grants access only to this checkout. availability reflects configuration, allocation, technical limits and merchant approval; payment confirmation is separate.",
        "parameters": [
          {
            "name": "method",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "card",
                "alipay",
                "sbp",
                "crypto"
              ]
            },
            "description": "Должен входить в сохранённый methods счёта."
          }
        ],
        "responses": {
          "200": {
            "description": "Public invoice and the existing payment, if dispatched.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "invoice": {
                      "$ref": "#/components/schemas/CheckoutInvoice"
                    },
                    "payment": {
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/CheckoutPayment"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    }
                  },
                  "required": [
                    "invoice",
                    "payment"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "400": {
            "description": "Некорректный JSON, неизвестное поле или недопустимое значение.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "404": {
            "description": "Запись отсутствует, публичный token неверен или собственная запись принадлежит другому пользователю.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TICKET_NOT_FOUND",
              "LINK_NOT_FOUND"
            ]
          },
          "429": {
            "description": "Лимит частоты превышен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "string",
                  "const": "60"
                },
                "description": "Сервер всегда возвращает 60; это не гарантирует истечение часовой квоты."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "RATE_LIMITED"
            ]
          },
          "503": {
            "description": "Интеграция или хранилище не настроены, событие обрабатывается либо сервис недоступен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/checkout/{token}/pay": {
      "parameters": [
        {
          "name": "token",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{43}$"
          },
          "description": "Случайный публичный идентификатор из URL страницы оплаты. Даёт чтение только этого счёта."
        }
      ],
      "post": {
        "tags": [
          "Checkout"
        ],
        "operationId": "startCheckoutPayment",
        "summary": "Start or recover the invoice payment",
        "description": "Same-origin buyer operation; no account or CSRF token required. The server reserves one operation and a stable idempotency key before gateway dispatch. A repeat recovers the same operation; a lost response must be resolved through status. The payment method locks after dispatch. Card data must be browser-encrypted with a fresh payment intent. SBP/crypto send the saved customer total; card/Alipay use the supported immutable tax configuration. New charges require an approved merchant application. Existing dispatched payments can be recovered after invoice expiration, pause or approval changes. No /v2 or hosted-card route is used.",
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "description": "Должен точно совпасть с настроенным APP_ORIGIN. Sec-Fetch-Site: cross-site отклоняется. Сервер не предоставляет CORS-доступ.",
            "schema": {
              "type": "string",
              "format": "uri"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "description": "JSON-объект. Максимум 16 384 байта. Неизвестные поля отклоняются.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/StartCheckoutPayment"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Existing operation recovered; no second payment.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "payment": {
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/CheckoutPayment"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "replayed": {
                      "type": "boolean"
                    }
                  },
                  "required": [
                    "payment"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "202": {
            "description": "Operation dispatched; completion is asynchronous.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "payment": {
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/CheckoutPayment"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "replayed": {
                      "type": "boolean"
                    }
                  },
                  "required": [
                    "payment"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "400": {
            "description": "Некорректный JSON, неизвестное поле или недопустимое значение.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "403": {
            "description": "Не пройдена проверка Origin, CSRF или привязки входа к браузеру.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "404": {
            "description": "Запись отсутствует, публичный token неверен или собственная запись принадлежит другому пользователю.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TICKET_NOT_FOUND",
              "LINK_NOT_FOUND"
            ]
          },
          "409": {
            "description": "Запрос входа уже использован/отменён, личность ещё не подтверждена или конфликт обращения.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "CHALLENGE_UNAVAILABLE",
              "IDENTITY_INCOMPLETE",
              "TICKET_CONFLICT",
              "IDEMPOTENCY_CONFLICT",
              "LINK_CANCELLED",
              "LINK_EXPIRED",
              "LINK_UNAVAILABLE"
            ]
          },
          "410": {
            "description": "The gateway encryption intent or bank challenge expired. Obtain a fresh intent for the same operation; do not create a replacement payment.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "CARD_SESSION_INVALID"
            ]
          },
          "413": {
            "description": "Превышен размер тела: 16 384 байта; для /api/support/ask и Telegram webhook 65 536 байт.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "REQUEST_TOO_LARGE"
            ]
          },
          "415": {
            "description": "Ожидается Content-Type: application/json.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "JSON_REQUIRED"
            ]
          },
          "429": {
            "description": "Лимит частоты превышен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "string",
                  "const": "60"
                },
                "description": "Сервер всегда возвращает 60; это не гарантирует истечение часовой квоты."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "RATE_LIMITED"
            ]
          },
          "502": {
            "description": "Gateway response unavailable, malformed, or not verifiable. Read the existing payment status before attempting any retry.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "GATEWAY_REQUEST_UNCERTAIN",
              "GATEWAY_INVALID_RESPONSE"
            ]
          },
          "503": {
            "description": "Интеграция или хранилище не настроены, событие обрабатывается либо сервис недоступен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/v1/payments": {
      "get": {
        "tags": [
          "Merchant API"
        ],
        "operationId": "listOwnPaymentLinksViaPayments",
        "summary": "Список собственных ссылок",
        "security": [
          {
            "merchantKey": []
          }
        ],
        "description": "Сортировка createdAt DESC, id DESC. Публичные ссылки читаются между устройствами; доступ к списку требует аккаунт.",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 30
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "nextCursor из предыдущего ответа. Сервис использует base64 JSON [createdAt,id]; клиенту следует передавать значение без изменений через URLSearchParams."
          }
        ],
        "responses": {
          "200": {
            "description": "Страница собственных ссылок.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaymentLinksPage"
                }
              }
            }
          },
          "400": {
            "description": "Некорректный JSON, неизвестное поле или недопустимое значение.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "401": {
            "description": "Нет действующей сессии; для webhook — неверный секрет.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "503": {
            "description": "Интеграция или хранилище не настроены, событие обрабатывается либо сервис недоступен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        },
        "x-required-scope": "invoices:read"
      },
      "post": {
        "tags": [
          "Merchant API"
        ],
        "operationId": "createOwnPaymentLinkViaPayments",
        "summary": "Создать счёт с неизменными условиями",
        "security": [
          {
            "merchantKey": []
          }
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{16,100}$"
            },
            "description": "Один ключ на логический запрос. Повтор с теми же каноническими полями возвращает исходную запись; другое тело с тем же ключом даёт 409."
          }
        ],
        "description": "Create an immutable invoice and immediately receive checkoutUrl; this does not charge the buyer. USD: card/Alipay; RUB: SBP; USDT: crypto. USD crypto remains accepted for compatibility but cannot be paid without a USDT invoice. Fee and VAT customer shares are independent integers from 0 to 100; current live card/Alipay supports VAT customer=100 and fee customer=0. The customer total is never silently changed. Latest website application must be approved before a new live charge. Invoice creation and its merchant event commit atomically.",
        "requestBody": {
          "required": true,
          "description": "JSON-объект. Максимум 16 384 байта. Неизвестные поля отклоняются.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePaymentLink"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Идемпотентный повтор; replayed=true.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreatePaymentLinkResponse"
                }
              }
            }
          },
          "201": {
            "description": "Счёт создан; replayed=false.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreatePaymentLinkResponse"
                }
              }
            }
          },
          "400": {
            "description": "Некорректный JSON, неизвестное поле или недопустимое значение.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "401": {
            "description": "Нет действующей сессии; для webhook — неверный секрет.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "403": {
            "description": "Не пройдена проверка Origin, CSRF или привязки входа к браузеру.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "409": {
            "description": "Запрос входа уже использован/отменён, личность ещё не подтверждена или конфликт обращения.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "CHALLENGE_UNAVAILABLE",
              "IDENTITY_INCOMPLETE",
              "TICKET_CONFLICT",
              "IDEMPOTENCY_CONFLICT",
              "LINK_CANCELLED",
              "LINK_EXPIRED",
              "LINK_UNAVAILABLE"
            ]
          },
          "413": {
            "description": "Превышен размер тела: 16 384 байта; для /api/support/ask и Telegram webhook 65 536 байт.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "REQUEST_TOO_LARGE"
            ]
          },
          "415": {
            "description": "Ожидается Content-Type: application/json.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "JSON_REQUIRED"
            ]
          },
          "429": {
            "description": "Лимит частоты превышен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "string",
                  "const": "60"
                },
                "description": "Сервер всегда возвращает 60; это не гарантирует истечение часовой квоты."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "RATE_LIMITED"
            ]
          },
          "503": {
            "description": "Интеграция или хранилище не настроены, событие обрабатывается либо сервис недоступен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        },
        "x-required-scope": "invoices:write"
      }
    },
    "/api/v1/payments/{id}": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^lnk_[0-9a-f-]{36}$"
          },
          "description": "Идентификатор собственной ссылки; не публичный token."
        }
      ],
      "get": {
        "tags": [
          "Merchant API"
        ],
        "operationId": "getOwnPaymentLinkViaPayments",
        "summary": "Собственная ссылка и сохранённый расчёт",
        "security": [
          {
            "merchantKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Чужой и отсутствующий ID одинаково возвращают 404.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaymentLinkResponse"
                }
              }
            }
          },
          "401": {
            "description": "Нет действующей сессии; для webhook — неверный секрет.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "404": {
            "description": "Запись отсутствует, публичный token неверен или собственная запись принадлежит другому пользователю.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TICKET_NOT_FOUND",
              "LINK_NOT_FOUND"
            ]
          },
          "503": {
            "description": "Интеграция или хранилище не настроены, событие обрабатывается либо сервис недоступен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        },
        "parameters": [],
        "x-required-scope": "invoices:read"
      },
      "patch": {
        "tags": [
          "Merchant API"
        ],
        "operationId": "changePaymentLinkStatusViaPayments",
        "summary": "Приостановить, возобновить или отменить ссылку",
        "security": [
          {
            "merchantKey": []
          }
        ],
        "parameters": [],
        "description": "Changes only status. The update and immutable invoice.updated event commit atomically. Concurrent changes use a version check; refresh and retry on LINK_CHANGED. cancelled is terminal, expiration is never extended, and price, methods, cost shares and description stay frozen. Repeating the saved status returns the current invoice.",
        "requestBody": {
          "required": true,
          "description": "JSON-объект. Максимум 16 384 байта. Неизвестные поля отклоняются.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "status": {
                    "type": "string",
                    "enum": [
                      "active",
                      "paused",
                      "cancelled"
                    ]
                  }
                },
                "required": [
                  "status"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Актуальное состояние собственной ссылки.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaymentLinkResponse"
                }
              }
            }
          },
          "400": {
            "description": "Некорректный JSON, неизвестное поле или недопустимое значение.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "401": {
            "description": "Нет действующей сессии; для webhook — неверный секрет.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "403": {
            "description": "Не пройдена проверка Origin, CSRF или привязки входа к браузеру.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "404": {
            "description": "Запись отсутствует, публичный token неверен или собственная запись принадлежит другому пользователю.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TICKET_NOT_FOUND",
              "LINK_NOT_FOUND"
            ]
          },
          "409": {
            "description": "Запрос входа уже использован/отменён, личность ещё не подтверждена или конфликт обращения.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "CHALLENGE_UNAVAILABLE",
              "IDENTITY_INCOMPLETE",
              "TICKET_CONFLICT",
              "IDEMPOTENCY_CONFLICT",
              "LINK_CANCELLED",
              "LINK_EXPIRED",
              "LINK_UNAVAILABLE"
            ]
          },
          "413": {
            "description": "Превышен размер тела: 16 384 байта; для /api/support/ask и Telegram webhook 65 536 байт.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "REQUEST_TOO_LARGE"
            ]
          },
          "415": {
            "description": "Ожидается Content-Type: application/json.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "JSON_REQUIRED"
            ]
          },
          "503": {
            "description": "Интеграция или хранилище не настроены, событие обрабатывается либо сервис недоступен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        },
        "x-required-scope": "invoices:write"
      }
    },
    "/api/v1/payment-links": {
      "get": {
        "tags": [
          "Merchant API"
        ],
        "operationId": "listOwnPaymentLinksViaLinks",
        "summary": "Список собственных ссылок",
        "security": [
          {
            "merchantKey": []
          }
        ],
        "description": "Сортировка createdAt DESC, id DESC. Публичные ссылки читаются между устройствами; доступ к списку требует аккаунт.",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 30
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "nextCursor из предыдущего ответа. Сервис использует base64 JSON [createdAt,id]; клиенту следует передавать значение без изменений через URLSearchParams."
          }
        ],
        "responses": {
          "200": {
            "description": "Страница собственных ссылок.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaymentLinksPage"
                }
              }
            }
          },
          "400": {
            "description": "Некорректный JSON, неизвестное поле или недопустимое значение.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "401": {
            "description": "Нет действующей сессии; для webhook — неверный секрет.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "503": {
            "description": "Интеграция или хранилище не настроены, событие обрабатывается либо сервис недоступен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        },
        "x-required-scope": "invoices:read"
      },
      "post": {
        "tags": [
          "Merchant API"
        ],
        "operationId": "createOwnPaymentLinkViaLinks",
        "summary": "Создать счёт с неизменными условиями",
        "security": [
          {
            "merchantKey": []
          }
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{16,100}$"
            },
            "description": "Один ключ на логический запрос. Повтор с теми же каноническими полями возвращает исходную запись; другое тело с тем же ключом даёт 409."
          }
        ],
        "description": "Create an immutable invoice and immediately receive checkoutUrl; this does not charge the buyer. USD: card/Alipay; RUB: SBP; USDT: crypto. USD crypto remains accepted for compatibility but cannot be paid without a USDT invoice. Fee and VAT customer shares are independent integers from 0 to 100; current live card/Alipay supports VAT customer=100 and fee customer=0. The customer total is never silently changed. Latest website application must be approved before a new live charge. Invoice creation and its merchant event commit atomically.",
        "requestBody": {
          "required": true,
          "description": "JSON-объект. Максимум 16 384 байта. Неизвестные поля отклоняются.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePaymentLink"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Идемпотентный повтор; replayed=true.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreatePaymentLinkResponse"
                }
              }
            }
          },
          "201": {
            "description": "Счёт создан; replayed=false.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreatePaymentLinkResponse"
                }
              }
            }
          },
          "400": {
            "description": "Некорректный JSON, неизвестное поле или недопустимое значение.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "401": {
            "description": "Нет действующей сессии; для webhook — неверный секрет.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "403": {
            "description": "Не пройдена проверка Origin, CSRF или привязки входа к браузеру.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "409": {
            "description": "Запрос входа уже использован/отменён, личность ещё не подтверждена или конфликт обращения.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "CHALLENGE_UNAVAILABLE",
              "IDENTITY_INCOMPLETE",
              "TICKET_CONFLICT",
              "IDEMPOTENCY_CONFLICT",
              "LINK_CANCELLED",
              "LINK_EXPIRED",
              "LINK_UNAVAILABLE"
            ]
          },
          "413": {
            "description": "Превышен размер тела: 16 384 байта; для /api/support/ask и Telegram webhook 65 536 байт.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "REQUEST_TOO_LARGE"
            ]
          },
          "415": {
            "description": "Ожидается Content-Type: application/json.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "JSON_REQUIRED"
            ]
          },
          "429": {
            "description": "Лимит частоты превышен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "string",
                  "const": "60"
                },
                "description": "Сервер всегда возвращает 60; это не гарантирует истечение часовой квоты."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "RATE_LIMITED"
            ]
          },
          "503": {
            "description": "Интеграция или хранилище не настроены, событие обрабатывается либо сервис недоступен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        },
        "x-required-scope": "invoices:write"
      }
    },
    "/api/v1/payment-links/{id}": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^lnk_[0-9a-f-]{36}$"
          },
          "description": "Идентификатор собственной ссылки; не публичный token."
        }
      ],
      "get": {
        "tags": [
          "Merchant API"
        ],
        "operationId": "getOwnPaymentLinkViaLinks",
        "summary": "Собственная ссылка и сохранённый расчёт",
        "security": [
          {
            "merchantKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Чужой и отсутствующий ID одинаково возвращают 404.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaymentLinkResponse"
                }
              }
            }
          },
          "401": {
            "description": "Нет действующей сессии; для webhook — неверный секрет.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "404": {
            "description": "Запись отсутствует, публичный token неверен или собственная запись принадлежит другому пользователю.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TICKET_NOT_FOUND",
              "LINK_NOT_FOUND"
            ]
          },
          "503": {
            "description": "Интеграция или хранилище не настроены, событие обрабатывается либо сервис недоступен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        },
        "parameters": [],
        "x-required-scope": "invoices:read"
      },
      "patch": {
        "tags": [
          "Merchant API"
        ],
        "operationId": "changePaymentLinkStatusViaLinks",
        "summary": "Приостановить, возобновить или отменить ссылку",
        "security": [
          {
            "merchantKey": []
          }
        ],
        "parameters": [],
        "description": "Changes only status. The update and immutable invoice.updated event commit atomically. Concurrent changes use a version check; refresh and retry on LINK_CHANGED. cancelled is terminal, expiration is never extended, and price, methods, cost shares and description stay frozen. Repeating the saved status returns the current invoice.",
        "requestBody": {
          "required": true,
          "description": "JSON-объект. Максимум 16 384 байта. Неизвестные поля отклоняются.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "status": {
                    "type": "string",
                    "enum": [
                      "active",
                      "paused",
                      "cancelled"
                    ]
                  }
                },
                "required": [
                  "status"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Актуальное состояние собственной ссылки.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaymentLinkResponse"
                }
              }
            }
          },
          "400": {
            "description": "Некорректный JSON, неизвестное поле или недопустимое значение.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "401": {
            "description": "Нет действующей сессии; для webhook — неверный секрет.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "403": {
            "description": "Не пройдена проверка Origin, CSRF или привязки входа к браузеру.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "404": {
            "description": "Запись отсутствует, публичный token неверен или собственная запись принадлежит другому пользователю.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TICKET_NOT_FOUND",
              "LINK_NOT_FOUND"
            ]
          },
          "409": {
            "description": "Запрос входа уже использован/отменён, личность ещё не подтверждена или конфликт обращения.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "CHALLENGE_UNAVAILABLE",
              "IDENTITY_INCOMPLETE",
              "TICKET_CONFLICT",
              "IDEMPOTENCY_CONFLICT",
              "LINK_CANCELLED",
              "LINK_EXPIRED",
              "LINK_UNAVAILABLE"
            ]
          },
          "413": {
            "description": "Превышен размер тела: 16 384 байта; для /api/support/ask и Telegram webhook 65 536 байт.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "REQUEST_TOO_LARGE"
            ]
          },
          "415": {
            "description": "Ожидается Content-Type: application/json.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "JSON_REQUIRED"
            ]
          },
          "503": {
            "description": "Интеграция или хранилище не настроены, событие обрабатывается либо сервис недоступен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        },
        "x-required-scope": "invoices:write"
      }
    },
    "/api/api-keys": {
      "get": {
        "tags": [
          "Merchant API"
        ],
        "operationId": "listMerchantKeys",
        "summary": "List own key metadata",
        "security": [
          {
            "cookieSession": []
          }
        ],
        "responses": {
          "200": {
            "description": "Secrets and secret hashes are omitted.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "keys": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/MerchantKey"
                      }
                    }
                  },
                  "required": [
                    "keys"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "Нет действующей сессии; для webhook — неверный секрет.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "503": {
            "description": "Интеграция или хранилище не настроены, событие обрабатывается либо сервис недоступен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      },
      "post": {
        "tags": [
          "Merchant API"
        ],
        "operationId": "createMerchantKey",
        "summary": "Create a scoped key; reveal its secret once",
        "security": [
          {
            "cookieSession": [],
            "csrfToken": []
          }
        ],
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "description": "Должен точно совпасть с настроенным APP_ORIGIN. Sec-Fetch-Site: cross-site отклоняется. Сервер не предоставляет CORS-доступ.",
            "schema": {
              "type": "string",
              "format": "uri"
            }
          },
          {
            "name": "X-CSRF-Token",
            "in": "header",
            "required": true,
            "description": "Токен текущей сессии из GET /api/auth/me или успешного завершения входа.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{43}$"
            }
          }
        ],
        "description": "Maximum 10 active keys. At most 5 creations/hour/user. Keys expire, can be revoked and are rate-limited to 90 API requests/minute/key.",
        "requestBody": {
          "required": true,
          "description": "JSON-объект. Максимум 16 384 байта. Неизвестные поля отклоняются.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 60
                  },
                  "scopes": {
                    "type": "array",
                    "minItems": 1,
                    "maxItems": 3,
                    "uniqueItems": true,
                    "items": {
                      "type": "string",
                      "enum": [
                        "invoices:read",
                        "invoices:write",
                        "events:read"
                      ]
                    }
                  },
                  "expiresInDays": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 365,
                    "default": 90
                  }
                },
                "required": [
                  "name"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Store the secret securely on your server.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "key": {
                      "$ref": "#/components/schemas/MerchantKey"
                    },
                    "secret": {
                      "type": "string",
                      "pattern": "^kv_live_[A-Za-z0-9_-]{43}$"
                    }
                  },
                  "required": [
                    "key",
                    "secret"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "400": {
            "description": "Некорректный JSON, неизвестное поле или недопустимое значение.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "401": {
            "description": "Нет действующей сессии; для webhook — неверный секрет.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "403": {
            "description": "Не пройдена проверка Origin, CSRF или привязки входа к браузеру.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "409": {
            "description": "Запрос входа уже использован/отменён, личность ещё не подтверждена или конфликт обращения.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "CHALLENGE_UNAVAILABLE",
              "IDENTITY_INCOMPLETE",
              "TICKET_CONFLICT",
              "IDEMPOTENCY_CONFLICT",
              "LINK_CANCELLED",
              "LINK_EXPIRED",
              "LINK_UNAVAILABLE"
            ]
          },
          "429": {
            "description": "Лимит частоты превышен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "string",
                  "const": "60"
                },
                "description": "Сервер всегда возвращает 60; это не гарантирует истечение часовой квоты."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "RATE_LIMITED"
            ]
          },
          "503": {
            "description": "Интеграция или хранилище не настроены, событие обрабатывается либо сервис недоступен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/api-keys/{id}": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^key_[0-9a-f-]{36}$"
          }
        }
      ],
      "delete": {
        "tags": [
          "Merchant API"
        ],
        "operationId": "revokeMerchantKey",
        "summary": "Revoke own key",
        "security": [
          {
            "cookieSession": [],
            "csrfToken": []
          }
        ],
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "description": "Должен точно совпасть с настроенным APP_ORIGIN. Sec-Fetch-Site: cross-site отклоняется. Сервер не предоставляет CORS-доступ.",
            "schema": {
              "type": "string",
              "format": "uri"
            }
          },
          {
            "name": "X-CSRF-Token",
            "in": "header",
            "required": true,
            "description": "Токен текущей сессии из GET /api/auth/me или успешного завершения входа.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{43}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Future uses of the key are rejected.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "revoked": {
                      "const": true
                    }
                  },
                  "required": [
                    "revoked"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "Нет действующей сессии; для webhook — неверный секрет.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "403": {
            "description": "Не пройдена проверка Origin, CSRF или привязки входа к браузеру.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "404": {
            "description": "Запись отсутствует, публичный token неверен или собственная запись принадлежит другому пользователю.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TICKET_NOT_FOUND",
              "LINK_NOT_FOUND"
            ]
          },
          "503": {
            "description": "Интеграция или хранилище не настроены, событие обрабатывается либо сервис недоступен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/events": {
      "get": {
        "tags": [
          "Merchant API"
        ],
        "operationId": "listOwnEvents",
        "summary": "Read own immutable event history",
        "security": [
          {
            "cookieSession": []
          }
        ],
        "parameters": [
          {
            "name": "before",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "description": "Unix timestamp в миллисекундах, UTC."
            },
            "description": "Legacy exclusive timestamp boundary. Cannot be combined with cursor. Use nextCursor for lossless pagination."
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Opaque nextCursor returned by the previous page. Encodes [createdAt,id] and preserves events sharing one timestamp."
          }
        ],
        "responses": {
          "200": {
            "description": "Newest first; up to 50 events. Follow nextCursor until null.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "events": {
                      "type": "array",
                      "maxItems": 50,
                      "items": {
                        "$ref": "#/components/schemas/MerchantEvent"
                      }
                    },
                    "nextCursor": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  },
                  "required": [
                    "events",
                    "nextCursor"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "400": {
            "description": "Некорректный JSON, неизвестное поле или недопустимое значение.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "401": {
            "description": "Нет действующей сессии; для webhook — неверный секрет.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "503": {
            "description": "Интеграция или хранилище не настроены, событие обрабатывается либо сервис недоступен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/v1/events": {
      "get": {
        "tags": [
          "Merchant API"
        ],
        "operationId": "listMerchantEventsWithKey",
        "summary": "Read own immutable event history",
        "security": [
          {
            "merchantKey": []
          }
        ],
        "parameters": [
          {
            "name": "before",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "description": "Unix timestamp в миллисекундах, UTC."
            },
            "description": "Legacy exclusive timestamp boundary. Cannot be combined with cursor. Use nextCursor for lossless pagination."
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Opaque nextCursor returned by the previous page. Encodes [createdAt,id] and preserves events sharing one timestamp."
          }
        ],
        "responses": {
          "200": {
            "description": "Newest first; up to 50 events. Follow nextCursor until null.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "events": {
                      "type": "array",
                      "maxItems": 50,
                      "items": {
                        "$ref": "#/components/schemas/MerchantEvent"
                      }
                    },
                    "nextCursor": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  },
                  "required": [
                    "events",
                    "nextCursor"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "400": {
            "description": "Некорректный JSON, неизвестное поле или недопустимое значение.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "401": {
            "description": "Нет действующей сессии; для webhook — неверный секрет.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "503": {
            "description": "Интеграция или хранилище не настроены, событие обрабатывается либо сервис недоступен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        },
        "x-required-scope": "events:read"
      }
    },
    "/api/webhooks": {
      "get": {
        "tags": [
          "Webhooks"
        ],
        "operationId": "listWebhookEndpoints",
        "summary": "List endpoints and last 30 deliveries",
        "security": [
          {
            "cookieSession": []
          }
        ],
        "responses": {
          "200": {
            "description": "No signing secrets are returned.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "endpoints": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/WebhookEndpoint"
                      }
                    },
                    "deliveries": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/WebhookDelivery"
                      }
                    },
                    "available": {
                      "type": "boolean"
                    },
                    "eventTypes": {
                      "type": "array",
                      "items": {
                        "type": "string",
                        "enum": [
                          "invoice.created",
                          "invoice.updated",
                          "payment.succeeded",
                          "payment.failed",
                          "payment.refunded",
                          "payment.partially_refunded",
                          "payment.disputed",
                          "payment.review_required"
                        ]
                      }
                    }
                  },
                  "required": [
                    "endpoints",
                    "deliveries",
                    "available",
                    "eventTypes"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "Нет действующей сессии; для webhook — неверный секрет.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "404": {
            "description": "Запись отсутствует, публичный token неверен или собственная запись принадлежит другому пользователю.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TICKET_NOT_FOUND",
              "LINK_NOT_FOUND"
            ]
          },
          "503": {
            "description": "Интеграция или хранилище не настроены, событие обрабатывается либо сервис недоступен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      },
      "post": {
        "tags": [
          "Webhooks"
        ],
        "operationId": "createWebhookEndpoint",
        "summary": "Register a public HTTPS destination",
        "security": [
          {
            "cookieSession": [],
            "csrfToken": []
          }
        ],
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "description": "Должен точно совпасть с настроенным APP_ORIGIN. Sec-Fetch-Site: cross-site отклоняется. Сервер не предоставляет CORS-доступ.",
            "schema": {
              "type": "string",
              "format": "uri"
            }
          },
          {
            "name": "X-CSRF-Token",
            "in": "header",
            "required": true,
            "description": "Токен текущей сессии из GET /api/auth/me или успешного завершения входа.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{43}$"
            }
          }
        ],
        "description": "Up to 5 endpoints and 6 creations/hour/user. Public HTTPS domains only; no credentials, IP literals or custom ports. A newly created endpoint receives no live deliveries until its challenge succeeds.",
        "requestBody": {
          "required": true,
          "description": "JSON-объект. Максимум 16 384 байта. Неизвестные поля отклоняются.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "format": "uri",
                    "maxLength": 2048
                  },
                  "description": {
                    "type": "string",
                    "maxLength": 120
                  },
                  "events": {
                    "type": "array",
                    "minItems": 1,
                    "maxItems": 8,
                    "uniqueItems": true,
                    "items": {
                      "type": "string",
                      "enum": [
                        "invoice.created",
                        "invoice.updated",
                        "payment.succeeded",
                        "payment.failed",
                        "payment.refunded",
                        "payment.partially_refunded",
                        "payment.disputed",
                        "payment.review_required"
                      ]
                    }
                  }
                },
                "required": [
                  "url"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Save the one-time signing secret.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "endpoint": {
                      "$ref": "#/components/schemas/WebhookEndpoint"
                    },
                    "secret": {
                      "type": "string",
                      "pattern": "^whsec_[A-Za-z0-9_-]{43}$",
                      "description": "Shown only on create/rotate. Stored encrypted server-side."
                    }
                  },
                  "required": [
                    "endpoint",
                    "secret"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "400": {
            "description": "Некорректный JSON, неизвестное поле или недопустимое значение.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "401": {
            "description": "Нет действующей сессии; для webhook — неверный секрет.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "403": {
            "description": "Не пройдена проверка Origin, CSRF или привязки входа к браузеру.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "409": {
            "description": "Запрос входа уже использован/отменён, личность ещё не подтверждена или конфликт обращения.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "CHALLENGE_UNAVAILABLE",
              "IDENTITY_INCOMPLETE",
              "TICKET_CONFLICT",
              "IDEMPOTENCY_CONFLICT",
              "LINK_CANCELLED",
              "LINK_EXPIRED",
              "LINK_UNAVAILABLE"
            ]
          },
          "429": {
            "description": "Лимит частоты превышен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "string",
                  "const": "60"
                },
                "description": "Сервер всегда возвращает 60; это не гарантирует истечение часовой квоты."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "RATE_LIMITED"
            ]
          },
          "503": {
            "description": "Интеграция или хранилище не настроены, событие обрабатывается либо сервис недоступен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/webhooks/{id}": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^wh_[0-9a-f-]{36}$"
          }
        }
      ],
      "get": {
        "tags": [
          "Webhooks"
        ],
        "operationId": "getWebhookEndpoint",
        "summary": "List endpoints and last 30 deliveries",
        "security": [
          {
            "cookieSession": []
          }
        ],
        "responses": {
          "200": {
            "description": "No signing secrets are returned.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "endpoints": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/WebhookEndpoint"
                      }
                    },
                    "deliveries": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/WebhookDelivery"
                      }
                    },
                    "available": {
                      "type": "boolean"
                    },
                    "eventTypes": {
                      "type": "array",
                      "items": {
                        "type": "string",
                        "enum": [
                          "invoice.created",
                          "invoice.updated",
                          "payment.succeeded",
                          "payment.failed",
                          "payment.refunded",
                          "payment.partially_refunded",
                          "payment.disputed",
                          "payment.review_required"
                        ]
                      }
                    }
                  },
                  "required": [
                    "endpoints",
                    "deliveries",
                    "available",
                    "eventTypes"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "Нет действующей сессии; для webhook — неверный секрет.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "404": {
            "description": "Запись отсутствует, публичный token неверен или собственная запись принадлежит другому пользователю.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TICKET_NOT_FOUND",
              "LINK_NOT_FOUND"
            ]
          },
          "503": {
            "description": "Интеграция или хранилище не настроены, событие обрабатывается либо сервис недоступен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      },
      "patch": {
        "tags": [
          "Webhooks"
        ],
        "operationId": "setWebhookStatus",
        "summary": "Pause or resume a verified endpoint",
        "description": "Paused verified endpoints keep eligible events in the queue; resuming processes due deliveries.",
        "security": [
          {
            "cookieSession": [],
            "csrfToken": []
          }
        ],
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "description": "Должен точно совпасть с настроенным APP_ORIGIN. Sec-Fetch-Site: cross-site отклоняется. Сервер не предоставляет CORS-доступ.",
            "schema": {
              "type": "string",
              "format": "uri"
            }
          },
          {
            "name": "X-CSRF-Token",
            "in": "header",
            "required": true,
            "description": "Токен текущей сессии из GET /api/auth/me или успешного завершения входа.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{43}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "description": "JSON-объект. Максимум 16 384 байта. Неизвестные поля отклоняются.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "status": {
                    "type": "string",
                    "enum": [
                      "active",
                      "paused"
                    ]
                  }
                },
                "required": [
                  "status"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Status saved.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "updated": {
                      "const": true
                    }
                  },
                  "required": [
                    "updated"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "400": {
            "description": "Некорректный JSON, неизвестное поле или недопустимое значение.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "401": {
            "description": "Нет действующей сессии; для webhook — неверный секрет.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "403": {
            "description": "Не пройдена проверка Origin, CSRF или привязки входа к браузеру.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "404": {
            "description": "Запись отсутствует, публичный token неверен или собственная запись принадлежит другому пользователю.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TICKET_NOT_FOUND",
              "LINK_NOT_FOUND"
            ]
          },
          "409": {
            "description": "Запрос входа уже использован/отменён, личность ещё не подтверждена или конфликт обращения.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "CHALLENGE_UNAVAILABLE",
              "IDENTITY_INCOMPLETE",
              "TICKET_CONFLICT",
              "IDEMPOTENCY_CONFLICT",
              "LINK_CANCELLED",
              "LINK_EXPIRED",
              "LINK_UNAVAILABLE"
            ]
          },
          "503": {
            "description": "Интеграция или хранилище не настроены, событие обрабатывается либо сервис недоступен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      },
      "delete": {
        "tags": [
          "Webhooks"
        ],
        "operationId": "deleteWebhookEndpoint",
        "summary": "Remove endpoint and cancel undelivered jobs",
        "description": "Cancels pending, failed and leased jobs. A request already sent across the network cannot be recalled.",
        "security": [
          {
            "cookieSession": [],
            "csrfToken": []
          }
        ],
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "description": "Должен точно совпасть с настроенным APP_ORIGIN. Sec-Fetch-Site: cross-site отклоняется. Сервер не предоставляет CORS-доступ.",
            "schema": {
              "type": "string",
              "format": "uri"
            }
          },
          {
            "name": "X-CSRF-Token",
            "in": "header",
            "required": true,
            "description": "Токен текущей сессии из GET /api/auth/me или успешного завершения входа.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{43}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Endpoint removed.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "deleted": {
                      "const": true
                    }
                  },
                  "required": [
                    "deleted"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "Нет действующей сессии; для webhook — неверный секрет.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "403": {
            "description": "Не пройдена проверка Origin, CSRF или привязки входа к браузеру.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "404": {
            "description": "Запись отсутствует, публичный token неверен или собственная запись принадлежит другому пользователю.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TICKET_NOT_FOUND",
              "LINK_NOT_FOUND"
            ]
          },
          "503": {
            "description": "Интеграция или хранилище не настроены, событие обрабатывается либо сервис недоступен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/webhooks/{id}/verify": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^wh_[0-9a-f-]{36}$"
          }
        }
      ],
      "post": {
        "tags": [
          "Webhooks"
        ],
        "operationId": "verifyWebhookEndpoint",
        "summary": "Send a signed endpoint.verification challenge",
        "description": "Maximum 5 verification attempts/hour/user. Your server must validate Kevmi-Signature and return 2xx JSON {\"challenge\":\"<data.challenge>\"}. Request timeout: 8 seconds; response cap: 8192 bytes. Redirects are not followed. Verification activates the endpoint.",
        "security": [
          {
            "cookieSession": [],
            "csrfToken": []
          }
        ],
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "description": "Должен точно совпасть с настроенным APP_ORIGIN. Sec-Fetch-Site: cross-site отклоняется. Сервер не предоставляет CORS-доступ.",
            "schema": {
              "type": "string",
              "format": "uri"
            }
          },
          {
            "name": "X-CSRF-Token",
            "in": "header",
            "required": true,
            "description": "Токен текущей сессии из GET /api/auth/me или успешного завершения входа.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{43}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "description": "JSON-объект. Максимум 16 384 байта. Неизвестные поля отклоняются.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EmptyObject"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Verified and active.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "verified": {
                      "const": true
                    },
                    "endpoint": {
                      "$ref": "#/components/schemas/WebhookEndpoint"
                    }
                  },
                  "required": [
                    "verified",
                    "endpoint"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "400": {
            "description": "Некорректный JSON, неизвестное поле или недопустимое значение.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "401": {
            "description": "Нет действующей сессии; для webhook — неверный секрет.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "403": {
            "description": "Не пройдена проверка Origin, CSRF или привязки входа к браузеру.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "404": {
            "description": "Запись отсутствует, публичный token неверен или собственная запись принадлежит другому пользователю.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TICKET_NOT_FOUND",
              "LINK_NOT_FOUND"
            ]
          },
          "409": {
            "description": "Запрос входа уже использован/отменён, личность ещё не подтверждена или конфликт обращения.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "CHALLENGE_UNAVAILABLE",
              "IDENTITY_INCOMPLETE",
              "TICKET_CONFLICT",
              "IDEMPOTENCY_CONFLICT",
              "LINK_CANCELLED",
              "LINK_EXPIRED",
              "LINK_UNAVAILABLE"
            ]
          },
          "422": {
            "description": "Destination could not be verified.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "WEBHOOK_UNREACHABLE",
              "WEBHOOK_VERIFICATION_FAILED"
            ]
          },
          "429": {
            "description": "Лимит частоты превышен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "string",
                  "const": "60"
                },
                "description": "Сервер всегда возвращает 60; это не гарантирует истечение часовой квоты."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "RATE_LIMITED"
            ]
          },
          "503": {
            "description": "Интеграция или хранилище не настроены, событие обрабатывается либо сервис недоступен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/webhooks/{id}/rotate": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^wh_[0-9a-f-]{36}$"
          }
        }
      ],
      "post": {
        "tags": [
          "Webhooks"
        ],
        "operationId": "rotateWebhookSecret",
        "summary": "Replace signing secret and require verification again",
        "description": "Maximum 3 rotations/hour/user. Update your server and verify the endpoint again. An already in-flight request may still carry the previous signature.",
        "security": [
          {
            "cookieSession": [],
            "csrfToken": []
          }
        ],
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "description": "Должен точно совпасть с настроенным APP_ORIGIN. Sec-Fetch-Site: cross-site отклоняется. Сервер не предоставляет CORS-доступ.",
            "schema": {
              "type": "string",
              "format": "uri"
            }
          },
          {
            "name": "X-CSRF-Token",
            "in": "header",
            "required": true,
            "description": "Токен текущей сессии из GET /api/auth/me или успешного завершения входа.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{43}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "description": "JSON-объект. Максимум 16 384 байта. Неизвестные поля отклоняются.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EmptyObject"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "New secret shown once.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "secret": {
                      "type": "string",
                      "pattern": "^whsec_[A-Za-z0-9_-]{43}$",
                      "description": "Shown only on create/rotate. Stored encrypted server-side."
                    },
                    "requiresVerification": {
                      "const": true
                    }
                  },
                  "required": [
                    "secret",
                    "requiresVerification"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "400": {
            "description": "Некорректный JSON, неизвестное поле или недопустимое значение.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "401": {
            "description": "Нет действующей сессии; для webhook — неверный секрет.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "403": {
            "description": "Не пройдена проверка Origin, CSRF или привязки входа к браузеру.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "404": {
            "description": "Запись отсутствует, публичный token неверен или собственная запись принадлежит другому пользователю.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TICKET_NOT_FOUND",
              "LINK_NOT_FOUND"
            ]
          },
          "409": {
            "description": "Запрос входа уже использован/отменён, личность ещё не подтверждена или конфликт обращения.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "CHALLENGE_UNAVAILABLE",
              "IDENTITY_INCOMPLETE",
              "TICKET_CONFLICT",
              "IDEMPOTENCY_CONFLICT",
              "LINK_CANCELLED",
              "LINK_EXPIRED",
              "LINK_UNAVAILABLE"
            ]
          },
          "429": {
            "description": "Лимит частоты превышен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "string",
                  "const": "60"
                },
                "description": "Сервер всегда возвращает 60; это не гарантирует истечение часовой квоты."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "RATE_LIMITED"
            ]
          },
          "503": {
            "description": "Интеграция или хранилище не настроены, событие обрабатывается либо сервис недоступен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/webhooks/{id}/deliveries/{deliveryId}/retry": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^wh_[0-9a-f-]{36}$"
          }
        },
        {
          "name": "deliveryId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^del_[a-f0-9]{40}$"
          }
        }
      ],
      "post": {
        "tags": [
          "Webhooks"
        ],
        "operationId": "retryWebhookDelivery",
        "summary": "Retry a failed delivery to an active endpoint",
        "description": "Retains event ID and payload; generates a fresh timestamp and signature. Each automatic delivery cycle makes at most 6 attempts, including expired leases, with delays of 1m, 5m, 30m, 2h and 12h. Delivery is at least once; deduplicate event IDs on your server.",
        "security": [
          {
            "cookieSession": [],
            "csrfToken": []
          }
        ],
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "description": "Должен точно совпасть с настроенным APP_ORIGIN. Sec-Fetch-Site: cross-site отклоняется. Сервер не предоставляет CORS-доступ.",
            "schema": {
              "type": "string",
              "format": "uri"
            }
          },
          {
            "name": "X-CSRF-Token",
            "in": "header",
            "required": true,
            "description": "Токен текущей сессии из GET /api/auth/me или успешного завершения входа.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{43}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "description": "JSON-объект. Максимум 16 384 байта. Неизвестные поля отклоняются.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EmptyObject"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Retry scheduled.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "queued": {
                      "const": true
                    }
                  },
                  "required": [
                    "queued"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "400": {
            "description": "Некорректный JSON, неизвестное поле или недопустимое значение.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "401": {
            "description": "Нет действующей сессии; для webhook — неверный секрет.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "403": {
            "description": "Не пройдена проверка Origin, CSRF или привязки входа к браузеру.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "404": {
            "description": "Запись отсутствует, публичный token неверен или собственная запись принадлежит другому пользователю.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TICKET_NOT_FOUND",
              "LINK_NOT_FOUND"
            ]
          },
          "409": {
            "description": "Запрос входа уже использован/отменён, личность ещё не подтверждена или конфликт обращения.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "CHALLENGE_UNAVAILABLE",
              "IDENTITY_INCOMPLETE",
              "TICKET_CONFLICT",
              "IDEMPOTENCY_CONFLICT",
              "LINK_CANCELLED",
              "LINK_EXPIRED",
              "LINK_UNAVAILABLE"
            ]
          },
          "429": {
            "description": "Лимит частоты превышен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "string",
                  "const": "60"
                },
                "description": "Сервер всегда возвращает 60; это не гарантирует истечение часовой квоты."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "RATE_LIMITED"
            ]
          },
          "503": {
            "description": "Интеграция или хранилище не настроены, событие обрабатывается либо сервис недоступен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/applications": {
      "get": {
        "tags": [
          "Applications"
        ],
        "operationId": "listOwnApplications",
        "summary": "List up to 30 own applications",
        "security": [
          {
            "cookieSession": []
          }
        ],
        "parameters": [
          {
            "name": "X-Kevmi-Locale",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "ru",
                "en",
                "es",
                "de",
                "fr"
              ]
            },
            "description": "Tracking URL and system-message language. Without a supported value, same-origin referrer and browser language are considered; fallback is English."
          }
        ],
        "responses": {
          "200": {
            "description": "Newest first.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "applications": {
                      "type": "array",
                      "maxItems": 30,
                      "items": {
                        "$ref": "#/components/schemas/Application"
                      }
                    }
                  },
                  "required": [
                    "applications"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "Нет действующей сессии; для webhook — неверный секрет.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "503": {
            "description": "Интеграция или хранилище не настроены, событие обрабатывается либо сервис недоступен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      },
      "post": {
        "tags": [
          "Applications"
        ],
        "operationId": "submitWebsiteApplication",
        "summary": "Submit website information and receive a tracking URL",
        "description": "Requires confirmed Telegram sign-in. Up to 5 new submissions/day/user. Idempotent replay returns 200. The server advances real persisted stages; unavailable or risky automatic results require human review. Approval does not configure the payment gateway. Ownership and state cannot be supplied by the applicant.",
        "security": [
          {
            "cookieSession": [],
            "csrfToken": []
          }
        ],
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "description": "Должен точно совпасть с настроенным APP_ORIGIN. Sec-Fetch-Site: cross-site отклоняется. Сервер не предоставляет CORS-доступ.",
            "schema": {
              "type": "string",
              "format": "uri"
            }
          },
          {
            "name": "X-CSRF-Token",
            "in": "header",
            "required": true,
            "description": "Токен текущей сессии из GET /api/auth/me или успешного завершения входа.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{43}$"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{16,100}$"
            },
            "description": "Один ключ на логический запрос. Повтор с теми же каноническими полями возвращает исходную запись; другое тело с тем же ключом даёт 409."
          },
          {
            "name": "X-Kevmi-Locale",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "ru",
                "en",
                "es",
                "de",
                "fr"
              ]
            },
            "description": "Tracking URL and system-message language. Without a supported value, same-origin referrer and browser language are considered; fallback is English."
          }
        ],
        "requestBody": {
          "required": true,
          "description": "JSON-объект. Максимум 16 384 байта. Неизвестные поля отклоняются.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "websiteUrl": {
                    "type": "string",
                    "format": "uri",
                    "maxLength": 2048,
                    "description": "Public HTTPS domain without credentials, query parameters, IP literals or custom ports. A fragment is removed during normalization."
                  },
                  "businessName": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100
                  },
                  "businessType": {
                    "type": "string",
                    "enum": [
                      "digital_goods",
                      "software",
                      "services",
                      "physical_goods",
                      "education",
                      "other"
                    ]
                  },
                  "description": {
                    "type": "string",
                    "minLength": 40,
                    "maxLength": 3000
                  },
                  "contactTelegram": {
                    "type": "string",
                    "description": "A 5–32 character Telegram username beginning with a letter, then letters/digits/underscores. Optional @ or https://t.me/ prefix; surrounding whitespace is trimmed. Stored as @username."
                  },
                  "consent": {
                    "type": "boolean",
                    "const": true
                  }
                },
                "required": [
                  "websiteUrl",
                  "businessName",
                  "businessType",
                  "description",
                  "contactTelegram",
                  "consent"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Existing submission.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "application": {
                      "$ref": "#/components/schemas/Application"
                    },
                    "url": {
                      "type": "string",
                      "format": "uri"
                    },
                    "replayed": {
                      "type": "boolean"
                    }
                  },
                  "required": [
                    "application",
                    "url",
                    "replayed"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "202": {
            "description": "Accepted; processing continues on the server.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "application": {
                      "$ref": "#/components/schemas/Application"
                    },
                    "url": {
                      "type": "string",
                      "format": "uri"
                    },
                    "replayed": {
                      "type": "boolean"
                    }
                  },
                  "required": [
                    "application",
                    "url",
                    "replayed"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "400": {
            "description": "Некорректный JSON, неизвестное поле или недопустимое значение.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "401": {
            "description": "Нет действующей сессии; для webhook — неверный секрет.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "403": {
            "description": "Не пройдена проверка Origin, CSRF или привязки входа к браузеру.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "409": {
            "description": "Запрос входа уже использован/отменён, личность ещё не подтверждена или конфликт обращения.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "CHALLENGE_UNAVAILABLE",
              "IDENTITY_INCOMPLETE",
              "TICKET_CONFLICT",
              "IDEMPOTENCY_CONFLICT",
              "LINK_CANCELLED",
              "LINK_EXPIRED",
              "LINK_UNAVAILABLE"
            ]
          },
          "429": {
            "description": "Лимит частоты превышен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "string",
                  "const": "60"
                },
                "description": "Сервер всегда возвращает 60; это не гарантирует истечение часовой квоты."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "RATE_LIMITED"
            ]
          },
          "503": {
            "description": "Интеграция или хранилище не настроены, событие обрабатывается либо сервис недоступен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/applications/{id}": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^app_[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
          }
        }
      ],
      "get": {
        "tags": [
          "Applications"
        ],
        "operationId": "getOwnApplication",
        "summary": "Read own review stages and event history",
        "security": [
          {
            "cookieSession": []
          }
        ],
        "parameters": [
          {
            "name": "X-Kevmi-Locale",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "ru",
                "en",
                "es",
                "de",
                "fr"
              ]
            },
            "description": "Tracking URL and system-message language. Without a supported value, same-origin referrer and browser language are considered; fallback is English."
          }
        ],
        "responses": {
          "200": {
            "description": "Private applicant projection. Evidence and model output are not exposed.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "application": {
                      "$ref": "#/components/schemas/Application"
                    },
                    "events": {
                      "type": "array",
                      "maxItems": 40,
                      "items": {
                        "$ref": "#/components/schemas/ApplicationEvent"
                      }
                    }
                  },
                  "required": [
                    "application",
                    "events"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "Нет действующей сессии; для webhook — неверный секрет.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "404": {
            "description": "Запись отсутствует, публичный token неверен или собственная запись принадлежит другому пользователю.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TICKET_NOT_FOUND",
              "LINK_NOT_FOUND"
            ]
          },
          "503": {
            "description": "Интеграция или хранилище не настроены, событие обрабатывается либо сервис недоступен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/applications/{id}/resume": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^app_[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
          }
        }
      ],
      "post": {
        "tags": [
          "Applications"
        ],
        "operationId": "resumeApplicationJob",
        "summary": "Resume an eligible background stage",
        "description": "Cannot skip review or approve a stage. A server lease prevents duplicate work. Needs-review and final applications remain unchanged. At most 30 processing-resume requests/minute/user.",
        "security": [
          {
            "cookieSession": [],
            "csrfToken": []
          }
        ],
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "description": "Должен точно совпасть с настроенным APP_ORIGIN. Sec-Fetch-Site: cross-site отклоняется. Сервер не предоставляет CORS-доступ.",
            "schema": {
              "type": "string",
              "format": "uri"
            }
          },
          {
            "name": "X-CSRF-Token",
            "in": "header",
            "required": true,
            "description": "Токен текущей сессии из GET /api/auth/me или успешного завершения входа.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{43}$"
            }
          },
          {
            "name": "X-Kevmi-Locale",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "ru",
                "en",
                "es",
                "de",
                "fr"
              ]
            },
            "description": "Tracking URL and system-message language. Without a supported value, same-origin referrer and browser language are considered; fallback is English."
          }
        ],
        "requestBody": {
          "required": true,
          "description": "JSON-объект. Максимум 16 384 байта. Неизвестные поля отклоняются.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EmptyObject"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "No processing needed.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "application": {
                      "$ref": "#/components/schemas/Application"
                    }
                  },
                  "required": [
                    "application"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "202": {
            "description": "Processing scheduled.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "application": {
                      "$ref": "#/components/schemas/Application"
                    },
                    "scheduled": {
                      "type": "boolean",
                      "const": true
                    }
                  },
                  "required": [
                    "application",
                    "scheduled"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "400": {
            "description": "Некорректный JSON, неизвестное поле или недопустимое значение.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "401": {
            "description": "Нет действующей сессии; для webhook — неверный секрет.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "403": {
            "description": "Не пройдена проверка Origin, CSRF или привязки входа к браузеру.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "404": {
            "description": "Запись отсутствует, публичный token неверен или собственная запись принадлежит другому пользователю.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TICKET_NOT_FOUND",
              "LINK_NOT_FOUND"
            ]
          },
          "429": {
            "description": "Лимит частоты превышен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "string",
                  "const": "60"
                },
                "description": "Сервер всегда возвращает 60; это не гарантирует истечение часовой квоты."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "RATE_LIMITED"
            ]
          },
          "503": {
            "description": "Интеграция или хранилище не настроены, событие обрабатывается либо сервис недоступен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/moderation/applications": {
      "get": {
        "tags": [
          "Moderation"
        ],
        "operationId": "listModerationApplications",
        "summary": "List up to 100 applications for moderation",
        "description": "Requires the authenticated Telegram identity to be in MODERATOR_TELEGRAM_IDS. Includes all states, ordered needs_review first, processing second, then final states; newest updates first within a group.",
        "security": [
          {
            "cookieSession": []
          }
        ],
        "responses": {
          "200": {
            "description": "Moderator queue.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "applications": {
                      "type": "array",
                      "maxItems": 100,
                      "items": {
                        "$ref": "#/components/schemas/Application"
                      }
                    }
                  },
                  "required": [
                    "applications"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "Нет действующей сессии; для webhook — неверный секрет.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "403": {
            "description": "Не пройдена проверка Origin, CSRF или привязки входа к браузеру.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "503": {
            "description": "Интеграция или хранилище не настроены, событие обрабатывается либо сервис недоступен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/moderation/applications/{id}": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^app_[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
          }
        }
      ],
      "get": {
        "tags": [
          "Moderation"
        ],
        "operationId": "getModerationApplication",
        "summary": "Read review evidence and stage history",
        "security": [
          {
            "cookieSession": []
          }
        ],
        "responses": {
          "200": {
            "description": "Private moderator evidence.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "application": {
                      "$ref": "#/components/schemas/Application"
                    },
                    "events": {
                      "type": "array",
                      "maxItems": 40,
                      "items": {
                        "$ref": "#/components/schemas/ApplicationEvent"
                      }
                    },
                    "evidence": {
                      "type": "object",
                      "additionalProperties": true
                    }
                  },
                  "required": [
                    "application",
                    "events",
                    "evidence"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "Нет действующей сессии; для webhook — неверный секрет.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "403": {
            "description": "Не пройдена проверка Origin, CSRF или привязки входа к браузеру.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "404": {
            "description": "Запись отсутствует, публичный token неверен или собственная запись принадлежит другому пользователю.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TICKET_NOT_FOUND",
              "LINK_NOT_FOUND"
            ]
          },
          "503": {
            "description": "Интеграция или хранилище не настроены, событие обрабатывается либо сервис недоступен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/moderation/applications/{id}/decision": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^app_[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
          }
        }
      ],
      "post": {
        "tags": [
          "Moderation"
        ],
        "operationId": "decideApplicationStage",
        "summary": "Approve the current review stage or decline with a public reason",
        "description": "Requires a configured moderator; at most 30 decisions/minute/user. expectedVersion is compared atomically. Only the current needs_review stage can be approved; final applications cannot be silently reopened. A rejection requires an editable public reason. The decision, stage history and enabled applicant notification are saved together.",
        "security": [
          {
            "cookieSession": [],
            "csrfToken": []
          }
        ],
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "description": "Должен точно совпасть с настроенным APP_ORIGIN. Sec-Fetch-Site: cross-site отклоняется. Сервер не предоставляет CORS-доступ.",
            "schema": {
              "type": "string",
              "format": "uri"
            }
          },
          {
            "name": "X-CSRF-Token",
            "in": "header",
            "required": true,
            "description": "Токен текущей сессии из GET /api/auth/me или успешного завершения входа.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{43}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "description": "JSON-объект. Максимум 16 384 байта. Неизвестные поля отклоняются.",
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "type": "object",
                    "properties": {
                      "expectedVersion": {
                        "type": "integer",
                        "minimum": 1
                      },
                      "action": {
                        "type": "string",
                        "const": "approve_step"
                      },
                      "reason": {
                        "type": "string",
                        "maxLength": 0
                      }
                    },
                    "required": [
                      "expectedVersion",
                      "action"
                    ],
                    "additionalProperties": false
                  },
                  {
                    "type": "object",
                    "properties": {
                      "expectedVersion": {
                        "type": "integer",
                        "minimum": 1
                      },
                      "action": {
                        "type": "string",
                        "const": "reject"
                      },
                      "reason": {
                        "type": "string",
                        "minLength": 10,
                        "maxLength": 1500
                      }
                    },
                    "required": [
                      "expectedVersion",
                      "action",
                      "reason"
                    ],
                    "additionalProperties": false
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Decision saved.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "application": {
                      "$ref": "#/components/schemas/Application"
                    }
                  },
                  "required": [
                    "application"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "400": {
            "description": "Некорректный JSON, неизвестное поле или недопустимое значение.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "401": {
            "description": "Нет действующей сессии; для webhook — неверный секрет.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "403": {
            "description": "Не пройдена проверка Origin, CSRF или привязки входа к браузеру.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "404": {
            "description": "Запись отсутствует, публичный token неверен или собственная запись принадлежит другому пользователю.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TICKET_NOT_FOUND",
              "LINK_NOT_FOUND"
            ]
          },
          "409": {
            "description": "Запрос входа уже использован/отменён, личность ещё не подтверждена или конфликт обращения.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "CHALLENGE_UNAVAILABLE",
              "IDENTITY_INCOMPLETE",
              "TICKET_CONFLICT",
              "IDEMPOTENCY_CONFLICT",
              "LINK_CANCELLED",
              "LINK_EXPIRED",
              "LINK_UNAVAILABLE"
            ]
          },
          "429": {
            "description": "Лимит частоты превышен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "string",
                  "const": "60"
                },
                "description": "Сервер всегда возвращает 60; это не гарантирует истечение часовой квоты."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "RATE_LIMITED"
            ]
          },
          "503": {
            "description": "Интеграция или хранилище не настроены, событие обрабатывается либо сервис недоступен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/gateway/webhook": {
      "post": {
        "tags": [
          "Gateway events"
        ],
        "operationId": "receiveGatewayEvent",
        "summary": "Receive signed source-native gateway events",
        "description": "Native v3: supply X-Gateway-Timestamp (Unix seconds), X-Gateway-Signature and matching X-Gateway-Event-Id. Maximum timestamp skew is 300 seconds. After signature verification, Kevmi fetches the payment through the authenticated gateway API, checks saved order, exact currency/amount, method and provider-confirmed state, then atomically stores the receipt and merchant outbox event. Webhook text and browser observations alone never confirm a payment. Repeated IDs are deduplicated; a changed body for an existing ID is rejected. Delayed events use fresh authoritative state. Partial refunds, full refunds, disputes and review states are supported. Unbound orders are acknowledged and ignored. Legacy normalized events using Kevmi-Signature remain supported separately; only their succeeded/failed/full-refunded transitions apply.",
        "security": [
          {
            "nativeGatewaySignature": []
          },
          {
            "gatewaySignature": []
          }
        ],
        "parameters": [
          {
            "name": "X-Gateway-Timestamp",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{10}$"
            },
            "description": "Required for native v3 events."
          },
          {
            "name": "X-Gateway-Event-Id",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Required for native v3; must match body.id."
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Exact signed JSON body; native v3 limit: 524288 bytes. Do not parse and reserialize before signature verification.",
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/NativeGatewayEvent"
                  },
                  {
                    "$ref": "#/components/schemas/LegacyGatewayEvent"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Received, deduplicated, or safely ignored.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "received": {
                      "type": "boolean",
                      "const": true
                    },
                    "replayed": {
                      "type": "boolean"
                    },
                    "ignored": {
                      "type": "boolean"
                    },
                    "applied": {
                      "type": "boolean"
                    }
                  },
                  "required": [
                    "received"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "400": {
            "description": "Некорректный JSON, неизвестное поле или недопустимое значение.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "401": {
            "description": "The gateway signature is missing, invalid or outside the accepted time window.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_GATEWAY_SIGNATURE",
              "INVALID_SIGNATURE",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "404": {
            "description": "Запись отсутствует, публичный token неверен или собственная запись принадлежит другому пользователю.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TICKET_NOT_FOUND",
              "LINK_NOT_FOUND"
            ]
          },
          "409": {
            "description": "An event ID was reused with changed content or a payment ID conflicts with the saved invoice binding.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "GATEWAY_EVENT_CONFLICT",
              "PAYMENT_ID_CONFLICT"
            ]
          },
          "413": {
            "description": "Превышен размер тела: 16 384 байта; для /api/support/ask и Telegram webhook 65 536 байт.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "REQUEST_TOO_LARGE"
            ]
          },
          "415": {
            "description": "Ожидается Content-Type: application/json.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "JSON_REQUIRED"
            ]
          },
          "429": {
            "description": "The gateway is busy; retry webhook delivery with the same event ID.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "GATEWAY_BUSY"
            ]
          },
          "502": {
            "description": "Gateway response unavailable, malformed, or not verifiable. Read the existing payment status before attempting any retry.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "GATEWAY_REQUEST_UNCERTAIN",
              "GATEWAY_INVALID_RESPONSE"
            ]
          },
          "503": {
            "description": "The gateway configuration or signing secret is missing.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "GATEWAY_NOT_CONNECTED",
              "DATABASE_NOT_CONFIGURED"
            ]
          }
        }
      }
    },
    "/api/jobs/dispatch": {
      "post": {
        "tags": [
          "Service"
        ],
        "operationId": "dispatchBackgroundJobs",
        "summary": "Run due delivery and application jobs",
        "description": "Server scheduler entrypoint. Requires JOBS_SECRET, not a browser session or merchant key. Does not accept job IDs or arbitrary outbound URLs.",
        "security": [
          {
            "jobSecret": []
          }
        ],
        "responses": {
          "200": {
            "description": "Completed without a background context.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "202": {
            "description": "Accepted in a background execution context.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "accepted": {
                      "const": true
                    }
                  },
                  "required": [
                    "accepted"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "Нет действующей сессии; для webhook — неверный секрет.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "503": {
            "description": "Интеграция или хранилище не настроены, событие обрабатывается либо сервис недоступен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/checkout/{token}/status": {
      "parameters": [
        {
          "name": "token",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{43}$"
          },
          "description": "Случайный публичный идентификатор из URL страницы оплаты. Даёт чтение только этого счёта."
        }
      ],
      "get": {
        "tags": [
          "Checkout"
        ],
        "operationId": "getCheckoutPaymentStatus",
        "summary": "Read and refresh the same payment",
        "description": "No account is required. Refreshes an existing operation over authenticated gateway transport, with server-side throttling. No new payment is created. Returns null if nothing was dispatched. Confirm an order only when fulfillmentReady is true.",
        "responses": {
          "200": {
            "description": "Current sanitized payment state.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "payment": {
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/CheckoutPayment"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "replayed": {
                      "type": "boolean"
                    }
                  },
                  "required": [
                    "payment"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "400": {
            "description": "Некорректный JSON, неизвестное поле или недопустимое значение.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "404": {
            "description": "Запись отсутствует, публичный token неверен или собственная запись принадлежит другому пользователю.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TICKET_NOT_FOUND",
              "LINK_NOT_FOUND"
            ]
          },
          "429": {
            "description": "Лимит частоты превышен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "string",
                  "const": "60"
                },
                "description": "Сервер всегда возвращает 60; это не гарантирует истечение часовой квоты."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "RATE_LIMITED"
            ]
          },
          "502": {
            "description": "Gateway response unavailable, malformed, or not verifiable. Read the existing payment status before attempting any retry.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "GATEWAY_REQUEST_UNCERTAIN",
              "GATEWAY_INVALID_RESPONSE"
            ]
          },
          "503": {
            "description": "Интеграция или хранилище не настроены, событие обрабатывается либо сервис недоступен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/checkout/{token}/reconcile": {
      "parameters": [
        {
          "name": "token",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{43}$"
          },
          "description": "Случайный публичный идентификатор из URL страницы оплаты. Даёт чтение только этого счёта."
        }
      ],
      "post": {
        "tags": [
          "Checkout"
        ],
        "operationId": "reconcileCheckoutPayment",
        "summary": "Request an authoritative status reconciliation",
        "description": "Reads the existing operation and asks the gateway to reconcile its provider status. Does not create a payment. At most 3 requests per invoice per minute. Available for already-dispatched payments even if the invoice is no longer active.",
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "description": "Должен точно совпасть с настроенным APP_ORIGIN. Sec-Fetch-Site: cross-site отклоняется. Сервер не предоставляет CORS-доступ.",
            "schema": {
              "type": "string",
              "format": "uri"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "description": "JSON-объект. Максимум 16 384 байта. Неизвестные поля отклоняются.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EmptyObject"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Reconciled payment or null.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "payment": {
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/CheckoutPayment"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "replayed": {
                      "type": "boolean"
                    }
                  },
                  "required": [
                    "payment"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "400": {
            "description": "Некорректный JSON, неизвестное поле или недопустимое значение.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "403": {
            "description": "Не пройдена проверка Origin, CSRF или привязки входа к браузеру.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "404": {
            "description": "Запись отсутствует, публичный token неверен или собственная запись принадлежит другому пользователю.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TICKET_NOT_FOUND",
              "LINK_NOT_FOUND"
            ]
          },
          "409": {
            "description": "Запрос входа уже использован/отменён, личность ещё не подтверждена или конфликт обращения.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "CHALLENGE_UNAVAILABLE",
              "IDENTITY_INCOMPLETE",
              "TICKET_CONFLICT",
              "IDEMPOTENCY_CONFLICT",
              "LINK_CANCELLED",
              "LINK_EXPIRED",
              "LINK_UNAVAILABLE"
            ]
          },
          "410": {
            "description": "The gateway encryption intent or bank challenge expired. Obtain a fresh intent for the same operation; do not create a replacement payment.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "CARD_SESSION_INVALID"
            ]
          },
          "413": {
            "description": "Превышен размер тела: 16 384 байта; для /api/support/ask и Telegram webhook 65 536 байт.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "REQUEST_TOO_LARGE"
            ]
          },
          "415": {
            "description": "Ожидается Content-Type: application/json.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "JSON_REQUIRED"
            ]
          },
          "429": {
            "description": "Лимит частоты превышен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "string",
                  "const": "60"
                },
                "description": "Сервер всегда возвращает 60; это не гарантирует истечение часовой квоты."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "RATE_LIMITED"
            ]
          },
          "502": {
            "description": "Gateway response unavailable, malformed, or not verifiable. Read the existing payment status before attempting any retry.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "GATEWAY_REQUEST_UNCERTAIN",
              "GATEWAY_INVALID_RESPONSE"
            ]
          },
          "503": {
            "description": "Интеграция или хранилище не настроены, событие обрабатывается либо сервис недоступен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/checkout/{token}/card-intent": {
      "parameters": [
        {
          "name": "token",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{43}$"
          },
          "description": "Случайный публичный идентификатор из URL страницы оплаты. Даёт чтение только этого счёта."
        }
      ],
      "post": {
        "tags": [
          "Checkout"
        ],
        "operationId": "createCardEncryptionIntent",
        "summary": "Obtain a gateway public key and a bound encryption intent",
        "description": "The gateway alone owns the private key. An intent expires within five minutes and binds the merchant order, currency, base/total amounts, operation idempotency key and purpose. payment intents require an active invoice and approved merchant; code intents require an existing, current bank challenge. No PAN, CVV, bank code, or private JWK fields are accepted by this endpoint. At most 8 intents per invoice and 12 per client per minute. The encrypted plaintext is {intent,name,country,email?,card:{number,expiration,cvv,holder}} for payment or {intent,code} for code. Plaintext is assembled only inside the browser before JWE encryption.",
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "description": "Должен точно совпасть с настроенным APP_ORIGIN. Sec-Fetch-Site: cross-site отклоняется. Сервер не предоставляет CORS-доступ.",
            "schema": {
              "type": "string",
              "format": "uri"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "description": "JSON object, at most 2048 bytes.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "purpose": {
                    "type": "string",
                    "enum": [
                      "payment",
                      "code"
                    ],
                    "default": "payment"
                  }
                },
                "required": [],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Short-lived intent and public RSA key only.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CardIntent"
                }
              }
            }
          },
          "400": {
            "description": "Некорректный JSON, неизвестное поле или недопустимое значение.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "403": {
            "description": "Не пройдена проверка Origin, CSRF или привязки входа к браузеру.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "404": {
            "description": "Запись отсутствует, публичный token неверен или собственная запись принадлежит другому пользователю.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TICKET_NOT_FOUND",
              "LINK_NOT_FOUND"
            ]
          },
          "409": {
            "description": "Запрос входа уже использован/отменён, личность ещё не подтверждена или конфликт обращения.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "CHALLENGE_UNAVAILABLE",
              "IDENTITY_INCOMPLETE",
              "TICKET_CONFLICT",
              "IDEMPOTENCY_CONFLICT",
              "LINK_CANCELLED",
              "LINK_EXPIRED",
              "LINK_UNAVAILABLE"
            ]
          },
          "410": {
            "description": "The gateway encryption intent or bank challenge expired. Obtain a fresh intent for the same operation; do not create a replacement payment.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "CARD_SESSION_INVALID"
            ]
          },
          "413": {
            "description": "Превышен размер тела: 16 384 байта; для /api/support/ask и Telegram webhook 65 536 байт.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "REQUEST_TOO_LARGE"
            ]
          },
          "415": {
            "description": "Ожидается Content-Type: application/json.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "JSON_REQUIRED"
            ]
          },
          "429": {
            "description": "Лимит частоты превышен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "string",
                  "const": "60"
                },
                "description": "Сервер всегда возвращает 60; это не гарантирует истечение часовой квоты."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "RATE_LIMITED"
            ]
          },
          "502": {
            "description": "Gateway response unavailable, malformed, or not verifiable. Read the existing payment status before attempting any retry.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "GATEWAY_REQUEST_UNCERTAIN",
              "GATEWAY_INVALID_RESPONSE"
            ]
          },
          "503": {
            "description": "Интеграция или хранилище не настроены, событие обрабатывается либо сервис недоступен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/checkout/{token}/code": {
      "parameters": [
        {
          "name": "token",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{43}$"
          },
          "description": "Случайный публичный идентификатор из URL страницы оплаты. Даёт чтение только этого счёта."
        }
      ],
      "post": {
        "tags": [
          "Checkout"
        ],
        "operationId": "submitEncryptedBankCode",
        "summary": "Relay an encrypted code for the current bank challenge",
        "description": "Obtain a purpose=code intent and encrypt {intent,code} in the browser. The gateway validates the current challenge and consumes the sealed intent once. Kevmi never receives plaintext code. At most 5 submissions per invoice per minute; refresh status after an uncertain response.",
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "description": "Должен точно совпасть с настроенным APP_ORIGIN. Sec-Fetch-Site: cross-site отклоняется. Сервер не предоставляет CORS-доступ.",
            "schema": {
              "type": "string",
              "format": "uri"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "description": "JSON-объект. Максимум 16 384 байта. Неизвестные поля отклоняются.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "sealed": {
                    "$ref": "#/components/schemas/SealedCardData"
                  }
                },
                "required": [
                  "sealed"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Code sent; current payment state.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "payment": {
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/CheckoutPayment"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "replayed": {
                      "type": "boolean"
                    }
                  },
                  "required": [
                    "payment"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "400": {
            "description": "Некорректный JSON, неизвестное поле или недопустимое значение.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "403": {
            "description": "Не пройдена проверка Origin, CSRF или привязки входа к браузеру.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "404": {
            "description": "Запись отсутствует, публичный token неверен или собственная запись принадлежит другому пользователю.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TICKET_NOT_FOUND",
              "LINK_NOT_FOUND"
            ]
          },
          "409": {
            "description": "Запрос входа уже использован/отменён, личность ещё не подтверждена или конфликт обращения.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "CHALLENGE_UNAVAILABLE",
              "IDENTITY_INCOMPLETE",
              "TICKET_CONFLICT",
              "IDEMPOTENCY_CONFLICT",
              "LINK_CANCELLED",
              "LINK_EXPIRED",
              "LINK_UNAVAILABLE"
            ]
          },
          "410": {
            "description": "The gateway encryption intent or bank challenge expired. Obtain a fresh intent for the same operation; do not create a replacement payment.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "CARD_SESSION_INVALID"
            ]
          },
          "413": {
            "description": "Превышен размер тела: 16 384 байта; для /api/support/ask и Telegram webhook 65 536 байт.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "REQUEST_TOO_LARGE"
            ]
          },
          "415": {
            "description": "Ожидается Content-Type: application/json.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "JSON_REQUIRED"
            ]
          },
          "429": {
            "description": "Лимит частоты превышен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "string",
                  "const": "60"
                },
                "description": "Сервер всегда возвращает 60; это не гарантирует истечение часовой квоты."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "RATE_LIMITED"
            ]
          },
          "502": {
            "description": "Gateway response unavailable, malformed, or not verifiable. Read the existing payment status before attempting any retry.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "GATEWAY_REQUEST_UNCERTAIN",
              "GATEWAY_INVALID_RESPONSE"
            ]
          },
          "503": {
            "description": "Интеграция или хранилище не настроены, событие обрабатывается либо сервис недоступен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/checkout/{token}/crypto-services": {
      "parameters": [
        {
          "name": "token",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{43}$"
          },
          "description": "Случайный публичный идентификатор из URL страницы оплаты. Даёт чтение только этого счёта."
        }
      ],
      "get": {
        "tags": [
          "Checkout"
        ],
        "operationId": "getCheckoutCryptoServices",
        "summary": "Read the current coin and network catalog",
        "description": "Only for a USDT invoice that allows crypto. The invoice remains denominated in USDT; the gateway quotes the chosen payer coin. Never assume USD equals USDT or convert the transfer amount to a floating-point number. At most 10 catalog reads per invoice per minute.",
        "responses": {
          "200": {
            "description": "Gateway-provided catalog, with current availability and transfer limits.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "services": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "currency": {
                            "type": "string"
                          },
                          "network": {
                            "type": "string"
                          },
                          "networkLabel": {
                            "type": "string"
                          },
                          "available": {
                            "type": "boolean"
                          },
                          "minAmount": {
                            "type": "string",
                            "pattern": "^[0-9]+(?:\\.[0-9]+)?$",
                            "description": "Exact decimal value in the selected transfer coin."
                          },
                          "maxAmount": {
                            "type": "string",
                            "pattern": "^[0-9]+(?:\\.[0-9]+)?$",
                            "description": "Exact decimal value in the selected transfer coin."
                          },
                          "confirmations": {
                            "type": [
                              "integer",
                              "null"
                            ],
                            "minimum": 0
                          }
                        },
                        "required": [
                          "currency",
                          "network",
                          "networkLabel",
                          "available",
                          "minAmount",
                          "maxAmount",
                          "confirmations"
                        ],
                        "additionalProperties": false
                      }
                    },
                    "fetchedAt": {
                      "type": "integer",
                      "minimum": 0,
                      "description": "Unix timestamp в миллисекундах, UTC."
                    }
                  },
                  "required": [
                    "services",
                    "fetchedAt"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "400": {
            "description": "Некорректный JSON, неизвестное поле или недопустимое значение.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "404": {
            "description": "Запись отсутствует, публичный token неверен или собственная запись принадлежит другому пользователю.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TICKET_NOT_FOUND",
              "LINK_NOT_FOUND"
            ]
          },
          "429": {
            "description": "Лимит частоты превышен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "string",
                  "const": "60"
                },
                "description": "Сервер всегда возвращает 60; это не гарантирует истечение часовой квоты."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "RATE_LIMITED"
            ]
          },
          "502": {
            "description": "Gateway response unavailable, malformed, or not verifiable. Read the existing payment status before attempting any retry.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "GATEWAY_REQUEST_UNCERTAIN",
              "GATEWAY_INVALID_RESPONSE"
            ]
          },
          "503": {
            "description": "Интеграция или хранилище не настроены, событие обрабатывается либо сервис недоступен.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "cookieSession": {
        "type": "apiKey",
        "in": "cookie",
        "name": "__Host-kevmi-session",
        "description": "Случайный токен сессии, Secure/HttpOnly/SameSite=Lax, срок 24 часа. В базе хранится хеш. Получается только завершением подтверждённого Telegram-входа."
      },
      "browserProof": {
        "type": "apiKey",
        "in": "cookie",
        "name": "__Host-kevmi-login",
        "description": "HttpOnly cookie из start, challengeId.proof, срок 300 секунд. Не включается в Telegram deep link."
      },
      "csrfToken": {
        "type": "apiKey",
        "in": "header",
        "name": "X-CSRF-Token",
        "description": "Токен сессии, выдаётся /api/auth/me или /api/auth/telegram/complete. Для изменений дополнительно обязателен точный Origin."
      },
      "telegramWebhookSecret": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Telegram-Bot-Api-Secret-Token",
        "description": "Отдельный секрет из серверной конфигурации webhook. Его значение не публикуется. Это не токен бота."
      },
      "merchantKey": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "kv_live_…",
        "description": "Scoped merchant API key. Only its hash is stored. Server-to-server use only; never place it in a widget or browser bundle."
      },
      "gatewaySignature": {
        "type": "apiKey",
        "in": "header",
        "name": "Kevmi-Signature",
        "description": "t=<Unix seconds>,v1=<hex HMAC-SHA256(secret, timestamp + dot + exact UTF-8 request body)>. Maximum timestamp skew: 300 seconds."
      },
      "jobSecret": {
        "type": "http",
        "scheme": "bearer",
        "description": "Separate server-only JOBS_SECRET. Not a merchant API key."
      },
      "nativeGatewaySignature": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Gateway-Signature",
        "description": "v1=<hex HMAC-SHA256(GATEWAY_WEBHOOK_SECRET, timestamp + \".\" + exact raw UTF-8 body)>; separate from merchant Kevmi-Signature."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              }
            },
            "required": [
              "code",
              "message"
            ],
            "additionalProperties": false
          }
        },
        "required": [
          "error"
        ],
        "additionalProperties": false
      },
      "EmptyObject": {
        "type": "object",
        "properties": {},
        "required": [],
        "additionalProperties": false
      },
      "Config": {
        "type": "object",
        "properties": {
          "telegram": {
            "type": "object",
            "properties": {
              "enabled": {
                "type": "boolean"
              },
              "botUsername": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "enabled",
              "botUsername"
            ],
            "additionalProperties": false
          },
          "support": {
            "type": "object",
            "properties": {
              "mode": {
                "type": "string",
                "enum": [
                  "search",
                  "ai"
                ]
              },
              "available": {
                "type": "boolean",
                "const": true
              }
            },
            "required": [
              "mode",
              "available"
            ],
            "additionalProperties": false
          },
          "gateway": {
            "type": "object",
            "properties": {
              "configured": {
                "type": "boolean"
              },
              "connected": {
                "type": "boolean",
                "const": false,
                "description": "The public configuration endpoint does not probe gateway health. Configuration is not a successful live connection check."
              },
              "status": {
                "type": "string",
                "enum": [
                  "configured",
                  "not_configured"
                ]
              }
            },
            "required": [
              "configured",
              "connected",
              "status"
            ],
            "additionalProperties": false
          },
          "capabilities": {
            "type": "object",
            "properties": {
              "server": {
                "type": "boolean",
                "const": true
              },
              "account": {
                "type": "boolean"
              },
              "notifications": {
                "type": "boolean"
              },
              "tickets": {
                "type": "boolean"
              },
              "directPaymentsOnly": {
                "type": "boolean",
                "const": true
              },
              "paymentLinks": {
                "type": "boolean",
                "description": "D1 настроена для серверных ссылок. Это не готовность приёма денег."
              },
              "apiKeys": {
                "type": "boolean"
              },
              "webhooks": {
                "type": "boolean"
              },
              "widgets": {
                "type": "boolean"
              },
              "applications": {
                "type": "boolean"
              },
              "applicationNotifications": {
                "type": "boolean"
              }
            },
            "required": [
              "server",
              "account",
              "notifications",
              "tickets",
              "directPaymentsOnly",
              "paymentLinks",
              "apiKeys",
              "webhooks",
              "widgets",
              "applications",
              "applicationNotifications"
            ],
            "additionalProperties": false
          }
        },
        "required": [
          "telegram",
          "support",
          "gateway",
          "capabilities"
        ],
        "additionalProperties": false
      },
      "Health": {
        "type": "object",
        "properties": {
          "telegram": {
            "type": "object",
            "properties": {
              "enabled": {
                "type": "boolean"
              },
              "botUsername": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "enabled",
              "botUsername"
            ],
            "additionalProperties": false
          },
          "support": {
            "type": "object",
            "properties": {
              "mode": {
                "type": "string",
                "enum": [
                  "search",
                  "ai"
                ]
              },
              "available": {
                "type": "boolean",
                "const": true
              }
            },
            "required": [
              "mode",
              "available"
            ],
            "additionalProperties": false
          },
          "gateway": {
            "type": "object",
            "properties": {
              "configured": {
                "type": "boolean"
              },
              "connected": {
                "type": "boolean",
                "const": false,
                "description": "The public configuration endpoint does not probe gateway health. Configuration is not a successful live connection check."
              },
              "status": {
                "type": "string",
                "enum": [
                  "configured",
                  "not_configured"
                ]
              }
            },
            "required": [
              "configured",
              "connected",
              "status"
            ],
            "additionalProperties": false
          },
          "capabilities": {
            "type": "object",
            "properties": {
              "server": {
                "type": "boolean",
                "const": true
              },
              "account": {
                "type": "boolean"
              },
              "notifications": {
                "type": "boolean"
              },
              "tickets": {
                "type": "boolean"
              },
              "directPaymentsOnly": {
                "type": "boolean",
                "const": true
              },
              "paymentLinks": {
                "type": "boolean",
                "description": "D1 настроена для серверных ссылок. Это не готовность приёма денег."
              },
              "apiKeys": {
                "type": "boolean"
              },
              "webhooks": {
                "type": "boolean"
              },
              "widgets": {
                "type": "boolean"
              },
              "applications": {
                "type": "boolean"
              },
              "applicationNotifications": {
                "type": "boolean"
              }
            },
            "required": [
              "server",
              "account",
              "notifications",
              "tickets",
              "directPaymentsOnly",
              "paymentLinks",
              "apiKeys",
              "webhooks",
              "widgets",
              "applications",
              "applicationNotifications"
            ],
            "additionalProperties": false
          },
          "status": {
            "type": "string",
            "enum": [
              "ok",
              "degraded"
            ]
          },
          "storage": {
            "type": "string",
            "enum": [
              "ready",
              "not_configured",
              "unavailable"
            ]
          }
        },
        "required": [
          "telegram",
          "support",
          "gateway",
          "capabilities",
          "status",
          "storage"
        ],
        "additionalProperties": false
      },
      "NotificationPreferences": {
        "type": "object",
        "properties": {
          "payments": {
            "type": "boolean"
          },
          "payouts": {
            "type": "boolean"
          },
          "support": {
            "type": "boolean"
          },
          "security": {
            "type": "boolean"
          }
        },
        "required": [
          "payments",
          "payouts",
          "support",
          "security"
        ],
        "additionalProperties": false
      },
      "SettingsPatch": {
        "type": "object",
        "properties": {
          "storeName": {
            "type": "string",
            "minLength": 1,
            "x-trimmedMaxLength": 80,
            "x-trimmedMinLength": 1,
            "description": "Пробелы по краям удаляются. Длина после удаления: 1–80 символов. Управляющие символы, кроме табуляции и перевода строки, запрещены."
          },
          "vatPayer": {
            "type": "string",
            "enum": [
              "customer",
              "merchant"
            ]
          },
          "notifications": {
            "type": "object",
            "properties": {
              "payments": {
                "type": "boolean"
              },
              "payouts": {
                "type": "boolean"
              },
              "support": {
                "type": "boolean"
              },
              "security": {
                "type": "boolean"
              }
            },
            "required": [],
            "additionalProperties": false
          }
        },
        "required": [],
        "additionalProperties": false
      },
      "User": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "displayName": {
            "type": "string"
          },
          "username": {
            "type": [
              "string",
              "null"
            ]
          },
          "storeName": {
            "type": "string"
          },
          "vatPayer": {
            "type": "string",
            "enum": [
              "customer",
              "merchant"
            ]
          },
          "notifications": {
            "$ref": "#/components/schemas/NotificationPreferences"
          },
          "isModerator": {
            "type": "boolean",
            "description": "Whether this Telegram identity belongs to the configured moderator allowlist."
          }
        },
        "required": [
          "id",
          "displayName",
          "username",
          "storeName",
          "vatPayer",
          "notifications",
          "isModerator"
        ],
        "additionalProperties": false
      },
      "UserResponse": {
        "type": "object",
        "properties": {
          "user": {
            "$ref": "#/components/schemas/User"
          }
        },
        "required": [
          "user"
        ],
        "additionalProperties": false
      },
      "Anonymous": {
        "type": "object",
        "properties": {
          "authenticated": {
            "type": "boolean",
            "const": false
          }
        },
        "required": [
          "authenticated"
        ],
        "additionalProperties": false
      },
      "CurrentSession": {
        "type": "object",
        "properties": {
          "authenticated": {
            "type": "boolean",
            "const": true
          },
          "user": {
            "$ref": "#/components/schemas/User"
          },
          "csrfToken": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{43}$"
          },
          "expiresAt": {
            "type": "integer",
            "minimum": 0,
            "description": "Unix timestamp в миллисекундах, UTC."
          }
        },
        "required": [
          "authenticated",
          "user",
          "csrfToken",
          "expiresAt"
        ],
        "additionalProperties": false
      },
      "LoginChallenge": {
        "type": "object",
        "properties": {
          "challengeId": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{43}$"
          },
          "code": {
            "type": "string",
            "pattern": "^[0-9]{6}$"
          },
          "expiresAt": {
            "type": "integer",
            "minimum": 0,
            "description": "Unix timestamp в миллисекундах, UTC."
          },
          "telegramUrl": {
            "type": "string",
            "format": "uri",
            "pattern": "^https://t\\.me/"
          }
        },
        "required": [
          "challengeId",
          "code",
          "expiresAt",
          "telegramUrl"
        ],
        "additionalProperties": false
      },
      "CompletedLogin": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "const": "authenticated"
          },
          "user": {
            "$ref": "#/components/schemas/User"
          },
          "csrfToken": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{43}$"
          },
          "expiresAt": {
            "type": "integer",
            "minimum": 0,
            "description": "Unix timestamp в миллисекундах, UTC."
          }
        },
        "required": [
          "status",
          "user",
          "csrfToken",
          "expiresAt"
        ],
        "additionalProperties": false
      },
      "SupportQuestion": {
        "type": "object",
        "properties": {
          "question": {
            "type": "string",
            "minLength": 2,
            "x-trimmedMaxLength": 2000,
            "x-trimmedMinLength": 2,
            "description": "Пробелы по краям удаляются. Длина после удаления: 2–2000 символов. Управляющие символы, кроме табуляции и перевода строки, запрещены."
          },
          "locale": {
            "type": "string",
            "enum": [
              "ru",
              "en",
              "es",
              "de",
              "fr"
            ],
            "default": "en",
            "description": "Response language. If omitted, supported Accept-Language preferences are used; otherwise English. Articles for ES/DE/FR currently link to the English documentation edition."
          },
          "history": {
            "type": "array",
            "maxItems": 6,
            "description": "До трёх последних пар вопрос/ответ. Необязательно. Это недоверенные данные, не сообщения системной роли провайдера.",
            "items": {
              "oneOf": [
                {
                  "type": "object",
                  "properties": {
                    "role": {
                      "type": "string",
                      "const": "user"
                    },
                    "content": {
                      "type": "string",
                      "minLength": 1,
                      "x-trimmedMaxLength": 1800,
                      "x-trimmedMinLength": 1,
                      "description": "Пробелы по краям удаляются. Длина после удаления: 1–1800 символов. Управляющие символы, кроме табуляции и перевода строки, запрещены."
                    }
                  },
                  "required": [
                    "role",
                    "content"
                  ],
                  "additionalProperties": false
                },
                {
                  "type": "object",
                  "properties": {
                    "role": {
                      "type": "string",
                      "const": "assistant"
                    },
                    "content": {
                      "type": "string",
                      "minLength": 1,
                      "x-trimmedMaxLength": 3000,
                      "x-trimmedMinLength": 1,
                      "description": "Пробелы по краям удаляются. Длина после удаления: 1–3000 символов. Управляющие символы, кроме табуляции и перевода строки, запрещены."
                    }
                  },
                  "required": [
                    "role",
                    "content"
                  ],
                  "additionalProperties": false
                }
              ]
            }
          },
          "pageContext": {
            "type": "string",
            "minLength": 1,
            "x-trimmedMaxLength": 80,
            "x-trimmedMinLength": 1,
            "description": "Короткое название раздела после trim, 1–80 символов. Разрешены буквы, цифры, пробелы и ·.,—–-:(). Переносы строк, URL, query-параметры и HTML запрещены. Не передавайте токены или секреты.",
            "pattern": "^[\\p{L}\\p{N}\\s·.,—–\\-:()]+$",
            "not": {
              "pattern": "[\\r\\n]"
            }
          }
        },
        "required": [
          "question"
        ],
        "additionalProperties": false
      },
      "SupportSource": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "pattern": "^/(?:ru/|en/)?docs/[^/]+$",
            "description": "Относительная ссылка на статью опубликованной базы знаний."
          }
        },
        "required": [
          "id",
          "title",
          "url"
        ],
        "additionalProperties": false
      },
      "SearchSupportAnswer": {
        "type": "object",
        "properties": {
          "mode": {
            "type": "string",
            "const": "search"
          },
          "answer": {
            "type": "string"
          },
          "sources": {
            "type": "array",
            "maxItems": 3,
            "items": {
              "$ref": "#/components/schemas/SupportSource"
            }
          },
          "knowledgeVersion": {
            "type": [
              "string",
              "null"
            ]
          },
          "needsHuman": {
            "type": "boolean"
          },
          "aiUnavailable": {
            "type": "boolean",
            "const": true
          }
        },
        "required": [
          "mode",
          "answer",
          "sources",
          "knowledgeVersion",
          "needsHuman"
        ],
        "additionalProperties": false
      },
      "AISupportAnswer": {
        "type": "object",
        "properties": {
          "mode": {
            "type": "string",
            "const": "ai"
          },
          "answer": {
            "type": "string",
            "minLength": 1,
            "maxLength": 6000,
            "description": "Обычный текст; URL и HTML не принимаются. Ссылки возвращаются только в sources."
          },
          "sources": {
            "type": "array",
            "maxItems": 25,
            "uniqueItems": true,
            "items": {
              "$ref": "#/components/schemas/SupportSource"
            }
          },
          "knowledgeVersion": {
            "type": "string"
          },
          "needsHuman": {
            "type": "boolean"
          }
        },
        "required": [
          "mode",
          "answer",
          "sources",
          "knowledgeVersion",
          "needsHuman"
        ],
        "additionalProperties": false,
        "allOf": [
          {
            "if": {
              "properties": {
                "needsHuman": {
                  "const": false
                }
              }
            },
            "then": {
              "properties": {
                "sources": {
                  "minItems": 1
                }
              }
            }
          }
        ]
      },
      "SupportAnswer": {
        "oneOf": [
          {
            "$ref": "#/components/schemas/SearchSupportAnswer"
          },
          {
            "$ref": "#/components/schemas/AISupportAnswer"
          }
        ]
      },
      "Ticket": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^tkt_[a-f0-9-]{36}$"
          },
          "subject": {
            "type": "string"
          },
          "message": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "open",
              "answered",
              "closed"
            ],
            "description": "answered обозначает отвеченное обращение. Через публичный API пользователь может только закрыть собственное обращение."
          },
          "source": {
            "type": "string",
            "enum": [
              "web",
              "telegram"
            ]
          },
          "createdAt": {
            "type": "integer",
            "minimum": 0,
            "description": "Unix timestamp в миллисекундах, UTC."
          },
          "updatedAt": {
            "type": "integer",
            "minimum": 0,
            "description": "Unix timestamp в миллисекундах, UTC."
          }
        },
        "required": [
          "id",
          "subject",
          "message",
          "status",
          "source",
          "createdAt",
          "updatedAt"
        ],
        "additionalProperties": false
      },
      "TicketResponse": {
        "type": "object",
        "properties": {
          "ticket": {
            "$ref": "#/components/schemas/Ticket"
          }
        },
        "required": [
          "ticket"
        ],
        "additionalProperties": false
      },
      "Notification": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^ntf_[A-Za-z0-9-]{1,80}$"
          },
          "kind": {
            "type": "string",
            "enum": [
              "payments",
              "payouts",
              "support",
              "security",
              "test"
            ]
          },
          "message": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "sending",
              "sent",
              "failed"
            ],
            "description": "Состояние доставки Telegram; независимо от прочтения на сайте."
          },
          "createdAt": {
            "type": "integer",
            "minimum": 0,
            "description": "Unix timestamp в миллисекундах, UTC."
          },
          "sentAt": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "Unix timestamp в миллисекундах, UTC."
          },
          "readAt": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "Время первого прочтения на сайте; null — непрочитано. Не является подтверждением прочтения в Telegram."
          }
        },
        "required": [
          "id",
          "kind",
          "message",
          "status",
          "createdAt",
          "sentAt",
          "readAt"
        ],
        "additionalProperties": false
      },
      "NotificationsPage": {
        "type": "object",
        "properties": {
          "notifications": {
            "type": "array",
            "maxItems": 30,
            "items": {
              "$ref": "#/components/schemas/Notification"
            }
          },
          "unreadCount": {
            "type": "integer",
            "minimum": 0
          },
          "nextCursor": {
            "type": [
              "string",
              "null"
            ],
            "description": "Курсор следующей страницы; null, если больше записей нет."
          }
        },
        "required": [
          "notifications",
          "unreadCount",
          "nextCursor"
        ],
        "additionalProperties": false
      },
      "ReadNotifications": {
        "oneOf": [
          {
            "type": "object",
            "properties": {
              "ids": {
                "type": "array",
                "minItems": 1,
                "maxItems": 100,
                "description": "Дубликаты допустимы и учитываются один раз.",
                "items": {
                  "type": "string",
                  "pattern": "^ntf_[A-Za-z0-9-]{1,80}$"
                }
              }
            },
            "required": [
              "ids"
            ],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "all": {
                "type": "boolean",
                "const": true
              },
              "before": {
                "type": "integer",
                "minimum": 0,
                "description": "createdAt последнего уже показанного события. Сервер дополнительно требует before <= Date.now().",
                "maximum": 9007199254740991
              }
            },
            "required": [
              "all",
              "before"
            ],
            "additionalProperties": false
          }
        ]
      },
      "ReadNotificationsResult": {
        "type": "object",
        "properties": {
          "updated": {
            "type": "integer",
            "minimum": 0
          },
          "readAt": {
            "type": "integer",
            "minimum": 0,
            "description": "Unix timestamp в миллисекундах, UTC."
          },
          "unreadCount": {
            "type": "integer",
            "minimum": 0
          }
        },
        "required": [
          "updated",
          "readAt",
          "unreadCount"
        ],
        "additionalProperties": false
      },
      "TelegramUpdate": {
        "type": "object",
        "properties": {
          "update_id": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991
          },
          "message": {
            "type": "object",
            "additionalProperties": true,
            "description": "Telegram Message: обработчик использует message_id, text, from и chat."
          },
          "callback_query": {
            "type": "object",
            "additionalProperties": true,
            "description": "Telegram CallbackQuery: обработчик использует id, from, data и message.chat."
          }
        },
        "required": [
          "update_id"
        ],
        "additionalProperties": true
      },
      "IncomingQuote": {
        "type": "object",
        "properties": {
          "amountMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Целое количество минимальных денежных единиц."
          },
          "baseMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Целое количество минимальных денежных единиц."
          },
          "grossMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Целое количество минимальных денежных единиц."
          },
          "percentageFeeMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Целое количество минимальных денежных единиц."
          },
          "fixedFeeMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Целое количество минимальных денежных единиц."
          },
          "nominalFeeMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Целое количество минимальных денежных единиц."
          },
          "feeMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Целое количество минимальных денежных единиц."
          },
          "vatMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Целое количество минимальных денежных единиц."
          },
          "customerVatMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Целое количество минимальных денежных единиц."
          },
          "merchantVatMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Целое количество минимальных денежных единиц."
          },
          "customerTotalMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Целое количество минимальных денежных единиц."
          },
          "merchantDeductionMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Целое количество минимальных денежных единиц."
          },
          "totalFeeMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Целое количество минимальных денежных единиц."
          },
          "netMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Целое количество минимальных денежных единиц."
          },
          "currency": {
            "type": "string",
            "enum": [
              "USD",
              "RUB",
              "USDT"
            ],
            "description": "Invoice units: USD cents, RUB kopecks, or hundredths of USDT. No automatic currency conversion."
          },
          "method": {
            "type": "string",
            "enum": [
              "card",
              "alipay",
              "sbp",
              "crypto"
            ]
          },
          "vatPayer": {
            "type": "string",
            "enum": [
              "customer",
              "merchant",
              "shared"
            ]
          },
          "vatApplies": {
            "type": "boolean"
          },
          "pricingVersion": {
            "type": "integer",
            "minimum": 1,
            "description": "Версия расчёта, сохранённая вместе со счётом."
          },
          "vatCustomerPercent": {
            "type": "integer",
            "minimum": 0,
            "maximum": 100,
            "description": "Customer share, as a whole percentage. 0 means the merchant covers everything; 100 means the customer covers everything. Default: the store’s legacy VAT preference."
          },
          "feeCustomerPercent": {
            "type": "integer",
            "minimum": 0,
            "maximum": 100,
            "description": "Customer share, as a whole percentage. 0 means the merchant covers everything; 100 means the customer covers everything.",
            "default": 0
          },
          "customerFeeMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Целое количество минимальных денежных единиц."
          },
          "merchantFeeMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Целое количество минимальных денежных единиц."
          }
        },
        "required": [
          "amountMinor",
          "baseMinor",
          "grossMinor",
          "percentageFeeMinor",
          "fixedFeeMinor",
          "nominalFeeMinor",
          "feeMinor",
          "vatMinor",
          "customerVatMinor",
          "merchantVatMinor",
          "customerTotalMinor",
          "merchantDeductionMinor",
          "totalFeeMinor",
          "netMinor",
          "currency",
          "method",
          "vatPayer",
          "vatApplies",
          "pricingVersion"
        ],
        "additionalProperties": false
      },
      "PaymentLink": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^lnk_[0-9a-f-]{36}$"
          },
          "title": {
            "type": "string",
            "minLength": 1,
            "maxLength": 120
          },
          "description": {
            "type": "string",
            "maxLength": 500
          },
          "merchantName": {
            "type": "string"
          },
          "amountMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Целое количество минимальных денежных единиц."
          },
          "currency": {
            "type": "string",
            "enum": [
              "USD",
              "RUB",
              "USDT"
            ],
            "description": "Invoice units: USD cents, RUB kopecks, or hundredths of USDT. No automatic currency conversion."
          },
          "vatPayer": {
            "type": "string",
            "enum": [
              "customer",
              "merchant",
              "shared"
            ]
          },
          "methods": {
            "type": "array",
            "minItems": 1,
            "maxItems": 3,
            "uniqueItems": true,
            "items": {
              "type": "string",
              "enum": [
                "card",
                "alipay",
                "sbp",
                "crypto"
              ]
            }
          },
          "quotes": {
            "type": "object",
            "properties": {
              "card": {
                "$ref": "#/components/schemas/IncomingQuote"
              },
              "alipay": {
                "$ref": "#/components/schemas/IncomingQuote"
              },
              "sbp": {
                "$ref": "#/components/schemas/IncomingQuote"
              },
              "crypto": {
                "$ref": "#/components/schemas/IncomingQuote"
              }
            },
            "required": [],
            "additionalProperties": false
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "paused",
              "expired",
              "cancelled"
            ],
            "description": "expired определяется expiresAt при чтении. cancelled окончательный."
          },
          "createdAt": {
            "type": "integer",
            "minimum": 0,
            "description": "Unix timestamp в миллисекундах, UTC."
          },
          "updatedAt": {
            "type": "integer",
            "minimum": 0,
            "description": "Unix timestamp в миллисекундах, UTC."
          },
          "expiresAt": {
            "type": "integer",
            "minimum": 0,
            "description": "Unix timestamp в миллисекундах, UTC."
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Публичная страница /pay/{token} на APP_ORIGIN."
          },
          "vatCustomerPercent": {
            "type": "integer",
            "minimum": 0,
            "maximum": 100,
            "description": "Customer share, as a whole percentage. 0 means the merchant covers everything; 100 means the customer covers everything. Default: the store’s legacy VAT preference."
          },
          "feeCustomerPercent": {
            "type": "integer",
            "minimum": 0,
            "maximum": 100,
            "description": "Customer share, as a whole percentage. 0 means the merchant covers everything; 100 means the customer covers everything.",
            "default": 0
          },
          "orderId": {
            "type": "string",
            "maxLength": 100,
            "description": "Buyer-visible order reference."
          },
          "metadata": {
            "type": "object",
            "maxProperties": 10,
            "propertyNames": {
              "pattern": "^[A-Za-z0-9_-]{1,40}$"
            },
            "additionalProperties": {
              "type": "string",
              "maxLength": 500
            },
            "description": "Private merchant metadata. At most 3000 UTF-8 bytes after JSON serialization. Never exposed in public checkout."
          },
          "checkoutUrl": {
            "type": "string",
            "format": "uri"
          },
          "payment": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/PaymentSummary"
              },
              {
                "type": "null"
              }
            ],
            "description": "Included by owner list/detail GET requests. The invoice lifecycle is independent of the verified payment status. Does not contain card, bank-code, QR or buyer details."
          }
        },
        "required": [
          "id",
          "title",
          "description",
          "merchantName",
          "amountMinor",
          "currency",
          "vatPayer",
          "methods",
          "quotes",
          "status",
          "createdAt",
          "updatedAt",
          "expiresAt",
          "url",
          "vatCustomerPercent",
          "feeCustomerPercent",
          "orderId",
          "metadata",
          "checkoutUrl"
        ],
        "additionalProperties": false
      },
      "CreatePaymentLink": {
        "oneOf": [
          {
            "type": "object",
            "properties": {
              "title": {
                "type": "string",
                "minLength": 1,
                "x-trimmedMaxLength": 120,
                "x-trimmedMinLength": 1,
                "description": "Пробелы по краям удаляются. Длина после удаления: 1–120 символов. Управляющие символы, кроме табуляции и перевода строки, запрещены."
              },
              "description": {
                "type": "string",
                "x-trimmedMaxLength": 500,
                "description": "Необязательно; пустая строка разрешена. До 500 символов после trim."
              },
              "amountMinor": {
                "type": "integer",
                "minimum": 1,
                "maximum": 10000000000,
                "description": "Техническая граница целого значения, не коммерческий лимит провайдера. Отрицательное зачисление отклоняется."
              },
              "vatPayer": {
                "type": "string",
                "enum": [
                  "customer",
                  "merchant"
                ],
                "description": "При отсутствии сохраняется правило текущего магазина."
              },
              "expiresAt": {
                "type": "integer",
                "minimum": 0,
                "description": "В будущем, максимум 90 дней от момента создания. По умолчанию 7 дней. Срок сохраняется в снимке счёта."
              },
              "currency": {
                "type": "string",
                "const": "USD"
              },
              "methods": {
                "type": "array",
                "minItems": 1,
                "maxItems": 3,
                "uniqueItems": true,
                "items": {
                  "type": "string",
                  "enum": [
                    "card",
                    "alipay",
                    "crypto"
                  ]
                },
                "description": "New USD checkout supports card and Alipay. USD crypto invoices are accepted only for compatibility and return crypto_requires_usdt at live checkout; use USDT for crypto."
              },
              "vatCustomerPercent": {
                "type": "integer",
                "minimum": 0,
                "maximum": 100,
                "description": "Customer share, as a whole percentage. 0 means the merchant covers everything; 100 means the customer covers everything. Default: the store’s legacy VAT preference."
              },
              "feeCustomerPercent": {
                "type": "integer",
                "minimum": 0,
                "maximum": 100,
                "description": "Customer share, as a whole percentage. 0 means the merchant covers everything; 100 means the customer covers everything.",
                "default": 0
              },
              "orderId": {
                "type": "string",
                "maxLength": 100,
                "description": "Buyer-visible order reference."
              },
              "metadata": {
                "type": "object",
                "maxProperties": 10,
                "propertyNames": {
                  "pattern": "^[A-Za-z0-9_-]{1,40}$"
                },
                "additionalProperties": {
                  "type": "string",
                  "maxLength": 500
                },
                "description": "Private merchant metadata. At most 3000 UTF-8 bytes after JSON serialization. Never exposed in public checkout."
              }
            },
            "required": [
              "title",
              "amountMinor",
              "currency",
              "methods"
            ],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "title": {
                "type": "string",
                "minLength": 1,
                "x-trimmedMaxLength": 120,
                "x-trimmedMinLength": 1,
                "description": "Пробелы по краям удаляются. Длина после удаления: 1–120 символов. Управляющие символы, кроме табуляции и перевода строки, запрещены."
              },
              "description": {
                "type": "string",
                "x-trimmedMaxLength": 500,
                "description": "Необязательно; пустая строка разрешена. До 500 символов после trim."
              },
              "amountMinor": {
                "type": "integer",
                "minimum": 1,
                "maximum": 10000000000,
                "description": "Техническая граница целого значения, не коммерческий лимит провайдера. Отрицательное зачисление отклоняется."
              },
              "vatPayer": {
                "type": "string",
                "enum": [
                  "customer",
                  "merchant"
                ],
                "description": "При отсутствии сохраняется правило текущего магазина."
              },
              "expiresAt": {
                "type": "integer",
                "minimum": 0,
                "description": "В будущем, максимум 90 дней от момента создания. По умолчанию 7 дней. Срок сохраняется в снимке счёта."
              },
              "currency": {
                "type": "string",
                "const": "RUB"
              },
              "methods": {
                "type": "array",
                "minItems": 1,
                "maxItems": 1,
                "uniqueItems": true,
                "items": {
                  "type": "string",
                  "const": "sbp"
                }
              },
              "vatCustomerPercent": {
                "type": "integer",
                "minimum": 0,
                "maximum": 100,
                "description": "Customer share, as a whole percentage. 0 means the merchant covers everything; 100 means the customer covers everything. Default: the store’s legacy VAT preference."
              },
              "feeCustomerPercent": {
                "type": "integer",
                "minimum": 0,
                "maximum": 100,
                "description": "Customer share, as a whole percentage. 0 means the merchant covers everything; 100 means the customer covers everything.",
                "default": 0
              },
              "orderId": {
                "type": "string",
                "maxLength": 100,
                "description": "Buyer-visible order reference."
              },
              "metadata": {
                "type": "object",
                "maxProperties": 10,
                "propertyNames": {
                  "pattern": "^[A-Za-z0-9_-]{1,40}$"
                },
                "additionalProperties": {
                  "type": "string",
                  "maxLength": 500
                },
                "description": "Private merchant metadata. At most 3000 UTF-8 bytes after JSON serialization. Never exposed in public checkout."
              }
            },
            "required": [
              "title",
              "amountMinor",
              "currency",
              "methods"
            ],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "title": {
                "type": "string",
                "minLength": 1,
                "x-trimmedMaxLength": 120,
                "x-trimmedMinLength": 1,
                "description": "Пробелы по краям удаляются. Длина после удаления: 1–120 символов. Управляющие символы, кроме табуляции и перевода строки, запрещены."
              },
              "description": {
                "type": "string",
                "x-trimmedMaxLength": 500,
                "description": "Необязательно; пустая строка разрешена. До 500 символов после trim."
              },
              "amountMinor": {
                "type": "integer",
                "minimum": 1,
                "maximum": 10000000000,
                "description": "Техническая граница целого значения, не коммерческий лимит провайдера. Отрицательное зачисление отклоняется."
              },
              "vatPayer": {
                "type": "string",
                "enum": [
                  "customer",
                  "merchant"
                ],
                "description": "При отсутствии сохраняется правило текущего магазина."
              },
              "expiresAt": {
                "type": "integer",
                "minimum": 0,
                "description": "В будущем, максимум 90 дней от момента создания. По умолчанию 7 дней. Срок сохраняется в снимке счёта."
              },
              "currency": {
                "type": "string",
                "const": "USDT"
              },
              "methods": {
                "type": "array",
                "minItems": 1,
                "maxItems": 1,
                "uniqueItems": true,
                "items": {
                  "type": "string",
                  "const": "crypto"
                }
              },
              "vatCustomerPercent": {
                "type": "integer",
                "minimum": 0,
                "maximum": 100,
                "description": "Customer share, as a whole percentage. 0 means the merchant covers everything; 100 means the customer covers everything. Default: the store’s legacy VAT preference."
              },
              "feeCustomerPercent": {
                "type": "integer",
                "minimum": 0,
                "maximum": 100,
                "description": "Customer share, as a whole percentage. 0 means the merchant covers everything; 100 means the customer covers everything.",
                "default": 0
              },
              "orderId": {
                "type": "string",
                "maxLength": 100,
                "description": "Buyer-visible order reference."
              },
              "metadata": {
                "type": "object",
                "maxProperties": 10,
                "propertyNames": {
                  "pattern": "^[A-Za-z0-9_-]{1,40}$"
                },
                "additionalProperties": {
                  "type": "string",
                  "maxLength": 500
                },
                "description": "Private merchant metadata. At most 3000 UTF-8 bytes after JSON serialization. Never exposed in public checkout."
              }
            },
            "required": [
              "title",
              "amountMinor",
              "currency",
              "methods"
            ],
            "additionalProperties": false
          }
        ],
        "description": "Amounts use minor units. Fee and VAT are calculated on the base order amount. The customer share is rounded half-up; the merchant covers the exact remainder. A conflicting legacy vatPayer and vatCustomerPercent is rejected. Allocation is immutable after creation; issue a new invoice to change it. Live card/Alipay requires vatCustomerPercent=100 and feeCustomerPercent=0 because the configured gateway cannot override its exclusive tax. Other saved allocations return unsupported_allocation; they are never silently changed. SBP and USDT crypto support fee allocation. Use the public invoice availability object before collecting payment details.",
        "examples": [
          {
            "title": "Order 1042",
            "amountMinor": 500,
            "currency": "USD",
            "methods": [
              "card",
              "alipay"
            ],
            "vatCustomerPercent": 100,
            "feeCustomerPercent": 0,
            "orderId": "1042"
          },
          {
            "title": "Order 1043",
            "amountMinor": 1000,
            "currency": "USDT",
            "methods": [
              "crypto"
            ],
            "feeCustomerPercent": 23,
            "orderId": "1043"
          }
        ]
      },
      "PaymentLinkResponse": {
        "type": "object",
        "properties": {
          "link": {
            "$ref": "#/components/schemas/PaymentLink"
          },
          "checkoutUrl": {
            "type": "string",
            "format": "uri",
            "description": "Included in status-update responses; the nested link always contains its checkoutUrl."
          }
        },
        "required": [
          "link"
        ],
        "additionalProperties": false
      },
      "CreatePaymentLinkResponse": {
        "type": "object",
        "properties": {
          "link": {
            "$ref": "#/components/schemas/PaymentLink"
          },
          "replayed": {
            "type": "boolean"
          },
          "checkoutUrl": {
            "type": "string",
            "format": "uri",
            "description": "The payment link is available immediately; no polling is required."
          }
        },
        "required": [
          "link",
          "replayed",
          "checkoutUrl"
        ],
        "additionalProperties": false
      },
      "PaymentLinksPage": {
        "type": "object",
        "properties": {
          "links": {
            "type": "array",
            "maxItems": 100,
            "items": {
              "$ref": "#/components/schemas/PaymentLink"
            }
          },
          "nextCursor": {
            "type": [
              "string",
              "null"
            ],
            "description": "Непрозрачный курсор следующей страницы. Передавайте как query с URL-кодированием; null означает конец."
          }
        },
        "required": [
          "links",
          "nextCursor"
        ],
        "additionalProperties": false
      },
      "CheckoutQuote": {
        "type": "object",
        "properties": {
          "method": {
            "type": "string",
            "enum": [
              "card",
              "alipay",
              "sbp",
              "crypto"
            ]
          },
          "amountMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Целое количество минимальных денежных единиц."
          },
          "vatMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Целое количество минимальных денежных единиц."
          },
          "customerVatMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Целое количество минимальных денежных единиц."
          },
          "customerTotalMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Целое количество минимальных денежных единиц."
          },
          "vatApplies": {
            "type": "boolean"
          },
          "pricingVersion": {
            "type": "integer",
            "minimum": 1,
            "description": "Версия расчёта, сохранённая вместе со счётом."
          },
          "customerFeeMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Целое количество минимальных денежных единиц."
          },
          "merchantCoveredMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Целое количество минимальных денежных единиц."
          }
        },
        "required": [
          "method",
          "amountMinor",
          "vatMinor",
          "customerVatMinor",
          "customerTotalMinor",
          "vatApplies",
          "pricingVersion",
          "customerFeeMinor",
          "merchantCoveredMinor"
        ],
        "additionalProperties": false
      },
      "CheckoutInvoice": {
        "type": "object",
        "properties": {
          "token": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{43}$"
          },
          "title": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "merchantName": {
            "type": "string"
          },
          "amountMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Целое количество минимальных денежных единиц."
          },
          "currency": {
            "type": "string",
            "enum": [
              "USD",
              "RUB",
              "USDT"
            ],
            "description": "Invoice units: USD cents, RUB kopecks, or hundredths of USDT. No automatic currency conversion."
          },
          "vatPayer": {
            "type": "string",
            "enum": [
              "customer",
              "merchant",
              "shared"
            ]
          },
          "methods": {
            "type": "array",
            "minItems": 1,
            "maxItems": 3,
            "items": {
              "type": "string",
              "enum": [
                "card",
                "alipay",
                "sbp",
                "crypto"
              ]
            }
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "paused",
              "expired",
              "cancelled"
            ],
            "description": "expired определяется expiresAt при чтении. cancelled окончательный."
          },
          "expiresAt": {
            "type": "integer",
            "minimum": 0,
            "description": "Unix timestamp в миллисекундах, UTC."
          },
          "createdAt": {
            "type": "integer",
            "minimum": 0,
            "description": "Unix timestamp в миллисекундах, UTC."
          },
          "quote": {
            "$ref": "#/components/schemas/CheckoutQuote"
          },
          "gatewayConnected": {
            "type": "boolean",
            "description": "Compatibility alias for availability.available, not a gateway health probe."
          },
          "vatCustomerPercent": {
            "type": "integer",
            "minimum": 0,
            "maximum": 100,
            "description": "Customer share, as a whole percentage. 0 means the merchant covers everything; 100 means the customer covers everything. Default: the store’s legacy VAT preference."
          },
          "feeCustomerPercent": {
            "type": "integer",
            "minimum": 0,
            "maximum": 100,
            "description": "Customer share, as a whole percentage. 0 means the merchant covers everything; 100 means the customer covers everything.",
            "default": 0
          },
          "orderId": {
            "type": "string",
            "maxLength": 100,
            "description": "Buyer-visible order reference."
          },
          "availability": {
            "$ref": "#/components/schemas/CheckoutAvailability"
          }
        },
        "required": [
          "token",
          "title",
          "description",
          "merchantName",
          "amountMinor",
          "currency",
          "vatPayer",
          "methods",
          "status",
          "expiresAt",
          "createdAt",
          "quote",
          "gatewayConnected",
          "vatCustomerPercent",
          "feeCustomerPercent",
          "orderId",
          "availability"
        ],
        "additionalProperties": false
      },
      "MerchantKey": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^key_[0-9a-f-]{36}$"
          },
          "name": {
            "type": "string"
          },
          "prefix": {
            "type": "string"
          },
          "scopes": {
            "type": "array",
            "minItems": 1,
            "maxItems": 3,
            "uniqueItems": true,
            "items": {
              "type": "string",
              "enum": [
                "invoices:read",
                "invoices:write",
                "events:read"
              ]
            }
          },
          "createdAt": {
            "type": "integer",
            "minimum": 0,
            "description": "Unix timestamp в миллисекундах, UTC."
          },
          "expiresAt": {
            "type": "integer",
            "minimum": 0,
            "description": "Unix timestamp в миллисекундах, UTC."
          },
          "revokedAt": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "Unix timestamp в миллисекундах, UTC."
          },
          "lastUsedAt": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "Unix timestamp в миллисекундах, UTC."
          }
        },
        "required": [
          "id",
          "name",
          "prefix",
          "scopes",
          "createdAt",
          "expiresAt"
        ],
        "additionalProperties": false
      },
      "MerchantEvent": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^evt_[a-f0-9]{40}$"
          },
          "type": {
            "type": "string",
            "enum": [
              "invoice.created",
              "invoice.updated",
              "payment.succeeded",
              "payment.failed",
              "payment.refunded",
              "payment.partially_refunded",
              "payment.disputed",
              "payment.review_required"
            ]
          },
          "apiVersion": {
            "type": "string",
            "const": "2026-10-21"
          },
          "createdAt": {
            "type": "integer",
            "minimum": 0,
            "description": "Unix timestamp в миллисекундах, UTC."
          },
          "livemode": {
            "type": "boolean"
          },
          "data": {
            "type": "object",
            "additionalProperties": true,
            "description": "invoice.created/updated: persisted merchant invoice, including private metadata. payment events: verified payment facts. See the webhook guide for examples."
          }
        },
        "required": [
          "id",
          "type",
          "apiVersion",
          "createdAt",
          "livemode",
          "data"
        ],
        "additionalProperties": false
      },
      "WebhookEndpoint": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^wh_[0-9a-f-]{36}$"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "description": {
            "type": "string"
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "invoice.created",
                "invoice.updated",
                "payment.succeeded",
                "payment.failed",
                "payment.refunded",
                "payment.partially_refunded",
                "payment.disputed",
                "payment.review_required"
              ]
            }
          },
          "status": {
            "type": "string",
            "enum": [
              "unverified",
              "active",
              "paused"
            ]
          },
          "createdAt": {
            "type": "integer",
            "minimum": 0,
            "description": "Unix timestamp в миллисекундах, UTC."
          },
          "verifiedAt": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "Unix timestamp в миллисекундах, UTC."
          }
        },
        "required": [
          "id",
          "url",
          "description",
          "events",
          "status",
          "createdAt",
          "verifiedAt"
        ],
        "additionalProperties": false
      },
      "WebhookDelivery": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "event_id": {
            "type": "string"
          },
          "endpoint_id": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "invoice.created",
              "invoice.updated",
              "payment.succeeded",
              "payment.failed",
              "payment.refunded",
              "payment.partially_refunded",
              "payment.disputed",
              "payment.review_required"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "sending",
              "delivered",
              "failed",
              "cancelled"
            ]
          },
          "attempts": {
            "type": "integer",
            "minimum": 0,
            "maximum": 6
          },
          "next_attempt_at": {
            "type": "integer",
            "minimum": 0,
            "description": "Unix timestamp в миллисекундах, UTC."
          },
          "last_status": {
            "type": [
              "integer",
              "null"
            ]
          },
          "last_error": {
            "type": [
              "string",
              "null"
            ]
          },
          "created_at": {
            "type": "integer",
            "minimum": 0,
            "description": "Unix timestamp в миллисекундах, UTC."
          },
          "delivered_at": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "Unix timestamp в миллисекундах, UTC."
          }
        },
        "required": [
          "id",
          "event_id",
          "endpoint_id",
          "type",
          "status",
          "attempts"
        ],
        "additionalProperties": false
      },
      "Application": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^app_[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
          },
          "websiteUrl": {
            "type": "string",
            "format": "uri",
            "maxLength": 2048
          },
          "businessName": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "businessType": {
            "type": "string",
            "enum": [
              "digital_goods",
              "software",
              "services",
              "physical_goods",
              "education",
              "other"
            ]
          },
          "description": {
            "type": "string",
            "minLength": 40,
            "maxLength": 3000
          },
          "contactTelegram": {
            "type": "string",
            "pattern": "^@[A-Za-z][A-Za-z0-9_]{4,31}$"
          },
          "status": {
            "type": "string",
            "enum": [
              "processing",
              "needs_review",
              "approved",
              "rejected"
            ]
          },
          "currentStage": {
            "type": "string",
            "enum": [
              "received",
              "ai_review",
              "technical_review",
              "manual_review"
            ]
          },
          "version": {
            "type": "integer",
            "minimum": 1
          },
          "reason": {
            "type": "string",
            "description": "User-facing stage message or moderator-edited decline reason. Internal evidence is excluded."
          },
          "createdAt": {
            "type": "integer",
            "minimum": 0,
            "description": "Unix timestamp в миллисекундах, UTC."
          },
          "updatedAt": {
            "type": "integer",
            "minimum": 0,
            "description": "Unix timestamp в миллисекундах, UTC."
          },
          "stages": {
            "type": "array",
            "minItems": 4,
            "maxItems": 4,
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string",
                  "enum": [
                    "received",
                    "ai_review",
                    "technical_review",
                    "manual_review"
                  ]
                },
                "state": {
                  "type": "string",
                  "enum": [
                    "pending",
                    "running",
                    "complete",
                    "review",
                    "rejected"
                  ]
                },
                "message": {
                  "type": "string"
                },
                "updatedAt": {
                  "type": [
                    "integer",
                    "null"
                  ],
                  "minimum": 0,
                  "description": "Unix timestamp в миллисекундах, UTC."
                }
              },
              "required": [
                "id",
                "state",
                "message",
                "updatedAt"
              ],
              "additionalProperties": false
            }
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Private, explicit-locale tracking URL. Knowing the URL does not grant access."
          },
          "notificationCategory": {
            "type": "string",
            "const": "support"
          },
          "canResume": {
            "type": "boolean"
          }
        },
        "required": [
          "id",
          "websiteUrl",
          "businessName",
          "businessType",
          "description",
          "contactTelegram",
          "status",
          "currentStage",
          "version",
          "reason",
          "createdAt",
          "updatedAt",
          "stages",
          "url",
          "notificationCategory",
          "canResume"
        ],
        "additionalProperties": false
      },
      "ApplicationEvent": {
        "type": "object",
        "properties": {
          "version": {
            "type": "integer",
            "minimum": 1
          },
          "stage": {
            "type": "string",
            "enum": [
              "received",
              "ai_review",
              "technical_review",
              "manual_review"
            ]
          },
          "state": {
            "type": "string",
            "enum": [
              "pending",
              "running",
              "complete",
              "review",
              "rejected"
            ]
          },
          "message": {
            "type": "string"
          },
          "createdAt": {
            "type": "integer",
            "minimum": 0,
            "description": "Unix timestamp в миллисекундах, UTC."
          }
        },
        "required": [
          "version",
          "stage",
          "state",
          "message",
          "createdAt"
        ],
        "additionalProperties": false
      },
      "PaymentSummary": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Canonical gateway payment ID when known; otherwise the local gwp_ operation ID."
          },
          "method": {
            "type": "string",
            "enum": [
              "card",
              "alipay",
              "sbp",
              "crypto"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "requires_action",
              "processing",
              "succeeded",
              "failed",
              "expired",
              "review_required",
              "partially_paid",
              "partially_refunded",
              "refunded",
              "disputed"
            ]
          },
          "amountMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Целое количество минимальных денежных единиц."
          },
          "currency": {
            "type": "string",
            "enum": [
              "USD",
              "RUB",
              "USDT"
            ],
            "description": "Invoice units: USD cents, RUB kopecks, or hundredths of USDT. No automatic currency conversion."
          },
          "fulfillmentReady": {
            "type": "boolean"
          },
          "updatedAt": {
            "type": "integer",
            "minimum": 0,
            "description": "Unix timestamp в миллисекундах, UTC."
          },
          "refundedAmountMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Целое количество минимальных денежных единиц."
          }
        },
        "required": [
          "id",
          "method",
          "status",
          "amountMinor",
          "currency",
          "fulfillmentReady",
          "updatedAt"
        ],
        "additionalProperties": false
      },
      "CheckoutAvailability": {
        "type": "object",
        "properties": {
          "available": {
            "type": "boolean"
          },
          "code": {
            "type": "string",
            "enum": [
              "ready",
              "not_configured",
              "unsupported_allocation",
              "crypto_requires_usdt",
              "amount_out_of_range",
              "merchant_not_approved"
            ]
          },
          "flow": {
            "type": "string",
            "enum": [
              "encrypted_card",
              "qr",
              "crypto"
            ]
          },
          "minAmountMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Целое количество минимальных денежных единиц."
          },
          "maxAmountMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Целое количество минимальных денежных единиц."
          },
          "limitsSource": {
            "type": "string",
            "const": "adapter",
            "description": "Conservative limits enforced by this integration, not a claim about the upstream commercial limits."
          }
        },
        "required": [
          "available",
          "code",
          "flow",
          "minAmountMinor",
          "maxAmountMinor",
          "limitsSource"
        ],
        "additionalProperties": false
      },
      "CheckoutAction": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "redirect",
              "qr",
              "crypto"
            ]
          },
          "url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "qrImage": {
            "type": [
              "string",
              "null"
            ]
          },
          "qrPayload": {
            "type": [
              "string",
              "null"
            ]
          },
          "address": {
            "type": "string"
          },
          "amount": {
            "type": "string",
            "pattern": "^[0-9]+(?:\\.[0-9]+)?$",
            "description": "Exact transfer amount in the selected coin; preserve the decimal string without rounding or floating-point conversion."
          },
          "currency": {
            "type": "string"
          },
          "network": {
            "type": "string"
          },
          "networkLabel": {
            "type": "string"
          },
          "expiresAt": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "Unix timestamp в миллисекундах, UTC."
          },
          "addressQrImage": {
            "type": [
              "string",
              "null"
            ]
          },
          "amountQrImage": {
            "type": [
              "string",
              "null"
            ]
          },
          "amountQrPayload": {
            "type": [
              "string",
              "null"
            ]
          },
          "networkFeePaidByCustomer": {
            "type": "boolean"
          }
        },
        "required": [
          "type",
          "expiresAt"
        ],
        "additionalProperties": false
      },
      "CheckoutPayment": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^gwp_[0-9a-f-]{36}$"
          },
          "method": {
            "type": "string",
            "enum": [
              "card",
              "alipay",
              "sbp",
              "crypto"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "requires_action",
              "processing",
              "succeeded",
              "failed",
              "expired",
              "review_required",
              "partially_paid",
              "partially_refunded",
              "refunded",
              "disputed"
            ]
          },
          "providerStatus": {
            "type": "string"
          },
          "fulfillmentReady": {
            "type": "boolean",
            "description": "Only true after exact amount/currency/order binding and provider-confirmed success. A browser redirect is never payment confirmation."
          },
          "amountMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Целое количество минимальных денежных единиц."
          },
          "currency": {
            "type": "string",
            "enum": [
              "USD",
              "RUB",
              "USDT"
            ],
            "description": "Invoice units: USD cents, RUB kopecks, or hundredths of USDT. No automatic currency conversion."
          },
          "createdAt": {
            "type": "integer",
            "minimum": 0,
            "description": "Unix timestamp в миллисекундах, UTC."
          },
          "updatedAt": {
            "type": "integer",
            "minimum": 0,
            "description": "Unix timestamp в миллисекундах, UTC."
          },
          "nextAction": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/CheckoutAction"
              },
              {
                "type": "null"
              }
            ]
          },
          "expiresAt": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "Unix timestamp в миллисекундах, UTC."
          },
          "authentication": {
            "type": "object",
            "properties": {
              "required": {
                "type": "boolean"
              },
              "expiresAt": {
                "type": [
                  "integer",
                  "null"
                ],
                "minimum": 0,
                "description": "Unix timestamp в миллисекундах, UTC."
              },
              "attempt": {
                "type": "integer",
                "minimum": 0
              }
            },
            "required": [
              "required",
              "expiresAt",
              "attempt"
            ],
            "additionalProperties": false
          },
          "reason": {
            "type": "string",
            "enum": [
              "amount_mismatch",
              "confirmation_required",
              "refund_mismatch",
              "settlement_unverified"
            ]
          },
          "refundedAmountMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Целое количество минимальных денежных единиц."
          }
        },
        "required": [
          "id",
          "method",
          "status",
          "providerStatus",
          "fulfillmentReady",
          "amountMinor",
          "currency",
          "createdAt",
          "updatedAt",
          "nextAction",
          "expiresAt"
        ],
        "additionalProperties": false
      },
      "SealedCardData": {
        "type": "object",
        "properties": {
          "intent": {
            "type": "string",
            "minLength": 32,
            "maxLength": 8192,
            "description": "Signed, short-lived operation intent from /card-intent; forward unchanged."
          },
          "jwe": {
            "type": "string",
            "maxLength": 14000,
            "pattern": "^[A-Za-z0-9_-]+(?:\\.[A-Za-z0-9_-]+){4}$",
            "description": "Compact JWE using RSA-OAEP-256 and A256GCM. Protected header: kid from the public key, typ=kevmi-card+jwe. Only ciphertext is sent to Kevmi. Never send plaintext card or bank-code fields."
          }
        },
        "required": [
          "intent",
          "jwe"
        ],
        "additionalProperties": false
      },
      "CardIntent": {
        "type": "object",
        "properties": {
          "intent": {
            "type": "string",
            "minLength": 32,
            "maxLength": 8192
          },
          "intentId": {
            "type": "string",
            "maxLength": 100
          },
          "expiresAt": {
            "type": "integer",
            "minimum": 0,
            "description": "Unix timestamp в миллисекундах, UTC."
          },
          "key": {
            "type": "object",
            "properties": {
              "kid": {
                "type": "string"
              },
              "kty": {
                "type": "string",
                "const": "RSA"
              },
              "n": {
                "type": "string"
              },
              "e": {
                "type": "string"
              },
              "alg": {
                "type": "string",
                "const": "RSA-OAEP-256"
              },
              "use": {
                "type": "string",
                "const": "enc"
              }
            },
            "required": [
              "kid",
              "kty",
              "n",
              "e",
              "alg",
              "use"
            ],
            "additionalProperties": false
          },
          "algorithm": {
            "type": "string",
            "const": "RSA-OAEP-256"
          },
          "encryption": {
            "type": "string",
            "const": "A256GCM"
          },
          "protocol": {
            "type": "string",
            "const": "kevmi-card-v1"
          }
        },
        "required": [
          "intent",
          "intentId",
          "expiresAt",
          "key",
          "algorithm",
          "encryption",
          "protocol"
        ],
        "additionalProperties": false
      },
      "StartCheckoutPayment": {
        "oneOf": [
          {
            "type": "object",
            "properties": {
              "method": {
                "type": "string",
                "const": "card"
              },
              "sealed": {
                "$ref": "#/components/schemas/SealedCardData"
              }
            },
            "required": [
              "method",
              "sealed"
            ],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "method": {
                "type": "string",
                "const": "alipay"
              },
              "name": {
                "type": "string",
                "minLength": 1,
                "maxLength": 200
              },
              "country": {
                "type": "string",
                "const": "CN"
              },
              "email": {
                "type": "string",
                "format": "email",
                "maxLength": 254
              }
            },
            "required": [
              "method",
              "name",
              "country"
            ],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "method": {
                "type": "string",
                "const": "sbp"
              }
            },
            "required": [
              "method"
            ],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "method": {
                "type": "string",
                "const": "crypto"
              },
              "payerCurrency": {
                "type": "string",
                "pattern": "^[A-Z0-9]{2,16}$"
              },
              "network": {
                "type": "string",
                "pattern": "^[a-z0-9_-]{2,32}$"
              }
            },
            "required": [
              "method",
              "payerCurrency",
              "network"
            ],
            "additionalProperties": false
          }
        ]
      },
      "LegacyGatewayEvent": {
        "type": "object",
        "properties": {
          "eventId": {
            "type": "string",
            "maxLength": 100,
            "pattern": "^[A-Za-z0-9_.:-]+$"
          },
          "paymentId": {
            "type": "string",
            "maxLength": 100,
            "pattern": "^[A-Za-z0-9_.:-]+$"
          },
          "invoiceId": {
            "type": "string",
            "pattern": "^lnk_[0-9a-f-]{36}$"
          },
          "status": {
            "type": "string",
            "enum": [
              "succeeded",
              "failed",
              "refunded"
            ]
          },
          "amountMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Целое количество минимальных денежных единиц."
          },
          "currency": {
            "type": "string",
            "enum": [
              "USD",
              "RUB",
              "USDT"
            ],
            "description": "Invoice units: USD cents, RUB kopecks, or hundredths of USDT. No automatic currency conversion."
          },
          "method": {
            "type": "string",
            "enum": [
              "card",
              "alipay",
              "sbp",
              "crypto"
            ]
          },
          "occurredAt": {
            "type": "integer",
            "minimum": 0,
            "description": "Unix timestamp в миллисекундах, UTC."
          }
        },
        "required": [
          "eventId",
          "paymentId",
          "invoiceId",
          "status",
          "amountMinor",
          "currency",
          "method",
          "occurredAt"
        ],
        "additionalProperties": false
      },
      "NativeGatewayEvent": {
        "type": "object",
        "required": [
          "id",
          "api_version",
          "mode",
          "type",
          "data"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "api_version": {
            "type": "string",
            "const": "3"
          },
          "mode": {
            "type": "string",
            "const": "live"
          },
          "type": {
            "type": "string",
            "pattern": "^[a-z_.]{1,80}$"
          },
          "data": {
            "type": "object",
            "required": [
              "id",
              "version"
            ],
            "properties": {
              "id": {
                "type": "string",
                "format": "uuid"
              },
              "version": {
                "type": "integer",
                "minimum": 0
              },
              "merchant_order_id": {
                "type": "string"
              }
            }
          }
        }
      }
    }
  },
  "webhooks": {
    "merchantEvent": {
      "post": {
        "summary": "Verified merchant server delivery",
        "description": "Delivered only to active, challenge-verified endpoints. Raw JSON is signed; verify the timestamp and signature before parsing or changing order state. Return 2xx after durably accepting the event. Persist event IDs to handle duplicates. Network errors, timeout and non-2xx status trigger retries.",
        "parameters": [
          {
            "name": "Kevmi-Signature",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kevmi-Event-Id",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kevmi-Delivery-Id",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "description": "JSON-объект. Максимум 16 384 байта. Неизвестные поля отклоняются.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MerchantEvent"
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Accepted durably by the merchant server."
          }
        }
      }
    }
  }
}
