# General

Общие операции (профиль, заказы, справочники)

## Создать и оплатить заказ

`POST /user/api/orders/purchase`

```json
{
  "tags": [
    "General"
  ],
  "summary": "Создать и оплатить заказ",
  "description": "Покупка по имени продукта, локации и циклу.\nДля Datacenter/ISP; location обязателен.\nДля Standart Residential Proxy; location не требуется.\n",
  "requestBody": {
    "required": true,
    "content": {
      "application/json": {
        "schema": {
          "oneOf": [
            {
              "$ref": "#/components/schemas/PurchaseRequestDcIsp"
            },
            {
              "$ref": "#/components/schemas/PurchaseRequestResidentialStandard"
            },
            {
              "$ref": "#/components/schemas/PurchaseRequestResidentialPremium"
            },
            {
              "$ref": "#/components/schemas/PurchaseRequestResidentialUnmetered"
            },
            {
              "$ref": "#/components/schemas/PurchaseRequest"
            }
          ]
        }
      }
    }
  },
  "responses": {
    "200": {
      "description": "Успешно",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/PurchaseResponse"
          }
        }
      }
    },
    "400": {
      "description": "Ошибка валидации/баланса/недостаток стока",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ApiError"
          }
        }
      }
    },
    "401": {
      "description": "Неавторизован",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ApiError"
          }
        }
      }
    }
  }
}
```

## Рассчитать стоимость заказа

`GET /user/api/orders/calculate`

```json
{
  "tags": [
    "General"
  ],
  "summary": "Рассчитать стоимость заказа",
  "description": "Рассчитывает цену по названию продукта, названию цикла и количеству. Использует те же правила проверки, что и при покупке (разрешенные платежные циклы, правила промоакций).",
  "parameters": [
    {
      "in": "query",
      "name": "product",
      "required": true,
      "schema": {
        "type": "string"
      }
    },
    {
      "in": "query",
      "name": "location",
      "required": false,
      "schema": {
        "type": "string",
        "nullable": true
      }
    },
    {
      "in": "query",
      "name": "cycle",
      "required": false,
      "schema": {
        "type": "string",
        "nullable": true
      }
    },
    {
      "in": "query",
      "name": "quantity",
      "required": false,
      "schema": {
        "type": "integer",
        "nullable": true
      }
    },
    {
      "in": "query",
      "name": "promo_code",
      "required": false,
      "schema": {
        "type": "string",
        "nullable": true
      }
    },
    {
      "in": "query",
      "name": "addons_json",
      "required": false,
      "description": "Массив дополнений в URL-кодированном JSON, например [{\"addon_key\":\"p0f_slots\",\"qty\":5}]",
      "schema": {
        "type": "string",
        "nullable": true
      }
    }
  ],
  "responses": {
    "200": {
      "description": "Успех",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "original_price": {
                "type": "integer"
              },
              "final_price": {
                "type": "integer"
              },
              "discount_percent": {
                "type": "integer"
              },
              "addons_price": {
                "type": "integer",
                "description": "Общая стоимость дополнений в минимальных единицах"
              },
              "total_with_addons": {
                "type": "integer",
                "description": "final_price + addons_price"
              }
            }
          }
        }
      }
    },
    "400": {
      "description": "Ошибка проверки",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ApiError"
          }
        }
      }
    },
    "401": {
      "description": "Требуется авторизация",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ApiError"
          }
        }
      }
    }
  }
}
```

## Изменить биллинг-цикл заказа

`POST /user/api/orders/change-billing-cycle/{order_id}`

```json
{
  "tags": [
    "General"
  ],
  "summary": "Изменить биллинг-цикл заказа",
  "description": "Меняет цикл оплаты по названию цикла. Только для Datacenter & ISP прокси.\nЕсли промокод недоступен для выбранного цикла, он будет автоматически сброшен.\n",
  "parameters": [
    {
      "in": "path",
      "name": "order_id",
      "required": true,
      "schema": {
        "type": "integer"
      }
    }
  ],
  "requestBody": {
    "required": true,
    "content": {
      "application/json": {
        "schema": {
          "type": "object",
          "properties": {
            "cycle": {
              "type": "string"
            }
          },
          "required": [
            "cycle"
          ]
        }
      }
    }
  },
  "responses": {
    "200": {
      "description": "Успешно",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "success": {
                "type": "boolean"
              },
              "message": {
                "type": "string"
              },
              "order_id": {
                "type": "integer"
              },
              "original_price": {
                "type": "integer"
              },
              "final_price": {
                "type": "integer"
              },
              "discount_percent": {
                "type": "integer"
              }
            }
          }
        }
      }
    },
    "400": {
      "description": "Неверный продукт или цикл",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ApiError"
          }
        }
      }
    },
    "401": {
      "description": "Неавторизован",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ApiError"
          }
        }
      }
    },
    "403": {
      "description": "Цикл недоступен для этого пользователя",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ApiError"
          }
        }
      }
    }
  }
}
```

## Изменить авто-продление заказа

`POST /user/api/orders/edit-auto-renewal/{order_id}`

```json
{
  "tags": [
    "General"
  ],
  "summary": "Изменить авто-продление заказа",
  "description": "Включить/выключить авто-продление. Только для Datacenter & ISP прокси.\n",
  "parameters": [
    {
      "in": "path",
      "name": "order_id",
      "required": true,
      "schema": {
        "type": "integer"
      }
    },
    {
      "in": "query",
      "name": "auto_renewal",
      "required": true,
      "schema": {
        "type": "boolean"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "Успешно",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "success": {
                "type": "boolean"
              },
              "message": {
                "type": "string"
              }
            }
          }
        }
      }
    },
    "400": {
      "description": "Неверный продукт для операции",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ApiError"
          }
        }
      }
    },
    "401": {
      "description": "Неавторизован",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ApiError"
          }
        }
      }
    }
  }
}
```

## Получить продукты и их циклы

`GET /user/api/proxies/products`

```json
{
  "tags": [
    "General"
  ],
  "summary": "Получить продукты и их циклы",
  "description": "Возвращает продукты для API с названиями доступных циклов.",
  "responses": {
    "200": {
      "description": "Список продуктов",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "success": {
                "type": "boolean"
              },
              "products": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/ProductWithCycles"
                }
              }
            },
            "required": [
              "success",
              "products"
            ]
          }
        }
      }
    }
  }
}
```

## Получить доступное количество прокси

`GET /user/api/proxies/available-count`

```json
{
  "tags": [
    "General"
  ],
  "summary": "Получить доступное количество прокси",
  "description": "Возвращает суммарное доступное количество для всех продуктов.",
  "responses": {
    "200": {
      "description": "Успешно",
      "content": {
        "application/json": {
          "schema": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AvailableCountResponse"
            }
          }
        }
      }
    }
  }
}
```

## Информация о пользователе

`GET /user/api/me`

```json
{
  "tags": [
    "General"
  ],
  "summary": "Информация о пользователе",
  "responses": {
    "200": {
      "description": "Данные профиля",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ApiMeResponse"
          }
        }
      }
    }
  }
}
```

## Список заказов

`GET /user/api/orders`

```json
{
  "tags": [
    "General"
  ],
  "summary": "Список заказов",
  "parameters": [
    {
      "in": "query",
      "name": "status",
      "required": true,
      "description": "активный | в ожидании | отменен | все",
      "schema": {
        "type": "string"
      }
    },
    {
      "in": "query",
      "name": "offset",
      "required": false,
      "description": "Смещение выборки (по умолчанию 0)",
      "schema": {
        "type": "integer",
        "minimum": 0
      }
    },
    {
      "in": "query",
      "name": "limit",
      "required": false,
      "description": "Размер страницы (1..100, по умолчанию 20)",
      "schema": {
        "type": "integer",
        "minimum": 1,
        "maximum": 100
      }
    }
  ],
  "responses": {
    "200": {
      "description": "Список заказов",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "success": {
                "type": "boolean"
              },
              "orders": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "order_id": {
                      "type": "integer"
                    },
                    "product_id": {
                      "type": "integer"
                    },
                    "product_name": {
                      "type": "string"
                    },
                    "cycle_id": {
                      "type": "integer"
                    },
                    "cycle_name": {
                      "type": "string"
                    },
                    "expires_at": {
                      "type": "string",
                      "nullable": true,
                      "description": "ISO8601 время истечения"
                    },
                    "auto_renewal": {
                      "type": "boolean",
                      "nullable": true
                    },
                    "tag": {
                      "type": "string",
                      "nullable": true
                    }
                  },
                  "required": [
                    "order_id",
                    "product_id",
                    "product_name",
                    "cycle_id",
                    "cycle_name"
                  ]
                }
              },
              "count": {
                "type": "integer",
                "description": "Количество заказов в текущей выборке"
              },
              "prev": {
                "type": "string",
                "nullable": true,
                "description": "URI предыдущей страницы"
              },
              "next": {
                "type": "string",
                "nullable": true,
                "description": "URI следующей страницы"
              }
            },
            "required": [
              "success",
              "orders"
            ]
          }
        }
      }
    }
  }
}
```

## Получить информацию о заказе

`GET /user/api/orders/{id}`

```json
{
  "tags": [
    "General"
  ],
  "summary": "Получить информацию о заказе",
  "parameters": [
    {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
        "type": "integer"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "Информация о заказе",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "success": {
                "type": "boolean"
              },
              "order": {
                "type": "object",
                "properties": {
                  "order_id": {
                    "type": "integer"
                  },
                  "product_name": {
                    "type": "string"
                  },
                  "cycle_name": {
                    "type": "string"
                  },
                  "quantity": {
                    "type": "integer"
                  },
                  "price_paid": {
                    "type": "integer",
                    "description": "Базовая цена подписки в центах"
                  },
                  "addons_price_paid": {
                    "type": "integer",
                    "description": "Общая дополнительная стоимость в центах"
                  },
                  "addons": {
                    "type": "array",
                    "description": "Дополнительные строки, прикрепленные к этому заказу",
                    "items": {
                      "$ref": "#/components/schemas/AddonLine"
                    }
                  },
                  "p0f_slots_available": {
                    "type": "integer",
                    "description": "Активные слоты для подписи p0f (из дополнений)"
                  },
                  "p0f_slots_used": {
                    "type": "integer",
                    "description": "Слоты, в настоящее время занятые подписанными прокси"
                  },
                  "p0f_slots_next": {
                    "type": "integer",
                    "description": "Слоты, которые будут активны после следующего продления"
                  },
                  "status": {
                    "type": "string"
                  },
                  "created_at": {
                    "type": "string",
                    "nullable": true
                  },
                  "expires_at": {
                    "type": "string",
                    "nullable": true
                  },
                  "promo_code": {
                    "type": "string",
                    "nullable": true
                  },
                  "auto_renewal": {
                    "type": "boolean",
                    "nullable": true
                  },
                  "tag": {
                    "type": "string",
                    "nullable": true
                  }
                }
              }
            },
            "required": [
              "success",
              "order"
            ]
          }
        }
      }
    }
  }
}
```

## Продлить заказ

`POST /user/api/orders/{id}/renew`

```json
{
  "tags": [
    "General"
  ],
  "summary": "Продлить заказ",
  "description": "Продление доступно только при статусе заказа `on-hold`.",
  "parameters": [
    {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
        "type": "integer"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "Успешно",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "success": {
                "type": "boolean"
              },
              "message": {
                "type": "string",
                "example": "Order renewed successfully"
              }
            },
            "required": [
              "success",
              "message"
            ]
          }
        }
      }
    },
    "400": {
      "description": "Недостаточный баланс/валидация",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ApiError"
          }
        }
      }
    }
  }
}
```

## Изменить тег заказа

`POST /user/api/orders/{id}/tag`

```json
{
  "tags": [
    "General"
  ],
  "summary": "Изменить тег заказа",
  "parameters": [
    {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
        "type": "integer"
      }
    }
  ],
  "requestBody": {
    "required": true,
    "content": {
      "application/json": {
        "schema": {
          "type": "object",
          "properties": {
            "tag": {
              "type": "string"
            }
          },
          "required": [
            "tag"
          ]
        }
      }
    }
  },
  "responses": {
    "200": {
      "description": "Успешно",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "success": {
                "type": "boolean"
              },
              "message": {
                "type": "string",
                "example": "Order tag updated"
              }
            },
            "required": [
              "success",
              "message"
            ]
          }
        }
      }
    }
  }
}
```
