{
  "openapi": "3.1.0",
  "info": {
    "title": "Crystal VPN Organization Agent API",
    "version": "1.0.0",
    "description": "Agent-facing contract over the existing Crystal VPN Workspace API. Authentication and organization scope are enforced by the server for every request."
  },
  "servers": [
    {
      "url": "https://vpn.crystalstrategy.ru/vpn/api/remote-access",
      "description": "Crystal VPN"
    },
    {
      "url": "https://crystalstrategy.ru/vpn/api/remote-access",
      "description": "CrystalStrategy"
    }
  ],
  "paths": {
    "/workspace/login": {
      "post": {
        "summary": "Войти по логину и паролю",
        "responses": {
          "200": {
            "description": "Сессия создана; ответ содержит csrf и права, заголовок Set-Cookie содержит HttpOnly cookie"
          },
          "401": {
            "description": "Неверный логин или пароль"
          },
          "429": {
            "description": "Слишком много попыток"
          }
        },
        "description": "Сохраните cookie из Set-Cookie в защищённом cookie jar. Возвращённый csrf передавайте в X-CSRF-Token для всех POST.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "login": {
                    "type": "string",
                    "maxLength": 160
                  },
                  "password": {
                    "type": "string",
                    "format": "password",
                    "maxLength": 256
                  }
                },
                "required": [
                  "login",
                  "password"
                ]
              }
            }
          }
        }
      }
    },
    "/workspace/logout": {
      "post": {
        "summary": "Завершить сессию",
        "responses": {
          "200": {
            "description": "Сессия удалена и cookie очищена"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {}
              }
            }
          }
        },
        "security": [
          {
            "workspaceCookie": []
          }
        ],
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "https://vpn.crystalstrategy.ru",
                "https://crystalstrategy.ru",
                "https://www.crystalstrategy.ru"
              ]
            }
          },
          {
            "name": "X-CSRF-Token",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/workspace/session": {
      "get": {
        "summary": "Проверить сессию и права",
        "responses": {
          "200": {
            "description": "Успешно"
          },
          "401": {
            "description": "Сессия отсутствует или истекла"
          },
          "403": {
            "description": "Недостаточно прав"
          },
          "409": {
            "description": "Версия данных или бизнес-инвариант изменились"
          }
        },
        "security": [
          {
            "workspaceCookie": []
          }
        ]
      }
    },
    "/workspace/bootstrap": {
      "get": {
        "summary": "Получить сессию и доступные организации",
        "responses": {
          "200": {
            "description": "Успешно"
          },
          "401": {
            "description": "Сессия отсутствует или истекла"
          },
          "403": {
            "description": "Недостаточно прав"
          },
          "409": {
            "description": "Версия данных или бизнес-инвариант изменились"
          }
        },
        "parameters": [
          {
            "name": "month",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "pattern": "^20\\d{2}-(0[1-9]|1[0-2])$"
            }
          }
        ],
        "security": [
          {
            "workspaceCookie": []
          }
        ]
      }
    },
    "/workspace/company": {
      "get": {
        "summary": "Открыть карточку доступной организации",
        "responses": {
          "200": {
            "description": "Успешно"
          },
          "401": {
            "description": "Сессия отсутствует или истекла"
          },
          "403": {
            "description": "Недостаточно прав"
          },
          "409": {
            "description": "Версия данных или бизнес-инвариант изменились"
          }
        },
        "parameters": [
          {
            "name": "company_id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 160
            }
          },
          {
            "name": "month",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "security": [
          {
            "workspaceCookie": []
          }
        ]
      }
    },
    "/workspace/accounts": {
      "get": {
        "summary": "Получить сотрудников организации",
        "responses": {
          "200": {
            "description": "Успешно"
          },
          "401": {
            "description": "Сессия отсутствует или истекла"
          },
          "403": {
            "description": "Недостаточно прав"
          },
          "409": {
            "description": "Версия данных или бизнес-инвариант изменились"
          }
        },
        "parameters": [
          {
            "name": "company_id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 160
            }
          }
        ],
        "security": [
          {
            "workspaceCookie": []
          }
        ]
      },
      "post": {
        "summary": "Создать пользователя организации",
        "responses": {
          "200": {
            "description": "Успешно"
          },
          "401": {
            "description": "Сессия отсутствует или истекла"
          },
          "403": {
            "description": "Недостаточно прав"
          },
          "409": {
            "description": "Версия данных или бизнес-инвариант изменились"
          }
        },
        "description": "Владелец/заместитель или назначенный корпоративный менеджер. Результат содержит одноразовое приглашение на установку пароля.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "operation_id": {
                    "type": "string",
                    "minLength": 16,
                    "maxLength": 96,
                    "pattern": "^[A-Za-z0-9_-]+$",
                    "description": "Стабильный уникальный ID операции. При повторе запроса использовать тот же ID."
                  },
                  "organization_id": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 160
                  },
                  "login": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 160
                  },
                  "display_name": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 160
                  },
                  "role": {
                    "type": "string",
                    "enum": [
                      "employee",
                      "deputy",
                      "owner"
                    ]
                  }
                },
                "required": [
                  "operation_id",
                  "organization_id",
                  "login",
                  "display_name"
                ]
              }
            }
          }
        },
        "security": [
          {
            "workspaceCookie": []
          }
        ],
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "https://vpn.crystalstrategy.ru",
                "https://crystalstrategy.ru",
                "https://www.crystalstrategy.ru"
              ]
            }
          },
          {
            "name": "X-CSRF-Token",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/workspace/accounts/update": {
      "post": {
        "summary": "Изменить имя, логин или доступ пользователя",
        "responses": {
          "200": {
            "description": "Успешно"
          },
          "401": {
            "description": "Сессия отсутствует или истекла"
          },
          "403": {
            "description": "Недостаточно прав"
          },
          "409": {
            "description": "Версия данных или бизнес-инвариант изменились"
          }
        },
        "description": "Используйте только поля, которые требуется изменить. expected_version берётся из свежего GET /workspace/accounts.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "operation_id": {
                    "type": "string",
                    "minLength": 16,
                    "maxLength": 96,
                    "pattern": "^[A-Za-z0-9_-]+$",
                    "description": "Стабильный уникальный ID операции. При повторе запроса использовать тот же ID."
                  },
                  "organization_id": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 160
                  },
                  "account_id": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 160
                  },
                  "expected_version": {
                    "type": "integer",
                    "minimum": 1
                  },
                  "display_name": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 160
                  },
                  "login": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 160
                  },
                  "enabled": {
                    "type": "boolean"
                  }
                },
                "required": [
                  "operation_id",
                  "organization_id",
                  "account_id",
                  "expected_version"
                ]
              }
            }
          }
        },
        "security": [
          {
            "workspaceCookie": []
          }
        ],
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "https://vpn.crystalstrategy.ru",
                "https://crystalstrategy.ru",
                "https://www.crystalstrategy.ru"
              ]
            }
          },
          {
            "name": "X-CSRF-Token",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/workspace/organizations/role": {
      "post": {
        "summary": "Изменить роль пользователя",
        "responses": {
          "200": {
            "description": "Успешно"
          },
          "401": {
            "description": "Сессия отсутствует или истекла"
          },
          "403": {
            "description": "Недостаточно прав"
          },
          "409": {
            "description": "Версия данных или бизнес-инвариант изменились"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "operation_id": {
                    "type": "string",
                    "minLength": 16,
                    "maxLength": 96,
                    "pattern": "^[A-Za-z0-9_-]+$",
                    "description": "Стабильный уникальный ID операции. При повторе запроса использовать тот же ID."
                  },
                  "organization_id": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 160
                  },
                  "account_id": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 160
                  },
                  "expected_version": {
                    "type": "integer",
                    "minimum": 1
                  },
                  "role": {
                    "type": "string",
                    "enum": [
                      "employee",
                      "deputy",
                      "owner"
                    ]
                  }
                },
                "required": [
                  "operation_id",
                  "organization_id",
                  "account_id",
                  "expected_version",
                  "role"
                ]
              }
            }
          }
        },
        "security": [
          {
            "workspaceCookie": []
          }
        ],
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "https://vpn.crystalstrategy.ru",
                "https://crystalstrategy.ru",
                "https://www.crystalstrategy.ru"
              ]
            }
          },
          {
            "name": "X-CSRF-Token",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/workspace/organizations/member/remove": {
      "post": {
        "summary": "Удалить пользователя из организации и отозвать связанные VPN-ключи",
        "responses": {
          "200": {
            "description": "Успешно"
          },
          "401": {
            "description": "Сессия отсутствует или истекла"
          },
          "403": {
            "description": "Недостаточно прав"
          },
          "409": {
            "description": "Версия данных или бизнес-инвариант изменились"
          }
        },
        "description": "Необратимое для текущих ключей действие. История и расчёты сохраняются.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "operation_id": {
                    "type": "string",
                    "minLength": 16,
                    "maxLength": 96,
                    "pattern": "^[A-Za-z0-9_-]+$",
                    "description": "Стабильный уникальный ID операции. При повторе запроса использовать тот же ID."
                  },
                  "organization_id": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 160
                  },
                  "account_id": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 160
                  },
                  "expected_version": {
                    "type": "integer",
                    "minimum": 1
                  },
                  "confirmed": {
                    "const": true
                  }
                },
                "required": [
                  "operation_id",
                  "organization_id",
                  "account_id",
                  "expected_version",
                  "confirmed"
                ]
              }
            }
          }
        },
        "security": [
          {
            "workspaceCookie": []
          }
        ],
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "https://vpn.crystalstrategy.ru",
                "https://crystalstrategy.ru",
                "https://www.crystalstrategy.ru"
              ]
            }
          },
          {
            "name": "X-CSRF-Token",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/workspace/profiles/issue": {
      "post": {
        "summary": "Выдать пользователю новый VPN-профиль",
        "responses": {
          "200": {
            "description": "Успешно"
          },
          "401": {
            "description": "Сессия отсутствует или истекла"
          },
          "403": {
            "description": "Недостаточно прав"
          },
          "409": {
            "description": "Версия данных или бизнес-инвариант изменились"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "operation_id": {
                    "type": "string",
                    "minLength": 16,
                    "maxLength": 96,
                    "pattern": "^[A-Za-z0-9_-]+$",
                    "description": "Стабильный уникальный ID операции. При повторе запроса использовать тот же ID."
                  },
                  "organization_id": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 160
                  },
                  "account_id": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 160
                  },
                  "expected_version": {
                    "type": "integer",
                    "minimum": 1
                  },
                  "phone": {
                    "type": "string",
                    "minLength": 10,
                    "maxLength": 30
                  }
                },
                "required": [
                  "operation_id",
                  "organization_id",
                  "account_id",
                  "expected_version",
                  "phone"
                ]
              }
            }
          }
        },
        "security": [
          {
            "workspaceCookie": []
          }
        ],
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "https://vpn.crystalstrategy.ru",
                "https://crystalstrategy.ru",
                "https://www.crystalstrategy.ru"
              ]
            }
          },
          {
            "name": "X-CSRF-Token",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/workspace/profiles/status": {
      "post": {
        "summary": "Приостановить, вернуть или заменить VPN-ключ",
        "responses": {
          "200": {
            "description": "Успешно"
          },
          "401": {
            "description": "Сессия отсутствует или истекла"
          },
          "403": {
            "description": "Недостаточно прав"
          },
          "409": {
            "description": "Версия данных или бизнес-инвариант изменились"
          }
        },
        "description": "rotate требует confirmed=true, закрывает старые ссылки и выпускает новое ключевое поколение; после него запросите новую ссылку через profiles/share.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "operation_id": {
                    "type": "string",
                    "minLength": 16,
                    "maxLength": 96,
                    "pattern": "^[A-Za-z0-9_-]+$",
                    "description": "Стабильный уникальный ID операции. При повторе запроса использовать тот же ID."
                  },
                  "organization_id": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 160
                  },
                  "account_id": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 160
                  },
                  "expected_version": {
                    "type": "integer",
                    "minimum": 1
                  },
                  "profile_slug": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 160
                  },
                  "action": {
                    "type": "string",
                    "enum": [
                      "suspend",
                      "resume",
                      "rotate"
                    ]
                  },
                  "confirmed": {
                    "type": "boolean",
                    "description": "Обязательно true для action=rotate после явного подтверждения пользователя."
                  }
                },
                "required": [
                  "operation_id",
                  "organization_id",
                  "account_id",
                  "expected_version",
                  "profile_slug",
                  "action"
                ]
              }
            }
          }
        },
        "security": [
          {
            "workspaceCookie": []
          }
        ],
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "https://vpn.crystalstrategy.ru",
                "https://crystalstrategy.ru",
                "https://www.crystalstrategy.ru"
              ]
            }
          },
          {
            "name": "X-CSRF-Token",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/workspace/profiles/share": {
      "post": {
        "summary": "Создать ссылку установки VPN-профиля",
        "responses": {
          "200": {
            "description": "Успешно"
          },
          "401": {
            "description": "Сессия отсутствует или истекла"
          },
          "403": {
            "description": "Недостаточно прав"
          },
          "409": {
            "description": "Версия данных или бизнес-инвариант изменились"
          }
        },
        "description": "Ответ содержит секретную capability-ссылку. Не записывайте её в логи и показывайте только владельцу профиля.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "operation_id": {
                    "type": "string",
                    "minLength": 16,
                    "maxLength": 96,
                    "pattern": "^[A-Za-z0-9_-]+$",
                    "description": "Стабильный уникальный ID операции. При повторе запроса использовать тот же ID."
                  },
                  "organization_id": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 160
                  },
                  "account_id": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 160
                  },
                  "expected_version": {
                    "type": "integer",
                    "minimum": 1
                  },
                  "profile_slug": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 160
                  },
                  "link_mode": {
                    "type": "string",
                    "enum": [
                      "once",
                      "persistent"
                    ]
                  }
                },
                "required": [
                  "operation_id",
                  "organization_id",
                  "account_id",
                  "expected_version",
                  "profile_slug",
                  "link_mode"
                ]
              }
            }
          }
        },
        "security": [
          {
            "workspaceCookie": []
          }
        ],
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "https://vpn.crystalstrategy.ru",
                "https://crystalstrategy.ru",
                "https://www.crystalstrategy.ru"
              ]
            }
          },
          {
            "name": "X-CSRF-Token",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/workspace/audit": {
      "get": {
        "summary": "Получить доступный журнал действий",
        "responses": {
          "200": {
            "description": "Успешно"
          },
          "401": {
            "description": "Сессия отсутствует или истекла"
          },
          "403": {
            "description": "Недостаточно прав"
          },
          "409": {
            "description": "Версия данных или бизнес-инвариант изменились"
          }
        },
        "parameters": [
          {
            "name": "company_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 160
            }
          },
          {
            "name": "before",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 160
            }
          }
        ],
        "security": [
          {
            "workspaceCookie": []
          }
        ]
      }
    },
    "/referrals/overview": {
      "get": {
        "summary": "Получить доступный менеджеру или партнёру обзор кэшбэка",
        "responses": {
          "200": {
            "description": "Успешно"
          },
          "401": {
            "description": "Сессия отсутствует или истекла"
          },
          "403": {
            "description": "Недостаточно прав"
          },
          "409": {
            "description": "Версия данных или бизнес-инвариант изменились"
          }
        },
        "parameters": [
          {
            "name": "month",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "company_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 160
            }
          }
        ],
        "security": [
          {
            "workspaceCookie": []
          }
        ]
      }
    }
  },
  "components": {
    "securitySchemes": {
      "workspaceCookie": {
        "type": "apiKey",
        "in": "cookie",
        "name": "__Secure-crystal_workspace",
        "description": "HttpOnly cookie returned by /workspace/login. Keep only in a protected cookie jar."
      }
    }
  },
  "tags": [
    {
      "name": "Authentication"
    },
    {
      "name": "Organizations"
    },
    {
      "name": "Members"
    },
    {
      "name": "VPN access"
    }
  ]
}
