{
  "openapi": "3.0.3",
  "info": {
    "title": "Beltelecom SMS API",
    "description": "REST API для массовой отправки SMS через сервис [SMS Белтелеком](https://sms.beltelecom.by/).\n\n**Авторизация:** по логину и паролю учётной записи пользователя на сайте sms.beltelecom.by (Drupal). Учётную запись необходимо предварительно создать и подключить к услуге.\n\n**Кодировка:** запрос и ответ передаются в UTF-8. Тело запроса — только `application/json`.\n\n**Ограничения по контенту:** поле `text` проверяется на возможность конвертации в Windows-1251. Символы, не входящие в эту кодировку (эмодзи, символ евро €, часть спецсимволов и т.п.), в тексте SMS не допускаются. При ошибке в ответе возвращается массив `invalid_chars` с детализацией.\n\n**Номера телефонов:** только белорусские номера в формате 375 + код оператора (25, 29, 33, 44) + 7 цифр. До 10 номеров в одном запросе, через запятую.\n\n**Порядок обработки:** сначала проверяются обязательные поля и формат (логин, пароль, header, text, number, кодировка text, формат number). При любой ошибке на этом этапе возвращается HTTP 401 и коды в теле ответа. Если валидация пройдена — проверяется пользователь в БД (существование, активность, пароль). При ошибке авторизации возвращается HTTP 200 с кодами state_author \"-4\" или \"-5\". При успешной авторизации создаётся отправка (webform), в ответе возвращается её ID.",
    "version": "1.0.0",
    "contact": {
      "name": "SMS Белтелеком",
      "url": "https://sms.beltelecom.by/"
    }
  },
  "servers": [
    {
      "url": "https://sms.beltelecom.by",
      "description": "Сервис массовой отправки SMS Белтелеком"
    }
  ],
  "paths": {
    "/sites/all/modules/api_sms/xml.php": {
      "post": {
        "summary": "Отправка SMS",
        "description": "Единственный метод API: приём заявки на отправку SMS в виде JSON.\n\n**Шаги обработки:**\n1. Разбор JSON. При невалидном JSON — ответ 400 (text/plain).\n2. Проверка наличия и непустоты полей: login, password, header, text, number. Проверка формата номеров (375(25|29|33|44) + 7 цифр) и конвертируемости символов поля text в Windows-1251. При ошибке — 401, в теле JSON коды state_author и/или state_sms и при необходимости message, invalid_chars, invalid_numbers.\n3. Поиск пользователя по login в БД, проверка статуса (не заблокирован) и пароля. При неверных данных — 200 с state_author \"-4\" или \"-5\", id_sms=\"-1\".\n4. Создание отправки через webform. При успехе — 200 с state_author=\"-3\", state_sms=\"-4\", id_sms — идентификатор созданной отправки (строка).\n\nВсе ответы с телом JSON содержат поля state_author, state_sms и id_sms. Поля message, invalid_chars, invalid_numbers присутствуют только при соответствующих ошибках.",
        "operationId": "sendSms",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SmsRequest"
              },
              "examples": {
                "успешный запрос": {
                  "summary": "Корректный запрос на отправку",
                  "value": {
                    "login": "user_login",
                    "password": "secret_password",
                    "header": "Заголовок рассылки",
                    "text": "Текст SMS. Допускаются кириллица, латиница и символы, конвертируемые в Windows-1251.",
                    "number": "375291234567,375331234567"
                  }
                },
                "несколько номеров": {
                  "summary": "До 10 номеров через запятую",
                  "value": {
                    "login": "user_login",
                    "password": "secret_password",
                    "header": "Акция",
                    "text": "Скидка 10% до конца недели.",
                    "number": "375251112233,375291112233,375331112233"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Запрос обработан. Интерпретация по полям ответа:\n- **Успех:** state_author=\"-3\", state_sms=\"-4\", id_sms — строка с ID созданной отправки (положительное число).\n- **Ошибка авторизации после валидации:** state_author=\"-4\" (неверный логин или пароль) или \"-5\" (учётная запись заблокирована), state_sms=\"-4\", id_sms=\"-1\".",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SmsResponse"
                },
                "examples": {
                  "успех": {
                    "summary": "SMS принята в обработку",
                    "value": {
                      "state_author": "-3",
                      "state_sms": "-4",
                      "id_sms": "12345"
                    }
                  },
                  "неверный пароль": {
                    "summary": "Логин найден, пароль неверный",
                    "value": {
                      "state_author": "-4",
                      "state_sms": "-4",
                      "id_sms": "-1"
                    }
                  },
                  "пользователь заблокирован": {
                    "summary": "Учётная запись отключена",
                    "value": {
                      "state_author": "-5",
                      "state_sms": "-4",
                      "id_sms": "-1"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Ошибка валидации полей запроса. HTTP 401 возвращается до проверки пользователя в БД. В теле — JSON с кодами state_author и state_sms (см. таблицы кодов в схемах). При state_sms=\"-6\" дополнительно приходят message и invalid_chars; при state_sms=\"-7\" — message и invalid_numbers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SmsResponse"
                },
                "examples": {
                  "пустой логин": {
                    "summary": "Не указан логин",
                    "value": {
                      "state_author": "-1",
                      "state_sms": "-4",
                      "id_sms": "-1"
                    }
                  },
                  "неверный формат номеров": {
                    "summary": "В number есть номера не формата 375(25|29|33|44)+7 цифр",
                    "value": {
                      "state_author": "-3",
                      "state_sms": "-7",
                      "id_sms": "-1",
                      "message": "Номера телефонов должны быть в формате 375(25|29|33|44) и 7 цифр",
                      "invalid_numbers": ["801234567", "375991234567"]
                    }
                  },
                  "недопустимые символы в text": {
                    "summary": "В тексте есть символы не из Windows-1251",
                    "value": {
                      "state_author": "-3",
                      "state_sms": "-6",
                      "id_sms": "-1",
                      "message": "Данные символы не конвертируются в кодировку Windows-1251",
                      "invalid_chars": [
                        {
                          "char": "€",
                          "hex": "e282ac",
                          "code": "U+20AC",
                          "description": "Символ валюты"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Тело запроса не является валидным JSON или пустое. Ответ в формате text/plain.",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string",
                  "example": "Неверный формат JSON."
                }
              }
            }
          },
          "500": {
            "description": "Внутренняя ошибка сервера. Детали в логах сервера. Ответ в формате text/plain.",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string",
                  "example": "Внутренняя ошибка сервера."
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "SmsRequest": {
        "type": "object",
        "required": ["login", "password", "header", "text", "number"],
        "description": "Тело запроса на отправку SMS. Все поля обязательны. Кодировка — UTF-8.",
        "properties": {
          "login": {
            "type": "string",
            "description": "Логин учётной записи пользователя на sms.beltelecom.by (имя пользователя Drupal). Не может быть пустым; при пустом значении возвращается 401 с state_author=\"-1\"."
          },
          "password": {
            "type": "string",
            "description": "Пароль учётной записи. Не может быть пустым; при пустом значении возвращается 401 с state_author=\"-2\". Сверяется с хешем в БД после успешной валидации остальных полей."
          },
          "header": {
            "type": "string",
            "minLength": 1,
            "maxLength": 60,
            "description": "Заголовок (подпись отправителя) SMS. Передаётся в UTF-8, при сохранении обрезается до 60 символов. Не может быть пустым; при пустом — 401 с state_sms=\"-1\"."
          },
          "text": {
            "type": "string",
            "minLength": 1,
            "maxLength": 670,
            "description": "Текст сообщения SMS. UTF-8, при сохранении обрезается до 670 символов. Допускаются только символы, конвертируемые в Windows-1251 (кириллица, латиница, стандартная пунктуация). Запрещены: эмодзи, часть символов Unicode (стрелки, мат. операторы и т.п.). При наличии недопустимых символов — 401 с state_sms=\"-6\", message и массив invalid_chars с детализацией по каждому символу."
          },
          "number": {
            "type": "string",
            "description": "Список номеров получателей через запятую, без пробелов или с пробелами (пробелы обрезаются). Допускается до 10 номеров. Формат каждого номера: 375 + код оператора (25, 29, 33 или 44) + ровно 7 цифр, например 375291234567. При пустом значении — 401 с state_sms=\"-3\". При неверном формате хотя бы одного номера — 401 с state_sms=\"-7\", message и массив invalid_numbers с перечнем невалидных номеров."
          }
        }
      },
      "SmsResponse": {
        "type": "object",
        "description": "Тело ответа при любом успешном разборе JSON (HTTP 200 или 401). Всегда присутствуют state_author, state_sms, id_sms. Остальные поля — при соответствующих ошибках.",
        "properties": {
          "state_author": {
            "type": "string",
            "enum": ["-1", "-2", "-3", "-4", "-5"],
            "description": "Код результата проверки авторизации (логин/пароль/статус пользователя). Таблица: \"-1\" — пустой логин; \"-2\" — пустой пароль; \"-3\" — успех (пользователь найден, активен, пароль верный); \"-4\" — неверный логин или пароль; \"-5\" — пользователь заблокирован (status != 1)."
          },
          "state_sms": {
            "type": "string",
            "enum": ["-1", "-2", "-3", "-4", "-5", "-6", "-7"],
            "description": "Код результата проверки полей SMS и создания отправки. Таблица: \"-1\" — пустой header; \"-2\" — пустой text; \"-3\" — пустой number; \"-4\" — успех (поля валидны и/или отправка создана); \"-5\" — сервер недоступен (в текущей реализации не используется); \"-6\" — в text есть символы, не конвертируемые в Windows-1251; \"-7\" — неверный формат номера (требуется 375(25|29|33|44) + 7 цифр)."
          },
          "id_sms": {
            "type": "string",
            "description": "Идентификатор созданной отправки (webform submission ID) в виде строки. При ошибке до создания отправки (ошибка валидации или авторизации) всегда \"-1\"."
          },
          "message": {
            "type": "string",
            "description": "Человекочитаемое сообщение об ошибке. Присутствует при state_sms=\"-6\" (текст про кодировку Windows-1251) или state_sms=\"-7\" (текст про формат номера)."
          },
          "invalid_chars": {
            "type": "array",
            "description": "При state_sms=\"-6\": массив объектов с информацией о каждом символе из text, не конвертируемом в Windows-1251 (char, hex, code, description). Позволяет подсветить проблемные символы на стороне клиента.",
            "items": {
              "$ref": "#/components/schemas/InvalidChar"
            }
          },
          "invalid_numbers": {
            "type": "array",
            "description": "При state_sms=\"-7\": массив строк — номера из поля number, не прошедшие проверку формата (375(25|29|33|44) + 7 цифр).",
            "items": { "type": "string" }
          }
        }
      },
      "InvalidChar": {
        "type": "object",
        "description": "Элемент массива invalid_chars: описание одного недопустимого символа в поле text.",
        "properties": {
          "char": {
            "type": "string",
            "description": "Сам символ (в UTF-8)."
          },
          "hex": {
            "type": "string",
            "description": "Байты символа в UTF-8 в шестнадцатеричном виде (например e282ac для €)."
          },
          "code": {
            "type": "string",
            "description": "Кодовая точка Unicode в формате U+XXXX (например U+20AC для €)."
          },
          "description": {
            "type": "string",
            "description": "Краткое описание категории символа: «Эмодзи», «Символ валюты», «Стрелки», «Математические операторы», «Символ Unicode» и т.д."
          }
        }
      }
    }
  }
}
