{
  "openapi": "3.0.3",
  "info": {
    "title": "Godeli Verification & Messaging API",
    "version": "0.5.0",
    "description": "Go-микросервис: парк Android-телефонов, входящие подтверждения, SMS OTP с собственных SIM, Flash Call REDSMS, Telegram Gateway, Telegram Bot, личный WhatsApp через Android-телефон. Внутренние ключи остаются в backend Godeli. Core связывает challenge_id с пользовательской сессией."
  },
  "servers": [
    {
      "url": "/",
      "description": "Текущий сервис"
    },
    {
      "url": "http://localhost:8084",
      "description": "Local Docker Compose"
    }
  ],
  "paths": {
    "/internal/v1/devices": {
      "post": {
        "summary": "Зарегистрировать телефон и принадлежащие ему номера",
        "description": "Один номер принадлежит ровно одному устройству. Повтор номера возвращает 409; ключ можно восстановить ротацией.",
        "security": [
          {
            "InternalKey": []
          }
        ],
        "responses": {
          "201": {
            "description": "Зарегистрировать телефон и принадлежащие ему номера",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Credentials"
                }
              }
            }
          },
          "401": {
            "description": "Неверный ключ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Телефону не принадлежит номер",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Не найдено",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Конфликт заявки, idempotency key или lease",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Ошибка валидации",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Лимит запросов (Retry-After)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "БД/канал недоступны либо нет готовой SMS-SIM",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DeviceInput"
              }
            }
          }
        }
      },
      "get": {
        "summary": "Список телефонов",
        "description": "",
        "security": [
          {
            "InternalKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Список телефонов",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "devices": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Device"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Неверный ключ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Телефону не принадлежит номер",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Не найдено",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Конфликт заявки, idempotency key или lease",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Ошибка валидации",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Лимит запросов (Retry-After)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "БД/канал недоступны либо нет готовой SMS-SIM",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/internal/v1/devices/{id}": {
      "patch": {
        "summary": "Включить или отключить телефон",
        "description": "",
        "security": [
          {
            "InternalKey": []
          }
        ],
        "responses": {
          "204": {
            "description": "Включить или отключить телефон"
          },
          "401": {
            "description": "Неверный ключ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Телефону не принадлежит номер",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Не найдено",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Конфликт заявки, idempotency key или lease",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Ошибка валидации",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Лимит запросов (Retry-After)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "БД/канал недоступны либо нет готовой SMS-SIM",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "enabled"
                ],
                "properties": {
                  "enabled": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ]
      }
    },
    "/internal/v1/devices/{id}/rotate-key": {
      "post": {
        "summary": "Сменить ключ телефона",
        "description": "Старый ключ перестаёт приниматься. Введите новый ключ в приложении.",
        "security": [
          {
            "InternalKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Сменить ключ телефона",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "device_id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "device_key": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Неверный ключ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Телефону не принадлежит номер",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Не найдено",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Конфликт заявки, idempotency key или lease",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Ошибка валидации",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Лимит запросов (Retry-After)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "БД/канал недоступны либо нет готовой SMS-SIM",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ]
      }
    },
    "/internal/v1/challenges": {
      "post": {
        "summary": "Создать заявку на входящий звонок",
        "description": "Если gateway_number не указан, выбирается включённый номер с минимумом активных заявок. Это не проверка доступности телефона онлайн. На звонящего допускается одна активная заявка среди входящих и OTP.",
        "security": [
          {
            "InternalKey": []
          }
        ],
        "responses": {
          "201": {
            "description": "Создать заявку на входящий звонок",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Challenge"
                }
              }
            }
          },
          "401": {
            "description": "Неверный ключ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Телефону не принадлежит номер",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Не найдено",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Конфликт заявки, idempotency key или lease",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Ошибка валидации",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Лимит запросов (Retry-After)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "БД/канал недоступны либо нет готовой SMS-SIM",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateChallenge"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            },
            "description": "Повтор с тем же телом возвращает исходный ресурс; другое тело — 409. Ключи уникальны в рамках семейства ресурсов."
          }
        ]
      }
    },
    "/internal/v1/challenges/{id}": {
      "get": {
        "summary": "Статус входящего подтверждения",
        "description": "",
        "security": [
          {
            "InternalKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Статус входящего подтверждения",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Challenge"
                }
              }
            }
          },
          "401": {
            "description": "Неверный ключ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Телефону не принадлежит номер",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Не найдено",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Конфликт заявки, idempotency key или lease",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Ошибка валидации",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Лимит запросов (Retry-After)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "БД/канал недоступны либо нет готовой SMS-SIM",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ]
      }
    },
    "/api/events": {
      "post": {
        "summary": "Сообщить о входящем звонке",
        "description": "Совместимо с Android APK. Событие привязано к ключу устройства и номеру. event_id защищает от повторного применения; событие и его доставка должны попасть в срок заявки.",
        "security": [
          {
            "DeviceKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Сообщить о входящем звонке",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventResult"
                }
              }
            }
          },
          "401": {
            "description": "Неверный ключ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Телефону не принадлежит номер",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Не найдено",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Конфликт заявки, idempotency key или lease",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Ошибка валидации",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Лимит запросов (Retry-After)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "БД/канал недоступны либо нет готовой SMS-SIM",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CallEvent"
              }
            }
          }
        }
      }
    },
    "/device/v1/events": {
      "post": {
        "summary": "Алиас события звонка",
        "description": "",
        "security": [
          {
            "DeviceKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Алиас события звонка",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventResult"
                }
              }
            }
          },
          "401": {
            "description": "Неверный ключ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Телефону не принадлежит номер",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Не найдено",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Конфликт заявки, idempotency key или lease",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Ошибка валидации",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Лимит запросов (Retry-After)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "БД/канал недоступны либо нет готовой SMS-SIM",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CallEvent"
              }
            }
          }
        }
      }
    },
    "/internal/v1/otp": {
      "post": {
        "summary": "Создать и поставить в очередь отправку OTP",
        "description": "SMS: 6 цифр с собственной SIM. Flash Call: 4 цифры через REDSMS. Telegram Gateway и WhatsApp: 6 цифр. Код не возвращается в ответе. До 5 попыток проверки и 3 заявок на получателя за 10 минут.",
        "security": [
          {
            "InternalKey": []
          }
        ],
        "responses": {
          "201": {
            "description": "Создать и поставить в очередь отправку OTP",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OTPChallenge"
                }
              }
            }
          },
          "401": {
            "description": "Неверный ключ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Телефону не принадлежит номер",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Не найдено",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Конфликт заявки, idempotency key или lease",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Ошибка валидации",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Лимит запросов (Retry-After)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "БД/канал недоступны либо нет готовой SMS-SIM",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OTPInput"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            },
            "description": "Повтор с тем же телом возвращает исходный ресурс; другое тело — 409. Ключи уникальны в рамках семейства ресурсов."
          }
        ]
      }
    },
    "/internal/v1/otp/{id}": {
      "get": {
        "summary": "Статус OTP и отправки",
        "description": "accepted означает принятие внешним API; sent для SMS означает результат отправки от Android, а не доставку получателю. Только verify переводит OTP в confirmed.",
        "security": [
          {
            "InternalKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Статус OTP и отправки",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OTPChallenge"
                }
              }
            }
          },
          "401": {
            "description": "Неверный ключ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Телефону не принадлежит номер",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Не найдено",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Конфликт заявки, idempotency key или lease",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Ошибка валидации",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Лимит запросов (Retry-After)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "БД/канал недоступны либо нет готовой SMS-SIM",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ]
      }
    },
    "/internal/v1/otp/{id}/verify": {
      "post": {
        "summary": "Проверить код",
        "description": "",
        "security": [
          {
            "InternalKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Проверить код",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OTPChallenge"
                }
              }
            }
          },
          "401": {
            "description": "Неверный ключ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Телефону не принадлежит номер",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Не найдено",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Конфликт заявки, idempotency key или lease",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Ошибка валидации",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Лимит запросов (Retry-After)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "БД/канал недоступны либо нет готовой SMS-SIM",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VerifyCode"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ]
      }
    },
    "/internal/v1/otp/{id}/sms-fallback": {
      "post": {
        "summary": "Отправить код той же заявки через свою SMS-SIM",
        "description": "Для не-SMS заявки. Повтор не создаёт вторую SMS. Срок и счётчик попыток сохраняются; Flash Call сохраняет четырёхзначный код.",
        "security": [
          {
            "InternalKey": []
          }
        ],
        "responses": {
          "204": {
            "description": "Отправить код той же заявки через свою SMS-SIM"
          },
          "401": {
            "description": "Неверный ключ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Телефону не принадлежит номер",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Не найдено",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Конфликт заявки, idempotency key или lease",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Ошибка валидации",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Лимит запросов (Retry-After)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "БД/канал недоступны либо нет готовой SMS-SIM",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "gateway_number": {
                    "type": "string",
                    "pattern": "^\\+7[0-9]{10}$",
                    "example": "+79991234567"
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ]
      }
    },
    "/device/v1/sms/claim": {
      "post": {
        "summary": "Заявить готовность SIM и получить задание",
        "description": "Опрос каждые 5 секунд из foreground service. Готовность SIM действует 60 секунд. Lease задания — 90 секунд; локальная дедупликация телефона предотвращает повторную отправку после восстановления lease.",
        "security": [
          {
            "DeviceKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Заявить готовность SIM и получить задание",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "task": {
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/SMSJob"
                        }
                      ],
                      "nullable": true
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Неверный ключ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Телефону не принадлежит номер",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Не найдено",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Конфликт заявки, idempotency key или lease",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Ошибка валидации",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Лимит запросов (Retry-After)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "БД/канал недоступны либо нет готовой SMS-SIM",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ClaimSMS"
              }
            }
          }
        }
      }
    },
    "/device/v1/sms/{id}/result": {
      "post": {
        "summary": "Передать результат отправки с SIM",
        "description": "",
        "security": [
          {
            "DeviceKey": []
          }
        ],
        "responses": {
          "204": {
            "description": "Передать результат отправки с SIM"
          },
          "401": {
            "description": "Неверный ключ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Телефону не принадлежит номер",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Не найдено",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Конфликт заявки, idempotency key или lease",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Ошибка валидации",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Лимит запросов (Retry-After)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "БД/канал недоступны либо нет готовой SMS-SIM",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SMSResult"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ]
      }
    },
    "/api/device/ping": {
      "post": {
        "summary": "Проверить ключ телефона",
        "description": "",
        "security": [
          {
            "DeviceKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Проверить ключ телефона",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "device": {
                      "$ref": "#/components/schemas/Device"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Неверный ключ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Телефону не принадлежит номер",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Не найдено",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Конфликт заявки, idempotency key или lease",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Ошибка валидации",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Лимит запросов (Retry-After)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "БД/канал недоступны либо нет готовой SMS-SIM",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        }
      }
    },
    "/internal/v1/messages": {
      "post": {
        "summary": "Отправить личное сообщение WhatsApp или текст Telegram Bot",
        "description": "WhatsApp отправляет Android-телефон через свою сеть. Нужен привязанный подключённый аккаунт; account_id выбирает отправителя. Telegram Bot использует известный chat_id. accepted не означает delivered.",
        "security": [
          {
            "InternalKey": []
          }
        ],
        "responses": {
          "202": {
            "description": "Message queued",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Message"
                }
              }
            }
          },
          "401": {
            "description": "Неверный ключ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Телефону не принадлежит номер",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Не найдено",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Конфликт заявки, idempotency key или lease",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Ошибка валидации",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Лимит запросов (Retry-After)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "БД/канал недоступны либо нет готовой SMS-SIM",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MessageInput"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            },
            "description": "Повтор с тем же телом возвращает исходный ресурс; другое тело — 409. Ключи уникальны в рамках семейства ресурсов."
          }
        ]
      }
    },
    "/internal/v1/messages/{id}": {
      "get": {
        "summary": "Статус сообщения",
        "description": "",
        "security": [
          {
            "InternalKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Статус сообщения",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Message"
                }
              }
            }
          },
          "401": {
            "description": "Неверный ключ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Телефону не принадлежит номер",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Не найдено",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Конфликт заявки, idempotency key или lease",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Ошибка валидации",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Лимит запросов (Retry-After)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "БД/канал недоступны либо нет готовой SMS-SIM",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ]
      }
    },
    "/internal/v1/logs/stream": {
      "get": {
        "summary": "Журнал в реальном времени (SSE)",
        "description": "Нужен X-Internal-API-Key. Передайте Last-Event-ID для продолжения. Формат data — LogEntry. Журнал общий для api и worker, задержка опроса до 500 мс, хранение 24 часа. LOG_SENSITIVE=true включает полные номера, коды и использованные ключи.",
        "security": [
          {
            "InternalKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Журнал в реальном времени (SSE)",
            "content": {
              "text/event-stream": {
                "schema": {
                  "type": "string",
                  "example": "id: 123\ndata: {\"id\":123,\"level\":\"INFO\",\"message\":\"SMS task result\",\"fields\":{\"state\":\"sent\"}}\n\n"
                }
              }
            }
          },
          "401": {
            "description": "Неверный ключ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Телефону не принадлежит номер",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Не найдено",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Конфликт заявки, idempotency key или lease",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Ошибка валидации",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Лимит запросов (Retry-After)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "БД/канал недоступны либо нет готовой SMS-SIM",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "Last-Event-ID",
            "in": "header",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ]
      }
    },
    "/health/live": {
      "get": {
        "summary": "Проверка работоспособности",
        "description": "",
        "security": [],
        "responses": {
          "200": {
            "description": "Проверка работоспособности",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string"
                    },
                    "version": {
                      "type": "string"
                    },
                    "ok": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Неверный ключ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Телефону не принадлежит номер",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Не найдено",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Конфликт заявки, idempotency key или lease",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Ошибка валидации",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Лимит запросов (Retry-After)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "БД/канал недоступны либо нет готовой SMS-SIM",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/health/ready": {
      "get": {
        "summary": "Проверка работоспособности",
        "description": "",
        "security": [],
        "responses": {
          "200": {
            "description": "Проверка работоспособности",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string"
                    },
                    "version": {
                      "type": "string"
                    },
                    "ok": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Неверный ключ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Телефону не принадлежит номер",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Не найдено",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Конфликт заявки, idempotency key или lease",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Ошибка валидации",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Лимит запросов (Retry-After)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "БД/канал недоступны либо нет готовой SMS-SIM",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/health": {
      "get": {
        "summary": "Проверка работоспособности",
        "description": "",
        "security": [],
        "responses": {
          "200": {
            "description": "Проверка работоспособности",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string"
                    },
                    "version": {
                      "type": "string"
                    },
                    "ok": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Неверный ключ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Телефону не принадлежит номер",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Не найдено",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Конфликт заявки, idempotency key или lease",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Ошибка валидации",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Лимит запросов (Retry-After)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "БД/канал недоступны либо нет готовой SMS-SIM",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/logs": {
      "get": {
        "summary": "UI журнала",
        "description": "",
        "security": [],
        "responses": {
          "200": {
            "description": "UI журнала"
          },
          "401": {
            "description": "Неверный ключ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Телефону не принадлежит номер",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Не найдено",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Конфликт заявки, idempotency key или lease",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Ошибка валидации",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Лимит запросов (Retry-After)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "БД/канал недоступны либо нет готовой SMS-SIM",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/docs": {
      "get": {
        "summary": "UI документации",
        "description": "",
        "security": [],
        "responses": {
          "200": {
            "description": "UI документации"
          },
          "401": {
            "description": "Неверный ключ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Телефону не принадлежит номер",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Не найдено",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Конфликт заявки, idempotency key или lease",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Ошибка валидации",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Лимит запросов (Retry-After)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "БД/канал недоступны либо нет готовой SMS-SIM",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/openapi.json": {
      "get": {
        "summary": "Спецификация OpenAPI",
        "description": "",
        "security": [],
        "responses": {
          "200": {
            "description": "Спецификация OpenAPI"
          },
          "401": {
            "description": "Неверный ключ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Телефону не принадлежит номер",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Не найдено",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Конфликт заявки, idempotency key или lease",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Ошибка валидации",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Лимит запросов (Retry-After)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "БД/канал недоступны либо нет готовой SMS-SIM",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/metrics": {
      "get": {
        "summary": "Метрики Prometheus",
        "description": "",
        "security": [],
        "responses": {
          "200": {
            "description": "Метрики Prometheus",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "401": {
            "description": "Неверный ключ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Телефону не принадлежит номер",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Не найдено",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Конфликт заявки, idempotency key или lease",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Ошибка валидации",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Лимит запросов (Retry-After)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "БД/канал недоступны либо нет готовой SMS-SIM",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/challenges": {
      "post": {
        "summary": "Локальный demo: создать входящую заявку",
        "description": "Доступен только при DEMO_ENABLED=true; Idempotency-Key необязателен.",
        "security": [
          {
            "DemoKey": []
          }
        ],
        "responses": {
          "201": {
            "description": "Локальный demo: создать входящую заявку",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Challenge"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "status_token": {
                          "type": "string"
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Неверный ключ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Телефону не принадлежит номер",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Не найдено",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Конфликт заявки, idempotency key или lease",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Ошибка валидации",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Лимит запросов (Retry-After)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "БД/канал недоступны либо нет готовой SMS-SIM",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateChallenge"
              }
            }
          }
        }
      }
    },
    "/api/challenges/{id}": {
      "get": {
        "summary": "Локальный demo: статус по секрету заявки",
        "description": "Bearer здесь — status_token конкретной заявки. Доступен только при DEMO_ENABLED=true.",
        "security": [
          {
            "DemoKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Локальный demo: статус по секрету заявки",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Challenge"
                }
              }
            }
          },
          "401": {
            "description": "Неверный ключ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Телефону не принадлежит номер",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Не найдено",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Конфликт заявки, idempotency key или lease",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Ошибка валидации",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Лимит запросов (Retry-After)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "БД/канал недоступны либо нет готовой SMS-SIM",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ]
      }
    },
    "/device/v1/enroll": {
      "post": {
        "summary": "Создать заявку и код устройства",
        "responses": {
          "201": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Enrollment"
                }
              }
            }
          },
          "422": {
            "description": "Invalid request"
          },
          "503": {
            "description": "Service unavailable"
          }
        },
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EnrollmentInput"
              }
            }
          }
        }
      }
    },
    "/device/v1/enrollments/{id}": {
      "get": {
        "summary": "Статус заявки; Bearer секрет заявки",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Enrollment"
                }
              }
            }
          },
          "422": {
            "description": "Invalid request"
          },
          "503": {
            "description": "Service unavailable"
          }
        },
        "security": [
          {
            "EnrollmentSecret": []
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ]
      }
    },
    "/internal/v1/enrollments": {
      "get": {
        "summary": "Ожидающие заявки",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "enrollments": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Enrollment"
                      }
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Invalid request"
          },
          "503": {
            "description": "Service unavailable"
          }
        },
        "security": [
          {
            "InternalKey": []
          }
        ]
      }
    },
    "/internal/v1/enrollments/{id}/approve": {
      "post": {
        "summary": "Подтвердить код и номера телефона",
        "responses": {
          "201": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Device"
                }
              }
            }
          },
          "422": {
            "description": "Invalid request"
          },
          "503": {
            "description": "Service unavailable"
          }
        },
        "security": [
          {
            "InternalKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "numbers": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                },
                "required": [
                  "name",
                  "numbers"
                ]
              }
            }
          }
        },
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ]
      }
    },
    "/device/v1/heartbeat": {
      "post": {
        "summary": "Пинг и диагностика телефона",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "server_time": {
                      "type": "integer",
                      "format": "int64"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Invalid request"
          },
          "503": {
            "description": "Service unavailable"
          }
        },
        "security": [
          {
            "DeviceKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Heartbeat"
              }
            }
          }
        }
      }
    },
    "/internal/v1/control": {
      "get": {
        "summary": "Панель: устройства, процессы и ошибки",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Overview"
                }
              }
            }
          },
          "422": {
            "description": "Invalid request"
          },
          "503": {
            "description": "Service unavailable"
          }
        },
        "security": [
          {
            "InternalKey": []
          }
        ]
      }
    },
    "/internal/v1/whatsapp/accounts": {
      "get": {
        "summary": "Личные аккаунты WhatsApp",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "accounts": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/WhatsAppAccount"
                      }
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Invalid request"
          },
          "503": {
            "description": "Service unavailable"
          }
        },
        "security": [
          {
            "InternalKey": []
          }
        ]
      },
      "post": {
        "summary": "Назначить WhatsApp-аккаунт Android-телефону",
        "security": [
          {
            "InternalKey": []
          }
        ],
        "responses": {
          "201": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WhatsAppAccount"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized"
          },
          "403": {
            "description": "Account belongs to another device"
          },
          "409": {
            "description": "Lease or request conflict"
          },
          "422": {
            "description": "Invalid request"
          },
          "503": {
            "description": "Service or connected account unavailable"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "phone": {
                    "type": "string"
                  },
                  "device_id": {
                    "type": "string",
                    "format": "uuid"
                  }
                },
                "required": [
                  "name",
                  "phone",
                  "device_id"
                ]
              }
            }
          }
        }
      }
    },
    "/internal/v1/whatsapp/accounts/{id}/connect": {
      "post": {
        "summary": "Включить аккаунт на телефоне",
        "security": [
          {
            "InternalKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized"
          },
          "403": {
            "description": "Account belongs to another device"
          },
          "409": {
            "description": "Lease or request conflict"
          },
          "422": {
            "description": "Invalid request"
          },
          "503": {
            "description": "Service or connected account unavailable"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {}
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ]
      }
    },
    "/internal/v1/whatsapp/accounts/{id}/disconnect": {
      "post": {
        "summary": "Отключить аккаунт на телефоне",
        "security": [
          {
            "InternalKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized"
          },
          "403": {
            "description": "Account belongs to another device"
          },
          "409": {
            "description": "Lease or request conflict"
          },
          "422": {
            "description": "Invalid request"
          },
          "503": {
            "description": "Service or connected account unavailable"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {}
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ]
      }
    },
    "/device/v1/whatsapp/accounts": {
      "get": {
        "summary": "Аккаунты WhatsApp этого телефона",
        "security": [
          {
            "DeviceKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "accounts": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/WhatsAppAccount"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized"
          },
          "403": {
            "description": "Account belongs to another device"
          },
          "409": {
            "description": "Lease or request conflict"
          },
          "422": {
            "description": "Invalid request"
          },
          "503": {
            "description": "Service or connected account unavailable"
          }
        }
      },
      "post": {
        "summary": "Добавить WhatsApp-аккаунт своего телефона",
        "security": [
          {
            "DeviceKey": []
          }
        ],
        "responses": {
          "201": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WhatsAppAccount"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized"
          },
          "403": {
            "description": "Account belongs to another device"
          },
          "409": {
            "description": "Lease or request conflict"
          },
          "422": {
            "description": "Invalid request"
          },
          "503": {
            "description": "Service or connected account unavailable"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "phone": {
                    "type": "string"
                  }
                },
                "required": [
                  "name",
                  "phone"
                ]
              }
            }
          }
        }
      }
    },
    "/device/v1/whatsapp/accounts/{id}/status": {
      "post": {
        "summary": "Состояние локального WhatsApp-клиента",
        "security": [
          {
            "DeviceKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized"
          },
          "403": {
            "description": "Account belongs to another device"
          },
          "409": {
            "description": "Lease or request conflict"
          },
          "422": {
            "description": "Invalid request"
          },
          "503": {
            "description": "Service or connected account unavailable"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WhatsAppStatus"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ]
      }
    },
    "/device/v1/whatsapp/claim": {
      "post": {
        "summary": "Получить задание WhatsApp для Android",
        "security": [
          {
            "DeviceKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "task": {
                      "$ref": "#/components/schemas/WhatsAppTask",
                      "nullable": true
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized"
          },
          "403": {
            "description": "Account belongs to another device"
          },
          "409": {
            "description": "Lease or request conflict"
          },
          "422": {
            "description": "Invalid request"
          },
          "503": {
            "description": "Service or connected account unavailable"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WhatsAppClaim"
              }
            }
          }
        }
      }
    },
    "/device/v1/whatsapp/{id}/result": {
      "post": {
        "summary": "Результат отправки WhatsApp телефоном",
        "security": [
          {
            "DeviceKey": []
          }
        ],
        "responses": {
          "204": {
            "description": "Success"
          },
          "401": {
            "description": "Unauthorized"
          },
          "403": {
            "description": "Account belongs to another device"
          },
          "409": {
            "description": "Lease or request conflict"
          },
          "422": {
            "description": "Invalid request"
          },
          "503": {
            "description": "Service or connected account unavailable"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WhatsAppResult"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ]
      }
    }
  },
  "components": {
    "securitySchemes": {
      "InternalKey": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Internal-API-Key"
      },
      "DeviceKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "Индивидуальный device_key телефона"
      },
      "DemoKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "Внутренний ключ для создания demo-заявки; status_token для её чтения"
      },
      "EnrollmentSecret": {
        "type": "http",
        "scheme": "bearer",
        "description": "Installation enrollment secret (not device_key)"
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "detail": {
            "type": "string"
          },
          "error": {
            "type": "string"
          }
        },
        "required": [
          "detail",
          "error"
        ]
      },
      "DeviceInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 120
          },
          "numbers": {
            "type": "array",
            "items": {
              "type": "string",
              "pattern": "^\\+7[0-9]{10}$",
              "example": "+79991234567"
            },
            "minItems": 1,
            "maxItems": 16,
            "uniqueItems": true
          }
        },
        "required": [
          "name",
          "numbers"
        ]
      },
      "Device": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "device_id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "enabled": {
            "type": "boolean"
          },
          "numbers": {
            "type": "array",
            "items": {
              "type": "string",
              "pattern": "^\\+7[0-9]{10}$",
              "example": "+79991234567"
            }
          },
          "device_code": {
            "type": "string"
          }
        },
        "required": [
          "device_id",
          "name",
          "enabled",
          "numbers"
        ]
      },
      "Credentials": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "device_id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "enabled": {
            "type": "boolean"
          },
          "numbers": {
            "type": "array",
            "items": {
              "type": "string",
              "pattern": "^\\+7[0-9]{10}$",
              "example": "+79991234567"
            }
          },
          "device_key": {
            "type": "string",
            "description": "Выдаётся при регистрации/ротации. Для enrollment зашифрованная копия доступна держателю секрета в течение 15 минут; основная таблица хранит hash."
          },
          "device_code": {
            "type": "string"
          }
        },
        "required": [
          "device_id",
          "name",
          "enabled",
          "numbers",
          "device_key"
        ]
      },
      "CreateChallenge": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "phone": {
            "type": "string",
            "pattern": "^\\+7[0-9]{10}$",
            "example": "+79991234567"
          },
          "gateway_number": {
            "type": "string",
            "pattern": "^\\+7[0-9]{10}$",
            "example": "+79991234567"
          }
        },
        "required": [
          "phone"
        ]
      },
      "Challenge": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "challenge_id": {
            "type": "string",
            "format": "uuid"
          },
          "call_to": {
            "type": "string",
            "pattern": "^\\+7[0-9]{10}$",
            "example": "+79991234567"
          },
          "expires_at": {
            "type": "integer",
            "format": "int64"
          },
          "status": {
            "enum": [
              "pending",
              "confirmed",
              "expired"
            ]
          }
        },
        "required": [
          "challenge_id",
          "call_to",
          "expires_at",
          "status"
        ]
      },
      "CallEvent": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "event_id": {
            "type": "string",
            "format": "uuid"
          },
          "type": {
            "enum": [
              "incoming_call"
            ]
          },
          "caller": {
            "type": "string",
            "pattern": "^\\+7[0-9]{10}$",
            "example": "+79991234567"
          },
          "gateway_number": {
            "type": "string",
            "pattern": "^\\+7[0-9]{10}$",
            "example": "+79991234567"
          },
          "observed_at": {
            "type": "integer",
            "format": "int64"
          }
        },
        "required": [
          "event_id",
          "type",
          "caller",
          "gateway_number",
          "observed_at"
        ]
      },
      "EventResult": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "accepted": {
            "type": "boolean"
          },
          "confirmed": {
            "type": "boolean"
          },
          "duplicate": {
            "type": "boolean"
          }
        },
        "required": [
          "accepted",
          "confirmed",
          "duplicate"
        ]
      },
      "OTPInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "phone": {
            "type": "string",
            "pattern": "^\\+7[0-9]{10}$",
            "example": "+79991234567"
          },
          "method": {
            "type": "string",
            "enum": [
              "sms",
              "flash_call",
              "telegram_gateway",
              "whatsapp"
            ]
          },
          "gateway_number": {
            "type": "string",
            "pattern": "^\\+7[0-9]{10}$",
            "example": "+79991234567",
            "description": "Опциональный номер своей SIM для SMS."
          },
          "account_id": {
            "type": "string",
            "format": "uuid"
          }
        },
        "required": [
          "phone",
          "method"
        ]
      },
      "OTPChallenge": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "challenge_id": {
            "type": "string",
            "format": "uuid"
          },
          "method": {
            "type": "string"
          },
          "expires_at": {
            "type": "integer",
            "format": "int64"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "confirmed",
              "expired",
              "locked",
              "incorrect_code"
            ]
          },
          "delivery_status": {
            "type": "string",
            "enum": [
              "queued",
              "accepted",
              "sent",
              "failed",
              "uncertain",
              "sms_fallback_queued"
            ]
          }
        },
        "required": [
          "challenge_id",
          "method",
          "expires_at",
          "status",
          "delivery_status"
        ]
      },
      "VerifyCode": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "code": {
            "type": "string",
            "minLength": 1,
            "maxLength": 12,
            "example": "012345"
          }
        },
        "required": [
          "code"
        ]
      },
      "MessageInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "channel": {
            "enum": [
              "telegram_bot",
              "whatsapp"
            ]
          },
          "to": {
            "type": "string",
            "description": "Telegram chat_id как строка либо номер WhatsApp +7…"
          },
          "text": {
            "type": "string",
            "maxLength": 4096
          },
          "account_id": {
            "type": "string",
            "format": "uuid"
          }
        },
        "required": [
          "channel",
          "to",
          "text"
        ]
      },
      "Message": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "message_id": {
            "type": "string",
            "format": "uuid"
          },
          "channel": {
            "type": "string"
          },
          "status": {
            "enum": [
              "pending",
              "sending",
              "accepted",
              "failed",
              "uncertain"
            ]
          },
          "provider_id": {
            "type": "string"
          }
        },
        "required": [
          "message_id",
          "channel",
          "status"
        ]
      },
      "SMSJob": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "task_id": {
            "type": "string",
            "format": "uuid"
          },
          "lease_token": {
            "type": "string",
            "format": "uuid"
          },
          "to": {
            "type": "string",
            "pattern": "^\\+7[0-9]{10}$",
            "example": "+79991234567"
          },
          "from": {
            "type": "string",
            "pattern": "^\\+7[0-9]{10}$",
            "example": "+79991234567"
          },
          "text": {
            "type": "string"
          },
          "expires_at": {
            "type": "integer",
            "format": "int64"
          }
        },
        "required": [
          "task_id",
          "lease_token",
          "to",
          "from",
          "text",
          "expires_at"
        ]
      },
      "ClaimSMS": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "numbers": {
            "type": "array",
            "items": {
              "type": "string",
              "pattern": "^\\+7[0-9]{10}$",
              "example": "+79991234567"
            },
            "maxItems": 16,
            "description": "Активные SIM, разрешённые пользователем для отправки SMS. Пустой список снимает readiness."
          }
        },
        "required": [
          "numbers"
        ]
      },
      "SMSResult": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "lease_token": {
            "type": "string",
            "format": "uuid"
          },
          "state": {
            "enum": [
              "sent",
              "failed",
              "uncertain"
            ]
          }
        },
        "required": [
          "lease_token",
          "state"
        ]
      },
      "LogEntry": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "time": {
            "type": "string",
            "format": "date-time"
          },
          "level": {
            "type": "string"
          },
          "message": {
            "type": "string"
          },
          "fields": {
            "type": "object",
            "additionalProperties": true
          }
        },
        "required": [
          "id",
          "time",
          "level",
          "message",
          "fields"
        ]
      },
      "EnrollmentInput": {
        "type": "object",
        "properties": {
          "installation_id": {
            "type": "string",
            "format": "uuid"
          },
          "secret": {
            "type": "string",
            "minLength": 32,
            "maxLength": 128
          },
          "name": {
            "type": "string"
          },
          "numbers": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "installation_id",
          "secret",
          "name"
        ]
      },
      "Enrollment": {
        "type": "object",
        "properties": {
          "enrollment_id": {
            "type": "string",
            "format": "uuid"
          },
          "device_code": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "numbers": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "expires_at": {
            "type": "integer",
            "format": "int64"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "approved",
              "expired"
            ]
          },
          "credentials": {
            "$ref": "#/components/schemas/Credentials"
          }
        },
        "required": [
          "enrollment_id",
          "device_code",
          "status",
          "expires_at"
        ]
      },
      "Heartbeat": {
        "type": "object",
        "properties": {
          "app_version": {
            "type": "string"
          },
          "calls_enabled": {
            "type": "boolean"
          },
          "sms_enabled": {
            "type": "boolean"
          },
          "screening_role": {
            "type": "boolean"
          },
          "phone_permission": {
            "type": "boolean"
          },
          "sms_permission": {
            "type": "boolean"
          },
          "active_numbers": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sms_numbers": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "queued_events": {
            "type": "integer",
            "minimum": 0
          }
        }
      },
      "DeviceHealth": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Device"
          },
          {
            "type": "object",
            "properties": {
              "last_seen_at": {
                "type": "integer",
                "format": "int64",
                "nullable": true
              },
              "created_at": {
                "type": "integer",
                "format": "int64"
              },
              "heartbeat": {
                "$ref": "#/components/schemas/Heartbeat"
              },
              "online": {
                "type": "boolean"
              }
            }
          }
        ]
      },
      "WhatsAppAccount": {
        "type": "object",
        "properties": {
          "account_id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "jid": {
            "type": "string"
          },
          "enabled": {
            "type": "boolean"
          },
          "state": {
            "type": "string",
            "enum": [
              "pending",
              "connecting",
              "pairing",
              "connected",
              "disconnected",
              "paused",
              "error",
              "disabled"
            ]
          },
          "error": {
            "type": "string"
          },
          "device_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "phone": {
            "type": "string"
          },
          "last_seen_at": {
            "type": "integer",
            "format": "int64",
            "nullable": true
          }
        }
      },
      "Overview": {
        "type": "object",
        "properties": {
          "server_time": {
            "type": "integer",
            "format": "int64"
          },
          "devices": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DeviceHealth"
            }
          },
          "services": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "role": {
                  "type": "string"
                },
                "last_seen_at": {
                  "type": "integer",
                  "format": "int64"
                },
                "online": {
                  "type": "boolean"
                }
              }
            }
          },
          "problems": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "key": {
                  "type": "string"
                },
                "message": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "WhatsAppStatus": {
        "type": "object",
        "properties": {
          "state": {
            "type": "string",
            "enum": [
              "connecting",
              "pairing",
              "connected",
              "disconnected",
              "paused",
              "error"
            ]
          },
          "error": {
            "type": "string"
          },
          "jid": {
            "type": "string"
          }
        },
        "required": [
          "state"
        ]
      },
      "WhatsAppTask": {
        "type": "object",
        "properties": {
          "task_id": {
            "type": "string",
            "format": "uuid"
          },
          "lease_token": {
            "type": "string",
            "format": "uuid"
          },
          "account_id": {
            "type": "string",
            "format": "uuid"
          },
          "to": {
            "type": "string"
          },
          "text": {
            "type": "string"
          },
          "expires_at": {
            "type": "integer",
            "format": "int64"
          }
        }
      },
      "WhatsAppClaim": {
        "type": "object",
        "properties": {
          "accounts": {
            "type": "array",
            "maxItems": 20,
            "items": {
              "type": "string",
              "format": "uuid"
            }
          }
        },
        "required": [
          "accounts"
        ]
      },
      "WhatsAppResult": {
        "type": "object",
        "properties": {
          "lease_token": {
            "type": "string",
            "format": "uuid"
          },
          "state": {
            "type": "string",
            "enum": [
              "accepted",
              "failed",
              "uncertain"
            ]
          },
          "provider_id": {
            "type": "string"
          }
        },
        "required": [
          "lease_token",
          "state"
        ]
      }
    }
  }
}
