{
  "openapi": "3.0.3",
  "info": {
    "title": "SMScash API",
    "version": "0.23.0",
    "description": "SMScash: выдача реальных номеров через выбранного поставщика, получение SMS и начисления в USD. Цена определяется провайдером и страной, а не сервисом. Тариф и реферальные доли фиксируются при выдаче. Сессия длится 20 минут; SMS проверяются каждые 20 секунд. Передавайте Idempotency-Key: одинаковый запрос не выдаёт второй номер даже после перезапуска. ALLOCATION_PENDING означает, что запрос ещё выполняется; ALLOCATION_UNCERTAIN запрещает автоматический повтор при неизвестном результате у поставщика. Денежные поля *_minor в USD содержат целые единицы 10^-8 доллара; GET /api/v1/me возвращает accounting_precision=8. country tariffs worker_reward и getBalance передают точные десятичные суммы. getNumbersStatus показывает общий пул поставщика; выбранный канал проверяется при выдаче. Разрешённые связки сервиса, страны и оператора возвращает GET /api/v1/catalog. Каталог учитывает текущие ограничения аккаунта, сервисов, стран и поставщиков, а также область доступа API-ключа. Наличие номеров проверяется при выдаче. Ограничения стран и областей API-ключа сохраняются. Принимаются заявки на ручной вывод USDT TRC20. Комиссия 4 USD удерживается из суммы заявки. Отменённые и истёкшие номера без SMS удаляются. Новая регистрация требует подтверждения почты. Срок выплаты — от 1 до 45 дней. После получения SMS начисление уходит в холд на срок поставщика. В указанную дату сумма автоматически становится доступной для вывода. GET /api/v1/balance возвращает balance и held_balance точными строками USD, суммы *_minor строками целых единиц 10^-8 USD, единое as_of и ближайшую дату next_release_at. getHoldBalance — дополнение SMScash для чтения суммы в холде через совместимые интерфейсы. Эти запросы не выдают и не отменяют номера и не меняют деньги. New activations credit the customer and referral/software bonuses only for the first ordinary code. All SMS remain available. Later distinct codes add the full frozen supplier price to accrued supplier debt and profit, without additional customer rewards. Equal codes within one activation do not create additional debt. Existing activations retain their saved accounting policy and previous credits."
  },
  "servers": [
    {
      "url": "/"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    },
    {
      "sessionCookie": []
    }
  ],
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer"
      },
      "sessionCookie": {
        "type": "apiKey",
        "in": "cookie",
        "name": "sms_session"
      },
      "legacyAPIKey": {
        "type": "apiKey",
        "in": "query",
        "name": "api_key"
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              },
              "request_id": {
                "type": "string",
                "description": "Совпадает с X-Request-ID в заголовке ответа."
              },
              "hint": {
                "type": "string",
                "description": "Подсказка для исправления запроса; технический текст на английском."
              },
              "retryable": {
                "type": "boolean",
                "description": "true только для ALLOCATION_PENDING или HTTP 429. Клиенты не выполняют автоматические повторы. Для записи сохраняйте исходный Idempotency-Key и параметры."
              },
              "retry_after_seconds": {
                "type": "integer",
                "minimum": 0
              },
              "details": {
                "type": "object",
                "additionalProperties": true,
                "description": "Поле, ожидаемый JSON-тип или позиция ошибки. Значения полей запроса не возвращаются."
              }
            },
            "required": [
              "code",
              "message"
            ]
          }
        },
        "required": [
          "error"
        ]
      },
      "APIKeyPolicy": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "requests_per_minute": {
            "type": "integer",
            "default": 0,
            "deprecated": true,
            "description": "Устаревшее поле: игнорируется и сохраняется как 0. Лимиты отключены."
          },
          "daily_limit": {
            "type": "integer",
            "default": 0,
            "deprecated": true,
            "description": "Устаревшее поле: игнорируется и сохраняется как 0. Лимиты отключены."
          },
          "service_daily_limit": {
            "type": "integer",
            "default": 0,
            "deprecated": true,
            "description": "Устаревшее поле: игнорируется и сохраняется как 0. Лимиты отключены."
          },
          "service_hourly_limit": {
            "type": "integer",
            "default": 0,
            "deprecated": true,
            "description": "Устаревшее поле: игнорируется и сохраняется как 0. Лимиты отключены."
          },
          "services": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "countries": {
            "type": "array",
            "items": {
              "type": "integer",
              "minimum": 1
            }
          },
          "providers": {
            "type": "array",
            "items": {
              "type": "integer",
              "minimum": 1
            }
          }
        },
        "description": "Пустые списки разрешают все доступные аккаунту сервисы, страны и поставщиков; они не снимают ограничения аккаунта. Поля квот устарели, игнорируются и сохраняются как 0. Частота запросов и количество номеров не ограничены. Разрешённые связки сервиса, страны и оператора возвращает GET /api/v1/catalog. Каталог учитывает текущие ограничения аккаунта, сервисов, стран и поставщиков, а также область доступа API-ключа. Наличие номеров проверяется при выдаче."
      },
      "SMS": {
        "type": "object",
        "required": [
          "id",
          "code",
          "text",
          "sender",
          "received_at"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "external_id": {
            "type": "string"
          },
          "code": {
            "type": "string"
          },
          "text": {
            "type": "string"
          },
          "sender": {
            "type": "string"
          },
          "received_at": {
            "type": "string",
            "format": "date-time"
          },
          "country": {
            "type": "object",
            "required": [
              "id",
              "name"
            ],
            "properties": {
              "id": {
                "type": "integer",
                "format": "int64"
              },
              "name": {
                "type": "string"
              }
            }
          },
          "service": {
            "type": "object",
            "required": [
              "id",
              "name"
            ],
            "properties": {
              "id": {
                "type": "integer",
                "format": "int64"
              },
              "name": {
                "type": "string"
              },
              "code": {
                "type": "string"
              }
            }
          },
          "provider": {
            "type": "object",
            "required": [
              "id",
              "name"
            ],
            "properties": {
              "id": {
                "type": "integer",
                "format": "int64"
              },
              "name": {
                "type": "string"
              }
            }
          }
        }
      },
      "Activation": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "phone": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "waiting",
              "received",
              "finished",
              "canceled",
              "expired"
            ]
          },
          "offer_id": {
            "type": "integer",
            "format": "int64"
          },
          "service": {
            "type": "string"
          },
          "service_name": {
            "type": "string"
          },
          "country_id": {
            "type": "integer",
            "format": "int64"
          },
          "country_name": {
            "type": "string"
          },
          "provider_id": {
            "type": "integer",
            "format": "int64"
          },
          "provider_name": {
            "type": "string"
          },
          "operator_id": {
            "type": "integer",
            "format": "int64"
          },
          "operator_name": {
            "type": "string"
          },
          "reward_minor": {
            "type": "integer",
            "format": "int64",
            "description": "Live USD amount in integer units of 10^-8 dollars, captured from the provider/country rate when allocated."
          },
          "currency": {
            "type": "string",
            "enum": [
              "USD"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "expires_at": {
            "type": "string",
            "format": "date-time"
          },
          "duration_minutes": {
            "type": "integer",
            "minimum": 1,
            "description": "New sessions last 20 minutes. Closed historical sessions retain their original duration."
          },
          "ref": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64,
            "example": "2",
            "description": "ID владельца кода в виде строки. Старые реферальные коды также принимаются и сохраняют прежнего владельца."
          },
          "referral_percent": {
            "type": "integer",
            "enum": [
              0,
              5,
              10
            ]
          },
          "software_percent": {
            "type": "integer",
            "enum": [
              0,
              5
            ]
          },
          "retry_after_sms_id": {
            "type": "integer",
            "format": "int64"
          },
          "code": {
            "type": "string"
          },
          "sms_count": {
            "type": "integer",
            "format": "int64"
          },
          "sms": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SMS"
            }
          },
          "last_code": {
            "type": "string",
            "description": "Most recent received code for history display, including while retry waits for a new code. The code field still describes the current wait."
          },
          "operator": {
            "type": "integer",
            "format": "int64",
            "description": "Public provider ID to pass as operator when requesting a number."
          }
        }
      },
      "SMSPage": {
        "type": "object",
        "required": [
          "session_id",
          "sms",
          "next_cursor",
          "has_more"
        ],
        "properties": {
          "session_id": {
            "type": "integer",
            "format": "int64"
          },
          "sms": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SMS"
            }
          },
          "next_cursor": {
            "type": "integer",
            "format": "int64"
          },
          "has_more": {
            "type": "boolean"
          }
        }
      },
      "LegacySMSFull": {
        "type": "object",
        "required": [
          "success",
          "session_id",
          "phone",
          "status",
          "sms_count",
          "sms"
        ],
        "properties": {
          "success": {
            "type": "boolean"
          },
          "session_id": {
            "type": "integer",
            "format": "int64"
          },
          "phone": {
            "type": "string",
            "description": "Phone without +, or an empty string for a deleted closed session without SMS."
          },
          "status": {
            "type": "integer",
            "enum": [
              1,
              6,
              8
            ],
            "description": "1 active; 6 finished; 8 canceled or expired."
          },
          "status_name": {
            "type": "string",
            "enum": [
              "waiting",
              "received",
              "finished",
              "canceled",
              "expired"
            ]
          },
          "sms_count": {
            "type": "integer",
            "format": "int64"
          },
          "sms": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SMS"
            }
          },
          "expires_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "CountryReward": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "provider_id",
          "provider_name",
          "country_id",
          "country_name",
          "currency",
          "worker_reward",
          "services",
          "issuance_enabled"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "provider_id": {
            "type": "integer",
            "format": "int64",
            "minimum": 1,
            "example": 2,
            "description": "Public API provider ID. Operator 1 uses provider_id=1. Copy provider_id from tariffs/catalog or id from operators/getOperators and pass it when requesting a number. The upstream supplier channel is a separate identifier."
          },
          "provider_name": {
            "type": "string"
          },
          "country_id": {
            "type": "integer",
            "format": "int64"
          },
          "country_name": {
            "type": "string"
          },
          "currency": {
            "type": "string",
            "nullable": true,
            "enum": [
              "USD"
            ],
            "description": "US dollars. Null is retained only for historical unconfirmed revisions or unfinished setup."
          },
          "worker_reward": {
            "type": "string",
            "pattern": "^-?[0-9]+\\.[0-9]{8}$",
            "description": "Exact decimal amount, 8 places. Do not use binary floating point for accounting."
          },
          "services": {
            "type": "array",
            "minItems": 1,
            "description": "Approved services for this provider and country, filtered by all restrictions and API key scopes. Every service uses the same country worker_reward.",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "code",
                "name"
              ],
              "properties": {
                "code": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                }
              }
            }
          },
          "issuance_enabled": {
            "type": "boolean",
            "description": "True when the selected supplier and USD country rates are ready for live allocation."
          },
          "earnings_hold_days": {
            "type": "integer",
            "minimum": 0,
            "maximum": 45,
            "description": "Срок после получения нового SMS. 0 означает без холда."
          },
          "operator": {
            "type": "integer",
            "format": "int64",
            "minimum": 1,
            "example": 2,
            "description": "Public provider ID to pass as operator when requesting a number."
          }
        }
      },
      "ServiceStatisticsRow": {
        "type": "object",
        "required": [
          "provider_id",
          "provider_name",
          "country_id",
          "country_name",
          "service",
          "service_name",
          "sms_30d",
          "sms_7d",
          "sms_24h",
          "sms_1h",
          "worker_reward",
          "currency"
        ],
        "properties": {
          "provider_id": {
            "type": "integer",
            "format": "int64",
            "nullable": true
          },
          "provider_name": {
            "type": "string",
            "description": "Публичное имя оператора. Пустая строка для удалённого поставщика."
          },
          "country_id": {
            "type": "integer"
          },
          "country_name": {
            "type": "string"
          },
          "service": {
            "type": "string"
          },
          "service_name": {
            "type": "string"
          },
          "sms_30d": {
            "type": "integer",
            "format": "int64",
            "minimum": 0,
            "description": "Полученные коды за последние 720 ч. до as_of, включая нижнюю границу."
          },
          "sms_7d": {
            "type": "integer",
            "format": "int64",
            "minimum": 0,
            "description": "Полученные коды за последние 168 ч. до as_of, включая нижнюю границу."
          },
          "sms_24h": {
            "type": "integer",
            "format": "int64",
            "minimum": 0,
            "description": "Полученные коды за последние 24 ч. до as_of, включая нижнюю границу."
          },
          "sms_1h": {
            "type": "integer",
            "format": "int64",
            "minimum": 0,
            "description": "Полученные коды за последние 1 ч. до as_of, включая нижнюю границу."
          },
          "worker_reward": {
            "type": "string",
            "nullable": true,
            "pattern": "^\\d+\\.\\d{8}$",
            "description": "Текущее вознаграждение пользователя за один код по тарифу страны, с точностью до 8 знаков. null для связок без действующего USD-тарифа или недоступных пользователю. Исторические начисления не изменяются."
          },
          "currency": {
            "type": "string",
            "nullable": true,
            "enum": [
              "USD",
              null
            ],
            "description": "Валюта цены за код. null, если действующая цена недоступна."
          },
          "operator": {
            "type": "integer",
            "format": "int64",
            "nullable": true,
            "description": "Public provider ID to pass as operator when requesting a number."
          },
          "sessions_30d": {
            "type": "integer",
            "format": "int64",
            "minimum": 0,
            "nullable": true,
            "description": "Issued sessions, including canceled/expired sessions without a code. Null if historical provider attribution is incomplete."
          },
          "delivery_30d": {
            "type": "string",
            "nullable": true,
            "pattern": "^[0-9]+\\.[0-9]{2}$",
            "example": "75.00",
            "description": "Received nonempty codes × 100 / issued sessions for the same window. Two decimal places. Repeated codes or receipt/issuance timing can exceed 100. Null when there are no issued sessions or historical provider attribution is incomplete."
          },
          "sessions_7d": {
            "type": "integer",
            "format": "int64",
            "minimum": 0,
            "nullable": true,
            "description": "Issued sessions, including canceled/expired sessions without a code. Null if historical provider attribution is incomplete."
          },
          "delivery_7d": {
            "type": "string",
            "nullable": true,
            "pattern": "^[0-9]+\\.[0-9]{2}$",
            "example": "75.00",
            "description": "Received nonempty codes × 100 / issued sessions for the same window. Two decimal places. Repeated codes or receipt/issuance timing can exceed 100. Null when there are no issued sessions or historical provider attribution is incomplete."
          },
          "sessions_24h": {
            "type": "integer",
            "format": "int64",
            "minimum": 0,
            "nullable": true,
            "description": "Issued sessions, including canceled/expired sessions without a code. Null if historical provider attribution is incomplete."
          },
          "delivery_24h": {
            "type": "string",
            "nullable": true,
            "pattern": "^[0-9]+\\.[0-9]{2}$",
            "example": "75.00",
            "description": "Received nonempty codes × 100 / issued sessions for the same window. Two decimal places. Repeated codes or receipt/issuance timing can exceed 100. Null when there are no issued sessions or historical provider attribution is incomplete."
          },
          "sessions_1h": {
            "type": "integer",
            "format": "int64",
            "minimum": 0,
            "nullable": true,
            "description": "Issued sessions, including canceled/expired sessions without a code. Null if historical provider attribution is incomplete."
          },
          "delivery_1h": {
            "type": "string",
            "nullable": true,
            "pattern": "^[0-9]+\\.[0-9]{2}$",
            "example": "75.00",
            "description": "Received nonempty codes × 100 / issued sessions for the same window. Two decimal places. Repeated codes or receipt/issuance timing can exceed 100. Null when there are no issued sessions or historical provider attribution is incomplete."
          }
        }
      },
      "ServiceStatistics": {
        "type": "object",
        "required": [
          "scope",
          "as_of",
          "rows"
        ],
        "properties": {
          "scope": {
            "type": "string",
            "enum": [
              "platform",
              "personal"
            ],
            "description": "Scope of the received-code counts. personal always refers to the authenticated account."
          },
          "as_of": {
            "type": "string",
            "format": "date-time"
          },
          "rows": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ServiceStatisticsRow"
            }
          },
          "daily": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ServiceStatisticsDay"
            }
          },
          "delivery_daily": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/StatisticsDeliveryDay"
            }
          },
          "timezone_offset_minutes": {
            "type": "integer",
            "enum": [
              180
            ]
          },
          "delivery_groups": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/StatisticsDeliveryGroup"
            },
            "description": "Exact country/service totals across all providers in the same owner, service and country scope. Empty for provider-restricted API keys. Individual provider percentages remain nullable when a historic route is unknown."
          },
          "delivery_group_daily": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/StatisticsDeliveryGroupDay"
            },
            "description": "Daily country/service totals across all providers. Contains legacy sessions without inventing their route. Empty for provider-restricted API keys."
          }
        }
      },
      "User": {
        "type": "object",
        "required": [
          "id",
          "public_id",
          "email",
          "name",
          "role"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Существующий внутренний идентификатор; сохранён для совместимости API."
          },
          "public_id": {
            "type": "integer",
            "format": "int64",
            "minimum": 1,
            "example": 2,
            "description": "Постоянный числовой ID пользователя. Новые аккаунты получают следующий номер; удалённые ID не используются повторно."
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "name": {
            "type": "string"
          },
          "role": {
            "type": "string"
          }
        }
      },
      "PayoutSettings": {
        "type": "object",
        "required": [
          "asset",
          "network",
          "fee_minor",
          "minimum_minor",
          "maximum_minor",
          "accounting_precision",
          "amount_decimals",
          "fee_mode",
          "usd_per_usdt"
        ],
        "properties": {
          "asset": {
            "enum": [
              "USDT"
            ],
            "type": "string"
          },
          "network": {
            "enum": [
              "TRC20"
            ],
            "type": "string"
          },
          "fee_minor": {
            "type": "integer",
            "format": "int64",
            "enum": [
              400000000
            ],
            "description": "4 USD; удерживается из amount_minor."
          },
          "minimum_minor": {
            "type": "integer",
            "format": "int64",
            "enum": [
              10000000000
            ]
          },
          "maximum_minor": {
            "type": "integer",
            "format": "int64",
            "enum": [
              100000000000000
            ]
          },
          "accounting_precision": {
            "type": "integer",
            "enum": [
              8
            ]
          },
          "amount_decimals": {
            "type": "integer",
            "enum": [
              6
            ]
          },
          "fee_mode": {
            "type": "string",
            "enum": [
              "deducted"
            ]
          },
          "usd_per_usdt": {
            "type": "string",
            "enum": [
              "1"
            ]
          }
        },
        "description": " Срок выплаты — от 1 до 45 дней."
      },
      "Withdrawal": {
        "type": "object",
        "description": "Заявка на ручной перевод. Сумма и комиссия фиксируются при создании. Исторические заявки сохраняют прежнюю валюту и нулевую комиссию; asset и network у них пустые. Срок выплаты — от 1 до 45 дней.",
        "required": [
          "id",
          "amount_minor",
          "fee_minor",
          "payout_minor",
          "currency",
          "asset",
          "network",
          "destination",
          "status",
          "note",
          "txid",
          "payout_amount",
          "accounting_precision",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "amount_minor": {
            "type": "integer",
            "format": "int64",
            "description": "Вся зарезервированная сумма в единицах 10^-8 USD, включая комиссию.",
            "example": 2000000000
          },
          "fee_minor": {
            "type": "integer",
            "format": "int64",
            "description": "Комиссия этой заявки; для новых USDT-заявок 400000000 = 4 USD.",
            "example": 400000000
          },
          "payout_minor": {
            "type": "integer",
            "format": "int64",
            "description": "amount_minor минус fee_minor в единицах 10^-8 USD.",
            "example": 1600000000
          },
          "currency": {
            "type": "string",
            "enum": [
              "USD",
              "TEST"
            ]
          },
          "asset": {
            "type": "string",
            "enum": [
              "USDT",
              ""
            ]
          },
          "network": {
            "type": "string",
            "enum": [
              "TRC20",
              ""
            ]
          },
          "destination": {
            "type": "string",
            "description": "Для USDT: TRON Base58Check-адрес с проверкой контрольной суммы.",
            "example": "TNPeeaaFB7K9cmo4uQpcU32zGK8G1NYqeL"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "paid",
              "rejected"
            ]
          },
          "note": {
            "type": "string"
          },
          "txid": {
            "type": "string",
            "description": "Хеш вручную выполненного перевода, 64 шестнадцатеричных символа; пустой до выплаты."
          },
          "payout_amount": {
            "type": "string",
            "description": "Точная сумма USDT строкой, шесть знаков после точки; для исторических заявок пустая строка.",
            "example": "16.000000"
          },
          "accounting_precision": {
            "type": "integer",
            "enum": [
              8,
              2
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "HeldEarning": {
        "type": "object",
        "required": [
          "id",
          "sms_id",
          "kind",
          "amount_minor",
          "currency",
          "received_at",
          "available_at",
          "hold_days",
          "hold_status"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "sms_id": {
            "type": "integer",
            "format": "int64"
          },
          "kind": {
            "type": "string",
            "enum": [
              "sms_reward",
              "referral_reward",
              "software_reward"
            ]
          },
          "amount_minor": {
            "type": "integer",
            "format": "int64",
            "description": "Точные единицы 10^-8 USD."
          },
          "currency": {
            "type": "string"
          },
          "bonus_percent": {
            "type": "integer",
            "nullable": true
          },
          "received_at": {
            "type": "string",
            "format": "date-time"
          },
          "available_at": {
            "type": "string",
            "format": "date-time"
          },
          "hold_days": {
            "type": "integer",
            "minimum": 0,
            "maximum": 45,
            "description": "Срок после получения нового SMS. 0 означает без холда."
          },
          "provider_id": {
            "type": "integer",
            "format": "int64",
            "nullable": true
          },
          "provider_name": {
            "type": "string"
          },
          "phone": {
            "type": "string",
            "nullable": true
          },
          "code": {
            "type": "string",
            "nullable": true
          },
          "service_name": {
            "type": "string"
          },
          "hold_status": {
            "type": "string",
            "enum": [
              "held",
              "released"
            ]
          },
          "operator": {
            "type": "integer",
            "format": "int64",
            "nullable": true,
            "description": "Public provider ID to pass as operator when requesting a number."
          }
        }
      },
      "HoldProvider": {
        "type": "object",
        "properties": {
          "provider_id": {
            "type": "integer",
            "format": "int64"
          },
          "provider_name": {
            "type": "string"
          },
          "hold_days": {
            "type": "integer",
            "minimum": 0,
            "maximum": 45,
            "description": "Срок после получения нового SMS. 0 означает без холда."
          },
          "held_minor": {
            "type": "integer",
            "format": "int64"
          },
          "next_release_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "operator": {
            "type": "integer",
            "format": "int64",
            "description": "Public provider ID to pass as operator when requesting a number."
          }
        }
      },
      "HoldDaily": {
        "type": "object",
        "properties": {
          "day": {
            "type": "string",
            "format": "date"
          },
          "sms_count": {
            "type": "integer",
            "format": "int64"
          },
          "earned_minor": {
            "type": "integer",
            "format": "int64"
          },
          "held_minor": {
            "type": "integer",
            "format": "int64"
          },
          "released_minor": {
            "type": "integer",
            "format": "int64"
          },
          "first_release_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "last_release_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "HoldSchedule": {
        "type": "object",
        "properties": {
          "day": {
            "type": "string",
            "format": "date"
          },
          "provider_id": {
            "type": "integer",
            "format": "int64",
            "nullable": true
          },
          "provider_name": {
            "type": "string"
          },
          "hold_days": {
            "type": "integer",
            "minimum": 0,
            "maximum": 45,
            "description": "Срок после получения нового SMS. 0 означает без холда."
          },
          "sms_count": {
            "type": "integer",
            "format": "int64"
          },
          "amount_minor": {
            "type": "integer",
            "format": "int64"
          },
          "first_release_at": {
            "type": "string",
            "format": "date-time"
          },
          "last_release_at": {
            "type": "string",
            "format": "date-time"
          },
          "operator": {
            "type": "integer",
            "format": "int64",
            "nullable": true,
            "description": "Public provider ID to pass as operator when requesting a number."
          }
        }
      },
      "HoldReport": {
        "type": "object",
        "required": [
          "as_of",
          "currency",
          "timezone",
          "from",
          "to",
          "totals",
          "selected",
          "providers",
          "daily",
          "schedule",
          "rows",
          "page",
          "pages",
          "page_size",
          "total"
        ],
        "properties": {
          "as_of": {
            "type": "string",
            "format": "date-time"
          },
          "currency": {
            "type": "string"
          },
          "timezone": {
            "type": "string",
            "enum": [
              "UTC"
            ]
          },
          "from": {
            "type": "string",
            "format": "date"
          },
          "to": {
            "type": "string",
            "format": "date"
          },
          "totals": {
            "type": "object",
            "properties": {
              "held_minor": {
                "type": "integer",
                "format": "int64"
              },
              "next_release_at": {
                "type": "string",
                "format": "date-time",
                "nullable": true
              },
              "released_minor": {
                "type": "integer",
                "format": "int64",
                "description": "Разблокированные начисления до учёта вывода; не доступный баланс."
              }
            }
          },
          "selected": {
            "type": "object",
            "properties": {
              "total": {
                "type": "integer",
                "format": "int64"
              },
              "earned_minor": {
                "type": "integer",
                "format": "int64"
              },
              "sms_count": {
                "type": "integer",
                "format": "int64"
              }
            }
          },
          "providers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HoldProvider"
            }
          },
          "daily": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HoldDaily"
            }
          },
          "schedule": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HoldSchedule"
            }
          },
          "rows": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HeldEarning"
            }
          },
          "page": {
            "type": "integer",
            "format": "int64"
          },
          "pages": {
            "type": "integer",
            "format": "int64"
          },
          "page_size": {
            "type": "integer",
            "format": "int64"
          },
          "total": {
            "type": "integer",
            "format": "int64"
          }
        }
      },
      "CatalogEntry": {
        "type": "object",
        "required": [
          "offer_id",
          "service",
          "service_name",
          "country_id",
          "country_name",
          "provider_id",
          "provider_name",
          "reward",
          "currency",
          "accounting_precision",
          "earnings_hold_days"
        ],
        "properties": {
          "offer_id": {
            "type": "integer",
            "format": "int64"
          },
          "service": {
            "type": "string"
          },
          "service_name": {
            "type": "string"
          },
          "country_id": {
            "type": "integer"
          },
          "country_name": {
            "type": "string"
          },
          "provider_id": {
            "type": "integer",
            "format": "int64",
            "minimum": 1,
            "example": 2,
            "description": "Public API provider ID. Operator 1 uses provider_id=1. Copy provider_id from tariffs/catalog or id from operators/getOperators and pass it when requesting a number. The upstream supplier channel is a separate identifier."
          },
          "provider_name": {
            "type": "string"
          },
          "reward": {
            "type": "string",
            "example": "0.00300000",
            "description": "Вознаграждение пользователя за SMS; определяется поставщиком и страной. Не цена покупки номера."
          },
          "currency": {
            "type": "string",
            "enum": [
              "USD",
              "TEST"
            ]
          },
          "accounting_precision": {
            "type": "integer",
            "enum": [
              8,
              2
            ]
          },
          "earnings_hold_days": {
            "type": "integer",
            "minimum": 0,
            "maximum": 45
          },
          "operator": {
            "type": "integer",
            "format": "int64",
            "minimum": 1,
            "example": 2,
            "description": "Public provider ID to pass as operator when requesting a number."
          }
        }
      },
      "CatalogPage": {
        "type": "object",
        "required": [
          "rows",
          "page",
          "page_size",
          "total",
          "pages",
          "has_more",
          "accounting_precision"
        ],
        "properties": {
          "rows": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CatalogEntry"
            }
          },
          "page": {
            "type": "integer",
            "minimum": 1
          },
          "page_size": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100
          },
          "total": {
            "type": "integer",
            "minimum": 0
          },
          "pages": {
            "type": "integer",
            "minimum": 1
          },
          "has_more": {
            "type": "boolean"
          },
          "accounting_precision": {
            "type": "integer",
            "enum": [
              8,
              2
            ]
          }
        }
      },
      "BatchActivation": {
        "oneOf": [
          {
            "type": "object",
            "required": [
              "id",
              "found",
              "phone",
              "status",
              "service",
              "country_id",
              "provider_id",
              "expires_at",
              "sms_count",
              "code",
              "last_sms"
            ],
            "properties": {
              "id": {
                "type": "integer",
                "format": "int64"
              },
              "found": {
                "type": "boolean",
                "enum": [
                  true
                ]
              },
              "phone": {
                "type": "string"
              },
              "status": {
                "type": "string",
                "enum": [
                  "waiting",
                  "received",
                  "finished",
                  "canceled",
                  "expired"
                ]
              },
              "service": {
                "type": "string"
              },
              "country_id": {
                "type": "integer"
              },
              "provider_id": {
                "type": "integer",
                "format": "int64",
                "nullable": true
              },
              "expires_at": {
                "type": "string",
                "format": "date-time"
              },
              "sms_count": {
                "type": "integer",
                "minimum": 0
              },
              "code": {
                "type": "string",
                "example": "001234",
                "description": "Новый код после последнего retry; пустая строка при ожидании. Не преобразовывайте в число."
              },
              "last_sms": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/SMS"
                  }
                ],
                "nullable": true,
                "description": "Последнее сообщение, включая ранее полученное до retry. Для всей истории используйте /activations/{id}/sms."
              }
            }
          },
          {
            "type": "object",
            "required": [
              "id",
              "found",
              "error"
            ],
            "properties": {
              "id": {
                "type": "integer",
                "format": "int64"
              },
              "found": {
                "type": "boolean",
                "enum": [
                  false
                ]
              },
              "error": {
                "type": "object",
                "required": [
                  "code",
                  "message"
                ],
                "properties": {
                  "code": {
                    "type": "string",
                    "enum": [
                      "NO_ACTIVATION"
                    ]
                  },
                  "message": {
                    "type": "string",
                    "example": "Session not found."
                  }
                }
              }
            }
          }
        ]
      },
      "BatchActivationPage": {
        "type": "object",
        "required": [
          "rows",
          "as_of",
          "poll_interval_seconds"
        ],
        "properties": {
          "rows": {
            "type": "array",
            "maxItems": 100,
            "items": {
              "$ref": "#/components/schemas/BatchActivation"
            }
          },
          "as_of": {
            "type": "string",
            "format": "date-time"
          },
          "poll_interval_seconds": {
            "type": "integer",
            "enum": [
              20
            ]
          }
        }
      },
      "CompatibleActivation": {
        "type": "object",
        "required": [
          "activationId",
          "phoneNumber",
          "activationCost",
          "currency",
          "countryCode",
          "canGetAnotherSms",
          "activationTime",
          "activationEndTime",
          "reward"
        ],
        "properties": {
          "activationId": {
            "type": "string",
            "pattern": "^[1-9]\\d*$"
          },
          "phoneNumber": {
            "type": "string",
            "pattern": "^\\d{5,15}$"
          },
          "activationCost": {
            "type": "number",
            "enum": [
              0
            ],
            "description": "Номер предоставляется бесплатно. Списание с баланса не производится."
          },
          "currency": {
            "type": "integer",
            "enum": [
              840
            ],
            "description": "ISO 4217: USD."
          },
          "countryCode": {
            "type": "integer",
            "minimum": 1
          },
          "canGetAnotherSms": {
            "type": "boolean"
          },
          "activationTime": {
            "type": "string",
            "format": "date-time"
          },
          "activationEndTime": {
            "type": "string",
            "format": "date-time"
          },
          "activationOperator": {
            "type": "string",
            "nullable": true
          },
          "reward": {
            "type": "string",
            "pattern": "^\\d+\\.\\d{8}$",
            "example": "0.00300000",
            "description": "Вознаграждение пользователя за SMS в USD по тарифу страны, с холдом поставщика; это не цена покупки номера."
          }
        }
      },
      "CompatibleStatus": {
        "type": "object",
        "required": [
          "verificationType",
          "sms",
          "call"
        ],
        "properties": {
          "verificationType": {
            "type": "integer",
            "enum": [
              1
            ]
          },
          "sms": {
            "type": "object",
            "nullable": true,
            "required": [
              "code",
              "text",
              "dateTime"
            ],
            "properties": {
              "code": {
                "type": "string",
                "example": "001234"
              },
              "text": {
                "type": "string"
              },
              "dateTime": {
                "type": "string",
                "format": "date-time"
              }
            }
          },
          "call": {
            "nullable": true,
            "enum": [
              null
            ]
          }
        }
      },
      "ClientBalance": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "currency",
          "accounting_precision",
          "balance",
          "held_balance",
          "balance_minor",
          "held_minor",
          "as_of",
          "next_release_at"
        ],
        "properties": {
          "currency": {
            "type": "string",
            "enum": [
              "USD"
            ]
          },
          "accounting_precision": {
            "type": "integer",
            "enum": [
              8
            ]
          },
          "balance": {
            "type": "string",
            "pattern": "^-?[0-9]+\\.[0-9]{8}$",
            "description": "Доступный остаток после резервирования заявок на выплату, без холда."
          },
          "held_balance": {
            "type": "string",
            "pattern": "^-?[0-9]+\\.[0-9]{8}$",
            "description": "Сумма всех ещё недоступных USD-начислений владельца ключа, с бонусами и вычетом отменённых начислений."
          },
          "balance_minor": {
            "type": "string",
            "pattern": "^-?[0-9]+$",
            "description": "Доступный баланс в единицах 10^-8 USD. Строка сохраняет точность больших сумм."
          },
          "held_minor": {
            "type": "string",
            "pattern": "^-?[0-9]+$",
            "description": "Холд в единицах 10^-8 USD. Строка сохраняет точность больших сумм."
          },
          "as_of": {
            "type": "string",
            "format": "date-time",
            "description": "Единое время снимка базы, UTC."
          },
          "next_release_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Ближайшее окончание положительного холда, UTC; null, если такого холда нет."
          }
        },
        "example": {
          "currency": "USD",
          "accounting_precision": 8,
          "balance": "12.00000000",
          "held_balance": "34.50000001",
          "balance_minor": "1200000000",
          "held_minor": "3450000001",
          "as_of": "2026-10-12T20:00:00Z",
          "next_release_at": "2026-11-26T20:00:00Z"
        }
      },
      "ServiceStatisticsDay": {
        "type": "object",
        "required": [
          "provider_id",
          "country_id",
          "service",
          "date",
          "codes_count"
        ],
        "properties": {
          "provider_id": {
            "type": "integer",
            "format": "int64",
            "nullable": true
          },
          "operator": {
            "type": "integer",
            "format": "int64",
            "nullable": true
          },
          "country_id": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "service": {
            "type": "string"
          },
          "date": {
            "type": "string",
            "format": "date"
          },
          "codes_count": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          }
        }
      },
      "StatisticsDeliveryDay": {
        "type": "object",
        "required": [
          "provider_id",
          "country_id",
          "service",
          "date",
          "codes_count",
          "sessions_count",
          "delivery_percent"
        ],
        "properties": {
          "provider_id": {
            "type": "integer",
            "format": "int64",
            "nullable": true
          },
          "operator": {
            "type": "integer",
            "format": "int64",
            "nullable": true
          },
          "country_id": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "service": {
            "type": "string"
          },
          "date": {
            "type": "string",
            "format": "date"
          },
          "codes_count": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "sessions_count": {
            "type": "integer",
            "format": "int64",
            "minimum": 0,
            "nullable": true
          },
          "delivery_percent": {
            "type": "string",
            "nullable": true,
            "pattern": "^[0-9]+\\.[0-9]{2}$",
            "example": "75.00",
            "description": "Received nonempty codes × 100 / issued sessions for the same window. Two decimal places. Repeated codes or receipt/issuance timing can exceed 100. Null when there are no issued sessions or historical provider attribution is incomplete."
          }
        }
      },
      "StatisticsDeliveryGroup": {
        "type": "object",
        "required": [
          "country_id",
          "service",
          "sms_30d",
          "sessions_30d",
          "delivery_30d",
          "sms_7d",
          "sessions_7d",
          "delivery_7d",
          "sms_24h",
          "sessions_24h",
          "delivery_24h",
          "sms_1h",
          "sessions_1h",
          "delivery_1h"
        ],
        "properties": {
          "country_id": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "service": {
            "type": "string"
          },
          "sms_30d": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "sessions_30d": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "delivery_30d": {
            "type": "string",
            "nullable": true,
            "pattern": "^[0-9]+\\.[0-9]{2}$",
            "example": "75.00",
            "description": "All-provider received codes × 100 / all issued sessions for this country/service and window, including unattributed legacy sessions. Null only when there are no sessions."
          },
          "sms_7d": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "sessions_7d": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "delivery_7d": {
            "type": "string",
            "nullable": true,
            "pattern": "^[0-9]+\\.[0-9]{2}$",
            "example": "75.00",
            "description": "All-provider received codes × 100 / all issued sessions for this country/service and window, including unattributed legacy sessions. Null only when there are no sessions."
          },
          "sms_24h": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "sessions_24h": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "delivery_24h": {
            "type": "string",
            "nullable": true,
            "pattern": "^[0-9]+\\.[0-9]{2}$",
            "example": "75.00",
            "description": "All-provider received codes × 100 / all issued sessions for this country/service and window, including unattributed legacy sessions. Null only when there are no sessions."
          },
          "sms_1h": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "sessions_1h": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "delivery_1h": {
            "type": "string",
            "nullable": true,
            "pattern": "^[0-9]+\\.[0-9]{2}$",
            "example": "75.00",
            "description": "All-provider received codes × 100 / all issued sessions for this country/service and window, including unattributed legacy sessions. Null only when there are no sessions."
          }
        }
      },
      "StatisticsDeliveryGroupDay": {
        "type": "object",
        "required": [
          "country_id",
          "service",
          "date",
          "codes_count",
          "sessions_count",
          "unattributed_sessions_count",
          "delivery_percent"
        ],
        "properties": {
          "country_id": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "service": {
            "type": "string"
          },
          "date": {
            "type": "string",
            "format": "date"
          },
          "codes_count": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "sessions_count": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "unattributed_sessions_count": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "delivery_percent": {
            "type": "string",
            "nullable": true,
            "pattern": "^[0-9]+\\.[0-9]{2}$",
            "example": "75.00",
            "description": "All-provider daily delivery percentage for this country/service in UTC+3. Null when there are no sessions."
          }
        }
      },
      "RewardsCatalog": {
        "type": "object",
        "description": "getRewards (SMScash): country ID → service code → public provider ID → reward. Rewards are exact USD decimal strings with 8 places. country, service and operator are optional filters; omit operator or use any/0 to include every permitted provider. The IDs match operator in catalog/tariffs and getOperators, not upstream channel IDs. Current enabled tariffs, account permissions and API key scopes apply. Empty selection returns {}. No stock check, allocation or financial operation is performed.",
        "example": {
          "59": {
            "vi": {
              "1": "0.01000000",
              "3": "0.00500000"
            }
          }
        },
        "additionalProperties": {
          "type": "object",
          "description": "Country ID → service code.",
          "additionalProperties": {
            "type": "object",
            "description": "Service code → public provider ID accepted by operator.",
            "additionalProperties": {
              "type": "string",
              "pattern": "^[0-9]+\\.[0-9]{8}$",
              "example": "0.01000000",
              "description": "Current reward paid to the user per eligible SMS, in USD. No supplier income or platform margin."
            }
          }
        }
      },
      "PublicOperator": {
        "type": "object",
        "required": [
          "id",
          "operator",
          "provider_id",
          "name",
          "earnings_hold_days"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64",
            "minimum": 1,
            "example": 1,
            "description": "Public API operator ID. Pass this integer as operator when requesting a number."
          },
          "operator": {
            "type": "integer",
            "format": "int64",
            "minimum": 1,
            "example": 1,
            "description": "Canonical number-allocation selector; identical to id."
          },
          "provider_id": {
            "type": "integer",
            "format": "int64",
            "minimum": 1,
            "example": 1,
            "description": "Response alias of id. Request parameters use operator."
          },
          "name": {
            "type": "string",
            "example": "Оператор 1"
          },
          "earnings_hold_days": {
            "type": "integer",
            "minimum": 0,
            "maximum": 45
          }
        }
      },
      "OperatorsCatalog": {
        "type": "object",
        "additionalProperties": {
          "$ref": "#/components/schemas/PublicOperator"
        }
      },
      "CompatibleOperators": {
        "type": "object",
        "required": [
          "status",
          "countryOperators",
          "operators"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "success"
            ]
          },
          "countryOperators": {
            "type": "object",
            "additionalProperties": {
              "type": "array",
              "items": {
                "type": "string",
                "pattern": "^[1-9][0-9]*$"
              }
            }
          },
          "operators": {
            "$ref": "#/components/schemas/OperatorsCatalog"
          }
        }
      }
    }
  },
  "paths": {
    "/api/v1/auth/login": {
      "post": {
        "summary": "Вход",
        "tags": [
          "Worker"
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/User"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "201": {
            "description": "Object created",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "400": {
            "description": "Invalid input",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "403": {
            "description": "EMAIL_NOT_VERIFIED: verify the email address before signing in",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "405": {
            "description": "METHOD_NOT_ALLOWED: допустимые методы перечислены в Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              },
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "409": {
            "description": "State or idempotency conflict",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "ALLOCATION_PENDING: 3 секунды, retryable=true; повторить те же параметры с прежним ключом. ALLOCATION_UNCERTAIN: retryable=false, автоматический повтор запрещён."
              }
            }
          },
          "429": {
            "description": "Rate limit, retry after 60 seconds",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          }
        },
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "password": {
                    "type": "string",
                    "format": "password"
                  }
                },
                "required": [
                  "email",
                  "password"
                ]
              }
            }
          }
        }
      }
    },
    "/api/v1/auth/register": {
      "post": {
        "summary": "Регистрация и закрепление реферера",
        "tags": [
          "Worker"
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "201": {
            "description": "Account created; email verification required when enabled",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "verification_required": {
                      "type": "boolean"
                    },
                    "public_id": {
                      "type": "integer",
                      "format": "int64",
                      "minimum": 1,
                      "example": 2,
                      "description": "Постоянный числовой ID пользователя. Новые аккаунты получают следующий номер; удалённые ID не используются повторно."
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "400": {
            "description": "Invalid input",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "403": {
            "description": "Insufficient privileges",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "405": {
            "description": "METHOD_NOT_ALLOWED: допустимые методы перечислены в Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              },
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "409": {
            "description": "State or idempotency conflict",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "ALLOCATION_PENDING: 3 секунды, retryable=true; повторить те же параметры с прежним ключом. ALLOCATION_UNCERTAIN: retryable=false, автоматический повтор запрещён."
              }
            }
          },
          "429": {
            "description": "Rate limit, retry after 60 seconds",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "503": {
            "description": "EMAIL_SEND_FAILED: retry sending the verification email after one minute",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          }
        },
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "name": {
                    "type": "string"
                  },
                  "password": {
                    "type": "string",
                    "minLength": 12,
                    "maxLength": 72
                  },
                  "referral_code": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 64,
                    "example": "2",
                    "description": "ID владельца кода в виде строки. Старые реферальные коды также принимаются и сохраняют прежнего владельца."
                  },
                  "language": {
                    "type": "string",
                    "description": "Язык письма и страницы подтверждения, например ru или en. По умолчанию en."
                  }
                },
                "required": [
                  "email",
                  "name",
                  "password"
                ]
              }
            }
          }
        },
        "description": "Создаёт аккаунт и сохраняет пригласившего. При включённом подтверждении почты отправляет одноразовую ссылку на 24 часа, возвращает verification_required=true и не создаёт сессию. Вход доступен после POST /api/v1/auth/verify-email. При ошибке отправки аккаунт остаётся неподтверждённым; запросите повторное письмо с почтой и паролем."
      }
    },
    "/api/v1/auth/logout": {
      "post": {
        "summary": "Выход",
        "tags": [
          "Worker"
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "201": {
            "description": "Object created",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "400": {
            "description": "Invalid input",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "403": {
            "description": "Insufficient privileges",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "405": {
            "description": "METHOD_NOT_ALLOWED: допустимые методы перечислены в Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              },
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "409": {
            "description": "State or idempotency conflict",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "ALLOCATION_PENDING: 3 секунды, retryable=true; повторить те же параметры с прежним ключом. ALLOCATION_UNCERTAIN: retryable=false, автоматический повтор запрещён."
              }
            }
          },
          "429": {
            "description": "Rate limit, retry after 60 seconds",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {},
                "required": []
              }
            }
          }
        }
      }
    },
    "/api/v1/me": {
      "get": {
        "summary": "Профиль",
        "tags": [
          "Worker"
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "user": {
                      "$ref": "#/components/schemas/User"
                    },
                    "currency": {
                      "type": "string",
                      "enum": [
                        "USD",
                        "TEST"
                      ]
                    },
                    "accounting_precision": {
                      "type": "integer"
                    },
                    "payouts_enabled": {
                      "type": "boolean",
                      "description": "Приём заявок включён; не означает автоматический перевод.",
                      "example": true
                    },
                    "provider": {
                      "type": "object"
                    },
                    "payouts_mode": {
                      "type": "string",
                      "enum": [
                        "manual_requests"
                      ]
                    },
                    "automatic_payouts_enabled": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "payout_settings": {
                      "$ref": "#/components/schemas/PayoutSettings"
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "400": {
            "description": "Invalid input",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "403": {
            "description": "Insufficient privileges",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "405": {
            "description": "METHOD_NOT_ALLOWED: допустимые методы перечислены в Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              },
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "409": {
            "description": "State or idempotency conflict",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "ALLOCATION_PENDING: 3 секунды, retryable=true; повторить те же параметры с прежним ключом. ALLOCATION_UNCERTAIN: retryable=false, автоматический повтор запрещён."
              }
            }
          }
        },
        "description": "Рабочий баланс в USD, accounting_precision=8. payouts_enabled=true включает приём заявок USDT TRC20; payouts_mode=manual_requests, automatic_payouts_enabled=false. Доступность выдачи номеров и подтверждение почты проверяются отдельно. Срок выплаты — от 1 до 45 дней."
      }
    },
    "/api/v1/summary": {
      "get": {
        "summary": "Баланс и начисления",
        "tags": [
          "Worker"
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "400": {
            "description": "Invalid input",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "403": {
            "description": "Insufficient privileges",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "405": {
            "description": "METHOD_NOT_ALLOWED: допустимые методы перечислены в Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              },
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "409": {
            "description": "State or idempotency conflict",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "ALLOCATION_PENDING: 3 секунды, retryable=true; повторить те же параметры с прежним ключом. ALLOCATION_UNCERTAIN: retryable=false, автоматический повтор запрещён."
              }
            }
          }
        },
        "description": " balance_minor содержит доступный остаток после резервов и возвратов, без сумм в холде; held_minor — ещё недоступные начисления; next_release_at — ближайшая дата доступности. Холды заканчиваются автоматически по времени, без повторных начислений или отдельного перевода. Срок поставщика фиксируется для каждого нового SMS и его бонусов. Дополнительно balance и held_balance — точные денежные строки с accounting_precision; прежние числовые *_minor и остальные поля сохраняются."
      }
    },
    "/api/v1/offers": {
      "get": {
        "summary": "Тарифы",
        "tags": [
          "Worker"
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "400": {
            "description": "Invalid input",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "403": {
            "description": "Insufficient privileges",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "405": {
            "description": "METHOD_NOT_ALLOWED: допустимые методы перечислены в Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              },
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "409": {
            "description": "State or idempotency conflict",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "ALLOCATION_PENDING: 3 секунды, retryable=true; повторить те же параметры с прежним ключом. ALLOCATION_UNCERTAIN: retryable=false, автоматический повтор запрещён."
              }
            }
          }
        }
      }
    },
    "/api/v1/activations": {
      "get": {
        "summary": "Последние 200 сессий",
        "tags": [
          "Worker"
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "400": {
            "description": "Invalid input",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "403": {
            "description": "Insufficient privileges",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "405": {
            "description": "METHOD_NOT_ALLOWED: допустимые методы перечислены в Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              },
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "409": {
            "description": "State or idempotency conflict",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "ALLOCATION_PENDING: 3 секунды, retryable=true; повторить те же параметры с прежним ключом. ALLOCATION_UNCERTAIN: retryable=false, автоматический повтор запрещён."
              }
            }
          }
        },
        "description": "Up to 200 sessions per scope. History includes only sessions with received SMS codes. Waiting reservations remain separate; closed sessions without SMS are deleted.",
        "parameters": [
          {
            "name": "scope",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "all",
                "history",
                "waiting"
              ],
              "default": "all"
            },
            "description": "history: received codes; waiting: open reservations without a code; all: both."
          }
        ]
      },
      "post": {
        "summary": "Выдать номер",
        "tags": [
          "Worker"
        ],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "sessionCookie": []
          }
        ],
        "responses": {
          "200": {
            "description": "Идемпотентный повтор",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Activation"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "201": {
            "description": "Новая сессия",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Activation"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "400": {
            "description": "Ошибка запроса, доступа или состояния Для API-ключа BAD_SERVICE означает несуществующий, отключённый или заблокированный сервис без персонального разрешения. Персональное разрешение не отменяет отключение сервиса или ограничения API-ключа.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "401": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "403": {
            "description": "Ошибка доступа: Разрешённые связки сервиса, страны и оператора возвращает GET /api/v1/catalog. Каталог учитывает текущие ограничения аккаунта, сервисов, стран и поставщиков, а также область доступа API-ключа. Наличие номеров проверяется при выдаче.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "404": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "405": {
            "description": "METHOD_NOT_ALLOWED: допустимые методы перечислены в Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              },
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "409": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "ALLOCATION_PENDING: 3 секунды, retryable=true; повторить те же параметры с прежним ключом. ALLOCATION_UNCERTAIN: retryable=false, автоматический повтор запрещён."
              }
            }
          },
          "503": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 128
            },
            "description": "Один ключ на логическую операцию. При повторе сохраните его и параметры."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "offer_id": {
                    "type": "integer",
                    "format": "int64",
                    "minimum": 1,
                    "description": "Совместимый прежний формат: ID из offers или catalog. Не сочетайте с service/country."
                  },
                  "duration_minutes": {
                    "type": "integer",
                    "enum": [
                      20,
                      15
                    ],
                    "default": 20,
                    "description": "New reservations last 20 minutes. The previous value 15 is accepted as a compatibility alias for 20. Idempotent replays return the original reservation and do not extend it."
                  },
                  "operator": {
                    "oneOf": [
                      {
                        "type": "integer",
                        "format": "int64",
                        "minimum": 0,
                        "maximum": 2147483647,
                        "example": 1
                      },
                      {
                        "type": "string",
                        "pattern": "^([0-9]+|[aA][nN][yY])?$",
                        "example": "1"
                      }
                    ],
                    "description": "Public provider ID from operators/getOperators or the operator field in tariffs/catalog. Operator 1 uses operator=1. Accepts an integer or its decimal string. Omit operator or use any/0 for automatic selection; an explicit ID selects only that provider. Country operator record IDs and provider names are not selectors."
                  },
                  "ref": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 64,
                    "example": "2",
                    "description": "ID владельца кода в виде строки. Старые реферальные коды также принимаются и сохраняют прежнего владельца."
                  },
                  "service": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 64,
                    "example": "go",
                    "description": "Точный код из catalog или services."
                  },
                  "country": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 2147483647,
                    "example": 86,
                    "description": "Числовой ID страны из catalog/countries, а не ISO-код."
                  }
                },
                "oneOf": [
                  {
                    "required": [
                      "offer_id"
                    ],
                    "not": {
                      "anyOf": [
                        {
                          "required": [
                            "service"
                          ]
                        },
                        {
                          "required": [
                            "country"
                          ]
                        }
                      ]
                    }
                  },
                  {
                    "required": [
                      "service",
                      "country"
                    ],
                    "not": {
                      "required": [
                        "offer_id"
                      ]
                    }
                  }
                ]
              },
              "examples": {
                "serviceCountry": {
                  "summary": "Сервис и страна",
                  "value": {
                    "service": "go",
                    "country": 86
                  }
                },
                "offer": {
                  "summary": "Совместимый формат",
                  "value": {
                    "offer_id": 42,
                    "duration_minutes": 20
                  }
                },
                "software": {
                  "summary": "Код владельца софта",
                  "value": {
                    "service": "go",
                    "country": 86,
                    "ref": "123"
                  }
                },
                "operator": {
                  "summary": "Selected provider: Operator 1 uses operator=1",
                  "value": {
                    "service": "go",
                    "country": 86,
                    "operator": 1
                  }
                }
              }
            }
          }
        },
        "description": "Выберите service + country либо offer_id. Два формата возвращают одинаковую сессию и используют одну защиту повторов; смешивать их нельзя. Частота запросов и количество активных номеров не ограничены; выдача зависит от наличия и области доступа ключа. Выдача сама по себе не оплачивается. Вознаграждение начисляется автоматически при получении нового SMS с непустым кодом, до завершения сессии. Keys of deleted no-SMS sessions stay consumed. Replaying the key cannot issue a new number; allocation returns SESSION_CLOSED (or NO_ACTIVATION when repeat ownership no longer exists). Разрешённые связки сервиса, страны и оператора возвращает GET /api/v1/catalog. Каталог учитывает текущие ограничения аккаунта, сервисов, стран и поставщиков, а также область доступа API-ключа. Наличие номеров проверяется при выдаче. Числовой код именованного сервиса разрешён. Коды wa, bye, tg и eh, а также новые коды этих сервисов из каталога поставщика недоступны. Запрет действует для новой и повторной выдачи, retry и повторов запросов с прежним Idempotency-Key. REST с API-ключом: HTTP 400 с кодом BAD_SERVICE; handler_api.php: HTTP 200 с текстом BAD_SERVICE. Несуществующий или отключённый сервис также возвращает BAD_SERVICE. Явное персональное разрешение пользователя снимает только блокировку сервиса. Оно не разрешает отсутствующий или отключённый сервис и не отменяет область доступа API-ключа. Исторические SMS и начисления сохраняются.",
        "x-smscash-automatic-routing": {
          "mode": "received_codes",
          "pair": [
            "service",
            "country"
          ],
          "priority": [
            "codes_last_1h",
            "codes_last_24h",
            "reward_desc",
            "provider_id_asc"
          ],
          "statistics_cache_seconds": 30,
          "empty_pool_fallback": true,
          "fallback_codes": [
            "EMPTY_POOL",
            "NO_NUMBERS"
          ],
          "explicit_provider_is_strict": true,
          "explicit_operator_is_strict": true,
          "repeat_number_keeps_its_provider": true,
          "uncertain_result_fallback": false,
          "idempotency_key_preserved": true,
          "current_key_scopes_and_restrictions": true
        }
      }
    },
    "/api/v1/activations/{id}": {
      "get": {
        "summary": "Сессия и история SMS",
        "tags": [
          "Worker"
        ],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "sessionCookie": []
          }
        ],
        "responses": {
          "200": {
            "description": "Успешный ответ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Activation"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "400": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "401": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "403": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "404": {
            "description": "NO_ACTIVATION: unknown session, another user’s session, or a deleted closed session without SMS.",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "405": {
            "description": "METHOD_NOT_ALLOWED: допустимые методы перечислены в Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              },
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "409": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "ALLOCATION_PENDING: 3 секунды, retryable=true; повторить те же параметры с прежним ключом. ALLOCATION_UNCERTAIN: retryable=false, автоматический повтор запрещён."
              }
            }
          },
          "503": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ]
      }
    },
    "/api/v1/ledger": {
      "get": {
        "summary": "Последние 200 операций",
        "tags": [
          "Worker"
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "400": {
            "description": "Invalid input",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "403": {
            "description": "Insufficient privileges",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "405": {
            "description": "METHOD_NOT_ALLOWED: допустимые методы перечислены в Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              },
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "409": {
            "description": "State or idempotency conflict",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "ALLOCATION_PENDING: 3 секунды, retryable=true; повторить те же параметры с прежним ключом. ALLOCATION_UNCERTAIN: retryable=false, автоматический повтор запрещён."
              }
            }
          }
        },
        "description": "Виды операций: sms_reward, referral_reward, software_reward, withdrawal_hold, withdrawal_refund. bonus_percent хранит ставку конкретного бонуса: 10 или 5 для referral_reward, 5 для software_reward, null для остальных операций. Код SMS и номер возвращаются только для sms_reward владельцу номера. balance_minor содержит доступный остаток после резервов и возвратов, без сумм в холде; held_minor — ещё недоступные начисления; next_release_at — ближайшая дата доступности. Холды заканчиваются автоматически по времени, без повторных начислений или отдельного перевода. Срок поставщика фиксируется для каждого нового SMS и его бонусов."
      }
    },
    "/api/v1/referrals": {
      "get": {
        "summary": "Приглашения, код для софта и отдельная статистика бонусов",
        "tags": [
          "Worker"
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "referral_code": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 64,
                      "example": "2",
                      "description": "ID владельца кода в виде строки. Старые реферальные коды также принимаются и сохраняют прежнего владельца."
                    },
                    "software_ref": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 64,
                      "example": "2",
                      "description": "ID владельца кода в виде строки. Старые реферальные коды также принимаются и сохраняют прежнего владельца."
                    },
                    "percent": {
                      "type": "integer",
                      "enum": [
                        10
                      ]
                    },
                    "software_percent": {
                      "type": "integer",
                      "enum": [
                        5
                      ]
                    },
                    "split_referral_percent": {
                      "type": "integer",
                      "enum": [
                        5
                      ]
                    },
                    "invited_count": {
                      "type": "integer",
                      "minimum": 0
                    },
                    "earned_minor": {
                      "type": "integer",
                      "minimum": 0
                    },
                    "referral_earned_minor": {
                      "type": "integer",
                      "minimum": 0
                    },
                    "software_earned_minor": {
                      "type": "integer",
                      "minimum": 0
                    },
                    "rewarded_sms": {
                      "type": "integer",
                      "minimum": 0
                    },
                    "software_rewarded_sms": {
                      "type": "integer",
                      "minimum": 0
                    },
                    "people": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "name": {
                            "type": "string"
                          },
                          "created_at": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "earned_minor": {
                            "type": "integer",
                            "description": "Только бонусы за приглашение этого пользователя."
                          },
                          "public_id": {
                            "type": "integer",
                            "format": "int64",
                            "minimum": 1,
                            "example": 2,
                            "description": "Постоянный числовой ID пользователя. Новые аккаунты получают следующий номер; удалённые ID не используются повторно."
                          }
                        }
                      }
                    },
                    "public_id": {
                      "type": "integer",
                      "format": "int64",
                      "minimum": 1,
                      "example": 2,
                      "description": "Постоянный числовой ID пользователя. Новые аккаунты получают следующий номер; удалённые ID не используются повторно."
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "400": {
            "description": "Invalid input",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "403": {
            "description": "Insufficient privileges",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "405": {
            "description": "METHOD_NOT_ALLOWED: допустимые методы перечислены в Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              },
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "409": {
            "description": "State or idempotency conflict",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "ALLOCATION_PENDING: 3 секунды, retryable=true; повторить те же параметры с прежним ключом. ALLOCATION_UNCERTAIN: retryable=false, автоматический повтор запрещён."
              }
            }
          }
        },
        "description": "Программа одноуровневая. referral_code используется при регистрации по приглашению; этот же публичный код передаётся как software_ref в поле ref при выдаче номера через софт. earned_minor включает оба вида бонусов; rewarded_sms считает уникальные оплаченные SMS, даже когда оба бонуса получает один аккаунт. people содержит только приглашённых пользователей и бонусы за их приглашение. Валюта сайта — USD. Условия реферальной программы: 10% без кода софта или 5% + 5% с кодом софта. Доход пользователя не уменьшается. referral_code и software_ref совпадают с public_id пользователя в виде строки, например \"2\". Старые ссылки и коды для софта продолжают работать; пригласивший зарегистрированного аккаунта не меняется."
      }
    },
    "/api/v1/keys": {
      "get": {
        "summary": "Личные API-ключи",
        "tags": [
          "Worker"
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "400": {
            "description": "Invalid input",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "403": {
            "description": "Insufficient privileges",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "405": {
            "description": "METHOD_NOT_ALLOWED: допустимые методы перечислены в Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              },
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "409": {
            "description": "State or idempotency conflict",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "ALLOCATION_PENDING: 3 секунды, retryable=true; повторить те же параметры с прежним ключом. ALLOCATION_UNCERTAIN: retryable=false, автоматический повтор запрещён."
              }
            }
          }
        }
      },
      "post": {
        "summary": "Создать ключ; секрет возвращается один раз",
        "tags": [
          "Worker"
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "201": {
            "description": "Object created",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "400": {
            "description": "Invalid input",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "403": {
            "description": "Insufficient privileges",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "405": {
            "description": "METHOD_NOT_ALLOWED: допустимые методы перечислены в Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              },
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "409": {
            "description": "State or idempotency conflict",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "ALLOCATION_PENDING: 3 секунды, retryable=true; повторить те же параметры с прежним ключом. ALLOCATION_UNCERTAIN: retryable=false, автоматический повтор запрещён."
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "label": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 80
                  },
                  "policy": {
                    "$ref": "#/components/schemas/APIKeyPolicy"
                  }
                },
                "required": [
                  "label"
                ]
              }
            }
          }
        },
        "security": [
          {
            "sessionCookie": []
          }
        ]
      }
    },
    "/api/v1/withdrawals": {
      "get": {
        "summary": "Последние 200 заявок",
        "tags": [
          "Worker"
        ],
        "responses": {
          "200": {
            "description": "Последние 200 собственных заявок, от новых к старым",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Withdrawal"
                  }
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "400": {
            "description": "Invalid input",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "403": {
            "description": "Insufficient privileges",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "405": {
            "description": "METHOD_NOT_ALLOWED: допустимые методы перечислены в Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              },
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "409": {
            "description": "State or idempotency conflict",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "ALLOCATION_PENDING: 3 секунды, retryable=true; повторить те же параметры с прежним ключом. ALLOCATION_UNCERTAIN: retryable=false, автоматический повтор запрещён."
              }
            }
          }
        },
        "description": " Срок выплаты — от 1 до 45 дней. balance_minor содержит доступный остаток после резервов и возвратов, без сумм в холде; held_minor — ещё недоступные начисления; next_release_at — ближайшая дата доступности. Холды заканчиваются автоматически по времени, без повторных начислений или отдельного перевода. Срок поставщика фиксируется для каждого нового SMS и его бонусов."
      },
      "post": {
        "summary": "Создать заявку на вывод USDT TRC20",
        "tags": [
          "Worker"
        ],
        "responses": {
          "200": {
            "description": "Заявка с фиксированными суммой, комиссией и реквизитами",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Withdrawal"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "201": {
            "description": "Заявка с фиксированными суммой, комиссией и реквизитами",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Withdrawal"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "400": {
            "description": "BAD_WITHDRAWAL_AMOUNT, BAD_TRC20_ADDRESS, UNSUPPORTED_PAYOUT_NETWORK или неверный запрос",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "403": {
            "description": "Insufficient privileges",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "405": {
            "description": "METHOD_NOT_ALLOWED: допустимые методы перечислены в Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              },
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "409": {
            "description": "INSUFFICIENT_BALANCE или IDEMPOTENCY_CONFLICT",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "ALLOCATION_PENDING: 3 секунды, retryable=true; повторить те же параметры с прежним ключом. ALLOCATION_UNCERTAIN: retryable=false, автоматический повтор запрещён."
              }
            }
          }
        },
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 128
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "amount_minor",
                  "destination"
                ],
                "properties": {
                  "amount_minor": {
                    "type": "integer",
                    "format": "int64",
                    "minimum": 10000000000,
                    "maximum": 100000000000000,
                    "multipleOf": 100,
                    "example": 10000000000
                  },
                  "destination": {
                    "type": "string",
                    "minLength": 34,
                    "maxLength": 34,
                    "pattern": "^T[1-9A-HJ-NP-Za-km-z]{33}$",
                    "description": "Кошелёк получателя TRC20. Сервер дополнительно проверяет Base58Check."
                  },
                  "asset": {
                    "type": "string",
                    "enum": [
                      "USDT"
                    ],
                    "default": "USDT"
                  },
                  "network": {
                    "type": "string",
                    "enum": [
                      "TRC20"
                    ],
                    "default": "TRC20"
                  }
                }
              }
            }
          }
        },
        "description": "Принимается заявка на ручную выплату USDT TRC20. Баланс ведётся в USD с точностью 10^-8. Курс вывода: 1 USD = 1 USDT. Комиссия 4 USD удерживается из amount_minor; Минимум 100 USD: при 10000000000 резервируется 100 USD и выплачивается 96 USDT. Максимум 6 знаков после запятой без скрытого округления. На балансе резервируется вся сумма. Повтор с тем же Idempotency-Key и параметрами возвращает ту же заявку даже после обработки; другие параметры дают 409. Сам запрос не отправляет криптовалюту. Срок выплаты — от 1 до 45 дней. Суммы, у которых ещё не наступила available_at, не могут быть зарезервированы для выплаты. Проверка доступного USD-баланса и резерв выполняются под одной блокировкой пользователя."
      }
    },
    "/api/v1/dashboard": {
      "get": {
        "summary": "Статистика по сессиям периода; Redis TTL 5s",
        "tags": [
          "Worker"
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "400": {
            "description": "Invalid input",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "403": {
            "description": "Insufficient privileges",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "405": {
            "description": "METHOD_NOT_ALLOWED: допустимые методы перечислены в Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              },
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "409": {
            "description": "State or idempotency conflict",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "ALLOCATION_PENDING: 3 секунды, retryable=true; повторить те же параметры с прежним ключом. ALLOCATION_UNCERTAIN: retryable=false, автоматический повтор запрещён."
              }
            }
          }
        },
        "parameters": [
          {
            "name": "period",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "today",
                "yesterday",
                "7d",
                "30d"
              ],
              "default": "today"
            }
          },
          {
            "name": "tz",
            "in": "query",
            "schema": {
              "type": "integer",
              "description": "UTC offset in minutes, multiple of 15",
              "minimum": -720,
              "maximum": 840
            }
          },
          {
            "name": "key",
            "in": "query",
            "schema": {
              "type": "string",
              "description": "API key UUID, web, or empty for all"
            }
          },
          {
            "name": "country",
            "in": "query",
            "schema": {
              "type": "integer",
              "description": "Chart filter; empty/0 means all"
            }
          }
        ]
      }
    },
    "/api/v1/activations/{id}/finish": {
      "post": {
        "summary": "Завершить сессию",
        "tags": [
          "Worker"
        ],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "sessionCookie": []
          }
        ],
        "responses": {
          "200": {
            "description": "Успешный ответ",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "status"
                  ],
                  "properties": {
                    "status": {
                      "type": "string",
                      "enum": [
                        "finished"
                      ]
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "400": {
            "description": "Ошибка запроса, доступа или состояния Для API-ключа BAD_SERVICE означает несуществующий, отключённый или заблокированный сервис без персонального разрешения. Персональное разрешение не отменяет отключение сервиса или ограничения API-ключа.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "401": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "403": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "404": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "405": {
            "description": "METHOD_NOT_ALLOWED: допустимые методы перечислены в Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              },
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "409": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "ALLOCATION_PENDING: 3 секунды, retryable=true; повторить те же параметры с прежним ключом. ALLOCATION_UNCERTAIN: retryable=false, автоматический повтор запрещён."
              }
            }
          },
          "503": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "description": "Завершает сессию после получения хотя бы одного SMS. Вознаграждение уже начислено при получении кода; завершение не создаёт нового начисления. Повторное завершение идемпотентно."
      }
    },
    "/api/v1/activations/{id}/cancel": {
      "post": {
        "summary": "Мгновенно отменить номер",
        "tags": [
          "Worker"
        ],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "sessionCookie": []
          }
        ],
        "responses": {
          "200": {
            "description": "Успешный ответ",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "status"
                  ],
                  "properties": {
                    "status": {
                      "type": "string",
                      "enum": [
                        "canceled"
                      ]
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "400": {
            "description": "Ошибка запроса, доступа или состояния Для API-ключа BAD_SERVICE означает несуществующий, отключённый или заблокированный сервис без персонального разрешения. Персональное разрешение не отменяет отключение сервиса или ограничения API-ключа.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "401": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "403": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "404": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "405": {
            "description": "METHOD_NOT_ALLOWED: допустимые методы перечислены в Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              },
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "409": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "ALLOCATION_PENDING: 3 секунды, retryable=true; повторить те же параметры с прежним ключом. ALLOCATION_UNCERTAIN: retryable=false, автоматический повтор запрещён."
              }
            }
          },
          "503": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "description": "Отмена доступна сразу после выдачи, без минимального времени ожидания и без SMS. Освобождает номер; уже начисленное вознаграждение сохраняется. Новые SMS после отмены не оплачиваются. Повторная отмена идемпотентна. Если SMS не получено, запись с номером удаляется сразу. Повторная отмена по прежнему ID остаётся идемпотентной; сессии с полученными кодами сохраняются."
      }
    },
    "/api/v1/keys/{id}": {
      "delete": {
        "summary": "Отозвать ключ",
        "tags": [
          "Worker"
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "400": {
            "description": "Invalid input",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "403": {
            "description": "Insufficient privileges",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "405": {
            "description": "METHOD_NOT_ALLOWED: допустимые методы перечислены в Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              },
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "409": {
            "description": "State or idempotency conflict",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "ALLOCATION_PENDING: 3 секунды, retryable=true; повторить те же параметры с прежним ключом. ALLOCATION_UNCERTAIN: retryable=false, автоматический повтор запрещён."
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "security": [
          {
            "sessionCookie": []
          }
        ]
      },
      "patch": {
        "summary": "Имя и ограничения своего ключа",
        "tags": [
          "Worker"
        ],
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "responses": {
          "200": {
            "description": "Успешный ответ",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "400": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "401": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "403": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "404": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "405": {
            "description": "METHOD_NOT_ALLOWED: допустимые методы перечислены в Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              },
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "409": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "ALLOCATION_PENDING: 3 секунды, retryable=true; повторить те же параметры с прежним ключом. ALLOCATION_UNCERTAIN: retryable=false, автоматический повтор запрещён."
              }
            }
          },
          "503": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "label": {
                    "type": "string"
                  },
                  "policy": {
                    "$ref": "#/components/schemas/APIKeyPolicy"
                  }
                },
                "required": []
              }
            }
          }
        },
        "description": "Поле policy заменяется целиком. Отозванный ключ изменить нельзя."
      }
    },
    "/healthz": {
      "get": {
        "summary": "Готовность PostgreSQL и Redis",
        "tags": [
          "Worker"
        ],
        "responses": {
          "200": {
            "description": "Successful response"
          },
          "400": {
            "description": "Invalid input"
          },
          "401": {
            "description": "Authentication required"
          },
          "403": {
            "description": "Insufficient privileges"
          },
          "409": {
            "description": "State or idempotency conflict"
          }
        },
        "security": []
      }
    },
    "/stubs/handler_api.php": {
      "get": {
        "summary": "Совместимый интерфейс handler_api.php",
        "operationId": "handlerAPI",
        "tags": [
          "Compatibility"
        ],
        "security": [
          {
            "legacyAPIKey": []
          }
        ],
        "description": "Обязательность параметров зависит от action; смотрите x-actions и https://docs.smscash.org/. Успешные справочники и getSmsFull возвращают JSON, другие действия — plain text. Ошибки всегда plain text. Валюта баланса — USD. Коды в теле важнее HTTP 200.",
        "parameters": [
          {
            "name": "action",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "getNumber",
                "getNumbersStatus",
                "getStatus",
                "setStatus",
                "getRepeatNumber",
                "getSmsFull",
                "getSms",
                "getServices",
                "getCountries",
                "getOperators",
                "getBalance",
                "getHoldBalance",
                "getRewards"
              ]
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 128
            },
            "description": "Один ключ на логическую операцию. При повторе сохраните его и параметры."
          },
          {
            "name": "service",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Доступные коды сервисов. Ответ ограничен областью API-ключа."
          },
          {
            "name": "country",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Возьмите ID из getCountries."
          },
          {
            "name": "operator",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "pattern": "^([0-9]+|[aA][nN][yY])?$",
              "example": "1"
            },
            "description": "Public provider ID from operators/getOperators or the operator field in tariffs/catalog. Operator 1 uses operator=1. Accepts an integer or its decimal string. Omit operator or use any/0 for automatic selection; an explicit ID selects only that provider. Country operator record IDs and provider names are not selectors."
          },
          {
            "name": "session_duration",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "enum": [
                20,
                15
              ],
              "default": 20,
              "description": "New reservations last 20 minutes. The previous value 15 is accepted as a compatibility alias for 20. Idempotent replays return the original reservation and do not extend it."
            },
            "description": "Срок сессии — 20 минут. Передайте 20 или пропустите параметр."
          },
          {
            "name": "with_operator",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "1 добавляет ID оператора в ответ; 0 или отсутствие — три сегмента."
          },
          {
            "name": "ref",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Публичный код владельца софта: 5% ему и 5% пригласившему. Без ref — 10% пригласившему."
          },
          {
            "name": "id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "ID вашей сессии, полученный при выдаче номера."
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "3 — ждать следующий код без продления; 6 — завершить после SMS; 8 — отменить сразу."
          },
          {
            "name": "number",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Ваш прежний номер. Допустимы только цифры и необязательный начальный +."
          }
        ],
        "responses": {
          "200": {
            "description": "Успех либо бизнес-исход",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                },
                "examples": {
                  "number": {
                    "value": "ACCESS_NUMBER:42:380670000000"
                  },
                  "waiting": {
                    "value": "STATUS_WAIT_CODE"
                  },
                  "sms": {
                    "value": "STATUS_OK:001234"
                  },
                  "empty": {
                    "value": "EMPTY_POOL"
                  },
                  "held_balance": {
                    "summary": "SMScash: сумма в холде",
                    "value": "ACCESS_HOLD_BALANCE:34.50000001"
                  }
                }
              },
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "$ref": "#/components/schemas/LegacySMSFull"
                    },
                    {
                      "type": "object"
                    },
                    {
                      "$ref": "#/components/schemas/RewardsCatalog"
                    },
                    {
                      "$ref": "#/components/schemas/OperatorsCatalog"
                    }
                  ]
                },
                "examples": {
                  "getRewards": {
                    "summary": "country → service → operator → reward (USD)",
                    "value": {
                      "59": {
                        "vi": {
                          "1": "0.01000000",
                          "3": "0.00500000"
                        }
                      }
                    }
                  },
                  "getOperators": {
                    "summary": "Operator ID → name and hold period",
                    "value": {
                      "1": {
                        "id": 1,
                        "provider_id": 1,
                        "operator": 1,
                        "name": "Оператор 1",
                        "earnings_hold_days": 45
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "BAD_KEY; BAD_COUNTRY; BAD_SESSION_DURATION; BAD_REQUEST; BAD_REF / SELF_REF",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "401": {
            "description": "INVALID_API_KEY",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL_ERROR",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        },
        "x-actions": [
          {
            "action": "getNumber",
            "required": [
              "service",
              "country"
            ],
            "description": "Создаёт сессию и закрепляет свободный номер за пользователем. Тариф и получатели реферальных долей фиксируются при выдаче, а вознаграждение начисляется после получения SMS с кодом.",
            "responses": {
              "Номер выдан": "ACCESS_NUMBER:42:380670000000:2",
              "Нет свободных номеров": "EMPTY_POOL"
            }
          },
          {
            "action": "getNumbersStatus",
            "required": [
              "country"
            ],
            "description": "Количество доступных номеров по сервисам и стране.",
            "responses": {
              "Свободные номера": {
                "go_0": 0
              }
            }
          },
          {
            "action": "getStatus",
            "required": [
              "id"
            ],
            "description": "Лёгкий запрос состояния сессии и последнего SMS-кода. Начальные нули в коде сохраняются.",
            "responses": {
              "Ожидание": "STATUS_WAIT_CODE",
              "Код получен": "STATUS_OK:001234",
              "Отмена или истечение": "STATUS_CANCEL",
              "Не найдено": "NO_ACTIVATION"
            }
          },
          {
            "action": "setStatus",
            "required": [
              "id",
              "status"
            ],
            "description": "Завершает, отменяет или возобновляет ожидание SMS. Срок сессии остаётся прежним.",
            "responses": {
              "Ожидание SMS": "ACCESS_RETRY_GET",
              "Завершена": "ACCESS_ACTIVATION",
              "Отменена": "ACCESS_CANCEL"
            }
          },
          {
            "action": "getRepeatNumber",
            "required": [
              "number",
              "service"
            ],
            "description": "Открывает новую сессию с конкретным номером из вашей истории. Можно выбрать другой доступный сервис той же страны.",
            "responses": {
              "Новая сессия": "ACCESS_NUMBER:43:380670000000",
              "Номер ещё занят": "NUMBER_IN_USE"
            }
          },
          {
            "action": "getSmsFull",
            "required": [
              "id"
            ],
            "description": "Структурированная история всех сообщений с ID, отправителем, кодом, текстом и данными страны, сервиса и поставщика.",
            "responses": {
              "JSON": {
                "success": true,
                "session_id": 42,
                "phone": "380670000000",
                "status": 1,
                "status_name": "received",
                "sms_count": 1,
                "sms": [
                  {
                    "id": 101,
                    "external_id": "message-101",
                    "sender": "Service",
                    "code": "001234",
                    "text": "Код подтверждения: 001234",
                    "received_at": "2026-10-09T12:00:00Z",
                    "country": {
                      "id": 86,
                      "name": "Italy"
                    },
                    "service": {
                      "code": "go",
                      "name": "Google"
                    },
                    "provider": {
                      "id": 1,
                      "name": "Оператор 1"
                    }
                  }
                ],
                "expires_at": "2026-10-09T12:20:00Z"
              }
            }
          },
          {
            "action": "getSms",
            "required": [
              "id"
            ],
            "description": "Возвращает всю историю SMS в строковом формате для существующих клиентов.",
            "responses": {
              "Сообщение": "STATUS_OK:2026-10-09T12:00:00Z|001234|Код подтверждения: 001234",
              "Ожидание": "STATUS_WAIT_CODE",
              "Отмена или истечение": "STATUS_CANCEL"
            }
          },
          {
            "action": "getServices",
            "required": [],
            "description": "Доступные коды сервисов. Ответ ограничен областью API-ключа.",
            "responses": {
              "Сервисы": {
                "go": {
                  "name": "Google",
                  "code": "go"
                }
              }
            }
          },
          {
            "action": "getCountries",
            "required": [],
            "description": "ID, название и телефонный префикс стран выбранного канала.",
            "responses": {
              "Страны": {
                "86": {
                  "id": 86,
                  "name": "Italy",
                  "phone_code": "39"
                }
              }
            }
          },
          {
            "action": "getOperators",
            "required": [],
            "optional": [
              "country",
              "operator"
            ],
            "description": "Доступные операторы: ID для API, название и срок холда.",
            "responses": {
              "Операторы": {
                "1": {
                  "id": 1,
                  "provider_id": 1,
                  "operator": 1,
                  "name": "Оператор 1",
                  "earnings_hold_days": 45
                }
              }
            },
            "schema": {
              "$ref": "#/components/schemas/OperatorsCatalog"
            }
          },
          {
            "action": "getBalance",
            "required": [],
            "description": "Дополнение SMScash: доступный баланс с учётом начислений, реферальных бонусов и заявок на выплату.",
            "responses": {
              "Баланс": "ACCESS_BALANCE:0.00"
            }
          },
          "getHoldBalance",
          {
            "action": "getRewards",
            "required": [],
            "optional": [
              "country",
              "service",
              "operator"
            ],
            "description": "getRewards (SMScash): country ID → service code → public provider ID → reward. Rewards are exact USD decimal strings with 8 places. country, service and operator are optional filters; omit operator or use any/0 to include every permitted provider. The IDs match operator in catalog/tariffs and getOperators, not upstream channel IDs. Current enabled tariffs, account permissions and API key scopes apply. Empty selection returns {}. No stock check, allocation or financial operation is performed.",
            "responses": {
              "JSON": {
                "59": {
                  "vi": {
                    "1": "0.01000000",
                    "3": "0.00500000"
                  }
                }
              }
            },
            "schema": {
              "$ref": "#/components/schemas/RewardsCatalog"
            }
          }
        ],
        "x-smscash-automatic-routing": {
          "mode": "received_codes",
          "pair": [
            "service",
            "country"
          ],
          "priority": [
            "codes_last_1h",
            "codes_last_24h",
            "reward_desc",
            "provider_id_asc"
          ],
          "statistics_cache_seconds": 30,
          "empty_pool_fallback": true,
          "fallback_codes": [
            "EMPTY_POOL",
            "NO_NUMBERS"
          ],
          "explicit_provider_is_strict": true,
          "explicit_operator_is_strict": true,
          "repeat_number_keeps_its_provider": true,
          "uncertain_result_fallback": false,
          "idempotency_key_preserved": true,
          "current_key_scopes_and_restrictions": true
        },
        "x-getRewards": {
          "description": "getRewards (SMScash): country ID → service code → public provider ID → reward. Rewards are exact USD decimal strings with 8 places. country, service and operator are optional filters; omit operator or use any/0 to include every permitted provider. The IDs match operator in catalog/tariffs and getOperators, not upstream channel IDs. Current enabled tariffs, account permissions and API key scopes apply. Empty selection returns {}. No stock check, allocation or financial operation is performed.",
          "schema": {
            "$ref": "#/components/schemas/RewardsCatalog"
          },
          "optional": [
            "country",
            "service",
            "operator"
          ]
        }
      }
    },
    "/api/v1/services": {
      "get": {
        "summary": "Справочник: services",
        "tags": [
          "Worker"
        ],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "sessionCookie": []
          }
        ],
        "responses": {
          "200": {
            "description": "Успешный ответ",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {
                    "type": "object"
                  }
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "400": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "401": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "403": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "404": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "405": {
            "description": "METHOD_NOT_ALLOWED: допустимые методы перечислены в Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              },
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "409": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "ALLOCATION_PENDING: 3 секунды, retryable=true; повторить те же параметры с прежним ключом. ALLOCATION_UNCERTAIN: retryable=false, автоматический повтор запрещён."
              }
            }
          },
          "503": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "country",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          }
        ]
      }
    },
    "/api/v1/countries": {
      "get": {
        "summary": "Справочник: countries",
        "tags": [
          "Worker"
        ],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "sessionCookie": []
          }
        ],
        "responses": {
          "200": {
            "description": "Успешный ответ",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {
                    "type": "object"
                  }
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "400": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "401": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "403": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "404": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "405": {
            "description": "METHOD_NOT_ALLOWED: допустимые методы перечислены в Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              },
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "409": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "ALLOCATION_PENDING: 3 секунды, retryable=true; повторить те же параметры с прежним ключом. ALLOCATION_UNCERTAIN: retryable=false, автоматический повтор запрещён."
              }
            }
          },
          "503": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          }
        },
        "parameters": []
      }
    },
    "/api/v1/operators": {
      "get": {
        "summary": "Справочник: operators",
        "tags": [
          "Worker"
        ],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "sessionCookie": []
          }
        ],
        "responses": {
          "200": {
            "description": "Успешный ответ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OperatorsCatalog"
                },
                "example": {
                  "1": {
                    "id": 1,
                    "provider_id": 1,
                    "operator": 1,
                    "name": "Оператор 1",
                    "earnings_hold_days": 45
                  }
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "400": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "401": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "403": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "404": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "405": {
            "description": "METHOD_NOT_ALLOWED: допустимые методы перечислены в Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              },
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "409": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "ALLOCATION_PENDING: 3 секунды, retryable=true; повторить те же параметры с прежним ключом. ALLOCATION_UNCERTAIN: retryable=false, автоматический повтор запрещён."
              }
            }
          },
          "503": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "country",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 2147483647
            },
            "description": "Optional country ID from getCountries."
          },
          {
            "name": "operator",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "pattern": "^([0-9]+|[aA][nN][yY])?$",
              "example": "1"
            },
            "description": "Optional public operator ID; omit or use any/0 for all permitted operators."
          }
        ],
        "description": "Enabled operators permitted by the account and API key. One entry per public operator ID, including its name and earnings_hold_days. Pass id as operator when requesting a number. Optional country and operator filters return {} when no permitted operator matches. No upstream request, number allocation or financial operation is performed."
      }
    },
    "/api/v1/availability": {
      "get": {
        "summary": "Справочник: availability",
        "tags": [
          "Worker"
        ],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "sessionCookie": []
          }
        ],
        "responses": {
          "200": {
            "description": "Успешный ответ",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {
                    "type": "integer",
                    "format": "int64"
                  }
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "400": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "401": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "403": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "404": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "405": {
            "description": "METHOD_NOT_ALLOWED: допустимые методы перечислены в Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              },
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "409": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "ALLOCATION_PENDING: 3 секунды, retryable=true; повторить те же параметры с прежним ключом. ALLOCATION_UNCERTAIN: retryable=false, автоматический повтор запрещён."
              }
            }
          },
          "503": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "country",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          }
        ]
      }
    },
    "/api/v1/activations/{id}/sms": {
      "get": {
        "summary": "SMS после курсора",
        "tags": [
          "Worker"
        ],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "sessionCookie": []
          }
        ],
        "responses": {
          "200": {
            "description": "Успешный ответ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SMSPage"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "400": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "401": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "403": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "404": {
            "description": "NO_ACTIVATION: unknown session, another user’s session, or a deleted closed session without SMS.",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "405": {
            "description": "METHOD_NOT_ALLOWED: допустимые методы перечислены в Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              },
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "409": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "ALLOCATION_PENDING: 3 секунды, retryable=true; повторить те же параметры с прежним ключом. ALLOCATION_UNCERTAIN: retryable=false, автоматический повтор запрещён."
              }
            }
          },
          "503": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "after_id",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 100
            }
          }
        ]
      }
    },
    "/api/v1/activations/{id}/retry": {
      "post": {
        "summary": "Продлить активную сессию",
        "tags": [
          "Worker"
        ],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "sessionCookie": []
          }
        ],
        "responses": {
          "200": {
            "description": "Успешный ответ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Activation"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "400": {
            "description": "Ошибка запроса, доступа или состояния Для API-ключа BAD_SERVICE означает несуществующий, отключённый или заблокированный сервис без персонального разрешения. Персональное разрешение не отменяет отключение сервиса или ограничения API-ключа.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "401": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "403": {
            "description": "Ошибка доступа: Разрешённые связки сервиса, страны и оператора возвращает GET /api/v1/catalog. Каталог учитывает текущие ограничения аккаунта, сервисов, стран и поставщиков, а также область доступа API-ключа. Наличие номеров проверяется при выдаче.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "404": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "405": {
            "description": "METHOD_NOT_ALLOWED: допустимые методы перечислены в Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              },
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "409": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "ALLOCATION_PENDING: 3 секунды, retryable=true; повторить те же параметры с прежним ключом. ALLOCATION_UNCERTAIN: retryable=false, автоматический повтор запрещён."
              }
            }
          },
          "503": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 128
            },
            "description": "Один ключ на логическую операцию. При повторе сохраните его и параметры."
          }
        ],
        "description": "Сохраняет ID, номер, тариф и ref. Новый код читается после retry_after_sms_id; история не очищается. Закрытые сессии не продлеваются. Разрешённые связки сервиса, страны и оператора возвращает GET /api/v1/catalog. Каталог учитывает текущие ограничения аккаунта, сервисов, стран и поставщиков, а также область доступа API-ключа. Наличие номеров проверяется при выдаче. Числовой код именованного сервиса разрешён. Коды wa, bye, tg и eh, а также новые коды этих сервисов из каталога поставщика недоступны. Запрет действует для новой и повторной выдачи, retry и повторов запросов с прежним Idempotency-Key. REST с API-ключом: HTTP 400 с кодом BAD_SERVICE; handler_api.php: HTTP 200 с текстом BAD_SERVICE. Несуществующий или отключённый сервис также возвращает BAD_SERVICE. Явное персональное разрешение пользователя снимает только блокировку сервиса. Оно не разрешает отсутствующий или отключённый сервис и не отменяет область доступа API-ключа. Исторические SMS и начисления сохраняются."
      }
    },
    "/api/v1/activations/repeat": {
      "post": {
        "summary": "Повторно выдать свой прежний номер",
        "tags": [
          "Worker"
        ],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "sessionCookie": []
          }
        ],
        "responses": {
          "200": {
            "description": "Идемпотентный повтор",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Activation"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "201": {
            "description": "Новая сессия",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Activation"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "400": {
            "description": "Ошибка запроса, доступа или состояния Для API-ключа BAD_SERVICE означает несуществующий, отключённый или заблокированный сервис без персонального разрешения. Персональное разрешение не отменяет отключение сервиса или ограничения API-ключа.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "401": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "403": {
            "description": "Ошибка доступа: Разрешённые связки сервиса, страны и оператора возвращает GET /api/v1/catalog. Каталог учитывает текущие ограничения аккаунта, сервисов, стран и поставщиков, а также область доступа API-ключа. Наличие номеров проверяется при выдаче.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "404": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "405": {
            "description": "METHOD_NOT_ALLOWED: допустимые методы перечислены в Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              },
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "409": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "ALLOCATION_PENDING: 3 секунды, retryable=true; повторить те же параметры с прежним ключом. ALLOCATION_UNCERTAIN: retryable=false, автоматический повтор запрещён."
              }
            }
          },
          "503": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 128
            },
            "description": "Один ключ на логическую операцию. При повторе сохраните его и параметры."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "duration_minutes": {
                    "type": "integer",
                    "enum": [
                      20,
                      15
                    ],
                    "default": 20,
                    "description": "New reservations last 20 minutes. The previous value 15 is accepted as a compatibility alias for 20. Idempotent replays return the original reservation and do not extend it."
                  },
                  "operator": {
                    "oneOf": [
                      {
                        "type": "integer",
                        "format": "int64",
                        "minimum": 0,
                        "maximum": 2147483647,
                        "example": 1
                      },
                      {
                        "type": "string",
                        "pattern": "^([0-9]+|[aA][nN][yY])?$",
                        "example": "1"
                      }
                    ],
                    "description": "Public provider ID from operators/getOperators or the operator field in tariffs/catalog. Operator 1 uses operator=1. Accepts an integer or its decimal string. Omit operator or use any/0 for automatic selection; an explicit ID selects only that provider. Country operator record IDs and provider names are not selectors."
                  },
                  "ref": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 64,
                    "example": "2",
                    "description": "ID владельца кода в виде строки. Старые реферальные коды также принимаются и сохраняют прежнего владельца."
                  },
                  "number": {
                    "type": "string"
                  },
                  "service": {
                    "type": "string"
                  }
                },
                "required": [
                  "number",
                  "service"
                ]
              }
            }
          }
        },
        "description": " Keys of deleted no-SMS sessions stay consumed. Replaying the key cannot issue a new number; allocation returns SESSION_CLOSED (or NO_ACTIVATION when repeat ownership no longer exists). Разрешённые связки сервиса, страны и оператора возвращает GET /api/v1/catalog. Каталог учитывает текущие ограничения аккаунта, сервисов, стран и поставщиков, а также область доступа API-ключа. Наличие номеров проверяется при выдаче. Числовой код именованного сервиса разрешён. Коды wa, bye, tg и eh, а также новые коды этих сервисов из каталога поставщика недоступны. Запрет действует для новой и повторной выдачи, retry и повторов запросов с прежним Idempotency-Key. REST с API-ключом: HTTP 400 с кодом BAD_SERVICE; handler_api.php: HTTP 200 с текстом BAD_SERVICE. Несуществующий или отключённый сервис также возвращает BAD_SERVICE. Явное персональное разрешение пользователя снимает только блокировку сервиса. Оно не разрешает отсутствующий или отключённый сервис и не отменяет область доступа API-ключа. Исторические SMS и начисления сохраняются."
      }
    },
    "/handler_api.php": {
      "get": {
        "summary": "Совместимый интерфейс handler_api.php",
        "operationId": "handlerAPIAlias",
        "tags": [
          "Compatibility"
        ],
        "security": [
          {
            "legacyAPIKey": []
          }
        ],
        "description": "Обязательность параметров зависит от action; смотрите x-actions и https://docs.smscash.org/. Успешные справочники и getSmsFull возвращают JSON, другие действия — plain text. Ошибки всегда plain text. Валюта баланса — USD. Коды в теле важнее HTTP 200.",
        "parameters": [
          {
            "name": "action",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "getNumber",
                "getNumbersStatus",
                "getStatus",
                "setStatus",
                "getRepeatNumber",
                "getSmsFull",
                "getSms",
                "getServices",
                "getCountries",
                "getOperators",
                "getBalance",
                "getHoldBalance",
                "getRewards"
              ]
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 128
            },
            "description": "Один ключ на логическую операцию. При повторе сохраните его и параметры."
          },
          {
            "name": "service",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Доступные коды сервисов. Ответ ограничен областью API-ключа."
          },
          {
            "name": "country",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Возьмите ID из getCountries."
          },
          {
            "name": "operator",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "pattern": "^([0-9]+|[aA][nN][yY])?$",
              "example": "1"
            },
            "description": "Public provider ID from operators/getOperators or the operator field in tariffs/catalog. Operator 1 uses operator=1. Accepts an integer or its decimal string. Omit operator or use any/0 for automatic selection; an explicit ID selects only that provider. Country operator record IDs and provider names are not selectors."
          },
          {
            "name": "session_duration",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "enum": [
                20,
                15
              ],
              "default": 20,
              "description": "New reservations last 20 minutes. The previous value 15 is accepted as a compatibility alias for 20. Idempotent replays return the original reservation and do not extend it."
            },
            "description": "Срок сессии — 20 минут. Передайте 20 или пропустите параметр."
          },
          {
            "name": "with_operator",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "1 добавляет ID оператора в ответ; 0 или отсутствие — три сегмента."
          },
          {
            "name": "ref",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Публичный код владельца софта: 5% ему и 5% пригласившему. Без ref — 10% пригласившему."
          },
          {
            "name": "id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "ID вашей сессии, полученный при выдаче номера."
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "3 — ждать следующий код без продления; 6 — завершить после SMS; 8 — отменить сразу."
          },
          {
            "name": "number",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Ваш прежний номер. Допустимы только цифры и необязательный начальный +."
          }
        ],
        "responses": {
          "200": {
            "description": "Успех либо бизнес-исход",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                },
                "examples": {
                  "number": {
                    "value": "ACCESS_NUMBER:42:380670000000"
                  },
                  "waiting": {
                    "value": "STATUS_WAIT_CODE"
                  },
                  "sms": {
                    "value": "STATUS_OK:001234"
                  },
                  "empty": {
                    "value": "EMPTY_POOL"
                  },
                  "held_balance": {
                    "summary": "SMScash: сумма в холде",
                    "value": "ACCESS_HOLD_BALANCE:34.50000001"
                  }
                }
              },
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "$ref": "#/components/schemas/LegacySMSFull"
                    },
                    {
                      "type": "object"
                    },
                    {
                      "$ref": "#/components/schemas/RewardsCatalog"
                    },
                    {
                      "$ref": "#/components/schemas/OperatorsCatalog"
                    }
                  ]
                },
                "examples": {
                  "getRewards": {
                    "summary": "country → service → operator → reward (USD)",
                    "value": {
                      "59": {
                        "vi": {
                          "1": "0.01000000",
                          "3": "0.00500000"
                        }
                      }
                    }
                  },
                  "getOperators": {
                    "summary": "Operator ID → name and hold period",
                    "value": {
                      "1": {
                        "id": 1,
                        "provider_id": 1,
                        "operator": 1,
                        "name": "Оператор 1",
                        "earnings_hold_days": 45
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "BAD_KEY; BAD_COUNTRY; BAD_SESSION_DURATION; BAD_REQUEST; BAD_REF / SELF_REF",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "401": {
            "description": "INVALID_API_KEY",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "500": {
            "description": "INTERNAL_ERROR",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        },
        "x-actions": [
          {
            "action": "getNumber",
            "required": [
              "service",
              "country"
            ],
            "description": "Создаёт сессию и закрепляет свободный номер за пользователем. Тариф и получатели реферальных долей фиксируются при выдаче, а вознаграждение начисляется после получения SMS с кодом.",
            "responses": {
              "Номер выдан": "ACCESS_NUMBER:42:380670000000:2",
              "Нет свободных номеров": "EMPTY_POOL"
            }
          },
          {
            "action": "getNumbersStatus",
            "required": [
              "country"
            ],
            "description": "Количество доступных номеров по сервисам и стране.",
            "responses": {
              "Свободные номера": {
                "go_0": 0
              }
            }
          },
          {
            "action": "getStatus",
            "required": [
              "id"
            ],
            "description": "Лёгкий запрос состояния сессии и последнего SMS-кода. Начальные нули в коде сохраняются.",
            "responses": {
              "Ожидание": "STATUS_WAIT_CODE",
              "Код получен": "STATUS_OK:001234",
              "Отмена или истечение": "STATUS_CANCEL",
              "Не найдено": "NO_ACTIVATION"
            }
          },
          {
            "action": "setStatus",
            "required": [
              "id",
              "status"
            ],
            "description": "Завершает, отменяет или возобновляет ожидание SMS. Срок сессии остаётся прежним.",
            "responses": {
              "Ожидание SMS": "ACCESS_RETRY_GET",
              "Завершена": "ACCESS_ACTIVATION",
              "Отменена": "ACCESS_CANCEL"
            }
          },
          {
            "action": "getRepeatNumber",
            "required": [
              "number",
              "service"
            ],
            "description": "Открывает новую сессию с конкретным номером из вашей истории. Можно выбрать другой доступный сервис той же страны.",
            "responses": {
              "Новая сессия": "ACCESS_NUMBER:43:380670000000",
              "Номер ещё занят": "NUMBER_IN_USE"
            }
          },
          {
            "action": "getSmsFull",
            "required": [
              "id"
            ],
            "description": "Структурированная история всех сообщений с ID, отправителем, кодом, текстом и данными страны, сервиса и поставщика.",
            "responses": {
              "JSON": {
                "success": true,
                "session_id": 42,
                "phone": "380670000000",
                "status": 1,
                "status_name": "received",
                "sms_count": 1,
                "sms": [
                  {
                    "id": 101,
                    "external_id": "message-101",
                    "sender": "Service",
                    "code": "001234",
                    "text": "Код подтверждения: 001234",
                    "received_at": "2026-10-09T12:00:00Z",
                    "country": {
                      "id": 86,
                      "name": "Italy"
                    },
                    "service": {
                      "code": "go",
                      "name": "Google"
                    },
                    "provider": {
                      "id": 1,
                      "name": "Оператор 1"
                    }
                  }
                ],
                "expires_at": "2026-10-09T12:20:00Z"
              }
            }
          },
          {
            "action": "getSms",
            "required": [
              "id"
            ],
            "description": "Возвращает всю историю SMS в строковом формате для существующих клиентов.",
            "responses": {
              "Сообщение": "STATUS_OK:2026-10-09T12:00:00Z|001234|Код подтверждения: 001234",
              "Ожидание": "STATUS_WAIT_CODE",
              "Отмена или истечение": "STATUS_CANCEL"
            }
          },
          {
            "action": "getServices",
            "required": [],
            "description": "Доступные коды сервисов. Ответ ограничен областью API-ключа.",
            "responses": {
              "Сервисы": {
                "go": {
                  "name": "Google",
                  "code": "go"
                }
              }
            }
          },
          {
            "action": "getCountries",
            "required": [],
            "description": "ID, название и телефонный префикс стран выбранного канала.",
            "responses": {
              "Страны": {
                "86": {
                  "id": 86,
                  "name": "Italy",
                  "phone_code": "39"
                }
              }
            }
          },
          {
            "action": "getOperators",
            "required": [],
            "optional": [
              "country",
              "operator"
            ],
            "description": "Доступные операторы: ID для API, название и срок холда.",
            "responses": {
              "Операторы": {
                "1": {
                  "id": 1,
                  "provider_id": 1,
                  "operator": 1,
                  "name": "Оператор 1",
                  "earnings_hold_days": 45
                }
              }
            },
            "schema": {
              "$ref": "#/components/schemas/OperatorsCatalog"
            }
          },
          {
            "action": "getBalance",
            "required": [],
            "description": "Дополнение SMScash: доступный баланс с учётом начислений, реферальных бонусов и заявок на выплату.",
            "responses": {
              "Баланс": "ACCESS_BALANCE:0.00"
            }
          },
          "getHoldBalance",
          {
            "action": "getRewards",
            "required": [],
            "optional": [
              "country",
              "service",
              "operator"
            ],
            "description": "getRewards (SMScash): country ID → service code → public provider ID → reward. Rewards are exact USD decimal strings with 8 places. country, service and operator are optional filters; omit operator or use any/0 to include every permitted provider. The IDs match operator in catalog/tariffs and getOperators, not upstream channel IDs. Current enabled tariffs, account permissions and API key scopes apply. Empty selection returns {}. No stock check, allocation or financial operation is performed.",
            "responses": {
              "JSON": {
                "59": {
                  "vi": {
                    "1": "0.01000000",
                    "3": "0.00500000"
                  }
                }
              }
            },
            "schema": {
              "$ref": "#/components/schemas/RewardsCatalog"
            }
          }
        ],
        "x-smscash-automatic-routing": {
          "mode": "received_codes",
          "pair": [
            "service",
            "country"
          ],
          "priority": [
            "codes_last_1h",
            "codes_last_24h",
            "reward_desc",
            "provider_id_asc"
          ],
          "statistics_cache_seconds": 30,
          "empty_pool_fallback": true,
          "fallback_codes": [
            "EMPTY_POOL",
            "NO_NUMBERS"
          ],
          "explicit_provider_is_strict": true,
          "explicit_operator_is_strict": true,
          "repeat_number_keeps_its_provider": true,
          "uncertain_result_fallback": false,
          "idempotency_key_preserved": true,
          "current_key_scopes_and_restrictions": true
        },
        "x-getRewards": {
          "description": "getRewards (SMScash): country ID → service code → public provider ID → reward. Rewards are exact USD decimal strings with 8 places. country, service and operator are optional filters; omit operator or use any/0 to include every permitted provider. The IDs match operator in catalog/tariffs and getOperators, not upstream channel IDs. Current enabled tariffs, account permissions and API key scopes apply. Empty selection returns {}. No stock check, allocation or financial operation is performed.",
          "schema": {
            "$ref": "#/components/schemas/RewardsCatalog"
          },
          "optional": [
            "country",
            "service",
            "operator"
          ]
        }
      }
    },
    "/api/v1/tariffs": {
      "get": {
        "summary": "Вознаграждение за SMS по странам",
        "tags": [
          "Worker"
        ],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "sessionCookie": []
          }
        ],
        "responses": {
          "200": {
            "description": "Успешный ответ",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/CountryReward"
                  }
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "400": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "401": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "403": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "404": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "405": {
            "description": "METHOD_NOT_ALLOWED: допустимые методы перечислены в Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              },
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "409": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "ALLOCATION_PENDING: 3 секунды, retryable=true; повторить те же параметры с прежним ключом. ALLOCATION_UNCERTAIN: retryable=false, автоматический повтор запрещён."
              }
            }
          },
          "503": {
            "description": "Ошибка запроса, доступа или состояния",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          }
        },
        "description": "Country worker rewards with approved services for each provider/country. Only enabled providers and countries with at least one permitted service within all API key scopes are returned. The reward belongs to the country, not an individual service. Only public operator names are returned. Belarus (51) and Russia (205) are excluded by the country allocation policy. Rates do not imply current number availability. Supplier income and platform margin are private."
      }
    },
    "/api/v1/statistics": {
      "get": {
        "summary": "Общая статистика полученных кодов",
        "description": "Полученные коды по публичным операторам, странам и сервисам. scope=platform (по умолчанию) показывает общие результаты; scope=personal — только собственные коды авторизованного аккаунта. Указание чужого user_id не меняет владельца отчёта. Требует сессию или API-ключ; область ключа ограничивает сочетания в обоих режимах. Четыре скользящих периода отсчитываются по received_at: 30 дней, 7 дней, 24 часа и 1 час до as_of. Исторические сочетания и дневные итоги UTC+3 сохраняются. Только непустые коды не позже as_of. Телефоны, значения кодов, тексты SMS, данные пользователей и частные данные поставщика не возвращаются. Кеш до 10 секунд; личный кеш разделён по владельцу и области ключа, текущие цены читаются свежими.",
        "responses": {
          "200": {
            "description": "Статистика платформы либо собственных полученных кодов выбранной области.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceStatistics"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "400": {
            "description": "Invalid input",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "401": {
            "description": "Необходима авторизация",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "405": {
            "description": "METHOD_NOT_ALLOWED: допустимые методы перечислены в Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              },
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "scope",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "platform",
                "personal"
              ],
              "default": "platform"
            },
            "description": "platform: received codes across the platform. personal: only codes belonging to the authenticated account. The owner cannot be selected by a user ID or another query parameter. API-key policy applies in both modes; personal caches are separated by owner and policy."
          }
        ]
      }
    },
    "/api/v1/auth/verify-email": {
      "post": {
        "summary": "Подтверждение почты",
        "description": "Подтверждает почту одноразовым токеном из письма. Срок — 24 часа. Не создаёт сессию; после подтверждения войдите с паролем. GET страницы не расходует токен. Неверная, истёкшая или использованная ссылка возвращает VERIFICATION_INVALID.",
        "tags": [
          "Worker"
        ],
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "token": {
                    "type": "string",
                    "pattern": "^verify_[a-f0-9]{64}$"
                  }
                },
                "required": [
                  "token"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Email verified or verification email sent",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "400": {
            "description": "Invalid or expired token/input",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "401": {
            "description": "Invalid email or password",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "403": {
            "description": "Invalid request origin",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "405": {
            "description": "METHOD_NOT_ALLOWED: допустимые методы перечислены в Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              },
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit or resend cooldown; retry in one minute",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "503": {
            "description": "Email service unavailable; retry sending in one minute",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/auth/resend-verification": {
      "post": {
        "summary": "Повторная отправка подтверждения",
        "description": "Требует почту и пароль аккаунта. Повторная отправка доступна через минуту и заменяет предыдущую ссылку. Если почта уже подтверждена, возвращает verified=true без отправки.",
        "tags": [
          "Worker"
        ],
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "password": {
                    "type": "string",
                    "format": "password"
                  },
                  "language": {
                    "type": "string"
                  }
                },
                "required": [
                  "email",
                  "password"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Email verified or verification email sent",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "400": {
            "description": "Invalid or expired token/input",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "401": {
            "description": "Invalid email or password",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "403": {
            "description": "Invalid request origin",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "405": {
            "description": "METHOD_NOT_ALLOWED: допустимые методы перечислены в Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              },
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit or resend cooldown; retry in one minute",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "503": {
            "description": "Email service unavailable; retry sending in one minute",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/earnings/holds": {
      "get": {
        "operationId": "ownEarningsHold",
        "tags": [
          "Worker"
        ],
        "summary": "Холд начислений и статистика по дням",
        "description": "После получения SMS начисление уходит в холд на срок поставщика. В указанную дату сумма автоматически становится доступной для вывода. Возвращает только начисления владельца. Бонусы от чужих SMS не раскрывают чужие номера и коды. Статистика группируется по дате получения SMS в UTC. График показывает будущие даты доступности по поставщику, независимо от периода получения. Начисления и бонусы от одного SMS учитываются как одно SMS. available_at фиксируется при получении; точный срок — hold_days × 24 часа, без влияния часового пояса. released_minor — разблокированные начисления, а не остаток после вывода.",
        "parameters": [
          {
            "name": "from",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Первый день получения SMS, UTC. По умолчанию последние 45 дней."
          },
          {
            "name": "to",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Последний день включительно, UTC; период до 366 дней."
          },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "all",
                "held",
                "released"
              ],
              "default": "all"
            },
            "description": "Фильтр дневной статистики и записей. График включает все суммы, ещё находящиеся в холде."
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 1000000,
              "default": 1
            },
            "description": "Страница подробных записей."
          },
          {
            "name": "page_size",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            },
            "description": "Количество подробных записей. Статистика и график учитывают весь результат."
          },
          {
            "name": "operator",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "pattern": "^([0-9]+|[aA][nN][yY])?$",
              "example": "1"
            },
            "description": "Public provider ID from operators/getOperators or the operator field in tariffs/catalog. Operator 1 uses operator=1. Accepts an integer or its decimal string. Omit operator or use any/0 for automatic selection; an explicit ID selects only that provider. Country operator record IDs and provider names are not selectors."
          }
        ],
        "responses": {
          "200": {
            "description": "Успешный ответ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HoldReport"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "400": {
            "description": "Некорректные фильтры, даты или срок холда.",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "401": {
            "description": "Требуется вход.",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "403": {
            "description": "Доступ запрещён.",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "404": {
            "description": "Пользователь или поставщик не найден.",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "405": {
            "description": "METHOD_NOT_ALLOWED: допустимые методы перечислены в Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              },
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/catalog": {
      "get": {
        "summary": "Сервисы и страны с вознаграждением",
        "tags": [
          "Worker"
        ],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "sessionCookie": []
          }
        ],
        "parameters": [
          {
            "name": "service",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 64
            },
            "description": "Точный код сервиса."
          },
          {
            "name": "country",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 2147483647
            },
            "description": "ID страны."
          },
          {
            "name": "q",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 100
            },
            "description": "Поиск по коду/названию сервиса, стране и её ID, без учёта регистра."
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 1000000,
              "default": 1
            },
            "description": "Страница; порядок service, country_id, provider_id."
          },
          {
            "name": "page_size",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            },
            "description": "Количество связок на странице."
          },
          {
            "name": "operator",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "pattern": "^([0-9]+|[aA][nN][yY])?$",
              "example": "1"
            },
            "description": "Public provider ID from operators/getOperators or the operator field in tariffs/catalog. Operator 1 uses operator=1. Accepts an integer or its decimal string. Omit operator or use any/0 for automatic selection; an explicit ID selects only that provider. Country operator record IDs and provider names are not selectors."
          }
        ],
        "description": "Только подключённые разрешённые связки в области API-ключа. Тариф зависит от поставщика и страны; reward — точная строка. Наличие проверяется при выдаче. Чтение каталога не обращается к поставщику, не выдаёт номера и не изменяет деньги.",
        "responses": {
          "200": {
            "description": "Успешный ответ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CatalogPage"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "400": {
            "description": "Неверные параметры фильтра/страницы.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "401": {
            "description": "Ключ неизвестен или отозван.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "405": {
            "description": "METHOD_NOT_ALLOWED: допустимые методы перечислены в Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              },
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "503": {
            "description": "Каталог временно недоступен.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/activations/batch": {
      "get": {
        "summary": "Проверить несколько номеров",
        "tags": [
          "Worker"
        ],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "sessionCookie": []
          }
        ],
        "parameters": [
          {
            "name": "ids",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "42,43"
            },
            "description": "От 1 до 100 положительных ID через запятую. Дубликаты удаляются, порядок сохраняется."
          }
        ],
        "description": "Один снимок состояния собственных сессий, без обращений к поставщику или изменения сессий. Чужой, отсутствующий и запрещённый области ключа ID возвращают только id, found=false и NO_ACTIVATION. Проверяйте раз в 20 секунд. last_sms — последнее SMS, а не полная история; code учитывает retry. Истёкшая сессия отображается expired, не изменяя записи при чтении.",
        "responses": {
          "200": {
            "description": "Успешный ответ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BatchActivationPage"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "400": {
            "description": "Неверный список ID.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "401": {
            "description": "Ключ неизвестен или отозван.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "405": {
            "description": "METHOD_NOT_ALLOWED: допустимые методы перечислены в Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              },
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          }
        }
      }
    },
    "/sms-activate/stubs/handler_api.php": {
      "get": {
        "tags": [
          "Compatibility"
        ],
        "security": [
          {
            "legacyAPIKey": []
          }
        ],
        "description": "Совместимые команды SMS-Activate/HeroSMS для собственных сессий SMScash. Используйте ключ SMScash и коды из его каталога. GET и POST form-url-encoded. Выдача бесплатно: cost и activationCost равны 0, reward — точное вознаграждение за SMS, баланс getBalance — только доступные средства, без холда. Сессия 20 минут, опрос раз в 20 секунд. status=1 не очищает SMS и не продлевает срок; status=3 сохраняет исходную сессию. Для сетевых повторов используйте прежний Idempotency-Key и параметры. ALLOCATION_UNCERTAIN запрещает автоматическую повторную выдачу. Аренда, звонки, переадресация, продление и несколько сервисов на номере не поддерживаются; неизвестные команды — BAD_ACTION, неподдерживаемые опции — BAD_REQUEST. Каталоги учитывают текущие ограничения, персональные разрешения и policy ключа.",
        "responses": {
          "200": {
            "description": "Успех либо текстовый бизнес-исход/ошибка ключа. Проверяйте Content-Type и тело, а не только HTTP.",
            "headers": {
              "X-Request-ID": {
                "schema": {
                  "type": "string"
                }
              },
              "X-SMScash-Availability-Scope": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "supplier-pool"
                  ]
                }
              }
            },
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                },
                "examples": {
                  "number": {
                    "value": "ACCESS_NUMBER:42:393331234567"
                  },
                  "waiting": {
                    "value": "STATUS_WAIT_CODE"
                  },
                  "code": {
                    "value": "STATUS_OK:001234"
                  },
                  "ready": {
                    "value": "ACCESS_READY"
                  },
                  "empty": {
                    "value": "NO_NUMBERS"
                  },
                  "key": {
                    "value": "BAD_KEY"
                  },
                  "uncertain": {
                    "value": "ALLOCATION_UNCERTAIN"
                  },
                  "held_balance": {
                    "summary": "SMScash: сумма в холде",
                    "value": "ACCESS_HOLD_BALANCE:34.50000001"
                  }
                }
              },
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "$ref": "#/components/schemas/CompatibleActivation"
                    },
                    {
                      "$ref": "#/components/schemas/CompatibleStatus"
                    },
                    {
                      "type": "object"
                    },
                    {
                      "$ref": "#/components/schemas/RewardsCatalog"
                    },
                    {
                      "$ref": "#/components/schemas/CompatibleOperators"
                    }
                  ]
                },
                "examples": {
                  "getRewards": {
                    "summary": "country → service → operator → reward (USD)",
                    "value": {
                      "59": {
                        "vi": {
                          "1": "0.01000000",
                          "3": "0.00500000"
                        }
                      }
                    }
                  },
                  "getOperators": {
                    "summary": "Country operator selectors plus the operator catalog",
                    "value": {
                      "status": "success",
                      "countryOperators": {
                        "86": [
                          "1"
                        ]
                      },
                      "operators": {
                        "1": {
                          "id": 1,
                          "provider_id": 1,
                          "operator": 1,
                          "name": "Оператор 1",
                          "earnings_hold_days": 45
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "405": {
            "description": "Поддерживаются GET и POST. HEAD не выполняет выдачу номера.",
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string",
                  "example": "GET, POST"
                }
              }
            },
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "500": {
            "description": "Ошибка сервера или недоступный поставщик. Текст INTERNAL_ERROR; при неизвестном результате выдачи нельзя автоматически создавать новую операцию.",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        },
        "x-actions": [
          "getNumber",
          "getNumberV2",
          "getStatus",
          "getStatusV2",
          "setStatus",
          "finishActivation",
          "cancelActivation",
          "getPrices",
          "getServicesList",
          "getServices",
          "getCountries",
          "getOperators",
          "getNumbersStatus",
          "getActiveActivations",
          "getBalance",
          "getRepeatNumber",
          "getSms",
          "getSmsFull",
          "getHoldBalance",
          "getRewards"
        ],
        "summary": "SMS-Activate-совместимый API",
        "operationId": "sms_activateCompatibilityGET",
        "parameters": [
          {
            "name": "action",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "getNumber",
                "getNumberV2",
                "getStatus",
                "getStatusV2",
                "setStatus",
                "finishActivation",
                "cancelActivation",
                "getPrices",
                "getServicesList",
                "getServices",
                "getCountries",
                "getOperators",
                "getNumbersStatus",
                "getActiveActivations",
                "getBalance",
                "getRepeatNumber",
                "getSms",
                "getSmsFull",
                "getHoldBalance",
                "getRewards"
              ]
            },
            "description": "Команда; обязательность остальных полей зависит от неё."
          },
          {
            "name": "service",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 64
            },
            "description": "Точный код из getServicesList или getServices."
          },
          {
            "name": "country",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 2147483647
            },
            "description": "ID страны из каталога SMScash; не ISO-код."
          },
          {
            "name": "id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64",
              "minimum": 1
            },
            "description": "id"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "enum": [
                1,
                3,
                6,
                8
              ]
            },
            "description": "1 — подтвердить готовность; 3 — ждать новое SMS в той же сессии; 6 — завершить после SMS; 8 — отменить."
          },
          {
            "name": "ref",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Необязательный код владельца софта. Используется при получении новой сессии."
          },
          {
            "name": "operator",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "pattern": "^([0-9]+|[aA][nN][yY])?$",
              "example": "1"
            },
            "description": "Public provider ID from operators/getOperators or the operator field in tariffs/catalog. Operator 1 uses operator=1. Accepts an integer or its decimal string. Omit operator or use any/0 for automatic selection; an explicit ID selects only that provider. Country operator record IDs and provider names are not selectors."
          },
          {
            "name": "number",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "number"
          },
          {
            "name": "session_duration",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "enum": [
                20,
                15
              ],
              "default": 20,
              "description": "New reservations last 20 minutes. The previous value 15 is accepted as a compatibility alias for 20. Idempotent replays return the original reservation and do not extend it."
            },
            "description": "session_duration"
          },
          {
            "name": "start",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 1000000
            },
            "description": "start"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            },
            "description": "limit"
          },
          {
            "name": "maxPrice",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "pattern": "^\\d+(\\.\\d{1,8})?$"
            },
            "description": "Максимальная цена покупки; фактическая стоимость выдачи — 0 USD. Поле reward содержит вознаграждение за SMS."
          },
          {
            "name": "freePrice",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "enum": [
                0,
                1
              ]
            },
            "description": "freePrice"
          },
          {
            "name": "forward",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "enum": [
                0
              ]
            },
            "description": "forward"
          },
          {
            "name": "verificationType",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "enum": [
                1
              ]
            },
            "description": "verificationType"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 128
            },
            "description": "Рекомендуется при получении номера и retry. Не меняйте ключ при сетевом повторе той же операции."
          }
        ],
        "x-smscash-automatic-routing": {
          "mode": "received_codes",
          "pair": [
            "service",
            "country"
          ],
          "priority": [
            "codes_last_1h",
            "codes_last_24h",
            "reward_desc",
            "provider_id_asc"
          ],
          "statistics_cache_seconds": 30,
          "empty_pool_fallback": true,
          "fallback_codes": [
            "EMPTY_POOL",
            "NO_NUMBERS"
          ],
          "explicit_provider_is_strict": true,
          "explicit_operator_is_strict": true,
          "repeat_number_keeps_its_provider": true,
          "uncertain_result_fallback": false,
          "idempotency_key_preserved": true,
          "current_key_scopes_and_restrictions": true
        },
        "x-getRewards": {
          "description": "getRewards (SMScash): country ID → service code → public provider ID → reward. Rewards are exact USD decimal strings with 8 places. country, service and operator are optional filters; omit operator or use any/0 to include every permitted provider. The IDs match operator in catalog/tariffs and getOperators, not upstream channel IDs. Current enabled tariffs, account permissions and API key scopes apply. Empty selection returns {}. No stock check, allocation or financial operation is performed.",
          "schema": {
            "$ref": "#/components/schemas/RewardsCatalog"
          },
          "optional": [
            "country",
            "service",
            "operator"
          ]
        },
        "x-getOperators": {
          "description": "countryOperators retains country → public operator ID strings. operators contains the same ID, name and earnings_hold_days records as GET /api/v1/operators.",
          "schema": {
            "$ref": "#/components/schemas/CompatibleOperators"
          },
          "optional": [
            "country",
            "operator"
          ]
        }
      },
      "post": {
        "tags": [
          "Compatibility"
        ],
        "security": [
          {
            "legacyAPIKey": []
          }
        ],
        "description": "Совместимые команды SMS-Activate/HeroSMS для собственных сессий SMScash. Используйте ключ SMScash и коды из его каталога. GET и POST form-url-encoded. Выдача бесплатно: cost и activationCost равны 0, reward — точное вознаграждение за SMS, баланс getBalance — только доступные средства, без холда. Сессия 20 минут, опрос раз в 20 секунд. status=1 не очищает SMS и не продлевает срок; status=3 сохраняет исходную сессию. Для сетевых повторов используйте прежний Idempotency-Key и параметры. ALLOCATION_UNCERTAIN запрещает автоматическую повторную выдачу. Аренда, звонки, переадресация, продление и несколько сервисов на номере не поддерживаются; неизвестные команды — BAD_ACTION, неподдерживаемые опции — BAD_REQUEST. Каталоги учитывают текущие ограничения, персональные разрешения и policy ключа.",
        "responses": {
          "200": {
            "description": "Успех либо текстовый бизнес-исход/ошибка ключа. Проверяйте Content-Type и тело, а не только HTTP.",
            "headers": {
              "X-Request-ID": {
                "schema": {
                  "type": "string"
                }
              },
              "X-SMScash-Availability-Scope": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "supplier-pool"
                  ]
                }
              }
            },
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                },
                "examples": {
                  "number": {
                    "value": "ACCESS_NUMBER:42:393331234567"
                  },
                  "waiting": {
                    "value": "STATUS_WAIT_CODE"
                  },
                  "code": {
                    "value": "STATUS_OK:001234"
                  },
                  "ready": {
                    "value": "ACCESS_READY"
                  },
                  "empty": {
                    "value": "NO_NUMBERS"
                  },
                  "key": {
                    "value": "BAD_KEY"
                  },
                  "uncertain": {
                    "value": "ALLOCATION_UNCERTAIN"
                  },
                  "held_balance": {
                    "summary": "SMScash: сумма в холде",
                    "value": "ACCESS_HOLD_BALANCE:34.50000001"
                  }
                }
              },
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "$ref": "#/components/schemas/CompatibleActivation"
                    },
                    {
                      "$ref": "#/components/schemas/CompatibleStatus"
                    },
                    {
                      "type": "object"
                    },
                    {
                      "$ref": "#/components/schemas/RewardsCatalog"
                    },
                    {
                      "$ref": "#/components/schemas/CompatibleOperators"
                    }
                  ]
                },
                "examples": {
                  "getRewards": {
                    "summary": "country → service → operator → reward (USD)",
                    "value": {
                      "59": {
                        "vi": {
                          "1": "0.01000000",
                          "3": "0.00500000"
                        }
                      }
                    }
                  },
                  "getOperators": {
                    "summary": "Country operator selectors plus the operator catalog",
                    "value": {
                      "status": "success",
                      "countryOperators": {
                        "86": [
                          "1"
                        ]
                      },
                      "operators": {
                        "1": {
                          "id": 1,
                          "provider_id": 1,
                          "operator": 1,
                          "name": "Оператор 1",
                          "earnings_hold_days": 45
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "405": {
            "description": "Поддерживаются GET и POST. HEAD не выполняет выдачу номера.",
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string",
                  "example": "GET, POST"
                }
              }
            },
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "500": {
            "description": "Ошибка сервера или недоступный поставщик. Текст INTERNAL_ERROR; при неизвестном результате выдачи нельзя автоматически создавать новую операцию.",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        },
        "x-actions": [
          "getNumber",
          "getNumberV2",
          "getStatus",
          "getStatusV2",
          "setStatus",
          "finishActivation",
          "cancelActivation",
          "getPrices",
          "getServicesList",
          "getServices",
          "getCountries",
          "getOperators",
          "getNumbersStatus",
          "getActiveActivations",
          "getBalance",
          "getRepeatNumber",
          "getSms",
          "getSmsFull",
          "getHoldBalance",
          "getRewards"
        ],
        "summary": "Те же команды через форму POST",
        "operationId": "sms_activateCompatibilityPOST",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 128
            },
            "description": "Рекомендуется при получении номера и retry. Не меняйте ключ при сетевом повторе той же операции."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "api_key",
                  "action"
                ],
                "properties": {
                  "action": {
                    "type": "string",
                    "enum": [
                      "getNumber",
                      "getNumberV2",
                      "getStatus",
                      "getStatusV2",
                      "setStatus",
                      "finishActivation",
                      "cancelActivation",
                      "getPrices",
                      "getServicesList",
                      "getServices",
                      "getCountries",
                      "getOperators",
                      "getNumbersStatus",
                      "getActiveActivations",
                      "getBalance",
                      "getRepeatNumber",
                      "getSms",
                      "getSmsFull",
                      "getHoldBalance",
                      "getRewards"
                    ],
                    "description": "Команда; обязательность остальных полей зависит от неё."
                  },
                  "api_key": {
                    "type": "string",
                    "minLength": 8,
                    "maxLength": 256,
                    "description": "Личный ключ SMScash. В POST допустим в форме или query, одинаковые повторные значения не создают новую операцию."
                  },
                  "service": {
                    "type": "string",
                    "maxLength": 64,
                    "description": "Точный код из getServicesList или getServices."
                  },
                  "country": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 2147483647,
                    "description": "ID страны из каталога SMScash; не ISO-код."
                  },
                  "id": {
                    "type": "integer",
                    "format": "int64",
                    "minimum": 1,
                    "description": "id"
                  },
                  "status": {
                    "type": "integer",
                    "enum": [
                      1,
                      3,
                      6,
                      8
                    ],
                    "description": "1 — подтвердить готовность; 3 — ждать новое SMS в той же сессии; 6 — завершить после SMS; 8 — отменить."
                  },
                  "ref": {
                    "type": "string",
                    "description": "Необязательный код владельца софта. Используется при получении новой сессии."
                  },
                  "operator": {
                    "type": "string",
                    "pattern": "^([0-9]+|[aA][nN][yY])?$",
                    "example": "1",
                    "description": "Public provider ID from operators/getOperators or the operator field in tariffs/catalog. Operator 1 uses operator=1. Accepts an integer or its decimal string. Omit operator or use any/0 for automatic selection; an explicit ID selects only that provider. Country operator record IDs and provider names are not selectors."
                  },
                  "number": {
                    "type": "string",
                    "description": "number"
                  },
                  "session_duration": {
                    "type": "integer",
                    "enum": [
                      20,
                      15
                    ],
                    "description": "New reservations last 20 minutes. The previous value 15 is accepted as a compatibility alias for 20. Idempotent replays return the original reservation and do not extend it.",
                    "default": 20
                  },
                  "start": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 1000000,
                    "description": "start"
                  },
                  "limit": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 100,
                    "description": "limit"
                  },
                  "maxPrice": {
                    "type": "string",
                    "pattern": "^\\d+(\\.\\d{1,8})?$",
                    "description": "Максимальная цена покупки; фактическая стоимость выдачи — 0 USD. Поле reward содержит вознаграждение за SMS."
                  },
                  "freePrice": {
                    "type": "integer",
                    "enum": [
                      0,
                      1
                    ],
                    "description": "freePrice"
                  },
                  "forward": {
                    "type": "integer",
                    "enum": [
                      0
                    ],
                    "description": "forward"
                  },
                  "verificationType": {
                    "type": "integer",
                    "enum": [
                      1
                    ],
                    "description": "verificationType"
                  }
                }
              }
            }
          }
        },
        "x-smscash-automatic-routing": {
          "mode": "received_codes",
          "pair": [
            "service",
            "country"
          ],
          "priority": [
            "codes_last_1h",
            "codes_last_24h",
            "reward_desc",
            "provider_id_asc"
          ],
          "statistics_cache_seconds": 30,
          "empty_pool_fallback": true,
          "fallback_codes": [
            "EMPTY_POOL",
            "NO_NUMBERS"
          ],
          "explicit_provider_is_strict": true,
          "explicit_operator_is_strict": true,
          "repeat_number_keeps_its_provider": true,
          "uncertain_result_fallback": false,
          "idempotency_key_preserved": true,
          "current_key_scopes_and_restrictions": true
        },
        "x-getRewards": {
          "description": "getRewards (SMScash): country ID → service code → public provider ID → reward. Rewards are exact USD decimal strings with 8 places. country, service and operator are optional filters; omit operator or use any/0 to include every permitted provider. The IDs match operator in catalog/tariffs and getOperators, not upstream channel IDs. Current enabled tariffs, account permissions and API key scopes apply. Empty selection returns {}. No stock check, allocation or financial operation is performed.",
          "schema": {
            "$ref": "#/components/schemas/RewardsCatalog"
          },
          "optional": [
            "country",
            "service",
            "operator"
          ]
        },
        "x-getOperators": {
          "description": "countryOperators retains country → public operator ID strings. operators contains the same ID, name and earnings_hold_days records as GET /api/v1/operators.",
          "schema": {
            "$ref": "#/components/schemas/CompatibleOperators"
          },
          "optional": [
            "country",
            "operator"
          ]
        }
      }
    },
    "/hero-sms/stubs/handler_api.php": {
      "get": {
        "tags": [
          "Compatibility"
        ],
        "security": [
          {
            "legacyAPIKey": []
          }
        ],
        "description": "Совместимые команды SMS-Activate/HeroSMS для собственных сессий SMScash. Используйте ключ SMScash и коды из его каталога. GET и POST form-url-encoded. Выдача бесплатно: cost и activationCost равны 0, reward — точное вознаграждение за SMS, баланс getBalance — только доступные средства, без холда. Сессия 20 минут, опрос раз в 20 секунд. status=1 не очищает SMS и не продлевает срок; status=3 сохраняет исходную сессию. Для сетевых повторов используйте прежний Idempotency-Key и параметры. ALLOCATION_UNCERTAIN запрещает автоматическую повторную выдачу. Аренда, звонки, переадресация, продление и несколько сервисов на номере не поддерживаются; неизвестные команды — BAD_ACTION, неподдерживаемые опции — BAD_REQUEST. Каталоги учитывают текущие ограничения, персональные разрешения и policy ключа.",
        "responses": {
          "200": {
            "description": "Успех либо текстовый бизнес-исход/ошибка ключа. Проверяйте Content-Type и тело, а не только HTTP.",
            "headers": {
              "X-Request-ID": {
                "schema": {
                  "type": "string"
                }
              },
              "X-SMScash-Availability-Scope": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "supplier-pool"
                  ]
                }
              }
            },
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                },
                "examples": {
                  "number": {
                    "value": "ACCESS_NUMBER:42:393331234567"
                  },
                  "waiting": {
                    "value": "STATUS_WAIT_CODE"
                  },
                  "code": {
                    "value": "STATUS_OK:001234"
                  },
                  "ready": {
                    "value": "ACCESS_READY"
                  },
                  "empty": {
                    "value": "NO_NUMBERS"
                  },
                  "key": {
                    "value": "BAD_KEY"
                  },
                  "uncertain": {
                    "value": "ALLOCATION_UNCERTAIN"
                  },
                  "held_balance": {
                    "summary": "SMScash: сумма в холде",
                    "value": "ACCESS_HOLD_BALANCE:34.50000001"
                  }
                }
              },
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "$ref": "#/components/schemas/CompatibleActivation"
                    },
                    {
                      "$ref": "#/components/schemas/CompatibleStatus"
                    },
                    {
                      "type": "object"
                    },
                    {
                      "$ref": "#/components/schemas/RewardsCatalog"
                    },
                    {
                      "$ref": "#/components/schemas/CompatibleOperators"
                    }
                  ]
                },
                "examples": {
                  "getRewards": {
                    "summary": "country → service → operator → reward (USD)",
                    "value": {
                      "59": {
                        "vi": {
                          "1": "0.01000000",
                          "3": "0.00500000"
                        }
                      }
                    }
                  },
                  "getOperators": {
                    "summary": "Country operator selectors plus the operator catalog",
                    "value": {
                      "status": "success",
                      "countryOperators": {
                        "86": [
                          "1"
                        ]
                      },
                      "operators": {
                        "1": {
                          "id": 1,
                          "provider_id": 1,
                          "operator": 1,
                          "name": "Оператор 1",
                          "earnings_hold_days": 45
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "405": {
            "description": "Поддерживаются GET и POST. HEAD не выполняет выдачу номера.",
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string",
                  "example": "GET, POST"
                }
              }
            },
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "500": {
            "description": "Ошибка сервера или недоступный поставщик. Текст INTERNAL_ERROR; при неизвестном результате выдачи нельзя автоматически создавать новую операцию.",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        },
        "x-actions": [
          "getNumber",
          "getNumberV2",
          "getStatus",
          "getStatusV2",
          "setStatus",
          "finishActivation",
          "cancelActivation",
          "getPrices",
          "getServicesList",
          "getServices",
          "getCountries",
          "getOperators",
          "getNumbersStatus",
          "getActiveActivations",
          "getBalance",
          "getRepeatNumber",
          "getSms",
          "getSmsFull",
          "getHoldBalance",
          "getRewards"
        ],
        "summary": "HeroSMS-совместимый API",
        "operationId": "hero_smsCompatibilityGET",
        "parameters": [
          {
            "name": "action",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "getNumber",
                "getNumberV2",
                "getStatus",
                "getStatusV2",
                "setStatus",
                "finishActivation",
                "cancelActivation",
                "getPrices",
                "getServicesList",
                "getServices",
                "getCountries",
                "getOperators",
                "getNumbersStatus",
                "getActiveActivations",
                "getBalance",
                "getRepeatNumber",
                "getSms",
                "getSmsFull",
                "getHoldBalance",
                "getRewards"
              ]
            },
            "description": "Команда; обязательность остальных полей зависит от неё."
          },
          {
            "name": "service",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 64
            },
            "description": "Точный код из getServicesList или getServices."
          },
          {
            "name": "country",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 2147483647
            },
            "description": "ID страны из каталога SMScash; не ISO-код."
          },
          {
            "name": "id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64",
              "minimum": 1
            },
            "description": "id"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "enum": [
                1,
                3,
                6,
                8
              ]
            },
            "description": "1 — подтвердить готовность; 3 — ждать новое SMS в той же сессии; 6 — завершить после SMS; 8 — отменить."
          },
          {
            "name": "ref",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Необязательный код владельца софта. Используется при получении новой сессии."
          },
          {
            "name": "operator",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "pattern": "^([0-9]+|[aA][nN][yY])?$",
              "example": "1"
            },
            "description": "Public provider ID from operators/getOperators or the operator field in tariffs/catalog. Operator 1 uses operator=1. Accepts an integer or its decimal string. Omit operator or use any/0 for automatic selection; an explicit ID selects only that provider. Country operator record IDs and provider names are not selectors."
          },
          {
            "name": "number",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "number"
          },
          {
            "name": "session_duration",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "enum": [
                20,
                15
              ],
              "default": 20,
              "description": "New reservations last 20 minutes. The previous value 15 is accepted as a compatibility alias for 20. Idempotent replays return the original reservation and do not extend it."
            },
            "description": "session_duration"
          },
          {
            "name": "start",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 1000000
            },
            "description": "start"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            },
            "description": "limit"
          },
          {
            "name": "maxPrice",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "pattern": "^\\d+(\\.\\d{1,8})?$"
            },
            "description": "Максимальная цена покупки; фактическая стоимость выдачи — 0 USD. Поле reward содержит вознаграждение за SMS."
          },
          {
            "name": "freePrice",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "enum": [
                0,
                1
              ]
            },
            "description": "freePrice"
          },
          {
            "name": "forward",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "enum": [
                0
              ]
            },
            "description": "forward"
          },
          {
            "name": "verificationType",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "enum": [
                1
              ]
            },
            "description": "verificationType"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 128
            },
            "description": "Рекомендуется при получении номера и retry. Не меняйте ключ при сетевом повторе той же операции."
          }
        ],
        "x-smscash-automatic-routing": {
          "mode": "received_codes",
          "pair": [
            "service",
            "country"
          ],
          "priority": [
            "codes_last_1h",
            "codes_last_24h",
            "reward_desc",
            "provider_id_asc"
          ],
          "statistics_cache_seconds": 30,
          "empty_pool_fallback": true,
          "fallback_codes": [
            "EMPTY_POOL",
            "NO_NUMBERS"
          ],
          "explicit_provider_is_strict": true,
          "explicit_operator_is_strict": true,
          "repeat_number_keeps_its_provider": true,
          "uncertain_result_fallback": false,
          "idempotency_key_preserved": true,
          "current_key_scopes_and_restrictions": true
        },
        "x-getRewards": {
          "description": "getRewards (SMScash): country ID → service code → public provider ID → reward. Rewards are exact USD decimal strings with 8 places. country, service and operator are optional filters; omit operator or use any/0 to include every permitted provider. The IDs match operator in catalog/tariffs and getOperators, not upstream channel IDs. Current enabled tariffs, account permissions and API key scopes apply. Empty selection returns {}. No stock check, allocation or financial operation is performed.",
          "schema": {
            "$ref": "#/components/schemas/RewardsCatalog"
          },
          "optional": [
            "country",
            "service",
            "operator"
          ]
        },
        "x-getOperators": {
          "description": "countryOperators retains country → public operator ID strings. operators contains the same ID, name and earnings_hold_days records as GET /api/v1/operators.",
          "schema": {
            "$ref": "#/components/schemas/CompatibleOperators"
          },
          "optional": [
            "country",
            "operator"
          ]
        }
      },
      "post": {
        "tags": [
          "Compatibility"
        ],
        "security": [
          {
            "legacyAPIKey": []
          }
        ],
        "description": "Совместимые команды SMS-Activate/HeroSMS для собственных сессий SMScash. Используйте ключ SMScash и коды из его каталога. GET и POST form-url-encoded. Выдача бесплатно: cost и activationCost равны 0, reward — точное вознаграждение за SMS, баланс getBalance — только доступные средства, без холда. Сессия 20 минут, опрос раз в 20 секунд. status=1 не очищает SMS и не продлевает срок; status=3 сохраняет исходную сессию. Для сетевых повторов используйте прежний Idempotency-Key и параметры. ALLOCATION_UNCERTAIN запрещает автоматическую повторную выдачу. Аренда, звонки, переадресация, продление и несколько сервисов на номере не поддерживаются; неизвестные команды — BAD_ACTION, неподдерживаемые опции — BAD_REQUEST. Каталоги учитывают текущие ограничения, персональные разрешения и policy ключа.",
        "responses": {
          "200": {
            "description": "Успех либо текстовый бизнес-исход/ошибка ключа. Проверяйте Content-Type и тело, а не только HTTP.",
            "headers": {
              "X-Request-ID": {
                "schema": {
                  "type": "string"
                }
              },
              "X-SMScash-Availability-Scope": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "supplier-pool"
                  ]
                }
              }
            },
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                },
                "examples": {
                  "number": {
                    "value": "ACCESS_NUMBER:42:393331234567"
                  },
                  "waiting": {
                    "value": "STATUS_WAIT_CODE"
                  },
                  "code": {
                    "value": "STATUS_OK:001234"
                  },
                  "ready": {
                    "value": "ACCESS_READY"
                  },
                  "empty": {
                    "value": "NO_NUMBERS"
                  },
                  "key": {
                    "value": "BAD_KEY"
                  },
                  "uncertain": {
                    "value": "ALLOCATION_UNCERTAIN"
                  },
                  "held_balance": {
                    "summary": "SMScash: сумма в холде",
                    "value": "ACCESS_HOLD_BALANCE:34.50000001"
                  }
                }
              },
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "$ref": "#/components/schemas/CompatibleActivation"
                    },
                    {
                      "$ref": "#/components/schemas/CompatibleStatus"
                    },
                    {
                      "type": "object"
                    },
                    {
                      "$ref": "#/components/schemas/RewardsCatalog"
                    },
                    {
                      "$ref": "#/components/schemas/CompatibleOperators"
                    }
                  ]
                },
                "examples": {
                  "getRewards": {
                    "summary": "country → service → operator → reward (USD)",
                    "value": {
                      "59": {
                        "vi": {
                          "1": "0.01000000",
                          "3": "0.00500000"
                        }
                      }
                    }
                  },
                  "getOperators": {
                    "summary": "Country operator selectors plus the operator catalog",
                    "value": {
                      "status": "success",
                      "countryOperators": {
                        "86": [
                          "1"
                        ]
                      },
                      "operators": {
                        "1": {
                          "id": 1,
                          "provider_id": 1,
                          "operator": 1,
                          "name": "Оператор 1",
                          "earnings_hold_days": 45
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "405": {
            "description": "Поддерживаются GET и POST. HEAD не выполняет выдачу номера.",
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string",
                  "example": "GET, POST"
                }
              }
            },
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "500": {
            "description": "Ошибка сервера или недоступный поставщик. Текст INTERNAL_ERROR; при неизвестном результате выдачи нельзя автоматически создавать новую операцию.",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        },
        "x-actions": [
          "getNumber",
          "getNumberV2",
          "getStatus",
          "getStatusV2",
          "setStatus",
          "finishActivation",
          "cancelActivation",
          "getPrices",
          "getServicesList",
          "getServices",
          "getCountries",
          "getOperators",
          "getNumbersStatus",
          "getActiveActivations",
          "getBalance",
          "getRepeatNumber",
          "getSms",
          "getSmsFull",
          "getHoldBalance",
          "getRewards"
        ],
        "summary": "Те же команды через форму POST",
        "operationId": "hero_smsCompatibilityPOST",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 128
            },
            "description": "Рекомендуется при получении номера и retry. Не меняйте ключ при сетевом повторе той же операции."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "api_key",
                  "action"
                ],
                "properties": {
                  "action": {
                    "type": "string",
                    "enum": [
                      "getNumber",
                      "getNumberV2",
                      "getStatus",
                      "getStatusV2",
                      "setStatus",
                      "finishActivation",
                      "cancelActivation",
                      "getPrices",
                      "getServicesList",
                      "getServices",
                      "getCountries",
                      "getOperators",
                      "getNumbersStatus",
                      "getActiveActivations",
                      "getBalance",
                      "getRepeatNumber",
                      "getSms",
                      "getSmsFull",
                      "getHoldBalance",
                      "getRewards"
                    ],
                    "description": "Команда; обязательность остальных полей зависит от неё."
                  },
                  "api_key": {
                    "type": "string",
                    "minLength": 8,
                    "maxLength": 256,
                    "description": "Личный ключ SMScash. В POST допустим в форме или query, одинаковые повторные значения не создают новую операцию."
                  },
                  "service": {
                    "type": "string",
                    "maxLength": 64,
                    "description": "Точный код из getServicesList или getServices."
                  },
                  "country": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 2147483647,
                    "description": "ID страны из каталога SMScash; не ISO-код."
                  },
                  "id": {
                    "type": "integer",
                    "format": "int64",
                    "minimum": 1,
                    "description": "id"
                  },
                  "status": {
                    "type": "integer",
                    "enum": [
                      1,
                      3,
                      6,
                      8
                    ],
                    "description": "1 — подтвердить готовность; 3 — ждать новое SMS в той же сессии; 6 — завершить после SMS; 8 — отменить."
                  },
                  "ref": {
                    "type": "string",
                    "description": "Необязательный код владельца софта. Используется при получении новой сессии."
                  },
                  "operator": {
                    "type": "string",
                    "pattern": "^([0-9]+|[aA][nN][yY])?$",
                    "example": "1",
                    "description": "Public provider ID from operators/getOperators or the operator field in tariffs/catalog. Operator 1 uses operator=1. Accepts an integer or its decimal string. Omit operator or use any/0 for automatic selection; an explicit ID selects only that provider. Country operator record IDs and provider names are not selectors."
                  },
                  "number": {
                    "type": "string",
                    "description": "number"
                  },
                  "session_duration": {
                    "type": "integer",
                    "enum": [
                      20,
                      15
                    ],
                    "description": "New reservations last 20 minutes. The previous value 15 is accepted as a compatibility alias for 20. Idempotent replays return the original reservation and do not extend it.",
                    "default": 20
                  },
                  "start": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 1000000,
                    "description": "start"
                  },
                  "limit": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 100,
                    "description": "limit"
                  },
                  "maxPrice": {
                    "type": "string",
                    "pattern": "^\\d+(\\.\\d{1,8})?$",
                    "description": "Максимальная цена покупки; фактическая стоимость выдачи — 0 USD. Поле reward содержит вознаграждение за SMS."
                  },
                  "freePrice": {
                    "type": "integer",
                    "enum": [
                      0,
                      1
                    ],
                    "description": "freePrice"
                  },
                  "forward": {
                    "type": "integer",
                    "enum": [
                      0
                    ],
                    "description": "forward"
                  },
                  "verificationType": {
                    "type": "integer",
                    "enum": [
                      1
                    ],
                    "description": "verificationType"
                  }
                }
              }
            }
          }
        },
        "x-smscash-automatic-routing": {
          "mode": "received_codes",
          "pair": [
            "service",
            "country"
          ],
          "priority": [
            "codes_last_1h",
            "codes_last_24h",
            "reward_desc",
            "provider_id_asc"
          ],
          "statistics_cache_seconds": 30,
          "empty_pool_fallback": true,
          "fallback_codes": [
            "EMPTY_POOL",
            "NO_NUMBERS"
          ],
          "explicit_provider_is_strict": true,
          "explicit_operator_is_strict": true,
          "repeat_number_keeps_its_provider": true,
          "uncertain_result_fallback": false,
          "idempotency_key_preserved": true,
          "current_key_scopes_and_restrictions": true
        },
        "x-getRewards": {
          "description": "getRewards (SMScash): country ID → service code → public provider ID → reward. Rewards are exact USD decimal strings with 8 places. country, service and operator are optional filters; omit operator or use any/0 to include every permitted provider. The IDs match operator in catalog/tariffs and getOperators, not upstream channel IDs. Current enabled tariffs, account permissions and API key scopes apply. Empty selection returns {}. No stock check, allocation or financial operation is performed.",
          "schema": {
            "$ref": "#/components/schemas/RewardsCatalog"
          },
          "optional": [
            "country",
            "service",
            "operator"
          ]
        },
        "x-getOperators": {
          "description": "countryOperators retains country → public operator ID strings. operators contains the same ID, name and earnings_hold_days records as GET /api/v1/operators.",
          "schema": {
            "$ref": "#/components/schemas/CompatibleOperators"
          },
          "optional": [
            "country",
            "operator"
          ]
        }
      }
    },
    "/api/v1/balance": {
      "get": {
        "summary": "Доступный баланс и сумма в холде",
        "tags": [
          "Worker"
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientBalance"
                },
                "example": {
                  "currency": "USD",
                  "accounting_precision": 8,
                  "balance": "12.00000000",
                  "held_balance": "34.50000001",
                  "balance_minor": "1200000000",
                  "held_minor": "3450000001",
                  "as_of": "2026-10-12T20:00:00Z",
                  "next_release_at": "2026-11-26T20:00:00Z"
                }
              }
            }
          },
          "400": {
            "description": "Invalid input",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "403": {
            "description": "Insufficient privileges",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "405": {
            "description": "METHOD_NOT_ALLOWED: допустимые методы перечислены в Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              },
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              }
            }
          },
          "409": {
            "description": "State or idempotency conflict",
            "headers": {
              "X-Request-ID": {
                "description": "Идентификатор запроса для обращения в поддержку. Не содержит API-ключа.",
                "schema": {
                  "type": "string",
                  "example": "req_4af73f583f6c4ca394928da2cb4e4a11"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "ALLOCATION_PENDING: 3 секунды, retryable=true; повторить те же параметры с прежним ключом. ALLOCATION_UNCERTAIN: retryable=false, автоматический повтор запрещён."
              }
            }
          }
        },
        "description": "Данные только владельца сессии или API-ключа. Параметры и выбор другого пользователя не поддерживаются. Все суммы и даты читаются одним SQL-снимком; доступность меняется по available_at. Чтение не меняет ledger, банк, заявки на выплату и номера и не вызывает поставщика.",
        "operationId": "getClientBalance"
      }
    }
  }
}
