openapi: 3.1.0
info:
  title: MEGOGO Partner Billing API
  version: 1.0.0
  summary: Пользователи, подписки и разовые покупки для партнеров, которые сами выставляют счета своим
    пользователям.
  description: 'Billing API для партнеров: запросы с путями вида `/partners/{partnerId}/`.


    ## Доступ


    Запросы не подписываются. Запросы, которые читают или изменяют услуги пользователя (`subscription/*`,
    `buyMovie`, `user/subscriptions`), MEGOGO принимает только с IP-адресов партнера. На запрос с другого
    IP-адреса API отвечает HTTP 401. Передайте свои IP-адреса вашему менеджеру MEGOGO. Чтобы изменить
    список, отправьте письмо на supportpartners@megogo.net и укажите свой ID партнера. Новый IP-адрес
    начинает работать через несколько минут после изменения.


    ## Ограничения


    1 000 запросов в минуту на каждый ID партнера. При превышении лимита API может вернуть HTTP 429 Too
    Many Requests.


    ## Тестовая среда


    Отдельной тестовой среды нет. MEGOGO выдает каждому партнеру тестовый ID партнера (например, `testprod_ua`,
    `testprod_az`) и тестовые ключи в рабочей среде (production).


    ## Правило списания оплаты


    MEGOGO регистрирует подписку или покупку, если запрос выполнен успешно (`"successful": true`), даже
    если пользователь ничего не смотрит. Списывайте оплату с пользователя только после успешного ответа.


    ## Повторные запросы


    Повторяйте запрос только после тайм-аута или ответа HTTP 5xx. Между попытками ждите 1 минуту. Делайте
    не больше 6 попыток. Для `subscribe` сначала прочитайте предупреждение (ВНИМАНИЕ) в разделе «Режимы
    продления».


    ## Ошибки


    Ошибка приходит с HTTP 200 и таким телом:


    ```json

    {"successful": false, "message": "<text>, code <number>"}

    ```


    Текст сообщения не фиксирован и может содержать код ошибки. Не разбирайте текст, разве что для того,
    чтобы найти код. На запрос с IP-адреса или ID партнера, которые MEGOGO не знает, API отвечает HTTP
    401 с телом в виде простого текста (не JSON).


    Самая частая ошибка — 2023: услуга уже активна для этого пользователя. Остальные коды помогают команде
    MEGOGO найти причину проблемы. Сообщите код и время запроса в поддержку MEGOGO.


    | Код | Название | Значение |

    |---|---|---|

    | 2009 | SUBSCRIPTION_NOT_SELLING | Подписка не продается |

    | 2010 | SUBSCRIPTION_NOT_FOUND | Подписка не найдена |

    | 2012 | INVALID_PERMISSIONS | Неверные настройки подписки или тарифа |

    | 2013 | SUBSCRIPTION_NOT_GEO_PRESENTED | Подписка недоступна в регионе |

    | 2015 | OBJECT_NO_VOD_PERMISSION_FOR_SALE | У видео нет модели доступа для продажи |

    | 2016 | USER_SERVICE_CREATION_ERROR | MEGOGO не может создать услугу пользователя |

    | 2017 | USER_SERVICE_NOT_FOUND | Услуга партнера не найдена |

    | 2022 | TARIFF_ID_DOESNT_MATCH_ORDER_SERVICE_ID | ID тарифа не относится к этой услуге |

    | 2023 | PROLONGATION_DISABLED | Услуга уже активна для этого пользователя (`subscribe` или `resume`).
    Никаких действий не требуется |

    | 2027 | DATE_FINISH_OUT_OF_BOUNDS | Дата окончания больше чем через 5 лет от текущего момента. Продлить
    больше нельзя |

    | 2029 | VOD_RULES_NOT_FOUND_FOR_OBJECT | У видео нет моделей доступа |

    | 2031 | SUBSCRIPTION_QUALITY_FOR_OBJECT_NOT_FOUND | Это качество видео не входит в услугу |

    | 400 | — | Запрос невозможно выполнить. Например, `buyMovie` для видео, которое пользователь уже
    купил |

    | 4001 | OBJECT_PREVIOUSLY_PURCHASED | Пользователь уже купил это видео |

    | 4003 | PARTNER_NOT_FOUND | Партнер не найден |

    | 5001 | USER_NOT_FOUND | Пользователь не найден (`"message": "User not found"`) |

    | 40416 | — | ID услуги или ID тарифа не найден для вашего ID партнера |

    | 42901 | error.too_many_requests | Слишком много запросов. Лимит — 1 000 запросов в минуту на каждый
    ID партнера |




    ## Режимы продления


    Для каждой услуги подписки MEGOGO задает один из двух режимов:


    | Режим | Продление | Повторный `subscribe` для активной подписки |

    |---|---|---|

    | Автоматическое продление | MEGOGO продлевает подписку каждый период, пока партнер не отправит `unsubscribe`
    | Ошибка 2023: услуга уже активна для этого пользователя. Никаких действий не требуется |

    | Без автоматического продления | Подписку продлевает партнер: он снова отправляет `subscribe` | Каждый
    запрос добавляет один период |


    Период задается в тарифе услуги, обычно это 30 дней. У тестовой услуги `ottsvod` партнера `testprod_ua`
    включено автоматическое продление и период 30 дней. Для пробного доступа MEGOGO может выдать отдельные
    услуги (например, на 7 или 14 дней). Не вычисляйте дату окончания сами: берите `dateFinish` из `user/subscriptions`.


    ВНИМАНИЕ: В режиме без автоматического продления `subscribe` **не идемпотентен**. Каждый успешный
    запрос добавляет еще один период. Прежде чем повторить запрос после тайм-аута, получите `user/subscriptions`
    и убедитесь, что первый запрос не был применен.


    ВНИМАНИЕ: Дата окончания подписки не может быть больше чем через 5 лет от текущего момента. Запрос
    `subscribe`, который выходит за этот предел, завершается ошибкой 2027.


    ## Логирование


    Рекомендуем сохранять в лог все запросы и ответы.

    '
  contact:
    name: MEGOGO partner support
    email: supportpartners@megogo.net
servers:
- url: https://billing.megogo.net
  description: 'Рабочая среда

    '
tags:
- name: Users
- name: Subscriptions
- name: Single purchases
paths:
  /partners/{partnerId}/user/create:
    get:
      tags:
      - Users
      operationId: createUser
      summary: Создать пользователя без услуги
      description: 'Создает пользователя в биллинге MEGOGO. Этот запрос нужен, если пользователь должен
        авторизоваться (`/auth/by_partners`) до покупки. `subscribe` и `buyMovie` тоже создают пользователя.


        Запрос можно отправить повторно: он вернет тот же `uid`.

        '
      parameters:
      - $ref: '#/components/parameters/partnerId'
      - $ref: '#/components/parameters/identifier'
      responses:
        '200':
          description: 'Пользователь создан.

            '
          content:
            application/json:
              schema:
                type: object
                properties:
                  uid:
                    type: integer
                    description: 'ID пользователя MEGOGO.

                      '
  /partners/{partnerId}/user/innerId:
    get:
      tags:
      - Users
      operationId: getUserInnerId
      summary: Получить ID пользователя MEGOGO и логин
      description: 'Если пользователя нет, запрос также создает его.

        '
      parameters:
      - $ref: '#/components/parameters/partnerId'
      - $ref: '#/components/parameters/identifier'
      responses:
        '200':
          description: 'ID пользователя MEGOGO. Ответ содержит только `uid`.

            '
          content:
            application/json:
              schema:
                type: object
                properties:
                  uid:
                    type: integer
  /partners/{partnerId}/user/subscriptions:
    get:
      tags:
      - Users
      operationId: listUserServices
      summary: Получить активные услуги пользователя
      description: 'С помощью этого запроса проверяйте, что услуги пользователя в вашей системе и в MEGOGO
        совпадают. Отправляйте его также перед повтором `subscribe` или `buyMovie`. Ответ содержит только
        услуги, которые вы активировали через этот API.

        '
      parameters:
      - $ref: '#/components/parameters/partnerId'
      - $ref: '#/components/parameters/identifier'
      responses:
        '200':
          description: 'Активные подписки и купленные видео.

            '
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UserServices'
              example:
                identifier: user123
                svod:
                - serviceId: examplesvod
                  serviceName: SVOD partners
                  dateFinish: 1798649598
                  dateFinishString: '2026-12-30 16:53:18'
  /partners/{partnerId}/subscription/{operation}:
    get:
      tags:
      - Subscriptions
      operationId: changeSubscription
      summary: Оформить, отменить, приостановить или возобновить подписку
      description: 'Изменяет подписку пользователя. Если пользователя нет, создает его.


        - `subscribe` — оформить подписку. Для **активной** подписки результат зависит от режима продления
        услуги: автоматическое продление → ошибка 2023 (подписка уже активна, никаких действий не требуется);
        без автоматического продления → добавляется еще один период. См. «Режимы продления».

        - `unsubscribe` — отменить подписку. Доступ прекращается **сразу**: после запроса подписки нет
        в `user/subscriptions`. Повторный `unsubscribe` возвращает `"successful": true`. Когда отправлять
        запрос, решаете вы: например, в момент отмены или в конце оплаченного пользователем периода.

        - `suspend` — приостановить подписку. У пользователя нет доступа. Подписки нет в `user/subscriptions`
        до `resume`. Оплаченное время пользователь не теряет: после `resume` дата окончания сдвигается
        вперед на время приостановки. Повторный `suspend` возвращает `"successful": true`.

        - `resume` — возобновить приостановленную подписку. Для активной подписки: ошибка 2023.


        Чтобы сменить услугу, отправьте `unsubscribe` для старой услуги, а затем `subscribe` для новой.

        '
      parameters:
      - $ref: '#/components/parameters/partnerId'
      - name: operation
        in: path
        required: true
        schema:
          type: string
          enum:
          - subscribe
          - unsubscribe
          - suspend
          - resume
      - $ref: '#/components/parameters/userId'
      - $ref: '#/components/parameters/serviceId'
      responses:
        '200':
          description: 'Результат.

            '
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Result'
        '500':
          $ref: '#/components/responses/ServerError'
  /partners/{partnerId}/buyMovie:
    get:
      tags:
      - Single purchases
      operationId: buyMovie
      summary: Зарегистрировать покупку видео (TVOD/DTO)
      description: 'Регистрирует покупку видео пользователем. Для ключей партнера должен быть включен
        TVOD.


        `serviceId` — это `tariff_id`, который Content API возвращает для этого видео в `purchase_info`.
        Не используйте `subscription_id` из Content API. Не используйте цены и ID из XML-фида: это тарифы
        MEGOGO. Неверный `serviceId` дает ошибку 40416.


        Период аренды начинается, когда пользователь начинает смотреть: с первого запроса `/stream`, который
        возвращает `src`. До этого у покупки статус `unwatched` и нет даты окончания.


        Повторный `buyMovie` для того же видео дает ошибку 400.

        '
      parameters:
      - $ref: '#/components/parameters/partnerId'
      - $ref: '#/components/parameters/userId'
      - name: videoId
        in: query
        required: true
        schema:
          type: integer
      - $ref: '#/components/parameters/serviceId'
      responses:
        '200':
          description: 'Результат.

            '
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Result'
        '500':
          $ref: '#/components/responses/ServerError'
components:
  parameters:
    partnerId:
      name: partnerId
      in: path
      required: true
      description: 'ID партнера.

        '
      schema:
        type: string
    identifier:
      name: identifier
      in: query
      required: true
      description: 'Идентификатор пользователя на стороне партнера. Любая строка длиной до 255 символов:
        номер договора, номер лицевого счета, логин, номер телефона или хеш, если вы не хотите передавать
        реальные данные пользователя.

        '
      schema:
        type: string
        maxLength: 255
    userId:
      name: userId
      in: query
      required: true
      description: 'Идентификатор пользователя на стороне партнера. То же значение, что и `identifier`.

        '
      schema:
        type: string
        maxLength: 255
    serviceId:
      name: serviceId
      in: query
      required: true
      description: 'ID услуги. MEGOGO создает его и передает партнеру.

        '
      schema:
        type: string
  responses:
    ServerError:
      description: 'Временная ошибка. Прежде чем повторить `subscribe` или `buyMovie`, проверьте услуги
        пользователя с помощью `user/subscriptions` (эти запросы не идемпотентны).

        '
  schemas:
    Result:
      type: object
      properties:
        successful:
          type: boolean
          description: '`true` — операция выполнена. Начинайте списывать оплату с пользователя. Любой
            другой ответ — не списывайте оплату. Коды ошибок см. в описании этого API.

            '
        message:
          type: string
    UserServices:
      type: object
      properties:
        identifier:
          type: string
        svod:
          type: array
          items:
            type: object
            properties:
              serviceId:
                type: string
              serviceName:
                type: string
              dateFinish:
                type: integer
                description: 'Unix-время (секунды).

                  '
              dateFinishString:
                type: string
                description: '`YYYY-MM-DD hh:mm:ss`, UTC.

                  '
        tvod:
          type: array
          description: 'Купленные видео. Если у пользователя нет покупок, этого ключа в ответе нет. `svod`
            в ответе есть всегда.

            '
          items:
            type: object
            properties:
              serviceId:
                type: string
                description: 'ID тарифа, переданный в `buyMovie`, в виде строки.

                  '
              serviceName:
                type: string
              objectId:
                type: integer
                description: 'ID видео.

                  '
              status:
                type: string
                enum:
                - unwatched
                - started
                description: '`unwatched` — период аренды не начался. `started` — пользователь начал смотреть.

                  '
              dateFinish:
                type: integer
                description: 'Конец периода аренды, Unix-время (секунды). Только для `started`.

                  '
              dateFinishString:
                type: string
                description: '`YYYY-MM-DD hh:mm:ss`, UTC. Только для `started`.

                  '
