openapi: 3.1.0
info:
  title: MEGOGO Terminals API (phone number)
  version: 1.0.0
  summary: Activate and stop MEGOGO subscriptions of your users by their phone number.
  description: "The Terminals API for partners that sell MEGOGO subscriptions to their\nusers, for example\
    \ mobile operators: requests under\n`/terminals/{partnerId}/` that identify the user by the phone\
    \ number.\n\n## Access\n\n- Each request must have the `sign` parameter. See \"Signature\".\n- MEGOGO\
    \ accepts the requests only from the IP addresses (IPv4) of your\n  servers. Give the addresses to\
    \ your MEGOGO manager. Tell MEGOGO before\n  the addresses of your servers change: requests from other\
    \ addresses\n  get HTTP 401.\n- The \"Try it out\" button is off. Send the requests from your server.\n\
    \n## Signature\n\n1. Write the private key, then `GET`, then the path of the request\n   (for example\
    \ `/terminals/example_operator/user/phone`).\n2. Sort the query parameters by name (ascending). Add\
    \ each parameter as\n   `name=value`, with no separator. Use the values before URL encoding\n   (`+380…`,\
    \ not `%2B380…`). Do not include `sign`.\n3. Calculate the SHA-256 hash of the text (UTF-8). Write\
    \ it as 64\n   lowercase hexadecimal characters.\n4. Encode the 64 characters with Base64. Remove\
    \ `=`. Replace `/` and\n   `+` with `-`.\n5. Add `_` and the public key.\n\nAll query parameters that\
    \ you send must be in the signature.\n\n## Limits\n\n1000 requests per minute for each partner ID.\
    \ Above this limit, you can\nget HTTP 429 Too Many Requests.\n\n## Test environment\n\nThere is no\
    \ separate test environment. Your MEGOGO manager gives you a\ntest partner ID, test keys and test\
    \ service IDs on production.\n\n## Responses and errors\n\nThe result of an operation comes with HTTP\
    \ 200:\n\n```json\n{\"successful\": true}\n```\n\n```json\n{\"successful\": false, \"message\": \"\
    Exception while trying to buy object, code 2023\"}\n```\n\nIf `message` ends with `code` and a number,\
    \ use the number. Do not use\nthe rest of the text. Access errors and request format errors come with\n\
    another HTTP status and this body:\n\n```json\n{\"message\": \"Not Authorized\", \"code\": 401, \"\
    result\": \"error\"}\n```\n\n| Code in `message` | Meaning | Action |\n|---|---|---|\n| 2006 | The\
    \ service ID is not a subscription (for example a tariff for a single video) | Use a subscription\
    \ service ID from your MEGOGO manager |\n| 2009 | The subscription is not for sale | Tell your MEGOGO\
    \ manager |\n| 2010 | The subscription is not found | Tell your MEGOGO manager |\n| 2012 | The settings\
    \ of the subscription or the tariff are not correct | Tell your MEGOGO manager |\n| 2013 | The subscription\
    \ is not available in the region | Tell your MEGOGO manager |\n| 2016 | MEGOGO cannot create the service\
    \ of the user | Retry later. If the error stays, tell MEGOGO support |\n| 2023 | The service is already\
    \ active and renewal is not permitted, or the end date would be more than 15 years from now | No action\
    \ is necessary |\n| 40009 | The subscription is not sold through partners | Tell your MEGOGO manager\
    \ |\n\nCodes 2023, 2006 and 40009 come from tests on production.\nThe other codes come from the error\
    \ list of the MEGOGO billing.\n\nMessages without a code:\n\n| `message` | Meaning |\n|---|---|\n\
    | `Service is not configured for this partner` | The service ID is not configured for your partner\
    \ ID |\n| `Invalid operation passed` | The operation in `subscription/{operation}` is not known |\n\
    | `Invalid phone number format` | The phone number has characters that are not digits (`user/phone`)\
    \ |\n| `General error` | The phone number has characters that are not digits (`subscriptions`, `subscription/{operation}`),\
    \ or another error |\n| `User doesn't not exist` | The phone number is not registered in MEGOGO (`user/phone`).\
    \ The text is as the API gives it |\n\n## Response language\n\nMEGOGO sets the language of the service\
    \ names and descriptions for each\npartner ID. By default, it is the language of the region of the\
    \ partner.\nTo change it, ask your MEGOGO manager. The error messages\nare always in English.\n"
  contact:
    name: MEGOGO partner support
    email: supportpartners@megogo.net
servers:
- url: https://billing.megogo.net
  description: 'Production

    '
tags:
- name: Users
- name: Subscriptions
paths:
  /terminals/{partnerId}/user/phone:
    get:
      tags:
      - Users
      operationId: checkUserByPhone
      summary: Check if a phone number is registered in MEGOGO
      description: 'Tells if MEGOGO has a user with this phone number. The request does

        not create a user. Send it before `subscriptions` for a number that

        can be new to MEGOGO.

        '
      parameters:
      - $ref: '#/components/parameters/partnerId'
      - $ref: '#/components/parameters/phone'
      - $ref: '#/components/parameters/sign'
      responses:
        '200':
          description: '`"successful": true` — the user exists. `"successful": false` — the

            user does not exist, or the number format is not correct (see `message`).

            '
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Result'
              examples:
                exists:
                  summary: The user exists
                  value:
                    successful: true
                notFound:
                  summary: The phone number is not registered
                  value:
                    successful: false
                    message: User doesn't not exist
                badFormat:
                  summary: The phone number has characters that are not digits
                  value:
                    successful: false
                    message: Invalid phone number format
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /terminals/{partnerId}/subscriptions:
    get:
      tags:
      - Subscriptions
      operationId: listSubscriptions
      summary: Get your services, or the active services of a user
      description: "- Without `phone`: the services that MEGOGO configured for your\n  partner ID and\
        \ shows to you. Use the list to check the service IDs\n  that your MEGOGO manager gave you. The\
        \ list can be shorter than the\n  list of your service IDs: if a service ID is not in the list,\
        \ ask\n  your MEGOGO manager. `dateFinish` is `-1`.\n- With `phone`: the active services of the\
        \ user that you can sell.\n  A suspended service is not in the list.\n\nWARNING: With `phone`,\
        \ the request creates a MEGOGO user if the\nnumber is not registered. Send `user/phone` first.\n\
        \nTwo service IDs of one MEGOGO subscription make one item: the\nperiods are added, and the item\
        \ has the service ID of the last\nrequest. Use this service ID in `unsubscribe`.\n"
      parameters:
      - $ref: '#/components/parameters/partnerId'
      - name: phone
        in: query
        required: false
        description: 'The phone number of the user. See the `phone` parameter of `user/phone`.

          '
        schema:
          type: string
          pattern: ^\+?[0-9]+$
          examples:
          - '380000000001'
      - $ref: '#/components/parameters/sign'
      responses:
        '200':
          description: 'A list of services. An empty list (`[]`) if the user has no active services.

            '
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Service'
              examples:
                userServices:
                  summary: Active service of a user
                  value:
                  - serviceId: example_light_30d
                    serviceName: Light (partner)
                    serviceDescription: TV channels and a movie collection
                    tariff:
                      tariffId: 12345
                      tariffName: 30 days
                      price: 0
                      tryAndBuy: false
                      dateFinish: 1796221882
                      dateFinishString: '2026-12-02 14:31:22'
                    dateFinish: 1796221882
                    dateFinishString: '2026-12-02 14:31:22'
                noServices:
                  summary: The user has no active services
                  value: []
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /terminals/{partnerId}/subscription/{operation}:
    get:
      tags:
      - Subscriptions
      operationId: changeSubscription
      summary: Subscribe, unsubscribe, suspend or resume
      description: "Changes the service of a user. If MEGOGO has no user with this phone\nnumber, `subscribe`\
        \ creates the user. MEGOGO does not send a\nmessage to the user: tell the user how to sign in.\n\
        \n- `subscribe` — start the service: one period from now. For an\n  active service, the result\
        \ depends on the renewal mode:\n  renewal by the partner → one more period after the current end\n\
        \  date; automatic renewal → code 2023, no change.\n- `unsubscribe` — stop the service immediately.\
        \ Also stops a\n  suspended service: the suspended time is lost.\n- `suspend` — stop the access\
        \ until `resume`. The service is not in\n  `subscriptions` until `resume`.\n- `resume` — start\
        \ a suspended service again. The end date moves\n  forward by the time of the suspension.\n\n\
        WARNING: Send `resume` only after your own `suspend`. If the user has\nno suspended service, `resume`\
        \ works as `subscribe`: it adds a period\nor starts a new service. Do not send `subscribe` while\
        \ the\nservice is suspended: after that, the suspended time does not come\nback.\n\n`unsubscribe`\
        \ and `suspend` give `\"successful\": true` also when the\nservice is not active.\n"
      parameters:
      - $ref: '#/components/parameters/partnerId'
      - name: operation
        in: path
        required: true
        schema:
          type: string
          enum:
          - subscribe
          - unsubscribe
          - suspend
          - resume
      - $ref: '#/components/parameters/phone'
      - $ref: '#/components/parameters/serviceId'
      - $ref: '#/components/parameters/sign'
      responses:
        '200':
          description: 'The result.

            '
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Result'
              examples:
                ok:
                  summary: Successful
                  value:
                    successful: true
                alreadyActive:
                  summary: 'Code 2023: the service is already active'
                  value:
                    successful: false
                    message: Exception while trying to buy object, code 2023
                unknownService:
                  summary: The service ID is not configured for your partner ID
                  value:
                    successful: false
                    message: Service is not configured for this partner
                unknownOperation:
                  summary: The operation is not known
                  value:
                    successful: false
                    message: Invalid operation passed
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          $ref: '#/components/responses/ServerError'
components:
  parameters:
    partnerId:
      name: partnerId
      in: path
      required: true
      description: 'Your partner ID.

        '
      schema:
        type: string
        examples:
        - example_operator
    phone:
      name: phone
      in: query
      required: true
      description: 'The phone number of the user in the international format: the

        country code and the number, digits only, for example `380000000001`.

        A `+` at the start is permitted: encode it as `%2B` in the URL. Do not

        use spaces, brackets or the local format (`0…`). MEGOGO does not check

        the length of the number: check it on your side.

        '
      schema:
        type: string
        pattern: ^\+?[0-9]+$
        examples:
        - '380000000001'
    serviceId:
      name: serviceId
      in: query
      required: true
      description: 'The service ID. MEGOGO makes it and gives it to you.

        '
      schema:
        type: string
        examples:
        - example_light_30d
    sign:
      name: sign
      in: query
      required: true
      description: 'The signature of the request. See "Signature" in the description of this API.

        '
      schema:
        type: string
  responses:
    BadRequest:
      description: 'A required parameter is not in the request, or it is empty.

        '
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            message: Invalid request format
            code: 400
            result: error
    Unauthorized:
      description: 'The signature is not correct or not in the request, the partner ID or

        the public key is not known, or the IP address is not in the list of

        your partner ID. The response is the same for all these

        causes.

        '
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            message: Not Authorized
            code: 401
            result: error
    TooManyRequests:
      description: 'More than 1000 requests per minute for your partner ID.

        '
    ServerError:
      description: 'Temporary error. Before you send `subscribe` or `resume` again, get

        `subscriptions` for the user: these operations are not idempotent.

        '
  schemas:
    Result:
      type: object
      required:
      - successful
      properties:
        successful:
          type: boolean
          description: '`true` — the operation is done. `false` — the operation is not

            done. Read `message`.

            '
        message:
          type: string
    Error:
      type: object
      properties:
        message:
          type: string
        code:
          type: integer
          description: 'The HTTP status.

            '
        result:
          type: string
          const: error
    Service:
      type: object
      properties:
        serviceId:
          type: string
          description: 'Your service ID.

            '
        serviceName:
          type: string
          description: 'The name of the MEGOGO subscription, in the response language of your partner
            ID.

            '
        serviceDescription:
          type: string
          description: 'The description of the subscription.

            '
        tariff:
          type: object
          properties:
            tariffId:
              type: integer
              description: 'The MEGOGO tariff ID.

                '
            tariffName:
              type: string
              description: 'The period of the tariff, for example `30 days`.

                '
            price:
              type: number
              description: 'The MEGOGO price of the tariff. Do not use it: you set the price

                for your users.

                '
            tryAndBuy:
              type: boolean
              description: 'Do not use it.

                '
            dateFinish:
              type: integer
              description: 'Only with `phone`. The same value as `dateFinish` of the service.

                '
            dateFinishString:
              type: string
              description: 'Only with `phone`. The same value as `dateFinishString` of the service.

                '
        dateFinish:
          type: integer
          description: 'The end of the paid period, Unix time (seconds). `-1` in the list without `phone`.

            '
        dateFinishString:
          type: string
          description: 'The same time, `YYYY-MM-DD hh:mm:ss`, UTC. `1969-12-31 23:59:59` in the list without
            `phone`.

            '
