# Proposed contract, version 1: endpoints, errors, paging, idempotency, security and the capability of every
# operation. Resource schemas were initialized from the data model (docs/06-data) and are kept aligned with it; input
# schemas (*Input, *Request) and views are specific to this contract. Status: proposal for review, not confirmed design.
# Conventions: docs/05-interfaces/choosing-an-interface.md. Vendor extensions: x-moonitoring-audience (who calls),
# x-moonitoring-capability (the capability checked), x-moonitoring-entitlement (the entitlement feature checked),
# x-moonitoring-requirements (the requirements of 1.requisiti-raffinati.txt the operation serves).
openapi: 3.1.0
info:
  title: Releases Channels API
  version: 1.0.0
  description: 'Who receives a version: channels and their access rule, releases of a build on a channel with their
    approval, pauses and rollbacks, recipient Organizations and tester groups. The download page lists what the
    caller may receive and never reveals what they may not.'
servers:
- url: https://releases.moonitoring.com/channels/v1
  description: Prod
- url: https://stage-releases.moonitoring.com/channels/v1
  description: Stage, through IAP
security:
- bearer: []
tags:
- name: Channels
  description: Lanes of distribution
- name: Releases
  description: A build on a channel
- name: Testers
  description: Groups that cut across audiences
- name: Download
  description: The download page
paths:
  /channels:
    get:
      summary: List channels
      operationId: listReleaseChannels
      tags:
      - Channels
      parameters:
      - name: application
        in: query
        required: false
        schema:
          type: string
          format: uuid
        description: Only this application's.
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/Cursor
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/Limit
      responses:
        '200':
          description: One page of results.
          content:
            application/json:
              schema:
                type: object
                description: One page of items.
                properties:
                  items:
                    type: array
                    items:
                      $ref: '#/components/schemas/ReleaseChannel'
                  next_cursor:
                    type: string
                    description: Where the next page starts; absent on the last page.
                required:
                - items
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
      x-moonitoring-audience: staff
      x-moonitoring-capability: releases.releases.read
      x-moonitoring-requirements:
      - '111'
      - '1006.5'
    post:
      summary: Create a channel
      operationId: createReleaseChannel
      tags:
      - Channels
      parameters:
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/IdempotencyKey
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ReleaseChannelInput'
      responses:
        '201':
          description: The result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReleaseChannel'
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '409':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Conflict
        '422':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/UnprocessableEntity
      x-moonitoring-audience: staff
      x-moonitoring-capability: releases.channels.manage
      x-moonitoring-requirements:
      - '111'
      - '111.7'
      - '111.8'
      - '1006.8'
  /channels/{channel_id}:
    get:
      summary: Read a channel
      operationId: getReleaseChannel
      tags:
      - Channels
      parameters:
      - name: channel_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      responses:
        '200':
          description: The result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReleaseChannel'
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '404':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/NotFound
      x-moonitoring-audience: staff
      x-moonitoring-capability: releases.releases.read
      x-moonitoring-requirements:
      - '111'
    patch:
      summary: Update a channel
      operationId: updateReleaseChannel
      tags:
      - Channels
      parameters:
      - name: channel_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ReleaseChannelInput'
      responses:
        '200':
          description: The result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReleaseChannel'
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '404':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/NotFound
        '409':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Conflict
        '422':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/UnprocessableEntity
      x-moonitoring-audience: staff
      x-moonitoring-capability: releases.channels.manage
      x-moonitoring-requirements:
      - '111.4'
      - '111.5'
      - '111.7'
      - '111.8'
      - '1006.8'
  /channels/{channel_id}/access:
    get:
      summary: List a channel's recipient Organizations
      operationId: listChannelAccess
      tags:
      - Channels
      parameters:
      - name: channel_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/Cursor
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/Limit
      responses:
        '200':
          description: One page of results.
          content:
            application/json:
              schema:
                type: object
                description: One page of items.
                properties:
                  items:
                    type: array
                    items:
                      $ref: '#/components/schemas/ReleaseChannelAccess'
                  next_cursor:
                    type: string
                    description: Where the next page starts; absent on the last page.
                required:
                - items
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '404':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/NotFound
      x-moonitoring-audience: staff
      x-moonitoring-capability: releases.releases.read
      x-moonitoring-requirements:
      - '113'
    post:
      summary: Add a recipient Organization
      operationId: createChannelAccess
      tags:
      - Channels
      parameters:
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/IdempotencyKey
      - name: channel_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ChannelAccessInput'
      responses:
        '201':
          description: The result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReleaseChannelAccess'
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '404':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/NotFound
        '409':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Conflict
        '422':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/UnprocessableEntity
      x-moonitoring-audience: staff
      x-moonitoring-capability: releases.channels.manage
      x-moonitoring-requirements:
      - '113'
      - '1006.8'
  /channels/{channel_id}/access/{access_id}:
    delete:
      summary: Remove a recipient Organization
      operationId: deleteChannelAccess
      tags:
      - Channels
      parameters:
      - name: channel_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      - name: access_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      responses:
        '204':
          description: Done.
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '404':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/NotFound
        '409':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Conflict
      x-moonitoring-audience: staff
      x-moonitoring-capability: releases.channels.manage
      x-moonitoring-requirements:
      - '113'
      - '1006.8'
  /channels/{channel_id}/releases:
    get:
      summary: List a channel's releases
      operationId: listChannelReleases
      tags:
      - Releases
      parameters:
      - name: channel_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      - name: state
        in: query
        required: false
        schema:
          type: string
          enum:
          - staged
          - active
          - paused
          - superseded
          - rolled_back
        description: Only this state.
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/Cursor
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/Limit
      responses:
        '200':
          description: One page of results.
          content:
            application/json:
              schema:
                type: object
                description: One page of items.
                properties:
                  items:
                    type: array
                    items:
                      $ref: '#/components/schemas/Release'
                  next_cursor:
                    type: string
                    description: Where the next page starts; absent on the last page.
                required:
                - items
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '404':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/NotFound
      x-moonitoring-audience: staff
      x-moonitoring-capability: releases.releases.read
      x-moonitoring-requirements:
      - '112'
      - '1006.5'
    post:
      summary: Stage a release
      operationId: stageRelease
      tags:
      - Releases
      parameters:
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/IdempotencyKey
      - name: channel_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ReleaseInput'
      responses:
        '201':
          description: The result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Release'
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '404':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/NotFound
        '409':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Conflict
        '422':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/UnprocessableEntity
      x-moonitoring-audience: staff
      x-moonitoring-capability: releases.releases.stage
      x-moonitoring-requirements:
      - '112'
      - '112.4'
      - '112.5'
      - '112.7'
      - '1006.11'
  /channels/{channel_id}/rollbacks:
    post:
      summary: Roll back a channel
      operationId: rollbackChannel
      description: A new release pointing to an older build. Publishes `release.rolled_back.v1`.
      tags:
      - Releases
      parameters:
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/IdempotencyKey
      - name: channel_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RollbackRequest'
      responses:
        '201':
          description: The result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Release'
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '404':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/NotFound
        '409':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Conflict
        '422':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/UnprocessableEntity
      x-moonitoring-audience: staff
      x-moonitoring-capability: releases.releases.rollback
      x-moonitoring-requirements:
      - '112'
      - '1006.14'
  /releases/{release_id}:
    get:
      summary: Read a release
      operationId: getRelease
      tags:
      - Releases
      parameters:
      - name: release_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      responses:
        '200':
          description: The result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Release'
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '404':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/NotFound
      x-moonitoring-audience: staff
      x-moonitoring-capability: releases.releases.read
      x-moonitoring-requirements:
      - '112'
  /releases/{release_id}/approve:
    post:
      summary: Approve a release
      operationId: approveRelease
      description: The approver must differ from who staged it and from the build's creator. The metadata is signed
        and the release becomes active. Publishes `release.activated.v1`.
      tags:
      - Releases
      parameters:
      - name: release_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      responses:
        '200':
          description: The result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Release'
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '404':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/NotFound
        '409':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Conflict
      x-moonitoring-audience: staff
      x-moonitoring-capability: releases.releases.approve
      x-moonitoring-requirements:
      - '112.8'
      - '112.10'
      - '112.11'
      - '115'
      - '1006.12'
  /releases/{release_id}/pause:
    post:
      summary: Pause a release
      operationId: pauseRelease
      description: Nothing changes on clients that already updated. Publishes `release.paused.v1`.
      tags:
      - Releases
      parameters:
      - name: release_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      responses:
        '200':
          description: The result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Release'
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '404':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/NotFound
        '409':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Conflict
      x-moonitoring-audience: staff
      x-moonitoring-capability: releases.releases.pause
      x-moonitoring-requirements:
      - '112.7'
      - '1006.13'
  /releases/{release_id}/resume:
    post:
      summary: Resume a paused release
      operationId: resumeRelease
      tags:
      - Releases
      parameters:
      - name: release_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      responses:
        '200':
          description: The result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Release'
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '404':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/NotFound
        '409':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Conflict
      x-moonitoring-audience: staff
      x-moonitoring-capability: releases.releases.approve
      x-moonitoring-requirements:
      - '112.7'
      - '1006.12'
  /tester-groups:
    get:
      summary: List tester groups
      operationId: listTesterGroups
      tags:
      - Testers
      parameters:
      - name: include_archived
        in: query
        required: false
        schema:
          type: boolean
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/Cursor
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/Limit
      responses:
        '200':
          description: One page of results.
          content:
            application/json:
              schema:
                type: object
                description: One page of items.
                properties:
                  items:
                    type: array
                    items:
                      $ref: '#/components/schemas/ReleaseTesterGroup'
                  next_cursor:
                    type: string
                    description: Where the next page starts; absent on the last page.
                required:
                - items
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
      x-moonitoring-audience: staff
      x-moonitoring-capability: releases.releases.read
      x-moonitoring-requirements:
      - '130'
    post:
      summary: Create a tester group
      operationId: createTesterGroup
      tags:
      - Testers
      parameters:
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/IdempotencyKey
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ReleaseTesterGroupInput'
      responses:
        '201':
          description: The result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReleaseTesterGroup'
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '409':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Conflict
        '422':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/UnprocessableEntity
      x-moonitoring-audience: staff
      x-moonitoring-capability: releases.channels.manage
      x-moonitoring-requirements:
      - '130'
      - '1006.8'
  /tester-groups/{group_id}:
    patch:
      summary: Update or archive a tester group
      operationId: updateTesterGroup
      tags:
      - Testers
      parameters:
      - name: group_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ReleaseTesterGroupInput'
      responses:
        '200':
          description: The result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReleaseTesterGroup'
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '404':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/NotFound
        '409':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Conflict
        '422':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/UnprocessableEntity
      x-moonitoring-audience: staff
      x-moonitoring-capability: releases.channels.manage
      x-moonitoring-requirements:
      - '130.4'
      - '130.5'
      - '1006.8'
  /tester-groups/{group_id}/channels/{channel_id}:
    put:
      summary: Open a channel to a group
      operationId: attachTesterGroupChannel
      tags:
      - Testers
      parameters:
      - name: group_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      - name: channel_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      responses:
        '204':
          description: Done.
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '404':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/NotFound
        '409':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Conflict
      x-moonitoring-audience: staff
      x-moonitoring-capability: releases.channels.manage
      x-moonitoring-requirements:
      - '130.3'
      - '1006.8'
    delete:
      summary: Close a channel to a group
      operationId: detachTesterGroupChannel
      tags:
      - Testers
      parameters:
      - name: group_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      - name: channel_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      responses:
        '204':
          description: Done.
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '404':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/NotFound
        '409':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Conflict
      x-moonitoring-audience: staff
      x-moonitoring-capability: releases.channels.manage
      x-moonitoring-requirements:
      - '130.3'
      - '1006.8'
  /tester-groups/{group_id}/testers:
    get:
      summary: List a group's testers
      operationId: listTesters
      tags:
      - Testers
      parameters:
      - name: group_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/Cursor
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/Limit
      responses:
        '200':
          description: One page of results.
          content:
            application/json:
              schema:
                type: object
                description: One page of items.
                properties:
                  items:
                    type: array
                    items:
                      $ref: '#/components/schemas/ReleaseTester'
                  next_cursor:
                    type: string
                    description: Where the next page starts; absent on the last page.
                required:
                - items
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '404':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/NotFound
      x-moonitoring-audience: staff
      x-moonitoring-capability: releases.releases.read
      x-moonitoring-requirements:
      - '131'
    post:
      summary: Invite a tester
      operationId: createTester
      description: Refused above the group's ceiling.
      tags:
      - Testers
      parameters:
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/IdempotencyKey
      - name: group_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ReleaseTesterInput'
      responses:
        '201':
          description: The result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReleaseTester'
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '404':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/NotFound
        '409':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Conflict
        '422':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/UnprocessableEntity
      x-moonitoring-audience: staff
      x-moonitoring-capability: releases.channels.manage
      x-moonitoring-requirements:
      - '131'
      - '131.4'
      - '1006.8'
  /testers/{tester_id}/revoke:
    post:
      summary: Revoke a tester
      operationId: revokeTester
      tags:
      - Testers
      parameters:
      - name: tester_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      responses:
        '200':
          description: The result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReleaseTester'
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '404':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/NotFound
        '409':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Conflict
      x-moonitoring-audience: staff
      x-moonitoring-capability: releases.channels.manage
      x-moonitoring-requirements:
      - '131.7'
      - '1006.8'
  /applications/{application_slug}/download:
    get:
      summary: Read the download page
      operationId: getDownloadPage
      description: 'Evaluates the channel rule for the caller: audience, recipient Organizations, required capabilities
        and features, or a verified tester e-mail (`Moonitoring-Tester-Proof` header). Only the public audience
        answers without a token. What the caller may not receive is absent, and an unknown or private application
        answers 404.'
      tags:
      - Download
      parameters:
      - name: application_slug
        in: path
        required: true
        schema:
          type: string
        description: The application's slug.
      - name: include_unlisted
        in: query
        required: false
        schema:
          type: string
        description: The enrolment link token of an unlisted channel.
      responses:
        '200':
          description: The result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DownloadPage'
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '404':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/NotFound
      security:
      - {}
      - bearer: []
      x-moonitoring-audience: any
      x-moonitoring-capability: null
      x-moonitoring-requirements:
      - '101.8'
      - '111'
      - '113'
      - '119'
      - '130'
      - '131'
components:
  schemas:
    ReleaseChannel:
      description: 'A lane of distribution for an application, such as stable, beta or internal. It carries the
        access rule: which capabilities and entitlement features a caller needs, whether the channel is listed,
        and whether a release needs approval; recipient Organizations and tester groups attach to it. A caller who
        does not pass the rule sees the channel as if it did not exist.'
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: Key.
        application:
          type: string
          format: uuid
          description: ID of the ReleaseApplication.
        name:
          type: string
          description: '`(application, name)` is unique.'
        listed:
          type: boolean
          default: true
          description: Shown in the client's channel picker and on the download page to those who may receive it.
            An unlisted channel is reached only by its enrolment link; the access rule applies the same. Replaces
            visibility (public, restricted, hidden), which mixed who may access with what is advertised.
        requires_approval:
          type: boolean
          default: true
          description: Always true when the application's audience is public.
        current_release:
          type: string
          format: uuid
          description: ID of the Release. The release of this channel that is active or paused; at most one.
        required_capabilities:
          type: array
          items:
            type: string
          description: 'Capabilities of the audience''s catalog (OrganizationRoleCapabilityEnum for organization,
            MoonitoringCapabilityEnum for moonitoring; none for public), all of which the caller''s role must hold.
            Empty: everyone in the audience.'
        required_features:
          type: array
          items:
            type: string
          description: 'Entitlement features of Entitlement the caller''s Organization must hold, all active; only
            for the organization audience. Empty: no entitlement needed.'
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
      required:
      - id
      - application
      - name
      - listed
      - requires_approval
      - created_at
      - updated_at
    Release:
      description: 'The decision to distribute a build on a channel, with a rollout percentage, an approval and
        signed metadata. Releases are only added: a rollback is a new release that points to an older build. Append-only.'
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: Key.
        channel:
          type: string
          format: uuid
          description: ID of the ReleaseChannel.
        build:
          type: string
          format: uuid
          description: ID of the ReleaseBuild. Must belong to the channel's application, with status ready.
        rollout_pct:
          type: integer
          description: '`0..100`: share of installations that receive it (see ReleaseInstallation, `ReleaseInstallation.rollout_bucket`).'
        min_build_number:
          type: integer
          description: Installations below it must update.
        notes:
          type: string
          description: Markdown.
        state:
          type: string
          enum:
          - staged
          - active
          - paused
          - superseded
          - rolled_back
        signed_metadata:
          type: string
          format: uuid
          description: 'ID of the ReleaseSignedMetadata. Empty while staged: the metadata is signed when the release
            becomes active.'
        released_by:
          type: string
          format: uuid
          description: ID of the MoonitoringUser. Who staged it.
        approved_by:
          type: string
          format: uuid
          description: ID of the MoonitoringUser that is a MoonitoringPerson. Required to become active when the
            channel requires approval. Must differ from `released_by` and from the build's `created_by`.
        released_at:
          type: string
          format: date-time
          description: When it became active; empty while staged.
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
      required:
      - id
      - channel
      - build
      - rollout_pct
      - state
      - released_by
      - created_at
      - updated_at
    ReleaseChannelAccess:
      description: Lists the Organizations that receive a channel of the organization audience. With no rows, every
        Organization that passes the channel's rule receives it; with rows, only those listed.
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: Key.
        channel:
          type: string
          format: uuid
          description: ID of the ReleaseChannel.
        organization:
          type: string
          format: uuid
          description: ID of the Organization. `(channel, organization)` is unique.
        granted_by:
          type: string
          format: uuid
          description: ID of the MoonitoringUser.
        created_at:
          type: string
          format: date-time
      required:
      - id
      - channel
      - organization
      - granted_by
      - created_at
    ReleaseTesterGroup:
      description: 'A named list of e-mail addresses that may receive the channels it is attached to, whatever their
        audience, Organization or role: the internal and closed testing of the app stores. A group is reusable across
        channels and applications, has a ceiling on its size, and every change to it is an audit event.'
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: Key.
        name:
          type: string
          description: Unique. e.g. internal-qa, coop-beta-2026.
        channels:
          type: array
          items:
            type: string
            format: uuid
          description: ID of the ReleaseChannel. The channels this group opens. `(group, channel)` is unique.
        max_testers:
          type: integer
          default: 100
          description: A ceiling the Console enforces, as the stores do; raise it on purpose, not by accident.
        archived_at:
          type: string
          format: date-time
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
      required:
      - id
      - name
      - max_testers
      - created_at
      - updated_at
    ReleaseTester:
      description: One e-mail address in a tester group. The person proves the address by signing in with it (through
        `access`, or with a one-time code when the address is not a registered user), and that proof is what the
        download page, enrolment and update checks compare with this row. A revoked tester keeps what is installed
        and receives nothing more.
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: Key.
        group:
          type: string
          format: uuid
          description: ID of the ReleaseTesterGroup.
        email:
          type: string
          description: Lower-cased. `(group, email)` is unique.
        invited_by:
          type: string
          format: uuid
          description: ID of the MoonitoringUser.
        invited_at:
          type: string
          format: date-time
        accepted_at:
          type: string
          format: date-time
          description: First time the address was proven; empty while the invitation is pending.
        revoked_at:
          type: string
          format: date-time
          description: A revoked tester keeps what is installed and receives nothing more.
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
      required:
      - id
      - group
      - email
      - invited_by
      - invited_at
      - created_at
      - updated_at
    ReleaseChannelInput:
      type: object
      description: Input to create or change a ReleaseChannel; server-managed fields are left out.
      properties:
        application:
          type: string
          format: uuid
          description: ID of the ReleaseApplication.
        name:
          type: string
          description: '`(application, name)` is unique.'
        listed:
          type: boolean
          default: true
          description: Shown in the client's channel picker and on the download page to those who may receive it.
            An unlisted channel is reached only by its enrolment link; the access rule applies the same. Replaces
            visibility (public, restricted, hidden), which mixed who may access with what is advertised.
        requires_approval:
          type: boolean
          default: true
          description: Always true when the application's audience is public.
        required_capabilities:
          type: array
          items:
            type: string
          description: 'Capabilities of the audience''s catalog (OrganizationRoleCapabilityEnum for organization,
            MoonitoringCapabilityEnum for moonitoring; none for public), all of which the caller''s role must hold.
            Empty: everyone in the audience.'
        required_features:
          type: array
          items:
            type: string
          description: 'Entitlement features of Entitlement the caller''s Organization must hold, all active; only
            for the organization audience. Empty: no entitlement needed.'
      required:
      - application
      - name
      - listed
      - requires_approval
      additionalProperties: false
    ReleaseInput:
      type: object
      description: Stages a ready build on the channel. It waits as staged, or becomes active at once on a channel
        that does not require approval.
      properties:
        build:
          type: string
          format: uuid
          description: ID of the ReleaseBuild. Must belong to the channel's application, with status ready.
        rollout_pct:
          type: integer
          description: '`0..100`: share of installations that receive it (see ReleaseInstallation, `ReleaseInstallation.rollout_bucket`).'
        min_build_number:
          type: integer
          description: Installations below it must update.
        notes:
          type: string
          description: Markdown.
      required:
      - build
      - rollout_pct
      additionalProperties: false
    RollbackRequest:
      type: object
      description: Makes current again a build that was already active on this channel and is not revoked; no second
        approval.
      properties:
        build:
          type: string
          format: uuid
        notes:
          type: string
      required:
      - build
    ChannelAccessInput:
      type: object
      description: Adds a recipient Organization to a channel of the organization audience.
      properties:
        organization:
          type: string
          format: uuid
      required:
      - organization
    ReleaseTesterGroupInput:
      type: object
      description: Input to create or change a ReleaseTesterGroup; server-managed fields are left out.
      properties:
        name:
          type: string
          description: Unique. e.g. internal-qa, coop-beta-2026.
        max_testers:
          type: integer
          default: 100
          description: A ceiling the Console enforces, as the stores do; raise it on purpose, not by accident.
        archived:
          type: boolean
          default: false
          description: Archive it, or bring it back; an archived one is kept and offered to nobody (decided 2026-11-05).
      required:
      - name
      - max_testers
      additionalProperties: false
    ReleaseTesterInput:
      type: object
      description: Invites an e-mail into a group.
      properties:
        email:
          type: string
          format: email
      required:
      - email
    DownloadPage:
      type: object
      description: 'What the caller may download for an application: per channel they may receive, the current build
        and its installer, through short-lived signed URLs.'
      properties:
        application:
          type: object
          properties:
            id:
              type: string
              format: uuid
            name:
              type: string
            kind:
              type: string
          required:
          - id
          - name
        channels:
          type: array
          items:
            type: object
            properties:
              channel:
                $ref: '#/components/schemas/ReleaseChannel'
              release:
                $ref: '#/components/schemas/Release'
              version_label:
                type: string
              installers:
                type: array
                items:
                  type: object
                  properties:
                    platform:
                      type: string
                      format: uuid
                    download:
                      $ref: ../../../../common/v1/schemas.yaml#/components/schemas/SignedUrl
                    size:
                      type: integer
                  required:
                  - platform
                  - download
            required:
            - channel
            - release
      required:
      - application
      - channels
  securitySchemes:
    bearer:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: 'The short-lived token signed by `access`: an Organization user token, a staff token or a client
        token, as the operation''s audience says.'
