{
  "openapi": "3.1.0",
  "info": {
    "title": "Tronity One API",
    "version": "1.0.0",
    "description": "Полная справка по публичному API Tronity One: ресурсы TRON, баланс, заказы и автоматическое пополнение Energy. Схемы сверены с обработчиками запросов в репозитории; внутренние методы и callbacks поставщиков не входят в публичный контракт.\n\n## Быстрый старт\n\n1. Откройте [Tronity One в Telegram](https://t.me/tronity_one_bot), выберите **API Key** и сохраните ключ и секрет. Секрет выдаётся при создании или ротации.\n2. Пополните баланс аккаунта в сервисе. Баланс и цены API выражены в **TRX**. USD на лендинге — отдельная расчётная оценка.\n3. Настройте серверные запросы с HMAC-подписью. Ключи не вставляются в код браузера: API предназначен для подключения с вашего сервера, CORS отключён.\n4. Проверьте баланс и оцените стоимость, затем создайте заказ и отслеживайте его статус.\n\n**Адрес после смены домена:** `https://api.tronityone.energy`. Здесь опубликована статическая документация. API-сервер по этому адресу ещё не проверен; публикация справки не запускает backend. Примеры работают после подключения API-сервера. Кнопки отправки запросов отключены.\n\nПубличный health-check не требует ключа:\n\n```bash\ncurl https://api.tronityone.energy/v1/health/\n```\n\n[Скачать безопасный пример Node.js](/api-quickstart.mjs) · [Скачать OpenAPI](/openapi.ru.json)\n\n## Авторизация и подпись\n\nВсе методы, кроме `GET /v1/health/`, требуют **одновременно** API-ключ и HMAC-SHA256:\n\n| Заголовок | Значение |\n| --- | --- |\n| x-api-key | Ваш ключ |\n| x-signature | HMAC-SHA256, результат в Base64 |\n| x-timestamp | Unix-время в секундах, 10 цифр; допуск ±300 секунд |\n| x-nonce | Новый UUID на запрос; необязателен, рекомендуется. Повтор блокируется на 600 секунд |\n\nПодписывается следующая строка; для запроса без тела последняя строка и перенос перед ней отсутствуют:\n\n```text\nMETHOD\n/v1/exact/path?query=exact\nUNIX_TIMESTAMP\nJSON.stringify(body)\n```\n\nМетод передаётся в верхнем регистре. Путь включает `/v1`, фактически отправленные query-параметры и завершающий слэш. Тело приводится к `JSON.stringify(parsedBody)`: не подписывайте форматированный JSON с пробелами. Порядок ключей сохраняется; сортировки и предварительного SHA256 тела нет. Nonce не входит в подпись.\n\nРабочая структура клиента Node.js 22+; оба вызова ниже только читают баланс и рассчитывают стоимость:\n\n```javascript\nimport { createHmac, randomUUID } from 'node:crypto';\n\nconst baseUrl = 'https://api.tronityone.energy';\nconst key = process.env.TRONITY_API_KEY;\nconst secret = process.env.TRONITY_API_SECRET;\nif (!key || !secret) throw new Error('API key and secret are required');\n\nasync function request(method, path, payload) {\n  const timestamp = String(Math.floor(Date.now() / 1000));\n  const body = payload === undefined ? undefined : JSON.stringify(payload);\n  const canonical = method + '\\n' + path + '\\n' + timestamp\n    + (body === undefined ? '' : '\\n' + body);\n  const signature = createHmac('sha256', secret)\n    .update(canonical).digest('base64');\n  const response = await fetch(baseUrl + path, {\n    method,\n    headers: {\n      'x-api-key': key,\n      'x-signature': signature,\n      'x-timestamp': timestamp,\n      'x-nonce': randomUUID(),\n      ...(body === undefined ? {} : { 'content-type': 'application/json' }),\n    },\n    body,\n    signal: AbortSignal.timeout(10000),\n  });\n  const result = await response.json();\n  if (!response.ok || result.status === false) {\n    throw new Error('API request failed: ' + response.status);\n  }\n  return result;\n}\n\nconsole.log(await request('GET', '/v1/user/balance/'));\nconsole.log(await request('POST', '/v1/energy/estimate/', {\n  period: '1h', amount: 131000,\n}));\n```\n\nАвтоматически сгенерированные примеры curl ниже показывают HTTP-контракт. Для реального вызова вычисляйте новую подпись и timestamp, как в этом примере.\n\n## Сценарий заказа\n\n1. `GET /v1/user/` — проверить права и лимиты своего ключа.\n2. `GET /v1/user/wallet/` — получить адрес пополнения и баланс. Если кошелька ещё нет, метод создаёт его.\n3. `POST /v1/estimate/tx` — оценить Energy, Bandwidth и необходимость активации адреса для перевода.\n4. `POST /v1/energy/estimate/` — получить стоимость ресурса для объёма и срока.\n5. `POST /v1/energy/buy/` — купить Energy для активного адреса TRON. Этот запрос списывает средства с баланса аккаунта.\n6. `GET /v1/orders/{id}` — проверить результат или принимать webhook и сверять его с заказом.\n\nEnergy: от **65 500 до 1 310 000** единиц. Bandwidth: от **5 000**, верхняя граница не задана схемой. Периоды: `1h`, `1d`, `3d`, `7d`, по умолчанию `1h`. В ответе покупки `period` — число минут: 60, 1440, 4320 или 10080. В оценке стоимости период остаётся строкой.\n\nSmart Orders автоматически поддерживают запас Energy: `amount` и `minEnergyThreshold` от 131 000 до 1 310 000, причём amount ≥ threshold. Создание требует отдельного права `order:write`; оно не входит в стандартный набор прав ключа.\n\nПри потере ответа на покупку сначала сверяйте историю заказов. Идемпотентный ключ для покупки в текущем контракте не предусмотрен: повтор POST может создать второй заказ.\n\n## Ответы и ошибки\n\nУспех — HTTP 200, `status: true`, результат в `data`. Health возвращает только `{ \"status\": true }`. Пример баланса ниже иллюстративный, это не фактический баланс:\n\n```json\n{\n  \"status\": true,\n  \"data\": {\n    \"balance\": 100\n  }\n}\n```\n\nСтандартная ошибка имеет MIME `application/problem+json`:\n\n```json\n{\n  \"status\": false,\n  \"error\": {\n    \"title\": \"Unauthorized\",\n    \"message\": \"Invalid signature\",\n    \"statusCode\": 401\n  }\n}\n```\n\n| HTTP | Причина |\n| --- | --- |\n| 400 | Ошибка операции, недостаточный баланс или неактивный адрес |\n| 401 | Неверный ключ, подпись, время, повтор nonce, истёкший или отозванный ключ |\n| 403 | Недостаточно прав ключа |\n| 404 | Пользователь или заказ не найден |\n| 422 | Ошибка проверки тела, параметров или заголовков; error.fields содержит поля |\n| 429 | Превышен лимит; учитывайте Retry-After |\n| 500 | Внутренняя ошибка |\n\n## Лимиты и пагинация\n\nДля нового ключа по умолчанию: **600 запросов в минуту**, **10 000 в день**. Реальные настройки возвращаются в `GET /v1/user/`; дневное окно сбрасывается в полночь UTC. При 429 сервер возвращает Retry-After: 60 секунд для минутного лимита или время до полуночи для дневного.\n\nСписки заказов объявляют limit (1–20, по умолчанию 10) и offset (от 0, по умолчанию 0). В текущем коде они проверяются как числа без приведения строк из URL; явные query-параметры могут дать 422. Для начала используйте запрос без параметров. Подписывайте точную строку URL, если добавляете query.\n\n## Webhook и статусы\n\nПри покупке можно передать `webhookUrl`. Сервис отправляет POST JSON на ваш обработчик. Пример, значения условные:\n\n```json\n{\n  \"address\": \"YOUR_TRON_ADDRESS\",\n  \"txId\": null,\n  \"status\": \"ACTIVE\",\n  \"user\": {\n    \"balance\": 100\n  }\n}\n```\n\nПоля: address — адрес TRON, txId — хеш делегирования или null, status — состояние заказа, user.balance — баланс TRX. txId не становится хешем отмены делегирования при завершении заказа. В payload нет поля url.\n\nСтатусы обычного заказа: `CREATED`, `ACTIVE`, `COMPLETED`, `FAILED`, `CANCELLED`. Smart Order: `CREATED`, `ACTIVATED`, `COMPLETED`, `EXPIRED`. Даты в JSON — ISO 8601.\n\nВозвращайте 2xx для успешной доставки. Текущий отправитель делает до трёх попыток с задержками 0, 1 и 4 секунды; таймаут каждой — 10 секунд. Подпись webhook не реализована, поэтому сверяйте события через `GET /v1/orders/{id}` и обрабатывайте повторные уведомления по address/txId/статусу и сопоставляйте с сохранённым ID заказа. Для Smart Orders используйте соответствующий метод статуса.\n\n## Версия контракта\n\nСправка собрана из исходного кода API 1.0.0. Определения: `apps/api/src/api/v1/`, авторизация: `auth-api-key.helpers.ts`, исходящие уведомления: `packages/core/src/modules/webhook/webhook.service.ts`. В старом Swagger-описании есть расхождения с реализацией HMAC и webhook; здесь отражён код. Это снимок контракта, без проверки работающего API.\n",
    "x-language": "ru"
  },
  "servers": [
    {
      "url": "https://api.tronityone.energy",
      "description": "Новый настроенный адрес API; доступность DNS и сервера не подтверждена."
    }
  ],
  "tags": [
    {
      "name": "Система"
    },
    {
      "name": "Аккаунт"
    },
    {
      "name": "Пул ресурсов"
    },
    {
      "name": "Заказы"
    },
    {
      "name": "Автозаказы"
    },
    {
      "name": "Energy"
    },
    {
      "name": "Bandwidth"
    },
    {
      "name": "Оценка перевода"
    }
  ],
  "paths": {
    "/v1/health/": {
      "get": {
        "operationId": "health",
        "tags": [
          "Система"
        ],
        "summary": "Проверка состояния",
        "description": "Публичная проверка доступности без ключа, подписи и покупок.",
        "x-source": "apps/api/src/api/v1/health/health.ts",
        "x-required-scope": null,
        "security": [],
        "responses": {
          "200": {
            "description": "Успешно.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "boolean",
                      "const": true
                    }
                  },
                  "required": [
                    "status"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/v1/user/": {
      "get": {
        "operationId": "getUser",
        "tags": [
          "Аккаунт"
        ],
        "summary": "Данные пользователя",
        "description": "Пользователь ключа, включая текущие квоты и scope при наличии.\n\n**Scope:** `user:read`.",
        "x-source": "apps/api/src/api/v1/user/user.route.ts",
        "x-required-scope": "user:read",
        "security": [
          {
            "ApiKey": [],
            "HMACSignature": [],
            "HMACTimestamp": []
          }
        ],
        "responses": {
          "200": {
            "description": "Успешно.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/User"
                    }
                  },
                  "required": [
                    "status",
                    "data"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Некорректный запрос",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Нет ключа, ключ истёк или отозван; неверная подпись, время или повтор nonce.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Недостаточно прав scope.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Пользователь или заказ не найден.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Ошибка проверки схемы; подробности могут быть в fields.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Превышен лимит ключа или дневная квота. Учитывайте Retry-After.",
            "headers": {
              "Retry-After": {
                "description": "Секунды до следующей попытки.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Внутренняя ошибка сервера.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "x-nonce",
            "in": "header",
            "required": false,
            "description": "Рекомендуется уникальный UUID. Повтор отклоняется 10 минут; nonce не входит в подпись.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ]
      }
    },
    "/v1/user/balance/": {
      "get": {
        "operationId": "getUserBalance",
        "tags": [
          "Аккаунт"
        ],
        "summary": "Баланс пользователя",
        "description": "Баланс счёта в TRX.\n\n**Scope:** `user:read`.",
        "x-source": "apps/api/src/api/v1/user/user-balance.route.ts",
        "x-required-scope": "user:read",
        "security": [
          {
            "ApiKey": [],
            "HMACSignature": [],
            "HMACTimestamp": []
          }
        ],
        "responses": {
          "200": {
            "description": "Успешно.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/UserBalance"
                    }
                  },
                  "required": [
                    "status",
                    "data"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Некорректный запрос",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Нет ключа, ключ истёк или отозван; неверная подпись, время или повтор nonce.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Недостаточно прав scope.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Пользователь или заказ не найден.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Ошибка проверки схемы; подробности могут быть в fields.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Превышен лимит ключа или дневная квота. Учитывайте Retry-After.",
            "headers": {
              "Retry-After": {
                "description": "Секунды до следующей попытки.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Внутренняя ошибка сервера.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "x-nonce",
            "in": "header",
            "required": false,
            "description": "Рекомендуется уникальный UUID. Повтор отклоняется 10 минут; nonce не входит в подпись.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ]
      }
    },
    "/v1/user/wallet/": {
      "get": {
        "operationId": "getUserWallet",
        "tags": [
          "Аккаунт"
        ],
        "summary": "Кошелёк пополнения",
        "description": "Возвращает кошелёк; СОЗДАЁТ его при отсутствии, несмотря на GET. Замороженные и заблокированные кошельки не проводят транзакции.\n\n**Scope:** `user:read`.",
        "x-source": "apps/api/src/api/v1/user/user-wallet.route.ts",
        "x-required-scope": "user:read",
        "security": [
          {
            "ApiKey": [],
            "HMACSignature": [],
            "HMACTimestamp": []
          }
        ],
        "responses": {
          "200": {
            "description": "Успешно.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/UserWallet"
                    }
                  },
                  "required": [
                    "status",
                    "data"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Некорректный запрос",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Нет ключа, ключ истёк или отозван; неверная подпись, время или повтор nonce.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Недостаточно прав scope.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Пользователь или заказ не найден.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Ошибка проверки схемы; подробности могут быть в fields.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Превышен лимит ключа или дневная квота. Учитывайте Retry-After.",
            "headers": {
              "Retry-After": {
                "description": "Секунды до следующей попытки.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Внутренняя ошибка сервера.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "x-nonce",
            "in": "header",
            "required": false,
            "description": "Рекомендуется уникальный UUID. Повтор отклоняется 10 минут; nonce не входит в подпись.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ]
      }
    },
    "/v1/pool/balance": {
      "get": {
        "operationId": "getPoolBalance",
        "tags": [
          "Пул ресурсов"
        ],
        "summary": "Доступные ресурсы пула",
        "description": "Суммарные ресурсы сервиса, а не TRX пользователя.\n\n**Scope:** `pool:read`.",
        "x-source": "apps/api/src/api/v1/pool/get-pool-balance.route.ts",
        "x-required-scope": "pool:read",
        "security": [
          {
            "ApiKey": [],
            "HMACSignature": [],
            "HMACTimestamp": []
          }
        ],
        "responses": {
          "200": {
            "description": "Успешно.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/PoolBalance"
                    }
                  },
                  "required": [
                    "status",
                    "data"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Некорректный запрос",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Нет ключа, ключ истёк или отозван; неверная подпись, время или повтор nonce.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Недостаточно прав scope.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Пользователь или заказ не найден.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Ошибка проверки схемы; подробности могут быть в fields.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Превышен лимит ключа или дневная квота. Учитывайте Retry-After.",
            "headers": {
              "Retry-After": {
                "description": "Секунды до следующей попытки.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Внутренняя ошибка сервера.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "x-nonce",
            "in": "header",
            "required": false,
            "description": "Рекомендуется уникальный UUID. Повтор отклоняется 10 минут; nonce не входит в подпись.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ]
      }
    },
    "/v1/orders/": {
      "get": {
        "operationId": "getOrders",
        "tags": [
          "Заказы"
        ],
        "summary": "Список заказов",
        "description": "Заказы пользователя; data — массив без метаданных пагинации.\n\n**Scope:** `order:read`.",
        "x-source": "apps/api/src/api/v1/orders/orders.route.ts",
        "x-required-scope": "order:read",
        "security": [
          {
            "ApiKey": [],
            "HMACSignature": [],
            "HMACTimestamp": []
          }
        ],
        "responses": {
          "200": {
            "description": "Успешно.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Order"
                      }
                    }
                  },
                  "required": [
                    "status",
                    "data"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Некорректный запрос",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Нет ключа, ключ истёк или отозван; неверная подпись, время или повтор nonce.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LegacyUnauthorized"
                }
              }
            }
          },
          "403": {
            "description": "Недостаточно прав scope.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Пользователь или заказ не найден.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Ошибка проверки схемы; подробности могут быть в fields.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Превышен лимит ключа или дневная квота. Учитывайте Retry-After.",
            "headers": {
              "Retry-After": {
                "description": "Секунды до следующей попытки.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Внутренняя ошибка сервера.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "x-nonce",
            "in": "header",
            "required": false,
            "description": "Рекомендуется уникальный UUID. Повтор отклоняется 10 минут; nonce не входит в подпись.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "number",
              "minimum": 1,
              "maximum": 20,
              "default": 10
            },
            "description": "Максимум элементов. В маршруте z.number() без coercion; проверьте обработку query на работающем API."
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "schema": {
              "type": "number",
              "minimum": 0,
              "default": 0
            },
            "description": "Пропустить элементов."
          }
        ]
      }
    },
    "/v1/orders/{id}": {
      "get": {
        "operationId": "getOrder",
        "tags": [
          "Заказы"
        ],
        "summary": "Детали заказа",
        "description": "Получить свой заказ по UUIDv7.\n\n**Scope:** `order:read`.",
        "x-source": "apps/api/src/api/v1/orders/order.route.ts",
        "x-required-scope": "order:read",
        "security": [
          {
            "ApiKey": [],
            "HMACSignature": [],
            "HMACTimestamp": []
          }
        ],
        "responses": {
          "200": {
            "description": "Успешно.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Order"
                    }
                  },
                  "required": [
                    "status",
                    "data"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Некорректный запрос",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Нет ключа, ключ истёк или отозван; неверная подпись, время или повтор nonce.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LegacyUnauthorized"
                }
              }
            }
          },
          "403": {
            "description": "Недостаточно прав scope.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Пользователь или заказ не найден.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Ошибка проверки схемы; подробности могут быть в fields.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Превышен лимит ключа или дневная квота. Учитывайте Retry-After.",
            "headers": {
              "Retry-After": {
                "description": "Секунды до следующей попытки.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Внутренняя ошибка сервера.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "x-nonce",
            "in": "header",
            "required": false,
            "description": "Рекомендуется уникальный UUID. Повтор отклоняется 10 минут; nonce не входит в подпись.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-7[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$",
              "description": "Идентификатор UUIDv7."
            }
          }
        ]
      }
    },
    "/v1/orders/smart": {
      "get": {
        "operationId": "getSmartOrders",
        "tags": [
          "Автозаказы"
        ],
        "summary": "Список умных заказов",
        "description": "Умные заказы Energy текущего пользователя.\n\n**Scope:** `order:read`.",
        "x-source": "apps/api/src/api/v1/smart-orders/smart-orders.route.ts",
        "x-required-scope": "order:read",
        "security": [
          {
            "ApiKey": [],
            "HMACSignature": [],
            "HMACTimestamp": []
          }
        ],
        "responses": {
          "200": {
            "description": "Успешно.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/SmartOrder"
                      }
                    }
                  },
                  "required": [
                    "status",
                    "data"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Некорректный запрос",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Нет ключа, ключ истёк или отозван; неверная подпись, время или повтор nonce.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LegacyUnauthorized"
                }
              }
            }
          },
          "403": {
            "description": "Недостаточно прав scope.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Пользователь или заказ не найден.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Ошибка проверки схемы; подробности могут быть в fields.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Превышен лимит ключа или дневная квота. Учитывайте Retry-After.",
            "headers": {
              "Retry-After": {
                "description": "Секунды до следующей попытки.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Внутренняя ошибка сервера.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "x-nonce",
            "in": "header",
            "required": false,
            "description": "Рекомендуется уникальный UUID. Повтор отклоняется 10 минут; nonce не входит в подпись.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "number",
              "minimum": 1,
              "maximum": 20,
              "default": 10
            },
            "description": "Максимум элементов. В маршруте z.number() без coercion; проверьте обработку query на работающем API."
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "schema": {
              "type": "number",
              "minimum": 0,
              "default": 0
            },
            "description": "Пропустить элементов."
          }
        ]
      }
    },
    "/v1/orders/smart/{id}": {
      "get": {
        "operationId": "getSmartOrder",
        "tags": [
          "Автозаказы"
        ],
        "summary": "Детали умного заказа",
        "description": "Получить свой умный заказ по UUIDv7.\n\n**Scope:** `order:read`.",
        "x-source": "apps/api/src/api/v1/smart-orders/smart-order.route.ts",
        "x-required-scope": "order:read",
        "security": [
          {
            "ApiKey": [],
            "HMACSignature": [],
            "HMACTimestamp": []
          }
        ],
        "responses": {
          "200": {
            "description": "Успешно.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/SmartOrder"
                    }
                  },
                  "required": [
                    "status",
                    "data"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Некорректный запрос",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Нет ключа, ключ истёк или отозван; неверная подпись, время или повтор nonce.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LegacyUnauthorized"
                }
              }
            }
          },
          "403": {
            "description": "Недостаточно прав scope.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Пользователь или заказ не найден.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Ошибка проверки схемы; подробности могут быть в fields.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Превышен лимит ключа или дневная квота. Учитывайте Retry-After.",
            "headers": {
              "Retry-After": {
                "description": "Секунды до следующей попытки.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Внутренняя ошибка сервера.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "x-nonce",
            "in": "header",
            "required": false,
            "description": "Рекомендуется уникальный UUID. Повтор отклоняется 10 минут; nonce не входит в подпись.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-7[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$",
              "description": "Идентификатор UUIDv7."
            }
          }
        ]
      }
    },
    "/v1/orders/smart/": {
      "post": {
        "operationId": "placeSmartOrder",
        "tags": [
          "Автозаказы"
        ],
        "summary": "Создать умный заказ",
        "description": "Создаёт автоматическое пополнение Energy. amount должен быть >= minEnergyThreshold. Возможно списание баланса. В стандартных scope ключа нет order:write: заранее согласуйте это право.\n\n**Scope:** `order:write`.",
        "x-source": "apps/api/src/api/v1/smart-orders/place-smart-order.route.ts",
        "x-required-scope": "order:write",
        "security": [
          {
            "ApiKey": [],
            "HMACSignature": [],
            "HMACTimestamp": []
          }
        ],
        "responses": {
          "200": {
            "description": "Успешно.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/SmartOrderPlaced"
                    }
                  },
                  "required": [
                    "status",
                    "data"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Некорректный запрос",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Нет ключа, ключ истёк или отозван; неверная подпись, время или повтор nonce.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LegacyUnauthorized"
                }
              }
            }
          },
          "403": {
            "description": "Недостаточно прав scope.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Пользователь или заказ не найден.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Ошибка проверки схемы; подробности могут быть в fields.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Превышен лимит ключа или дневная квота. Учитывайте Retry-After.",
            "headers": {
              "Retry-After": {
                "description": "Секунды до следующей попытки.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Внутренняя ошибка сервера.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "x-nonce",
            "in": "header",
            "required": false,
            "description": "Рекомендуется уникальный UUID. Повтор отклоняется 10 минут; nonce не входит в подпись.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SmartOrderRequest"
              },
              "example": {
                "address": "TExampleReplaceWithYourOwnValidAddress",
                "amount": 131000,
                "minEnergyThreshold": 131000,
                "autoRenew": false
              }
            }
          }
        }
      }
    },
    "/v1/energy/estimate/": {
      "post": {
        "operationId": "estimateEnergy",
        "tags": [
          "Energy"
        ],
        "summary": "Рассчитать стоимость Energy",
        "description": "Рассчитывает цену для пользователя без покупки. amount — единицы ресурса.\n\n**Scope:** `resource:read`.",
        "x-source": "apps/api/src/api/v1/energy/energy-estimate.route.ts",
        "x-required-scope": "resource:read",
        "security": [
          {
            "ApiKey": [],
            "HMACSignature": [],
            "HMACTimestamp": []
          }
        ],
        "responses": {
          "200": {
            "description": "Успешно.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/ResourceEstimate"
                    }
                  },
                  "required": [
                    "status",
                    "data"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Некорректный запрос",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Нет ключа, ключ истёк или отозван; неверная подпись, время или повтор nonce.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LegacyUnauthorized"
                }
              }
            }
          },
          "403": {
            "description": "Недостаточно прав scope.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Пользователь или заказ не найден.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Ошибка проверки схемы; подробности могут быть в fields.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Превышен лимит ключа или дневная квота. Учитывайте Retry-After.",
            "headers": {
              "Retry-After": {
                "description": "Секунды до следующей попытки.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Внутренняя ошибка сервера.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "x-nonce",
            "in": "header",
            "required": false,
            "description": "Рекомендуется уникальный UUID. Повтор отклоняется 10 минут; nonce не входит в подпись.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EnergyEstimateRequest"
              },
              "example": {
                "period": "1h",
                "amount": 131000
              }
            }
          }
        }
      }
    },
    "/v1/energy/buy/": {
      "post": {
        "operationId": "buyEnergy",
        "tags": [
          "Energy"
        ],
        "summary": "Купить Energy",
        "description": "Создаёт платный заказ ресурса на адрес получателя со списанием баланса. Idempotency key не реализован: при неоднозначном таймауте проверьте заказы до повтора. webhookUrl включает уведомления.\n\n**Scope:** `resource:write`.",
        "x-source": "apps/api/src/api/v1/energy/buy-energy.route.ts",
        "x-required-scope": "resource:write",
        "security": [
          {
            "ApiKey": [],
            "HMACSignature": [],
            "HMACTimestamp": []
          }
        ],
        "responses": {
          "200": {
            "description": "Успешно.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/ResourcePurchase"
                    }
                  },
                  "required": [
                    "status",
                    "data"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Некорректный запрос",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Нет ключа, ключ истёк или отозван; неверная подпись, время или повтор nonce.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Недостаточно прав scope.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Пользователь или заказ не найден.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Ошибка проверки схемы; подробности могут быть в fields.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Превышен лимит ключа или дневная квота. Учитывайте Retry-After.",
            "headers": {
              "Retry-After": {
                "description": "Секунды до следующей попытки.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Внутренняя ошибка сервера.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "x-nonce",
            "in": "header",
            "required": false,
            "description": "Рекомендуется уникальный UUID. Повтор отклоняется 10 минут; nonce не входит в подпись.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EnergyBuyRequest"
              },
              "example": {
                "period": "1h",
                "amount": 131000,
                "address": "TExampleReplaceWithYourOwnValidAddress"
              }
            }
          }
        }
      }
    },
    "/v1/bandwidth/estimate/": {
      "post": {
        "operationId": "estimateBandwidth",
        "tags": [
          "Bandwidth"
        ],
        "summary": "Рассчитать стоимость Bandwidth",
        "description": "Рассчитывает цену для пользователя без покупки. amount — единицы ресурса.\n\n**Scope:** `resource:read`.",
        "x-source": "apps/api/src/api/v1/bandwidth/bandwidth-estimate.route.ts",
        "x-required-scope": "resource:read",
        "security": [
          {
            "ApiKey": [],
            "HMACSignature": [],
            "HMACTimestamp": []
          }
        ],
        "responses": {
          "200": {
            "description": "Успешно.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/ResourceEstimate"
                    }
                  },
                  "required": [
                    "status",
                    "data"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Некорректный запрос",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Нет ключа, ключ истёк или отозван; неверная подпись, время или повтор nonce.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LegacyUnauthorized"
                }
              }
            }
          },
          "403": {
            "description": "Недостаточно прав scope.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Пользователь или заказ не найден.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Ошибка проверки схемы; подробности могут быть в fields.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Превышен лимит ключа или дневная квота. Учитывайте Retry-After.",
            "headers": {
              "Retry-After": {
                "description": "Секунды до следующей попытки.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Внутренняя ошибка сервера.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "x-nonce",
            "in": "header",
            "required": false,
            "description": "Рекомендуется уникальный UUID. Повтор отклоняется 10 минут; nonce не входит в подпись.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BandwidthEstimateRequest"
              },
              "example": {
                "period": "1h",
                "amount": 5000
              }
            }
          }
        }
      }
    },
    "/v1/bandwidth/buy/": {
      "post": {
        "operationId": "buyBandwidth",
        "tags": [
          "Bandwidth"
        ],
        "summary": "Купить Bandwidth",
        "description": "Создаёт платный заказ ресурса на адрес получателя со списанием баланса. Idempotency key не реализован: при неоднозначном таймауте проверьте заказы до повтора. webhookUrl включает уведомления.\n\n**Scope:** `resource:write`.",
        "x-source": "apps/api/src/api/v1/bandwidth/buy-bandwidth.route.ts",
        "x-required-scope": "resource:write",
        "security": [
          {
            "ApiKey": [],
            "HMACSignature": [],
            "HMACTimestamp": []
          }
        ],
        "responses": {
          "200": {
            "description": "Успешно.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/ResourcePurchase"
                    }
                  },
                  "required": [
                    "status",
                    "data"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Некорректный запрос",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Нет ключа, ключ истёк или отозван; неверная подпись, время или повтор nonce.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Недостаточно прав scope.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Пользователь или заказ не найден.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Ошибка проверки схемы; подробности могут быть в fields.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Превышен лимит ключа или дневная квота. Учитывайте Retry-After.",
            "headers": {
              "Retry-After": {
                "description": "Секунды до следующей попытки.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Внутренняя ошибка сервера.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "x-nonce",
            "in": "header",
            "required": false,
            "description": "Рекомендуется уникальный UUID. Повтор отклоняется 10 минут; nonce не входит в подпись.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BandwidthBuyRequest"
              },
              "example": {
                "period": "1h",
                "amount": 5000,
                "address": "TExampleReplaceWithYourOwnValidAddress"
              }
            }
          }
        }
      }
    },
    "/v1/estimate/tx": {
      "post": {
        "operationId": "estimateTransaction",
        "tags": [
          "Оценка перевода"
        ],
        "summary": "Оценить ресурсы перевода",
        "description": "Оценивает ресурсы и активацию для перевода TRX или токена. Не отправляет перевод и не покупает ресурсы.\n\n**Scope:** `resource:read`.",
        "x-source": "apps/api/src/api/v1/estimate/estimate.route.ts",
        "x-required-scope": "resource:read",
        "security": [
          {
            "ApiKey": [],
            "HMACSignature": [],
            "HMACTimestamp": []
          }
        ],
        "responses": {
          "200": {
            "description": "Успешно.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/TransactionEstimate"
                    }
                  },
                  "required": [
                    "status",
                    "data"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Некорректный запрос",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Нет ключа, ключ истёк или отозван; неверная подпись, время или повтор nonce.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Недостаточно прав scope.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Пользователь или заказ не найден.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Ошибка проверки схемы; подробности могут быть в fields.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Превышен лимит ключа или дневная квота. Учитывайте Retry-After.",
            "headers": {
              "Retry-After": {
                "description": "Секунды до следующей попытки.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Внутренняя ошибка сервера.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "x-nonce",
            "in": "header",
            "required": false,
            "description": "Рекомендуется уникальный UUID. Повтор отклоняется 10 минут; nonce не входит в подпись.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TransactionEstimateRequest"
              },
              "example": {
                "from": "TExampleReplaceWithYourOwnValidAddress",
                "to": "TExampleReplaceWithRecipientAddress",
                "token": "TRX",
                "count": 1,
                "amount": 1
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "x-api-key",
        "description": "Приватный API-ключ. Храните учётные данные на сервере."
      },
      "HMACSignature": {
        "type": "apiKey",
        "in": "header",
        "name": "x-signature",
        "description": "HMAC-SHA256 Base64 от METHOD + перенос + точный /v1/path?query + перенос + timestamp; при наличии тела добавить перенос + JSON.stringify(parsedBody). Обязательно при включённом HMAC (по умолчанию в репозитории)."
      },
      "HMACTimestamp": {
        "type": "apiKey",
        "in": "header",
        "name": "x-timestamp",
        "description": "Unix-время в секундах, 10 цифр; допуск ±300 секунд."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "status": {
            "type": "boolean",
            "const": false
          },
          "error": {
            "type": "object",
            "properties": {
              "title": {
                "type": "string"
              },
              "message": {
                "type": "string"
              },
              "statusCode": {
                "type": "integer"
              },
              "fields": {
                "type": "object",
                "additionalProperties": {
                  "type": "string"
                }
              }
            },
            "required": [
              "title",
              "statusCode"
            ]
          }
        },
        "required": [
          "status",
          "error"
        ]
      },
      "LegacyUnauthorized": {
        "type": "object",
        "properties": {
          "message": {
            "type": "string",
            "const": "Unauthorized"
          }
        },
        "required": [
          "message"
        ]
      },
      "User": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-7[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$",
            "description": "Идентификатор UUIDv7."
          },
          "referralCode": {
            "type": [
              "string",
              "null"
            ]
          },
          "referredBy": {
            "type": [
              "string",
              "null"
            ]
          },
          "email": {
            "type": "object",
            "properties": {
              "email": {
                "type": "string",
                "format": "email"
              },
              "verified": {
                "type": "boolean"
              }
            },
            "required": [
              "email",
              "verified"
            ]
          },
          "apiKey": {
            "type": "object",
            "properties": {
              "dailyQuota": {
                "type": "number"
              },
              "requestPerMinute": {
                "type": "number"
              },
              "scopes": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            },
            "required": []
          }
        },
        "required": [
          "id",
          "referralCode",
          "referredBy"
        ]
      },
      "UserBalance": {
        "type": "object",
        "properties": {
          "balance": {
            "type": "number",
            "minimum": 0,
            "description": "TRX."
          }
        },
        "required": [
          "balance"
        ]
      },
      "UserWallet": {
        "type": "object",
        "properties": {
          "address": {
            "type": "string",
            "description": "Корректный адрес TRON в Base58Check; пробелы по краям удаляются.",
            "example": "TExampleReplaceWithYourOwnValidAddress"
          },
          "balance": {
            "type": "number",
            "minimum": 0,
            "description": "TRX."
          },
          "status": {
            "type": "string",
            "enum": [
              "ACTIVE",
              "FROZEN",
              "BLOCKED"
            ]
          }
        },
        "required": [
          "address",
          "balance"
        ]
      },
      "PoolBalance": {
        "type": "object",
        "properties": {
          "energy": {
            "type": "number"
          },
          "bandwidth": {
            "type": "number"
          }
        },
        "required": [
          "energy",
          "bandwidth"
        ]
      },
      "Order": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-7[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$",
            "description": "Идентификатор UUIDv7."
          },
          "status": {
            "type": "string",
            "enum": [
              "CREATED",
              "ACTIVE",
              "COMPLETED",
              "FAILED",
              "CANCELLED"
            ]
          },
          "address": {
            "type": "string",
            "description": "Корректный адрес TRON в Base58Check; пробелы по краям удаляются.",
            "example": "TExampleReplaceWithYourOwnValidAddress"
          },
          "type": {
            "type": "string",
            "enum": [
              "ENERGY",
              "BANDWIDTH"
            ]
          },
          "amount": {
            "type": "number"
          },
          "price": {
            "type": "number"
          },
          "currency": {
            "type": "string",
            "enum": [
              "TRX",
              "USDT"
            ]
          },
          "txDelegate": {
            "type": "string"
          },
          "txUndelegate": {
            "type": "string"
          },
          "webhook": {
            "type": "object",
            "properties": {
              "url": {
                "type": "string",
                "format": "uri"
              },
              "status": {
                "type": "string",
                "enum": [
                  "PENDING",
                  "COMPLETED",
                  "FAILED"
                ]
              }
            },
            "required": [
              "url",
              "status"
            ]
          },
          "activatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "completedAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "status",
          "address",
          "type",
          "amount",
          "price",
          "currency"
        ]
      },
      "SmartOrder": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-7[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$",
            "description": "Идентификатор UUIDv7."
          },
          "status": {
            "type": "string",
            "enum": [
              "CREATED",
              "ACTIVATED",
              "COMPLETED",
              "EXPIRED"
            ]
          },
          "address": {
            "type": "string",
            "description": "Корректный адрес TRON в Base58Check; пробелы по краям удаляются.",
            "example": "TExampleReplaceWithYourOwnValidAddress"
          },
          "minEnergyThreshold": {
            "type": "number"
          },
          "amount": {
            "type": "number"
          },
          "autoRenew": {
            "type": "boolean"
          },
          "activatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "status",
          "address",
          "minEnergyThreshold",
          "amount",
          "autoRenew"
        ]
      },
      "EnergyEstimateRequest": {
        "type": "object",
        "properties": {
          "period": {
            "type": "string",
            "enum": [
              "1h",
              "1d",
              "3d",
              "7d"
            ],
            "default": "1h"
          },
          "amount": {
            "type": "number",
            "minimum": 65500,
            "maximum": 1310000,
            "description": "Объём Energy в единицах ресурса."
          }
        },
        "required": [
          "amount"
        ]
      },
      "BandwidthEstimateRequest": {
        "type": "object",
        "properties": {
          "period": {
            "type": "string",
            "enum": [
              "1h",
              "1d",
              "3d",
              "7d"
            ],
            "default": "1h"
          },
          "amount": {
            "type": "number",
            "minimum": 5000,
            "description": "Объём Bandwidth; верхняя граница в схеме не задана."
          }
        },
        "required": [
          "amount"
        ]
      },
      "ResourceEstimate": {
        "type": "object",
        "properties": {
          "period": {
            "type": "string",
            "enum": [
              "1h",
              "1d",
              "3d",
              "7d"
            ]
          },
          "amount": {
            "type": "number"
          },
          "price": {
            "type": "number",
            "description": "Расчётная стоимость в TRX; зависит от условий аккаунта."
          }
        },
        "required": [
          "period",
          "amount",
          "price"
        ]
      },
      "ResourcePurchase": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "address": {
            "type": "string",
            "description": "Корректный адрес TRON в Base58Check; пробелы по краям удаляются.",
            "example": "TExampleReplaceWithYourOwnValidAddress"
          },
          "type": {
            "type": "string",
            "enum": [
              "ENERGY",
              "BANDWIDTH"
            ]
          },
          "amount": {
            "type": "number"
          },
          "period": {
            "type": "number",
            "enum": [
              60,
              1440,
              4320,
              10080
            ],
            "description": "Срок в МИНУТАХ в ответе покупки; в запросе используются 1h / 1d / 3d / 7d."
          },
          "price": {
            "type": "number",
            "description": "TRX. Energy округляется до 2 знаков, Bandwidth — до 6."
          },
          "webhookUrl": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "address",
          "type",
          "amount",
          "period",
          "price"
        ]
      },
      "SmartOrderRequest": {
        "type": "object",
        "properties": {
          "address": {
            "type": "string",
            "description": "Корректный адрес TRON в Base58Check; пробелы по краям удаляются.",
            "example": "TExampleReplaceWithYourOwnValidAddress"
          },
          "amount": {
            "type": "number",
            "minimum": 131000,
            "maximum": 1310000
          },
          "minEnergyThreshold": {
            "type": "number",
            "minimum": 131000,
            "maximum": 1310000
          },
          "autoRenew": {
            "type": "boolean"
          },
          "webhookUrl": {
            "type": "string",
            "description": "Необязательная строка; схема этого метода не проверяет формат URL."
          }
        },
        "required": [
          "address",
          "amount",
          "minEnergyThreshold",
          "autoRenew"
        ]
      },
      "SmartOrderPlaced": {
        "type": "object",
        "properties": {
          "status": {
            "type": "boolean"
          },
          "smartOrderId": {
            "type": "string"
          }
        },
        "required": [
          "status",
          "smartOrderId"
        ]
      },
      "TransactionEstimateRequest": {
        "type": "object",
        "properties": {
          "from": {
            "type": "string",
            "description": "Корректный адрес TRON в Base58Check; пробелы по краям удаляются.",
            "example": "TExampleReplaceWithYourOwnValidAddress"
          },
          "to": {
            "type": "string",
            "description": "Корректный адрес TRON в Base58Check; пробелы по краям удаляются.",
            "example": "TExampleReplaceWithYourOwnValidAddress"
          },
          "token": {
            "type": "string",
            "description": "TRX для нативного перевода либо адрес контракта токена TRON."
          },
          "count": {
            "type": "number",
            "description": "Количество переводов; схема не задаёт целочисленность и минимум."
          },
          "amount": {
            "type": "number",
            "minimum": 0,
            "description": "Количество токенов."
          }
        },
        "required": [
          "from",
          "to",
          "token",
          "count",
          "amount"
        ]
      },
      "TransactionEstimate": {
        "type": "object",
        "properties": {
          "token": {
            "type": "object",
            "properties": {
              "address": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "exists": {
                "type": [
                  "boolean",
                  "null"
                ]
              }
            },
            "required": [
              "address",
              "exists"
            ]
          },
          "energy": {
            "type": "object",
            "properties": {
              "estimate": {
                "type": "number"
              },
              "available": {
                "type": "number"
              },
              "gap": {
                "type": "number"
              }
            },
            "required": [
              "estimate",
              "available",
              "gap"
            ]
          },
          "bandwidth": {
            "type": "object",
            "properties": {
              "estimate": {
                "type": "number"
              },
              "available": {
                "type": "number"
              },
              "gap": {
                "type": "number"
              }
            },
            "required": [
              "estimate",
              "available",
              "gap"
            ]
          },
          "count": {
            "type": "number"
          },
          "activated": {
            "type": "boolean"
          },
          "activationTRX": {
            "type": "number"
          },
          "notes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "token",
          "energy",
          "bandwidth",
          "count",
          "activated",
          "notes"
        ]
      },
      "EnergyBuyRequest": {
        "type": "object",
        "properties": {
          "period": {
            "type": "string",
            "enum": [
              "1h",
              "1d",
              "3d",
              "7d"
            ],
            "default": "1h"
          },
          "amount": {
            "type": "number",
            "minimum": 65500,
            "maximum": 1310000,
            "description": "Объём Energy в единицах ресурса."
          },
          "address": {
            "type": "string",
            "description": "Корректный адрес TRON в Base58Check; пробелы по краям удаляются.",
            "example": "TExampleReplaceWithYourOwnValidAddress"
          },
          "webhookUrl": {
            "anyOf": [
              {
                "type": "string",
                "format": "uri"
              },
              {
                "type": "null"
              },
              {
                "const": ""
              }
            ],
            "description": "Необязательный абсолютный URL для уведомлений. При обычной покупке допустимы также null и пустая строка."
          }
        },
        "required": [
          "amount",
          "address"
        ]
      },
      "BandwidthBuyRequest": {
        "type": "object",
        "properties": {
          "period": {
            "type": "string",
            "enum": [
              "1h",
              "1d",
              "3d",
              "7d"
            ],
            "default": "1h"
          },
          "amount": {
            "type": "number",
            "minimum": 5000,
            "description": "Объём Bandwidth; верхняя граница в схеме не задана."
          },
          "address": {
            "type": "string",
            "description": "Корректный адрес TRON в Base58Check; пробелы по краям удаляются.",
            "example": "TExampleReplaceWithYourOwnValidAddress"
          },
          "webhookUrl": {
            "anyOf": [
              {
                "type": "string",
                "format": "uri"
              },
              {
                "type": "null"
              },
              {
                "const": ""
              }
            ],
            "description": "Необязательный абсолютный URL для уведомлений. При обычной покупке допустимы также null и пустая строка."
          }
        },
        "required": [
          "amount",
          "address"
        ]
      }
    }
  },
  "x-source-repository": "https://github.com/qdanik/tronity-one",
  "x-source-entrypoint": "apps/api/src/api/v1/index.ts",
  "x-source-auth": "apps/api/src/plugins/auth-api-key/auth-api-key.helpers.ts",
  "webhooks": {
    "resourceStatus": {
      "post": {
        "operationId": "receiveResourceStatus",
        "summary": "Получить статус ресурса",
        "description": "Исходящий POST на ваш webhookUrl. Заголовки подписи не реализованы. Сверяйте заказ через API и учитывайте повторы. txId — хеш делегирования или null.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "address": {
                    "type": "string",
                    "description": "Корректный адрес TRON в Base58Check; пробелы по краям удаляются.",
                    "example": "TExampleReplaceWithYourOwnValidAddress"
                  },
                  "txId": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "status": {
                    "type": "string",
                    "enum": [
                      "CREATED",
                      "ACTIVE",
                      "COMPLETED",
                      "FAILED",
                      "CANCELLED"
                    ]
                  },
                  "user": {
                    "type": "object",
                    "properties": {
                      "balance": {
                        "type": "number",
                        "description": "TRX."
                      }
                    },
                    "required": [
                      "balance"
                    ]
                  }
                },
                "required": [
                  "address",
                  "txId",
                  "status",
                  "user"
                ]
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Доставка подтверждена."
          }
        },
        "x-source": "packages/core/src/modules/webhook/webhook.service.ts"
      }
    }
  }
}
