openapi: 3.1.0
info:
  title: Car2B Remote Sales API
  version: '1.0'
  description: 'Публичный API «Удалённого отдела продаж» для систем клиентов Car2B: владелец стока ведёт программу и

    сделки, удалённый ОП берёт сток, бронирует и фиксирует покупки. Car2B — площадка: сторона сделки и расчётов — сами участники.


    **Доступ.** Ключ (client_id + секрет) выпускает организация в личном кабинете (раздел «Интеграции»), тот же механизм, что у Import API.

    Секрет обменивается на короткоживущий токен:


    ```

    POST https://api.car2b.ru/api/v1/identity/oauth/token

    Authorization: Basic base64(client_id:client_secret)

    Content-Type: application/x-www-form-urlencoded


    grant_type=client_credentials

    ```


    Токен живёт 5 минут; клиент обновляет его заранее и повторяет запрос один раз при 401.


    **Роли и скоупы.** Две роли, каждая в своём префиксе пути: `/owner/*` (владелец стока) и `/agent/*` (удалённый ОП).

    Скоупы: `remote-sales:owner.read`, `remote-sales:owner.write`, `remote-sales:agent.read`, `remote-sales:agent.write`;

    `write` не включает `read`. Один ключ — одно назначение: организации, которая и организатор, и агент, нужны два ключа.


    **Авторизация = скоуп И участие.** Операции `/owner/*` работают только с собственными программами организации

    (чужая программа — 404). Операции `/agent/*` — только внутри `active` партнёрства организации

    (кроме каталога и чтения своих партнёрств). Если организация не участник ресурса, ответ `404 not_found`: существование чужих

    ресурсов не раскрывается.


    **Субъект действия.** Действия совершаются от имени владельца ключа; он обязан иметь право `partners.remote-sales.use`,

    иначе `403 permission_missing`. Ресурсы и действия, созданные через API, помечаются `source: api` (из интерфейса — `ui`).


    **Флаг.** За флагом `remote_sales_api_enabled`: выключен — `503 feature_disabled` (с `Retry-After`).


    **Идемпотентность.** `POST /agent/reservations` и `POST /agent/deals` требуют заголовок `Idempotency-Key` (до 128 символов):

    повтор с тем же ключом в течение 24 часов возвращает первый ответ с `Idempotency-Replayed: true` и не создаёт второй ресурс;

    тот же ключ с другим телом — `409 idempotency_key_reused`. На остальных `POST` заголовок необязателен (создающие — по тем же правилам).

    Переходы состояний (`accept`, `cancel`, `confirm` …) повторять безопасно: недопустимый переход — `409 invalid_state`.


    **Пагинация.** Курсорная: `limit` (1–200, по умолчанию 50) и `cursor` из `next_cursor`; пустой `next_cursor` — последняя страница.

    Порядок — новые сверху, у стока — по `(updated, vehicle_guid)`.


    **Лимиты.** 10 запросов/с (всплеск 50) на ключ; превышение — `429 rate_limited` / `daily_quota_exceeded` с `Retry-After`.

    Тела запросов до 64 КБ.


    **Ошибки** — `application/problem+json` с массивом `errors[]`, где `code` машинный, `message` по-русски.


    **Вебхуки.** Настраиваются на ключе в кабинете (`webhook_url`, секрет), доставка по тем же правилам, что у Import API.

    Тело: `{"id","type","occurred_at","data":{…}}`; заголовки `X-Car2B-Signature: sha256=<hex HMAC-SHA256(secret, сырое тело)>`,

    `X-Car2B-Delivery`, `X-Car2B-Event`. Таймаут 10 с, 2xx = доставлено, иначе повторы через 1, 5, 15, 60 и 300 с (всего 5 попыток).

    Возможны повторные доставки — обработчик идемпотентен по `id`. Ключ получает события тех ролей, чьи скоупы у него есть;

    события адресуются организации-участнику, чужие не приходят. Журнал — `GET /webhooks/deliveries`. Типы событий — раздел `webhooks` ниже.

    '
servers:
- url: https://api.car2b.ru/api/v1/remote-sales
security:
- partnerToken: []
tags:
- name: owner
  description: 'Владелец стока: своя программа, партнёрства, брони и сделки по своим автомобилям'
- name: agent
  description: 'Удалённый ОП: каталог, заявки, сток, брони и сделки'
- name: webhooks
  description: Вебхуки и журнал доставок
paths:
  /owner/programs:
    get:
      tags:
      - owner
      summary: Программы организации
      operationId: ownerListPrograms
      security:
      - partnerToken:
        - remote-sales:owner.read
      description: Неудалённые программы организации-владельца ключа. Сейчас у организации не более одной программы, но клиенты не должны на это
        опираться — список и `program_guid` во всех ручках сделаны под несколько программ.
      parameters:
      - $ref: '#/components/parameters/Cursor'
      - $ref: '#/components/parameters/Limit'
      responses:
        '200':
          description: Программы
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProgramList'
        '400':
          $ref: '#/components/responses/Malformed'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
        '503':
          $ref: '#/components/responses/Unavailable'
  /owner/programs/{program_guid}:
    parameters:
    - $ref: '#/components/parameters/ProgramGUID'
    get:
      tags:
      - owner
      summary: Программа
      operationId: ownerGetProgram
      security:
      - partnerToken:
        - remote-sales:owner.read
      description: Программа организации-владельца ключа. Чужая или удалённая — 404 `not_found`.
      responses:
        '200':
          description: Программа
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Program'
        '400':
          $ref: '#/components/responses/Malformed'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
        '503':
          $ref: '#/components/responses/Unavailable'
    patch:
      tags:
      - owner
      summary: Изменить программу
      operationId: ownerUpdateProgram
      security:
      - partnerToken:
        - remote-sales:owner.write
      description: Частичное обновление (merge-patch) полей карточки. Заблокированную админом программу менять нельзя — 409 `program_blocked`.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ProgramInput'
      responses:
        '200':
          description: Программа
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Program'
        '400':
          $ref: '#/components/responses/Malformed'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/RateLimited'
        '503':
          $ref: '#/components/responses/Unavailable'
  /owner/programs/{program_guid}/publish:
    parameters:
    - $ref: '#/components/parameters/ProgramGUID'
    post:
      tags:
      - owner
      summary: Опубликовать в каталоге
      operationId: ownerPublishProgram
      security:
      - partnerToken:
        - remote-sales:owner.write
      description: Переход draft|unpublished → published. Повтор на опубликованной — 200 без эффекта.
      responses:
        '200':
          description: Программа
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Program'
        '400':
          $ref: '#/components/responses/Malformed'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '429':
          $ref: '#/components/responses/RateLimited'
        '503':
          $ref: '#/components/responses/Unavailable'
  /owner/programs/{program_guid}/unpublish:
    parameters:
    - $ref: '#/components/parameters/ProgramGUID'
    post:
      tags:
      - owner
      summary: Снять с публикации
      operationId: ownerUnpublishProgram
      security:
      - partnerToken:
        - remote-sales:owner.write
      description: Переход published → unpublished. Действующие партнёрства не затрагиваются.
      responses:
        '200':
          description: Программа
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Program'
        '400':
          $ref: '#/components/responses/Malformed'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '429':
          $ref: '#/components/responses/RateLimited'
        '503':
          $ref: '#/components/responses/Unavailable'
  /owner/programs/{program_guid}/levels:
    parameters:
    - $ref: '#/components/parameters/ProgramGUID'
    get:
      tags:
      - owner
      summary: Уровни партнёрства
      operationId: ownerGetLevels
      security:
      - partnerToken:
        - remote-sales:owner.read
      responses:
        '200':
          description: Уровни
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LevelList'
        '400':
          $ref: '#/components/responses/Malformed'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
        '503':
          $ref: '#/components/responses/Unavailable'
    put:
      tags:
      - owner
      summary: Заменить уровни
      operationId: ownerPutLevels
      security:
      - partnerToken:
        - remote-sales:owner.write
      description: Полная замена набора. Уровень накопительный, прошлые сделки не пересчитываются.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - levels
              properties:
                levels:
                  type: array
                  items:
                    $ref: '#/components/schemas/LevelInput'
      responses:
        '200':
          description: Уровни
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LevelList'
        '400':
          $ref: '#/components/responses/Malformed'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/RateLimited'
        '503':
          $ref: '#/components/responses/Unavailable'
  /owner/programs/{program_guid}/stock-settings:
    parameters:
    - $ref: '#/components/parameters/ProgramGUID'
    get:
      tags:
      - owner
      summary: Настройки стока программы
      operationId: ownerGetStockSettings
      security:
      - partnerToken:
        - remote-sales:owner.read
      responses:
        '200':
          description: Настройки
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StockSettings'
        '400':
          $ref: '#/components/responses/Malformed'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
        '503':
          $ref: '#/components/responses/Unavailable'
    put:
      tags:
      - owner
      summary: Задать режим стока
      operationId: ownerPutStockSettings
      security:
      - partnerToken:
        - remote-sales:owner.write
      description: Режим `all|include|exclude`; для `include`/`exclude` — список `vehicle_guids` (объявления своей организации).
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/StockSettings'
      responses:
        '200':
          description: Настройки
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StockSettings'
        '400':
          $ref: '#/components/responses/Malformed'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/RateLimited'
        '503':
          $ref: '#/components/responses/Unavailable'
  /owner/partnerships:
    get:
      tags:
      - owner
      summary: Партнёрства программы
      operationId: ownerListPartnerships
      security:
      - partnerToken:
        - remote-sales:owner.read
      parameters:
      - $ref: '#/components/parameters/ProgramGUIDFilter'
      - &id002
        $ref: '#/components/parameters/Cursor'
      - &id003
        $ref: '#/components/parameters/Limit'
      - &id004
        name: status
        in: query
        schema:
          $ref: '#/components/schemas/PartnershipStatus'
      responses:
        '200':
          description: Страница
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PartnershipList'
        '400':
          $ref: '#/components/responses/Malformed'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
        '503':
          $ref: '#/components/responses/Unavailable'
    post:
      tags:
      - owner
      summary: Пригласить организацию (invite)
      operationId: ownerInvitePartnership
      security:
      - partnerToken:
        - remote-sales:owner.write
      description: Создаёт партнёрство `pending_invite`. Программа должна быть опубликована. Неизвестная или недоступная организация в `remote_org_guid`
        — 422 `unknown_organization`.
      parameters:
      - $ref: '#/components/parameters/IdempotencyKeyOptional'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - program_guid
              - remote_org_guid
              properties:
                program_guid:
                  type: string
                  format: uuid
                remote_org_guid:
                  type: string
                  format: uuid
                message:
                  type: string
                  maxLength: 2000
      responses:
        '201':
          description: Приглашение создано
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Partnership'
        '400':
          $ref: '#/components/responses/Malformed'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/RateLimited'
        '503':
          $ref: '#/components/responses/Unavailable'
  /owner/partnerships/{partnership_guid}:
    get:
      tags:
      - owner
      summary: Партнёрство
      operationId: ownerGetPartnership
      security:
      - partnerToken:
        - remote-sales:owner.read
      parameters:
      - $ref: '#/components/parameters/PartnershipGUID'
      responses:
        '200':
          description: Партнёрство
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Partnership'
        '400':
          $ref: '#/components/responses/Malformed'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
        '503':
          $ref: '#/components/responses/Unavailable'
  /owner/partnerships/{partnership_guid}/accept:
    post:
      tags:
      - owner
      summary: Принять заявку
      operationId: ownerAcceptPartnership
      security:
      - partnerToken:
        - remote-sales:owner.write
      description: '`pending_request` → `active`. Недопустимый переход — 409 `invalid_state`.'
      parameters:
      - $ref: '#/components/parameters/PartnershipGUID'
      responses:
        '200':
          description: Партнёрство
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Partnership'
        '400':
          $ref: '#/components/responses/Malformed'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '429':
          $ref: '#/components/responses/RateLimited'
        '503':
          $ref: '#/components/responses/Unavailable'
  /owner/partnerships/{partnership_guid}/decline:
    post:
      tags:
      - owner
      summary: Отклонить заявку
      operationId: ownerDeclinePartnership
      security:
      - partnerToken:
        - remote-sales:owner.write
      description: '`pending_request` → `declined`. Недопустимый переход — 409 `invalid_state`.'
      parameters:
      - $ref: '#/components/parameters/PartnershipGUID'
      requestBody: &id001
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                reason:
                  type: string
                  maxLength: 2000
      responses:
        '200':
          description: Партнёрство
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Partnership'
        '400':
          $ref: '#/components/responses/Malformed'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '429':
          $ref: '#/components/responses/RateLimited'
        '503':
          $ref: '#/components/responses/Unavailable'
  /owner/partnerships/{partnership_guid}/terminate:
    post:
      tags:
      - owner
      summary: Завершить партнёрство
      operationId: ownerTerminatePartnership
      security:
      - partnerToken:
        - remote-sales:owner.write
      description: '`active` → `terminated_by_owner`. Недопустимый переход — 409 `invalid_state`.'
      parameters:
      - $ref: '#/components/parameters/PartnershipGUID'
      requestBody: *id001
      responses:
        '200':
          description: Партнёрство
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Partnership'
        '400':
          $ref: '#/components/responses/Malformed'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '429':
          $ref: '#/components/responses/RateLimited'
        '503':
          $ref: '#/components/responses/Unavailable'
  /owner/reservations:
    get:
      tags:
      - owner
      summary: Брони на мои автомобили
      operationId: ownerListReservations
      security:
      - partnerToken:
        - remote-sales:owner.read
      parameters:
      - $ref: '#/components/parameters/ProgramGUIDFilter'
      - &id005
        $ref: '#/components/parameters/Cursor'
      - &id006
        $ref: '#/components/parameters/Limit'
      - &id007
        name: status
        in: query
        schema:
          $ref: '#/components/schemas/ReservationStatus'
      - &id008
        name: partnership_guid
        in: query
        schema:
          type: string
          format: uuid
      responses:
        '200':
          description: Страница
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReservationList'
        '400':
          $ref: '#/components/responses/Malformed'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
        '503':
          $ref: '#/components/responses/Unavailable'
  /owner/reservations/{reservation_guid}:
    get:
      tags:
      - owner
      summary: Бронь
      operationId: ownerGetReservation
      security:
      - partnerToken:
        - remote-sales:owner.read
      parameters:
      - $ref: '#/components/parameters/ReservationGUID'
      responses:
        '200':
          description: Бронь
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Reservation'
        '400':
          $ref: '#/components/responses/Malformed'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
        '503':
          $ref: '#/components/responses/Unavailable'
  /owner/reservations/{reservation_guid}/cancel:
    post:
      tags:
      - owner
      summary: Снять бронь (продавец)
      operationId: ownerCancelReservation
      security:
      - partnerToken:
        - remote-sales:owner.write
      description: Статус `cancelled_by_seller`. Причина по желанию.
      parameters:
      - $ref: '#/components/parameters/ReservationGUID'
      requestBody: *id001
      responses:
        '200':
          description: Бронь
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Reservation'
        '400':
          $ref: '#/components/responses/Malformed'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '429':
          $ref: '#/components/responses/RateLimited'
        '503':
          $ref: '#/components/responses/Unavailable'
  /owner/deals:
    get:
      tags:
      - owner
      summary: Сделки по моим автомобилям
      operationId: ownerListDeals
      security:
      - partnerToken:
        - remote-sales:owner.read
      parameters:
      - $ref: '#/components/parameters/ProgramGUIDFilter'
      - &id009
        $ref: '#/components/parameters/Cursor'
      - &id010
        $ref: '#/components/parameters/Limit'
      - &id011
        name: status
        in: query
        schema:
          $ref: '#/components/schemas/DealStatus'
      - &id012
        name: partnership_guid
        in: query
        schema:
          type: string
          format: uuid
      responses:
        '200':
          description: Страница
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DealList'
        '400':
          $ref: '#/components/responses/Malformed'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
        '503':
          $ref: '#/components/responses/Unavailable'
  /owner/deals/{deal_guid}:
    get:
      tags:
      - owner
      summary: Сделка
      operationId: ownerGetDeal
      security:
      - partnerToken:
        - remote-sales:owner.read
      parameters:
      - $ref: '#/components/parameters/DealGUID'
      responses:
        '200':
          description: Сделка
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Deal'
        '400':
          $ref: '#/components/responses/Malformed'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
        '503':
          $ref: '#/components/responses/Unavailable'
  /owner/deals/{deal_guid}/confirm:
    post:
      tags:
      - owner
      summary: Подтвердить сделку (продавец)
      operationId: ownerConfirmDeal
      security:
      - partnerToken:
        - remote-sales:owner.write
      description: Когда подтвердили обе стороны, сделка `completed`, автомобиль уходит в «Продан».
      parameters:
      - $ref: '#/components/parameters/DealGUID'
      responses:
        '200':
          description: Сделка
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Deal'
        '400':
          $ref: '#/components/responses/Malformed'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '429':
          $ref: '#/components/responses/RateLimited'
        '503':
          $ref: '#/components/responses/Unavailable'
  /owner/deals/{deal_guid}/cancel:
    post:
      tags:
      - owner
      summary: Отменить сделку до завершения
      operationId: ownerCancelDeal
      security:
      - partnerToken:
        - remote-sales:owner.write
      parameters:
      - $ref: '#/components/parameters/DealGUID'
      requestBody: *id001
      responses:
        '200':
          description: Сделка
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Deal'
        '400':
          $ref: '#/components/responses/Malformed'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '429':
          $ref: '#/components/responses/RateLimited'
        '503':
          $ref: '#/components/responses/Unavailable'
  /owner/deals/{deal_guid}/dispute:
    post:
      tags:
      - owner
      summary: Заявить расхождение
      operationId: ownerDisputeDeal
      security:
      - partnerToken:
        - remote-sales:owner.write
      description: Статус `disputed`; разбор идёт вне API (поддержка Car2B).
      parameters:
      - $ref: '#/components/parameters/DealGUID'
      requestBody: &id013
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DisputeInput'
      responses:
        '200':
          description: Сделка
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Deal'
        '400':
          $ref: '#/components/responses/Malformed'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/RateLimited'
        '503':
          $ref: '#/components/responses/Unavailable'
  /agent/catalog/programs:
    get:
      tags:
      - agent
      summary: Каталог опубликованных программ
      operationId: agentListCatalog
      security:
      - partnerToken:
        - remote-sales:agent.read
      description: Показываются только `published`. Программа с географическим запретом для города организации в выдаче остаётся, ограничение
        срабатывает при подаче заявки.
      parameters:
      - $ref: '#/components/parameters/Cursor'
      - $ref: '#/components/parameters/Limit'
      - name: q
        in: query
        schema:
          type: string
        description: Поиск по названию компании
      - name: city
        in: query
        schema:
          type: string
      - name: region
        in: query
        schema:
          type: string
        description: Код региона
      - name: brand
        in: query
        schema:
          type: string
        description: Марка в доступном стоке
      - name: min_vehicles
        in: query
        schema:
          type: integer
          minimum: 0
      - name: reservation_enabled
        in: query
        schema:
          type: boolean
      - name: external_advertising_allowed
        in: query
        schema:
          type: boolean
      - name: capability
        in: query
        style: form
        explode: true
        schema:
          type: array
          items:
            type: string
        description: Возможность из чек-листа (повторяется)
      - name: order_by
        in: query
        schema:
          type: string
          enum:
          - created
          - vehicles_count
          - remote_ops_count
          default: created
      responses:
        '200':
          description: Страница каталога
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CatalogList'
        '400':
          $ref: '#/components/responses/Malformed'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
        '503':
          $ref: '#/components/responses/Unavailable'
  /agent/catalog/programs/{program_guid}:
    get:
      tags:
      - agent
      summary: Карточка программы
      operationId: agentGetCatalogProgram
      security:
      - partnerToken:
        - remote-sales:agent.read
      description: Включает `my_partnership` — отношения вызывающей организации с программой.
      parameters:
      - $ref: '#/components/parameters/ProgramGUID'
      responses:
        '200':
          description: Карточка
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CatalogProgramCard'
        '400':
          $ref: '#/components/responses/Malformed'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
        '503':
          $ref: '#/components/responses/Unavailable'
  /agent/partnerships:
    post:
      tags:
      - agent
      summary: Подать заявку на программу
      operationId: agentRequestPartnership
      security:
      - partnerToken:
        - remote-sales:agent.write
      description: 'Создаёт партнёрство `pending_request`. 409: `already_exists` (живое партнёрство уже есть), `geography_restricted`, `self_partnership`,
        `program_blocked`.'
      parameters:
      - $ref: '#/components/parameters/IdempotencyKeyOptional'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - program_guid
              properties:
                program_guid:
                  type: string
                  format: uuid
                message:
                  type: string
                  maxLength: 2000
      responses:
        '201':
          description: Заявка создана
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Partnership'
        '400':
          $ref: '#/components/responses/Malformed'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '429':
          $ref: '#/components/responses/RateLimited'
        '503':
          $ref: '#/components/responses/Unavailable'
    get:
      tags:
      - agent
      summary: Мои партнёрства
      operationId: agentListPartnerships
      security:
      - partnerToken:
        - remote-sales:agent.read
      parameters:
      - *id002
      - *id003
      - *id004
      responses:
        '200':
          description: Страница
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PartnershipList'
        '400':
          $ref: '#/components/responses/Malformed'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
        '503':
          $ref: '#/components/responses/Unavailable'
  /agent/partnerships/{partnership_guid}:
    get:
      tags:
      - agent
      summary: Партнёрство
      operationId: agentGetPartnership
      security:
      - partnerToken:
        - remote-sales:agent.read
      parameters:
      - $ref: '#/components/parameters/PartnershipGUID'
      responses:
        '200':
          description: Партнёрство
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Partnership'
        '400':
          $ref: '#/components/responses/Malformed'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
        '503':
          $ref: '#/components/responses/Unavailable'
  /agent/partnerships/{partnership_guid}/terminate:
    post:
      tags:
      - agent
      summary: Завершить партнёрство
      operationId: agentTerminatePartnership
      security:
      - partnerToken:
        - remote-sales:agent.write
      description: '`active` → `terminated_by_remote`.'
      parameters:
      - $ref: '#/components/parameters/PartnershipGUID'
      requestBody: *id001
      responses:
        '200':
          description: Партнёрство
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Partnership'
        '400':
          $ref: '#/components/responses/Malformed'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '429':
          $ref: '#/components/responses/RateLimited'
        '503':
          $ref: '#/components/responses/Unavailable'
  /agent/partnerships/{partnership_guid}/stock:
    get:
      tags:
      - agent
      summary: Доступный сток партнёрства
      operationId: agentListStock
      security:
      - partnerToken:
        - remote-sales:agent.read
      description: 'Автомобили владельца в рамках режима стока программы. Розничную цену задаёт владелец. Только для `active` партнёрства (иначе 409
        `partnership_not_active`).


        **Порядок.** Полный обход (без `updated_since`) — по `(updated, vehicle_guid)`. Инкрементальный (с `updated_since`) — по позиции журнала
        изменений стока партнёрства: порядок монотонен, и записи с одинаковой меткой времени не теряются; по каждому автомобилю отдаётся последняя
        запись журнала за период, поэтому `updated` в инкрементальной выдаче не обязан возрастать.


        **Инкрементальная синхронизация.** Первый обход — без `updated_since`, затем сохраните `sync_token` последней страницы и передавайте его
        как `updated_since` в следующем обходе. В ответе с `updated_since` есть и снятые позиции — надгробия (`removed: true`, остальные поля
        отсутствуют) с причиной `removed_reason`: `unavailable` — автомобиль продан, удалён или снят с публикации; `excluded` — организатор
        исключил его из стока программы. Источник — журнал изменений стока партнёрства. Изменения, случившиеся во время обхода, попадут в следующий
        инкремент (позиция может повториться — обработка должна быть идемпотентной). Фильтры `brand` и `model` ограничивают только живые позиции:
        надгробия они не отсекают (после снятия автомобиль уже не сопоставить с маркой и моделью), поэтому инкремент с фильтром может содержать
        надгробия автомобилей, которых вы не видели. Надгробия хранятся 30 дней; при более старом токене — 410 `sync_token_expired`, нужен полный
        обход. `cursor` и `sync_token` привязаны к партнёрству и непрозрачны.'
      parameters:
      - $ref: '#/components/parameters/Cursor'
      - $ref: '#/components/parameters/Limit'
      - name: updated_since
        in: query
        schema:
          type: string
        description: Значение `sync_token` предыдущего обхода
      - name: brand
        in: query
        schema:
          type: string
      - name: model
        in: query
        schema:
          type: string
      - $ref: '#/components/parameters/PartnershipGUID'
      responses:
        '200':
          description: Страница стока
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StockList'
        '400':
          $ref: '#/components/responses/Malformed'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '429':
          $ref: '#/components/responses/RateLimited'
        '503':
          $ref: '#/components/responses/Unavailable'
        '410':
          $ref: '#/components/responses/Gone'
  /agent/reservations:
    post:
      tags:
      - agent
      summary: Забронировать автомобиль на 2 часа
      operationId: agentCreateReservation
      security:
      - partnerToken:
        - remote-sales:agent.write
      description: 'Бесплатно, максимум 2 часа. Правила: у программы включены брони и партнёру не отключены; не более одной активной брони у организации
        на платформе; не более одной брони в сутки на владельца; автомобиль доступен. Нарушение — 409 с кодом: `reservation_disabled`, `reservations_blocked`,
        `reservation_active_limit`, `reservation_daily_limit`, `vehicle_unavailable`, `partnership_not_active`. **`Idempotency-Key` обязателен.**'
      parameters:
      - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - partnership_guid
              - vehicle_guid
              properties:
                partnership_guid:
                  type: string
                  format: uuid
                vehicle_guid:
                  type: string
                  format: uuid
      responses:
        '201':
          description: Активная бронь
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Reservation'
        '400':
          $ref: '#/components/responses/Malformed'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '429':
          $ref: '#/components/responses/RateLimited'
        '503':
          $ref: '#/components/responses/Unavailable'
    get:
      tags:
      - agent
      summary: Мои брони
      operationId: agentListReservations
      security:
      - partnerToken:
        - remote-sales:agent.read
      parameters:
      - *id005
      - *id006
      - *id007
      - *id008
      responses:
        '200':
          description: Страница
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReservationList'
        '400':
          $ref: '#/components/responses/Malformed'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
        '503':
          $ref: '#/components/responses/Unavailable'
  /agent/reservations/{reservation_guid}:
    get:
      tags:
      - agent
      summary: Бронь
      operationId: agentGetReservation
      security:
      - partnerToken:
        - remote-sales:agent.read
      parameters:
      - $ref: '#/components/parameters/ReservationGUID'
      responses:
        '200':
          description: Бронь
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Reservation'
        '400':
          $ref: '#/components/responses/Malformed'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
        '503':
          $ref: '#/components/responses/Unavailable'
  /agent/reservations/{reservation_guid}/cancel:
    post:
      tags:
      - agent
      summary: Снять бронь (покупатель)
      operationId: agentCancelReservation
      security:
      - partnerToken:
        - remote-sales:agent.write
      description: Статус `cancelled_by_buyer`.
      parameters:
      - $ref: '#/components/parameters/ReservationGUID'
      requestBody: *id001
      responses:
        '200':
          description: Бронь
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Reservation'
        '400':
          $ref: '#/components/responses/Malformed'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '429':
          $ref: '#/components/responses/RateLimited'
        '503':
          $ref: '#/components/responses/Unavailable'
  /agent/deals:
    post:
      tags:
      - agent
      summary: Зафиксировать покупку
      operationId: agentCreateDeal
      security:
      - partnerToken:
        - remote-sales:agent.write
      description: Инициатор считается подтвердившим; сделка завершается после подтверждения продавцом. `reservation_guid` связывает сделку с
        бронью (бронь → `converted_to_deal`). **`Idempotency-Key` обязателен.**
      parameters:
      - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DealInput'
      responses:
        '201':
          description: Сделка создана
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Deal'
        '400':
          $ref: '#/components/responses/Malformed'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/RateLimited'
        '503':
          $ref: '#/components/responses/Unavailable'
    get:
      tags:
      - agent
      summary: Мои сделки
      operationId: agentListDeals
      security:
      - partnerToken:
        - remote-sales:agent.read
      parameters:
      - *id009
      - *id010
      - *id011
      - *id012
      responses:
        '200':
          description: Страница
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DealList'
        '400':
          $ref: '#/components/responses/Malformed'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
        '503':
          $ref: '#/components/responses/Unavailable'
  /agent/deals/{deal_guid}:
    get:
      tags:
      - agent
      summary: Сделка
      operationId: agentGetDeal
      security:
      - partnerToken:
        - remote-sales:agent.read
      parameters:
      - $ref: '#/components/parameters/DealGUID'
      responses:
        '200':
          description: Сделка
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Deal'
        '400':
          $ref: '#/components/responses/Malformed'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
        '503':
          $ref: '#/components/responses/Unavailable'
  /agent/deals/{deal_guid}/confirm:
    post:
      tags:
      - agent
      summary: Подтвердить сделку (покупатель)
      operationId: agentConfirmDeal
      security:
      - partnerToken:
        - remote-sales:agent.write
      parameters:
      - $ref: '#/components/parameters/DealGUID'
      responses:
        '200':
          description: Сделка
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Deal'
        '400':
          $ref: '#/components/responses/Malformed'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '429':
          $ref: '#/components/responses/RateLimited'
        '503':
          $ref: '#/components/responses/Unavailable'
  /agent/deals/{deal_guid}/cancel:
    post:
      tags:
      - agent
      summary: Отменить сделку до завершения
      operationId: agentCancelDeal
      security:
      - partnerToken:
        - remote-sales:agent.write
      parameters:
      - $ref: '#/components/parameters/DealGUID'
      requestBody: *id001
      responses:
        '200':
          description: Сделка
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Deal'
        '400':
          $ref: '#/components/responses/Malformed'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '429':
          $ref: '#/components/responses/RateLimited'
        '503':
          $ref: '#/components/responses/Unavailable'
  /agent/deals/{deal_guid}/dispute:
    post:
      tags:
      - agent
      summary: Заявить расхождение
      operationId: agentDisputeDeal
      security:
      - partnerToken:
        - remote-sales:agent.write
      parameters:
      - $ref: '#/components/parameters/DealGUID'
      requestBody: *id013
      responses:
        '200':
          description: Сделка
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Deal'
        '400':
          $ref: '#/components/responses/Malformed'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/RateLimited'
        '503':
          $ref: '#/components/responses/Unavailable'
  /webhooks/deliveries:
    get:
      tags:
      - webhooks
      summary: Журнал доставок вебхуков
      operationId: listWebhookDeliveries
      security:
      - partnerToken:
        - remote-sales:owner.read
      - partnerToken:
        - remote-sales:agent.read
      description: Вебхуки настраиваются на ключе в кабинете (`webhook_url`, секрет). Журнал по своему `client_id`, новые сверху. Подпись и ретраи
        — см. раздел «Вебхуки» в описании API. Достаточно любого из двух read-скоупов.
      parameters:
      - $ref: '#/components/parameters/Cursor'
      - $ref: '#/components/parameters/Limit'
      responses:
        '200':
          description: Страница журнала
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DeliveryList'
        '400':
          $ref: '#/components/responses/Malformed'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
        '503':
          $ref: '#/components/responses/Unavailable'
webhooks:
  partnership.requested:
    post:
      tags:
      - webhooks
      summary: Заявка удалённого ОП
      operationId: webhook_partnership_requested
      description: Адресат — организация-владелец программы.
      parameters:
      - name: X-Car2B-Signature
        in: header
        required: true
        schema:
          type: string
        description: '`sha256=<hex HMAC-SHA256(webhook_secret, сырое тело)>`'
      - name: X-Car2B-Delivery
        in: header
        required: true
        schema:
          type: string
          format: uuid
      - name: X-Car2B-Event
        in: header
        required: true
        schema:
          type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
              - $ref: '#/components/schemas/WebhookEnvelope'
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                    - partnership.requested
                  data:
                    $ref: '#/components/schemas/PartnershipEvent'
      responses:
        2XX:
          description: Доставлено. Любой другой ответ или таймаут 10 с — повтор
  partnership.invited:
    post:
      tags:
      - webhooks
      summary: Приглашение владельца
      operationId: webhook_partnership_invited
      description: Адресат — организация удалённого ОП.
      parameters:
      - name: X-Car2B-Signature
        in: header
        required: true
        schema:
          type: string
        description: '`sha256=<hex HMAC-SHA256(webhook_secret, сырое тело)>`'
      - name: X-Car2B-Delivery
        in: header
        required: true
        schema:
          type: string
          format: uuid
      - name: X-Car2B-Event
        in: header
        required: true
        schema:
          type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
              - $ref: '#/components/schemas/WebhookEnvelope'
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                    - partnership.invited
                  data:
                    $ref: '#/components/schemas/PartnershipEvent'
      responses:
        2XX:
          description: Доставлено. Любой другой ответ или таймаут 10 с — повтор
  partnership.accepted:
    post:
      tags:
      - webhooks
      summary: Партнёрство активировано
      operationId: webhook_partnership_accepted
      description: Заявка принята владельцем либо приглашение принято ОП. Адресат — обе стороны партнёрства (каждая получает через свой ключ).
        (в домене событие `partners.partnership.activated`).
      parameters:
      - name: X-Car2B-Signature
        in: header
        required: true
        schema:
          type: string
        description: '`sha256=<hex HMAC-SHA256(webhook_secret, сырое тело)>`'
      - name: X-Car2B-Delivery
        in: header
        required: true
        schema:
          type: string
          format: uuid
      - name: X-Car2B-Event
        in: header
        required: true
        schema:
          type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
              - $ref: '#/components/schemas/WebhookEnvelope'
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                    - partnership.accepted
                  data:
                    $ref: '#/components/schemas/PartnershipEvent'
      responses:
        2XX:
          description: Доставлено. Любой другой ответ или таймаут 10 с — повтор
  partnership.declined:
    post:
      tags:
      - webhooks
      summary: Заявка или приглашение отклонены
      operationId: webhook_partnership_declined
      description: 'Адресат — инициатор. При удалении программы владельцем приходит с `program_deleted: true`.'
      parameters:
      - name: X-Car2B-Signature
        in: header
        required: true
        schema:
          type: string
        description: '`sha256=<hex HMAC-SHA256(webhook_secret, сырое тело)>`'
      - name: X-Car2B-Delivery
        in: header
        required: true
        schema:
          type: string
          format: uuid
      - name: X-Car2B-Event
        in: header
        required: true
        schema:
          type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
              - $ref: '#/components/schemas/WebhookEnvelope'
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                    - partnership.declined
                  data:
                    $ref: '#/components/schemas/PartnershipEvent'
      responses:
        2XX:
          description: Доставлено. Любой другой ответ или таймаут 10 с — повтор
  partnership.terminated:
    post:
      tags:
      - webhooks
      summary: Партнёрство завершено
      operationId: webhook_partnership_terminated
      description: Адресат — обе стороны партнёрства (каждая получает через свой ключ). Инициатору — как подтверждение.
      parameters:
      - name: X-Car2B-Signature
        in: header
        required: true
        schema:
          type: string
        description: '`sha256=<hex HMAC-SHA256(webhook_secret, сырое тело)>`'
      - name: X-Car2B-Delivery
        in: header
        required: true
        schema:
          type: string
          format: uuid
      - name: X-Car2B-Event
        in: header
        required: true
        schema:
          type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
              - $ref: '#/components/schemas/WebhookEnvelope'
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                    - partnership.terminated
                  data:
                    $ref: '#/components/schemas/PartnershipEvent'
      responses:
        2XX:
          description: Доставлено. Любой другой ответ или таймаут 10 с — повтор
  reservation.created:
    post:
      tags:
      - webhooks
      summary: Бронь создана
      operationId: webhook_reservation_created
      description: Адресат — организация-владелец программы. Агент получает событие о брони, созданной не через его ключ (например из интерфейса).
      parameters:
      - name: X-Car2B-Signature
        in: header
        required: true
        schema:
          type: string
        description: '`sha256=<hex HMAC-SHA256(webhook_secret, сырое тело)>`'
      - name: X-Car2B-Delivery
        in: header
        required: true
        schema:
          type: string
          format: uuid
      - name: X-Car2B-Event
        in: header
        required: true
        schema:
          type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
              - $ref: '#/components/schemas/WebhookEnvelope'
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                    - reservation.created
                  data:
                    $ref: '#/components/schemas/ReservationEvent'
      responses:
        2XX:
          description: Доставлено. Любой другой ответ или таймаут 10 с — повтор
  reservation.cancelled:
    post:
      tags:
      - webhooks
      summary: Бронь снята
      operationId: webhook_reservation_cancelled
      description: Адресат — обе стороны партнёрства (каждая получает через свой ключ).
      parameters:
      - name: X-Car2B-Signature
        in: header
        required: true
        schema:
          type: string
        description: '`sha256=<hex HMAC-SHA256(webhook_secret, сырое тело)>`'
      - name: X-Car2B-Delivery
        in: header
        required: true
        schema:
          type: string
          format: uuid
      - name: X-Car2B-Event
        in: header
        required: true
        schema:
          type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
              - $ref: '#/components/schemas/WebhookEnvelope'
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                    - reservation.cancelled
                  data:
                    $ref: '#/components/schemas/ReservationEvent'
      responses:
        2XX:
          description: Доставлено. Любой другой ответ или таймаут 10 с — повтор
  reservation.expiring_soon:
    post:
      tags:
      - webhooks
      summary: Бронь истекает через 15 минут
      operationId: webhook_reservation_expiring_soon
      description: Однократно. Адресат — обе стороны партнёрства (каждая получает через свой ключ).
      parameters:
      - name: X-Car2B-Signature
        in: header
        required: true
        schema:
          type: string
        description: '`sha256=<hex HMAC-SHA256(webhook_secret, сырое тело)>`'
      - name: X-Car2B-Delivery
        in: header
        required: true
        schema:
          type: string
          format: uuid
      - name: X-Car2B-Event
        in: header
        required: true
        schema:
          type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
              - $ref: '#/components/schemas/WebhookEnvelope'
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                    - reservation.expiring_soon
                  data:
                    $ref: '#/components/schemas/ReservationEvent'
      responses:
        2XX:
          description: Доставлено. Любой другой ответ или таймаут 10 с — повтор
  reservation.expired:
    post:
      tags:
      - webhooks
      summary: Бронь истекла
      operationId: webhook_reservation_expired
      description: Адресат — обе стороны партнёрства (каждая получает через свой ключ).
      parameters:
      - name: X-Car2B-Signature
        in: header
        required: true
        schema:
          type: string
        description: '`sha256=<hex HMAC-SHA256(webhook_secret, сырое тело)>`'
      - name: X-Car2B-Delivery
        in: header
        required: true
        schema:
          type: string
          format: uuid
      - name: X-Car2B-Event
        in: header
        required: true
        schema:
          type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
              - $ref: '#/components/schemas/WebhookEnvelope'
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                    - reservation.expired
                  data:
                    $ref: '#/components/schemas/ReservationEvent'
      responses:
        2XX:
          description: Доставлено. Любой другой ответ или таймаут 10 с — повтор
  deal.created:
    post:
      tags:
      - webhooks
      summary: Сделка создана
      operationId: webhook_deal_created
      description: Адресат — вторая сторона (не инициатор).
      parameters:
      - name: X-Car2B-Signature
        in: header
        required: true
        schema:
          type: string
        description: '`sha256=<hex HMAC-SHA256(webhook_secret, сырое тело)>`'
      - name: X-Car2B-Delivery
        in: header
        required: true
        schema:
          type: string
          format: uuid
      - name: X-Car2B-Event
        in: header
        required: true
        schema:
          type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
              - $ref: '#/components/schemas/WebhookEnvelope'
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                    - deal.created
                  data:
                    $ref: '#/components/schemas/DealEvent'
      responses:
        2XX:
          description: Доставлено. Любой другой ответ или таймаут 10 с — повтор
  deal.confirmed:
    post:
      tags:
      - webhooks
      summary: Сделку подтвердила одна сторона
      operationId: webhook_deal_confirmed
      description: Адресат — вторая сторона.
      parameters:
      - name: X-Car2B-Signature
        in: header
        required: true
        schema:
          type: string
        description: '`sha256=<hex HMAC-SHA256(webhook_secret, сырое тело)>`'
      - name: X-Car2B-Delivery
        in: header
        required: true
        schema:
          type: string
          format: uuid
      - name: X-Car2B-Event
        in: header
        required: true
        schema:
          type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
              - $ref: '#/components/schemas/WebhookEnvelope'
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                    - deal.confirmed
                  data:
                    $ref: '#/components/schemas/DealEvent'
      responses:
        2XX:
          description: Доставлено. Любой другой ответ или таймаут 10 с — повтор
  deal.completed:
    post:
      tags:
      - webhooks
      summary: Сделка завершена
      operationId: webhook_deal_completed
      description: Адресат — обе стороны партнёрства (каждая получает через свой ключ).
      parameters:
      - name: X-Car2B-Signature
        in: header
        required: true
        schema:
          type: string
        description: '`sha256=<hex HMAC-SHA256(webhook_secret, сырое тело)>`'
      - name: X-Car2B-Delivery
        in: header
        required: true
        schema:
          type: string
          format: uuid
      - name: X-Car2B-Event
        in: header
        required: true
        schema:
          type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
              - $ref: '#/components/schemas/WebhookEnvelope'
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                    - deal.completed
                  data:
                    $ref: '#/components/schemas/DealEvent'
      responses:
        2XX:
          description: Доставлено. Любой другой ответ или таймаут 10 с — повтор
  deal.cancelled:
    post:
      tags:
      - webhooks
      summary: Сделка отменена
      operationId: webhook_deal_cancelled
      description: Адресат — обе стороны партнёрства (каждая получает через свой ключ).
      parameters:
      - name: X-Car2B-Signature
        in: header
        required: true
        schema:
          type: string
        description: '`sha256=<hex HMAC-SHA256(webhook_secret, сырое тело)>`'
      - name: X-Car2B-Delivery
        in: header
        required: true
        schema:
          type: string
          format: uuid
      - name: X-Car2B-Event
        in: header
        required: true
        schema:
          type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
              - $ref: '#/components/schemas/WebhookEnvelope'
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                    - deal.cancelled
                  data:
                    $ref: '#/components/schemas/DealEvent'
      responses:
        2XX:
          description: Доставлено. Любой другой ответ или таймаут 10 с — повтор
  deal.disputed:
    post:
      tags:
      - webhooks
      summary: Расхождение по сделке
      operationId: webhook_deal_disputed
      description: Адресат — обе стороны партнёрства (каждая получает через свой ключ).
      parameters:
      - name: X-Car2B-Signature
        in: header
        required: true
        schema:
          type: string
        description: '`sha256=<hex HMAC-SHA256(webhook_secret, сырое тело)>`'
      - name: X-Car2B-Delivery
        in: header
        required: true
        schema:
          type: string
          format: uuid
      - name: X-Car2B-Event
        in: header
        required: true
        schema:
          type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
              - $ref: '#/components/schemas/WebhookEnvelope'
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                    - deal.disputed
                  data:
                    $ref: '#/components/schemas/DealEvent'
      responses:
        2XX:
          description: Доставлено. Любой другой ответ или таймаут 10 с — повтор
  level.changed:
    post:
      tags:
      - webhooks
      summary: Достигнут новый уровень
      operationId: webhook_level_changed
      description: Адресат — удалённый ОП (и владелец).
      parameters:
      - name: X-Car2B-Signature
        in: header
        required: true
        schema:
          type: string
        description: '`sha256=<hex HMAC-SHA256(webhook_secret, сырое тело)>`'
      - name: X-Car2B-Delivery
        in: header
        required: true
        schema:
          type: string
          format: uuid
      - name: X-Car2B-Event
        in: header
        required: true
        schema:
          type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
              - $ref: '#/components/schemas/WebhookEnvelope'
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                    - level.changed
                  data:
                    $ref: '#/components/schemas/LevelEvent'
      responses:
        2XX:
          description: Доставлено. Любой другой ответ или таймаут 10 с — повтор
  stock.vehicle_added:
    post:
      tags:
      - webhooks
      summary: Автомобиль появился в доступном стоке
      operationId: webhook_stock_vehicle_added
      description: Адресат — удалённый ОП. Для сверки используйте `GET .../stock?updated_since=`; вебхук — ускоритель.
      parameters:
      - name: X-Car2B-Signature
        in: header
        required: true
        schema:
          type: string
        description: '`sha256=<hex HMAC-SHA256(webhook_secret, сырое тело)>`'
      - name: X-Car2B-Delivery
        in: header
        required: true
        schema:
          type: string
          format: uuid
      - name: X-Car2B-Event
        in: header
        required: true
        schema:
          type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
              - $ref: '#/components/schemas/WebhookEnvelope'
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                    - stock.vehicle_added
                  data:
                    $ref: '#/components/schemas/StockEvent'
      responses:
        2XX:
          description: Доставлено. Любой другой ответ или таймаут 10 с — повтор
  stock.price_changed:
    post:
      tags:
      - webhooks
      summary: Цена автомобиля изменилась
      operationId: webhook_stock_price_changed
      description: Адресат — удалённый ОП.
      parameters:
      - name: X-Car2B-Signature
        in: header
        required: true
        schema:
          type: string
        description: '`sha256=<hex HMAC-SHA256(webhook_secret, сырое тело)>`'
      - name: X-Car2B-Delivery
        in: header
        required: true
        schema:
          type: string
          format: uuid
      - name: X-Car2B-Event
        in: header
        required: true
        schema:
          type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
              - $ref: '#/components/schemas/WebhookEnvelope'
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                    - stock.price_changed
                  data:
                    $ref: '#/components/schemas/StockEvent'
      responses:
        2XX:
          description: Доставлено. Любой другой ответ или таймаут 10 с — повтор
  stock.vehicle_sold:
    post:
      tags:
      - webhooks
      summary: Автомобиль продан
      operationId: webhook_stock_vehicle_sold
      description: Адресат — удалённый ОП.
      parameters:
      - name: X-Car2B-Signature
        in: header
        required: true
        schema:
          type: string
        description: '`sha256=<hex HMAC-SHA256(webhook_secret, сырое тело)>`'
      - name: X-Car2B-Delivery
        in: header
        required: true
        schema:
          type: string
          format: uuid
      - name: X-Car2B-Event
        in: header
        required: true
        schema:
          type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
              - $ref: '#/components/schemas/WebhookEnvelope'
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                    - stock.vehicle_sold
                  data:
                    $ref: '#/components/schemas/StockEvent'
      responses:
        2XX:
          description: Доставлено. Любой другой ответ или таймаут 10 с — повтор
  stock.vehicle_unavailable:
    post:
      tags:
      - webhooks
      summary: Автомобиль снят, в архиве или удалён
      operationId: webhook_stock_vehicle_unavailable
      description: Адресат — удалённый ОП.
      parameters:
      - name: X-Car2B-Signature
        in: header
        required: true
        schema:
          type: string
        description: '`sha256=<hex HMAC-SHA256(webhook_secret, сырое тело)>`'
      - name: X-Car2B-Delivery
        in: header
        required: true
        schema:
          type: string
          format: uuid
      - name: X-Car2B-Event
        in: header
        required: true
        schema:
          type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
              - $ref: '#/components/schemas/WebhookEnvelope'
              - type: object
                properties:
                  type:
                    type: string
                    enum:
                    - stock.vehicle_unavailable
                  data:
                    $ref: '#/components/schemas/StockEvent'
      responses:
        2XX:
          description: Доставлено. Любой другой ответ или таймаут 10 с — повтор
components:
  securitySchemes:
    partnerToken:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: 'Токен из `POST /api/v1/identity/oauth/token` (client_credentials). Скоупы: `remote-sales:owner.read`, `remote-sales:owner.write`,
        `remote-sales:agent.read`, `remote-sales:agent.write`; `*.write` не включает `*.read`.'
  parameters:
    Cursor:
      name: cursor
      in: query
      schema:
        type: string
      description: Значение `next_cursor` предыдущей страницы
    Limit:
      name: limit
      in: query
      schema:
        type: integer
        minimum: 1
        maximum: 200
        default: 50
    IdempotencyKey:
      name: Idempotency-Key
      in: header
      required: true
      schema:
        type: string
        maxLength: 128
      description: 'Повтор с тем же ключом и телом в течение 24 часов возвращает первый ответ с заголовком `Idempotency-Replayed: true` и не создаёт
        второй ресурс. Тот же ключ с другим телом — 409 `idempotency_key_reused`'
    IdempotencyKeyOptional:
      name: Idempotency-Key
      in: header
      required: false
      schema:
        type: string
        maxLength: 128
      description: 'Повтор с тем же ключом и телом в течение 24 часов возвращает первый ответ с заголовком `Idempotency-Replayed: true` и не создаёт
        второй ресурс. Тот же ключ с другим телом — 409 `idempotency_key_reused`'
    ProgramGUIDFilter:
      name: program_guid
      in: query
      required: false
      schema:
        type: string
        format: uuid
      description: Только по указанной программе организации
    ProgramGUID:
      name: program_guid
      in: path
      required: true
      schema: &id014
        type: string
        format: uuid
    PartnershipGUID:
      name: partnership_guid
      in: path
      required: true
      schema: *id014
    ReservationGUID:
      name: reservation_guid
      in: path
      required: true
      schema: *id014
    DealGUID:
      name: deal_guid
      in: path
      required: true
      schema: *id014
  responses:
    Malformed:
      description: '`malformed` — невалидный JSON, неизвестное поле, неверный тип; `invalid_value` — параметр; `idempotency_key_required` — не
        передан `Idempotency-Key` там, где он обязателен'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
    Unauthorized:
      description: '`token_invalid` | `token_expired` — получите новый токен через /oauth/token; `client_revoked` — ключ отозван или неизвестен'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
    Forbidden:
      description: '`scope_missing` (нет нужного `remote-sales:*` скоупа) | `permission_missing` (владелец ключа не имеет права `partners.remote-sales.use`)
        | `organization_unverified` | `organization_blocked` | `subscription_required` (у организации-продавца нет активной подписки при включённом платном режиме) | `ip_not_allowed`'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
    NotFound:
      description: '`not_found` — ресурса нет, либо организация не участник (чужая программа, партнёрство, бронь или сделка неотличимы от несуществующих;
        агентские операции работают только внутри `active` партнёрства своей организации, исключение — собственные партнёрства `pending_*`/`declined`/`terminated_*`
        в чтении)'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
    Conflict:
      description: 'Нарушено бизнес-правило. Коды: `invalid_state`, `already_exists`, `program_blocked`, `geography_restricted`, `self_partnership`,
        `partnership_not_active`, `reservation_disabled`, `reservations_blocked`, `reservation_active_limit`, `reservation_daily_limit`, `vehicle_unavailable`,
        `idempotency_in_progress` (первый запрос с этим ключом ещё выполняется), `idempotency_key_reused` (ключ уже использован с другим телом)'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
    Gone:
      description: '`sync_token_expired` — `updated_since` старше срока хранения надгробий, нужен полный обход'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
    Unprocessable:
      description: 'Поля разобраны, но не проходят правила: `invalid_enum`, `invalid_value`, `required_field_missing`, `unknown_vehicle`, `unknown_organization`'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
    RateLimited:
      description: '`rate_limited` | `daily_quota_exceeded`, с заголовком Retry-After'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
      headers: &id015
        Retry-After:
          schema:
            type: integer
          description: Через сколько секунд повторить
    Unavailable:
      description: '`feature_disabled` — API выключен флагом `remote_sales_api_enabled`; `temporarily_unavailable` — проверка ключа временно недоступна.
        Повторите позже'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
      headers: *id015
  schemas:
    Geography:
      type: object
      required:
      - mode
      properties:
        mode:
          type: string
          enum:
          - all
          - include
          - exclude
        regions:
          type: array
          items:
            type: string
        no_same_city:
          type: boolean
          default: false
    MediaPermissions:
      type: object
      properties:
        photos_use:
          type: boolean
          default: false
        videos_use:
          type: boolean
          default: false
        photos_on_request:
          type: boolean
          default: false
        videos_on_request:
          type: boolean
          default: false
    ProgramInput:
      type: object
      properties:
        description:
          type: string
          maxLength: 8000
        advantages:
          type: string
          maxLength: 8000
        capabilities:
          type: array
          items:
            type: string
          description: 'Чек-лист возможностей, расширяемый: own_delivery, car_carrier, tow_truck, detailing, rop_direct_access, extra_photos_on_request,
            extra_videos_on_request, volume_discounts, individual_terms'
        geography:
          $ref: '#/components/schemas/Geography'
        reservation_enabled:
          type: boolean
        external_advertising_allowed:
          type: boolean
        media_permissions:
          $ref: '#/components/schemas/MediaPermissions'
    ProgramStatus:
      type: string
      enum:
      - draft
      - published
      - unpublished
      - blocked
      description: '`blocked` ставит только администратор Car2B; `deleted`-программы API не показывает'
    ProgramList:
      type: object
      required:
      - items
      - next_cursor
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/Program'
        next_cursor:
          type: string
    Program:
      allOf:
      - $ref: '#/components/schemas/ProgramInput'
      - type: object
        required:
        - guid
        - owner_org_guid
        - status
        - created
        - updated
        properties:
          guid: *id014
          owner_org_guid: *id014
          status:
            $ref: '#/components/schemas/ProgramStatus'
          blocked_reason:
            type:
            - string
            - 'null'
          created: &id016
            type: string
            format: date-time
          updated: *id016
    LevelInput:
      type: object
      required:
      - name
      - min_purchases
      properties:
        name:
          type: string
          maxLength: 200
        min_purchases:
          type: integer
          minimum: 0
        max_purchases:
          type:
          - integer
          - 'null'
        description:
          type: string
          maxLength: 4000
        commercial_conditions:
          type: string
          maxLength: 4000
          description: Свободный текст владельца
    Level:
      allOf:
      - $ref: '#/components/schemas/LevelInput'
      - type: object
        required:
        - guid
        - program_guid
        properties:
          guid: *id014
          program_guid: *id014
    LevelList:
      type: object
      required:
      - items
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/Level'
    StockSettings:
      type: object
      required:
      - mode
      properties:
        mode:
          type: string
          enum:
          - all
          - include
          - exclude
        vehicle_guids:
          type: array
          items: *id014
    CatalogProgramSummary:
      type: object
      required:
      - guid
      - owner_org_guid
      - company_name
      - vehicles_count
      - remote_ops_count
      - capabilities
      - reservation_enabled
      properties:
        guid: *id014
        owner_org_guid: *id014
        company_name:
          type: string
        city:
          type:
          - string
          - 'null'
        regions:
          type: array
          items:
            type: string
        vehicles_count:
          type: integer
        reels_count:
          type: integer
        remote_ops_count:
          type: integer
        brands:
          type: array
          items:
            type: string
        advantages_preview:
          type:
          - string
          - 'null'
        capabilities:
          type: array
          items:
            type: string
        reservation_enabled:
          type: boolean
        external_advertising_allowed:
          type: boolean
        media_permissions:
          $ref: '#/components/schemas/MediaPermissions'
    CatalogList:
      type: object
      required:
      - items
      - next_cursor
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/CatalogProgramSummary'
        next_cursor:
          type: string
    CatalogProgramCard:
      allOf:
      - $ref: '#/components/schemas/CatalogProgramSummary'
      - type: object
        properties:
          description:
            type:
            - string
            - 'null'
          advantages:
            type:
            - string
            - 'null'
          geography:
            $ref: '#/components/schemas/Geography'
          levels:
            type: array
            items:
              $ref: '#/components/schemas/Level'
          my_partnership:
            oneOf:
            - $ref: '#/components/schemas/Partnership'
            - type: 'null'
    PartnershipStatus:
      type: string
      enum:
      - pending_request
      - pending_invite
      - active
      - declined
      - terminated_by_owner
      - terminated_by_remote
      - suspended
      description: '`suspended` — партнёрство приостановлено модерацией площадки: чтение доступно, брони и сделки — нет'
    Partnership:
      type: object
      required:
      - guid
      - program_guid
      - owner_org_guid
      - remote_org_guid
      - status
      - initiated_by
      - reservations_disabled
      - created
      properties:
        guid: *id014
        program_guid: *id014
        owner_org_guid: *id014
        remote_org_guid: *id014
        owner_company_name:
          type:
          - string
          - 'null'
        remote_company_name:
          type:
          - string
          - 'null'
        status:
          $ref: '#/components/schemas/PartnershipStatus'
        initiated_by:
          type: string
          enum:
          - owner
          - remote
        message:
          type:
          - string
          - 'null'
        decline_reason:
          type:
          - string
          - 'null'
        reservations_disabled:
          type: boolean
        level_progress:
          oneOf:
          - type: object
            required:
            - purchases_count
            properties:
              purchases_count:
                type: integer
              current_level:
                oneOf:
                - $ref: '#/components/schemas/Level'
                - type: 'null'
              next_level:
                oneOf:
                - $ref: '#/components/schemas/Level'
                - type: 'null'
              purchases_to_next_level:
                type:
                - integer
                - 'null'
          - type: 'null'
        created: *id016
        responded_at:
          type:
          - string
          - 'null'
          format: date-time
        terminated_at:
          type:
          - string
          - 'null'
          format: date-time
        source: &id017
          type: string
          enum: &id018
          - ui
          - api
          description: 'Откуда выполнено действие: `api` — через этот API, `ui` — из интерфейса'
    PartnershipList:
      type: object
      required:
      - items
      - next_cursor
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/Partnership'
        next_cursor:
          type: string
    StockVehicle:
      type: object
      required:
      - vehicle_guid
      - updated
      - removed
      description: 'Позиция стока. При `removed: true` — надгробие: `vehicle_guid`, `updated` и `removed_reason`, остальные поля отсутствуют.'
      properties:
        vehicle_guid: *id014
        removed:
          type: boolean
        removed_reason:
          type:
          - string
          - 'null'
          enum:
          - unavailable
          - excluded
          - null
          description: 'Только при `removed: true`. `unavailable` — продан, удалён или снят с публикации; `excluded` — исключён из стока программы'
        title:
          type: string
        brand:
          type:
          - string
          - 'null'
        model:
          type:
          - string
          - 'null'
        year:
          type:
          - integer
          - 'null'
        vin:
          type:
          - string
          - 'null'
        vin_masked:
          type:
          - string
          - 'null'
        price:
          type:
          - number
          - 'null'
          format: double
        currency:
          type: string
          default: RUB
        photo_url:
          type:
          - string
          - 'null'
        reserved:
          type: boolean
        reserved_by_me:
          type: boolean
        reserved_until:
          type:
          - string
          - 'null'
          format: date-time
          description: Конец активной брони; кто бронировал — не раскрывается
        updated: *id016
    StockList:
      type: object
      required:
      - items
      - next_cursor
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/StockVehicle'
        next_cursor:
          type: string
          description: Пусто на последней странице
        sync_token:
          type: string
          description: Есть на последней странице обхода; передайте как `updated_since` в следующем обходе
    ReservationStatus:
      type: string
      enum:
      - active
      - cancelled_by_buyer
      - cancelled_by_seller
      - expired
      - converted_to_deal
    Reservation:
      type: object
      required:
      - guid
      - program_guid
      - partnership_guid
      - vehicle_guid
      - owner_org_guid
      - remote_org_guid
      - status
      - created
      - expires_at
      - source
      properties:
        guid: *id014
        program_guid: *id014
        partnership_guid: *id014
        vehicle_guid: *id014
        owner_org_guid: *id014
        remote_org_guid: *id014
        status:
          $ref: '#/components/schemas/ReservationStatus'
        cancellation_reason:
          type:
          - string
          - 'null'
        created: *id016
        expires_at: *id016
        cancelled_at:
          type:
          - string
          - 'null'
          format: date-time
        source: *id017
    ReservationList:
      type: object
      required:
      - items
      - next_cursor
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/Reservation'
        next_cursor:
          type: string
    DealStatus:
      type: string
      enum:
      - initiated
      - seller_confirmed
      - buyer_confirmed
      - completed
      - disputed
      - cancelled_before_completion
    DisputeCategory:
      type: string
      enum:
      - vehicle_unavailable
      - sold_during_reservation
      - price_mismatch
      - terms_violation
      - documents_issue
      - vehicle_condition
      - completion_not_confirmed
      - reservation_abuse
      - other
    DisputeInput:
      type: object
      required:
      - category
      - description
      properties:
        category:
          $ref: '#/components/schemas/DisputeCategory'
        description:
          type: string
          maxLength: 4000
    DealInput:
      type: object
      required:
      - partnership_guid
      - vehicle_guid
      - price
      properties:
        partnership_guid: *id014
        vehicle_guid: *id014
        price:
          type: number
          format: double
          description: Цена ДКП между сторонами, руб.
        currency:
          type: string
          default: RUB
        reservation_guid: *id014
    Deal:
      type: object
      required:
      - guid
      - program_guid
      - partnership_guid
      - vehicle_guid
      - seller_org_guid
      - buyer_org_guid
      - price
      - currency
      - status
      - seller_confirmed
      - buyer_confirmed
      - created
      - source
      properties:
        guid: *id014
        program_guid: *id014
        partnership_guid: *id014
        reservation_guid:
          type:
          - string
          - 'null'
          format: uuid
        vehicle_guid: *id014
        seller_org_guid: *id014
        buyer_org_guid: *id014
        price:
          type: number
          format: double
        currency:
          type: string
          default: RUB
        status:
          $ref: '#/components/schemas/DealStatus'
        seller_confirmed:
          type: boolean
        buyer_confirmed:
          type: boolean
        dispute_category:
          oneOf:
          - $ref: '#/components/schemas/DisputeCategory'
          - type: 'null'
        disputed_by_org_guid:
          type:
          - string
          - 'null'
          format: uuid
        cancel_reason:
          type:
          - string
          - 'null'
        created: *id016
        completed_at:
          type:
          - string
          - 'null'
          format: date-time
        source:
          type: string
          enum: *id018
          description: Откуда создана сделка
    DealList:
      type: object
      required:
      - items
      - next_cursor
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/Deal'
        next_cursor:
          type: string
    WebhookEnvelope:
      type: object
      required:
      - id
      - type
      - occurred_at
      - data
      properties:
        id: *id014
        type:
          type: string
        occurred_at: *id016
        data:
          type: object
    PartnershipEvent:
      type: object
      required:
      - partnership_guid
      - program_guid
      - owner_org_guid
      - remote_org_guid
      - status
      - initiated_by
      properties:
        partnership_guid: *id014
        program_guid: *id014
        owner_org_guid: *id014
        remote_org_guid: *id014
        status:
          $ref: '#/components/schemas/PartnershipStatus'
        initiated_by:
          type: string
          enum:
          - owner
          - remote
        message:
          type: string
        reason:
          type: string
        program_deleted:
          type: boolean
    ReservationEvent:
      type: object
      required:
      - reservation_guid
      - partnership_guid
      - vehicle_guid
      - owner_org_guid
      - remote_org_guid
      - status
      - expires_at
      properties:
        reservation_guid: *id014
        partnership_guid: *id014
        vehicle_guid: *id014
        owner_org_guid: *id014
        remote_org_guid: *id014
        status:
          $ref: '#/components/schemas/ReservationStatus'
        expires_at: *id016
        reason:
          type: string
        source: *id017
    DealEvent:
      type: object
      required:
      - deal_guid
      - partnership_guid
      - vehicle_guid
      - seller_org_guid
      - buyer_org_guid
      - price
      - currency
      - status
      properties:
        deal_guid: *id014
        partnership_guid: *id014
        vehicle_guid: *id014
        seller_org_guid: *id014
        buyer_org_guid: *id014
        price:
          type: number
        currency:
          type: string
        status:
          $ref: '#/components/schemas/DealStatus'
        previous_status:
          type: string
        reservation_guid: *id014
        reason:
          type: string
        dispute_category:
          $ref: '#/components/schemas/DisputeCategory'
        description:
          type: string
        disputed_by_org_guid: *id014
        source: *id017
    LevelEvent:
      type: object
      properties:
        partnership_guid: *id014
        program_guid: *id014
        owner_org_guid: *id014
        remote_org_guid: *id014
        level_guid: *id014
        level_name:
          type: string
        purchases_count:
          type: integer
    StockEvent:
      type: object
      required:
      - vehicle_guid
      - owner_org_guid
      - remote_org_guid
      - partnership_guid
      properties:
        vehicle_guid: *id014
        owner_org_guid: *id014
        remote_org_guid: *id014
        partnership_guid: *id014
        title:
          type: string
        brand:
          type: string
        model:
          type: string
        price:
          type: number
        old_price:
          type: number
          description: Только в price_changed
        currency:
          type: string
    Delivery:
      type: object
      required:
      - event_id
      - event_type
      - url
      - attempt
      - status_code
      - state
      - delivered_at
      - created_at
      properties:
        event_id:
          type: string
        event_type:
          type: string
        url:
          type: string
        attempt:
          type: integer
        status_code:
          type: integer
          description: 0 — ответа не было
        error:
          type: string
        state:
          type: string
          enum:
          - pending
          - delivered
          - failed
        delivered_at:
          type:
          - string
          - 'null'
          format: date-time
        created_at: *id016
    DeliveryList:
      type: object
      required:
      - items
      - next_cursor
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/Delivery'
        next_cursor:
          type: string
        webhook_failing_since: *id016
    FieldError:
      type: object
      required:
      - code
      - message
      properties:
        field:
          type: string
        code:
          type: string
        message:
          type: string
    Problem:
      type: object
      description: RFC 9457
      required:
      - type
      - title
      - status
      properties:
        type:
          type: string
          format: uri
        title:
          type: string
        status:
          type: integer
        detail:
          type: string
        instance:
          type: string
        errors:
          type: array
          items:
            $ref: '#/components/schemas/FieldError'
