]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blobdiff - support/doc/api/openapi.yaml
Instance homepage support (#4007)
[github/Chocobozzz/PeerTube.git] / support / doc / api / openapi.yaml
index 4fbf5b05521ea5ee77676738b8fe2c48b06aa48e..74910c3133eb7df54fe89aa6526bddd08ede8731 100644 (file)
@@ -1,15 +1,15 @@
 openapi: 3.0.0
 info:
   title: PeerTube
-  version: 3.1.0
+  version: 3.2.0
   contact:
     name: PeerTube Community
-    url: 'https://joinpeertube.org'
+    url: https://joinpeertube.org
   license:
     name: AGPLv3.0
-    url: 'https://github.com/Chocobozzz/PeerTube/blob/master/LICENSE'
+    url: https://github.com/Chocobozzz/PeerTube/blob/master/LICENSE
   x-logo:
-    url: 'https://joinpeertube.org/img/brand.png'
+    url: https://joinpeertube.org/img/brand.png
     altText: PeerTube Project Homepage
   description: |
     The PeerTube API is built on HTTP(S) and is RESTful. You can use your favorite
@@ -22,13 +22,13 @@ info:
     - [Kotlin](https://framagit.org/framasoft/peertube/clients/kotlin)
 
     See the [REST API quick start](https://docs.joinpeertube.org/api-rest-getting-started) for a few
-    examples of using with the PeerTube API.
+    examples of using the PeerTube API.
 
     # Authentication
 
     When you sign up for an account on a PeerTube instance, you are given the possibility
-    to generate sessions on it, and authenticate there using a session token. Only __one
-    session token can currently be used at a time__.
+    to generate sessions on it, and authenticate there using an access token. Only __one
+    access token can currently be used at a time__.
 
     ## Roles
 
@@ -38,28 +38,60 @@ info:
     # Errors
 
     The API uses standard HTTP status codes to indicate the success or failure
-    of the API call. The body of the response will be JSON in the following
-    format.
+    of the API call.
 
     ```
+    HTTP 1.1 404 Not Found
+    Content-Type: application/json
+
+    {
+      "errorCode": 1
+      "error": "Account not found"
+    }
+    ```
+
+    We provide error codes for [a growing number of cases](https://github.com/Chocobozzz/PeerTube/blob/develop/shared/models/server/server-error-code.enum.ts),
+    but it is still optional.
+
+    ### Validation errors
+
+    Each parameter is evaluated on its own against a set of rules before the route validator
+    proceeds with potential testing involving parameter combinations. Errors coming from Validation
+    errors appear earlier and benefit from a more detailed error type:
+
+    ```
+    HTTP 1.1 400 Bad Request
+    Content-Type: application/json
+
     {
-      "code": "unauthorized_request", // example inner error code
-      "error": "Token is invalid." // example exposed error message
+      "errors": {
+        "id": {
+          "value": "a117eb-c6a9-4756-bb09-2a956239f",
+          "msg": "Should have a valid id",
+          "param": "id",
+          "location": "params"
+        }
+      }
     }
     ```
 
+    Where `id` is the name of the field concerned by the error, within the route definition.
+    `errors.<field>.location` can be either 'params', 'body', 'header', 'query' or 'cookies', and
+    `errors.<field>.value` reports the value that didn't pass validation whose `errors.<field>.msg`
+    is about.
+
     # Rate limits
 
     We are rate-limiting all endpoints of PeerTube's API. Custom values can be set by administrators:
 
-    | Endpoint                | Calls            | Time frame                |
-    |-------------------------|------------------|---------------------------|
-    | `/*`                    | 50               | 10 seconds                |
-    | `POST /users/token`     | 15               | 5 minutes                 |
-    | `POST /users/register`  | 2¹               | 5 minutes                 |
-    | `POST /users/ask-send-verify-email` | 3    | 5 minutes                 |
+    | Endpoint (prefix: `/api/v1`) | Calls         | Time frame   |
+    |------------------------------|---------------|--------------|
+    | `/*`                         | 50            | 10 seconds   |
+    | `POST /users/token`          | 15            | 5 minutes    |
+    | `POST /users/register`       | 2<sup>*</sup> | 5 minutes    |
+    | `POST /users/ask-send-verify-email` | 3      | 5 minutes    |
 
-    Depending on the endpoint, ¹failed requests are not taken into account. A service
+    Depending on the endpoint, <sup>*</sup>failed requests are not taken into account. A service
     limit is announced by a `429 Too Many Requests` status code.
 
     You can get details about the current state of your rate limit by reading the
@@ -67,13 +99,37 @@ info:
 
     | Header                  | Description                                                |
     |-------------------------|------------------------------------------------------------|
-    | X-RateLimit-Limit       | Number of max requests allowed in the current time period  |
-    | X-RateLimit-Remaining   | Number of remaining requests in the current time period    |
-    | X-RateLimit-Reset       | Timestamp of end of current time period as UNIX timestamp  |
-    | Retry-After             | Seconds to delay after the first `429` is received         |
+    | `X-RateLimit-Limit`     | Number of max requests allowed in the current time period  |
+    | `X-RateLimit-Remaining` | Number of remaining requests in the current time period    |
+    | `X-RateLimit-Reset`     | Timestamp of end of current time period as UNIX timestamp  |
+    | `Retry-After`           | Seconds to delay after the first `429` is received         |
+
+    # CORS
+
+    This API features [Cross-Origin Resource Sharing (CORS)](https://fetch.spec.whatwg.org/),
+    allowing cross-domain communication from the browser for some routes:
+
+    | Endpoint                    |
+    |------------------------- ---|
+    | `/api/*`                    |
+    | `/download/*`               |
+    | `/lazy-static/*`            |
+    | `/live/segments-sha256/*`   |
+    | `/.well-known/webfinger`    |
+
+    In addition, all routes serving ActivityPub are CORS-enabled for all origins.
 externalDocs:
   url: https://docs.joinpeertube.org/api-rest-reference.html
 tags:
+  - name: Register
+    description: |
+      As a visitor, you can use this API to open an account (if registrations are open on
+      that PeerTube instance). As an admin, you should use the dedicated [User creation
+      API](#operation/addUser) instead.
+  - name: Session
+    x-displayName: Login/Logout
+    description: |
+      Sessions deal with access tokens over time. Only __one session token can currently be used at a time__.
   - name: Accounts
     description: >
       Accounts encompass remote accounts discovered across the federation,
@@ -191,12 +247,18 @@ tags:
 
       Administrators can also enable the use of a remote search system, indexing
       videos and channels not could be not federated by the instance.
+  - name: Homepage
+    description: Get and update the custom homepage
   - name: Video Mirroring
     description: |
       PeerTube instances can mirror videos from one another, and help distribute some videos.
 
-      For importing videos as your own, refer to [video imports](#tag/Video-Upload/paths/~1videos~1imports/post).
+      For importing videos as your own, refer to [video imports](#operation/importVideo).
 x-tagGroups:
+  - name: Auth
+    tags:
+      - Register
+      - Session
   - name: Accounts
     tags:
       - Accounts
@@ -221,6 +283,9 @@ x-tagGroups:
   - name: Search
     tags:
       - Search
+  - name: Custom pages
+    tags:
+      - Homepage
   - name: Moderation
     tags:
       - Abuses
@@ -242,6 +307,7 @@ paths:
       tags:
         - Accounts
       summary: Get an account
+      operationId: getAccount
       parameters:
         - $ref: '#/components/parameters/name'
       responses:
@@ -253,12 +319,14 @@ paths:
                 $ref: '#/components/schemas/Account'
         '404':
           description: account not found
+
   '/accounts/{name}/videos':
     get:
       tags:
         - Accounts
         - Video
       summary: 'List videos of an account'
+      operationId: getAccountVideos
       parameters:
         - $ref: '#/components/parameters/name'
         - $ref: '#/components/parameters/categoryOneOf'
@@ -314,11 +382,13 @@ paths:
             json = r.json()
 
             print(json)
+
   /accounts:
     get:
       tags:
         - Accounts
       summary: List accounts
+      operationId: getAccounts
       parameters:
         - $ref: '#/components/parameters/start'
         - $ref: '#/components/parameters/count'
@@ -332,11 +402,13 @@ paths:
                 type: array
                 items:
                   $ref: '#/components/schemas/Account'
+
   /config:
     get:
       tags:
         - Config
       summary: Get instance public configuration
+      operationId: getConfig
       responses:
         '200':
           description: successful operation
@@ -347,9 +419,11 @@ paths:
               examples:
                 nightly:
                   externalValue: https://peertube2.cpy.re/api/v1/config
+
   /config/about:
     get:
       summary: Get instance "About" information
+      operationId: getAbout
       tags:
         - Config
       responses:
@@ -362,9 +436,11 @@ paths:
               examples:
                 nightly:
                   externalValue: https://peertube2.cpy.re/api/v1/config/about
+
   /config/custom:
     get:
       summary: Get instance runtime configuration
+      operationId: getCustomConfig
       tags:
         - Config
       security:
@@ -379,6 +455,7 @@ paths:
                 $ref: '#/components/schemas/ServerConfigCustom'
     put:
       summary: Set instance runtime configuration
+      operationId: putCustomConfig
       tags:
         - Config
       security:
@@ -395,6 +472,7 @@ paths:
               - webtorrent and hls are disabled with transcoding enabled - you need at least one enabled
     delete:
       summary: Delete instance runtime configuration
+      operationId: delCustomConfig
       tags:
         - Config
       security:
@@ -403,9 +481,45 @@ paths:
       responses:
         '200':
           description: successful operation
+
+  /custom-pages/homepage/instance:
+    get:
+      summary: Get instance custom homepage
+      tags:
+        - Homepage
+      responses:
+        '404':
+          description: No homepage set
+        '200':
+          description: successful operation
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/CustomHomepage'
+    put:
+      summary: Set instance custom homepage
+      tags:
+        - Homepage
+      security:
+        - OAuth2:
+          - admin
+      requestBody:
+        content:
+          application/json:
+            schema:
+              type: object
+              properties:
+                content:
+                  type: string
+                  description: content of the homepage, that will be injected in the client
+      responses:
+        '204':
+          description: successful operation
+
   /jobs/{state}:
     get:
       summary: List instance jobs
+      operationId: getJobs
       security:
         - OAuth2:
           - admin
@@ -445,66 +559,108 @@ paths:
                     maxItems: 100
                     items:
                       $ref: '#/components/schemas/Job'
-  '/server/following/{host}':
+
+  /server/followers:
+    get:
+      tags:
+        - Instance Follows
+      summary: List instances following the server
+      parameters:
+        - $ref: '#/components/parameters/followState'
+        - $ref: '#/components/parameters/actorType'
+        - $ref: '#/components/parameters/start'
+        - $ref: '#/components/parameters/count'
+        - $ref: '#/components/parameters/sort'
+      responses:
+        '200':
+          description: successful operation
+          content:
+            application/json:
+              schema:
+                type: object
+                properties:
+                  total:
+                    type: integer
+                    example: 1
+                  data:
+                    type: array
+                    items:
+                      $ref: '#/components/schemas/Follow'
+
+  '/server/followers/{nameWithHost}':
     delete:
+      summary: Remove or reject a follower to your server
       security:
         - OAuth2:
           - admin
       tags:
         - Instance Follows
-      summary: Unfollow a server
       parameters:
-        - name: host
+        - name: nameWithHost
           in: path
           required: true
-          description: 'The host to unfollow '
+          description: The remote actor handle to remove from your followers
           schema:
             type: string
-            format: hostname
+            format: email
       responses:
-        '201':
+        '204':
           description: successful operation
-  /server/followers:
-    get:
+        '404':
+          description: follower not found
+
+  '/server/followers/{nameWithHost}/reject':
+    post:
+      summary: Reject a pending follower to your server
+      security:
+        - OAuth2:
+          - admin
       tags:
         - Instance Follows
-      summary: List instance followers
       parameters:
-        - $ref: '#/components/parameters/start'
-        - $ref: '#/components/parameters/count'
-        - $ref: '#/components/parameters/sort'
+        - name: nameWithHost
+          in: path
+          required: true
+          description: The remote actor handle to remove from your followers
+          schema:
+            type: string
+            format: email
       responses:
-        '200':
+        '204':
           description: successful operation
-          content:
-            application/json:
-              schema:
-                type: array
-                items:
-                  $ref: '#/components/schemas/Follow'
+        '404':
+          description: follower not found
+
+  '/server/followers/{nameWithHost}/accept':
+    post:
+      summary: Accept a pending follower to your server
+      security:
+        - OAuth2:
+          - admin
+      tags:
+        - Instance Follows
+      parameters:
+        - name: nameWithHost
+          in: path
+          required: true
+          description: The remote actor handle to remove from your followers
+          schema:
+            type: string
+            format: email
+      responses:
+        '204':
+          description: successful operation
+        '404':
+          description: follower not found
+
   /server/following:
     get:
       tags:
         - Instance Follows
       summary: List instances followed by the server
       parameters:
-        - name: state
-          in: query
-          schema:
-            type: string
-            enum:
-              - pending
-              - accepted
-        - name: actorType
-          in: query
-          schema:
-            type: string
-            enum:
-              - Person
-              - Application
-              - Group
-              - Service
-              - Organization
+        - $ref: '#/components/parameters/followState'
+        - $ref: '#/components/parameters/actorType'
         - $ref: '#/components/parameters/start'
         - $ref: '#/components/parameters/count'
         - $ref: '#/components/parameters/sort'
@@ -514,16 +670,22 @@ paths:
           content:
             application/json:
               schema:
-                type: array
-                items:
-                  $ref: '#/components/schemas/Follow'
+                type: object
+                properties:
+                  total:
+                    type: integer
+                    example: 1
+                  data:
+                    type: array
+                    items:
+                      $ref: '#/components/schemas/Follow'
     post:
       security:
         - OAuth2:
           - admin
       tags:
         - Instance Follows
-      summary: Follow a server
+      summary: Follow a list of servers
       responses:
         '204':
           description: successful operation
@@ -541,9 +703,33 @@ paths:
                     type: string
                     format: hostname
                   uniqueItems: true
+
+  '/server/following/{host}':
+    delete:
+      summary: Unfollow a server
+      security:
+        - OAuth2:
+          - admin
+      tags:
+        - Instance Follows
+      parameters:
+        - name: host
+          in: path
+          required: true
+          description: The host to unfollow
+          schema:
+            type: string
+            format: hostname
+      responses:
+        '204':
+          description: successful operation
+        '404':
+          description: host not found
+
   /users:
     post:
       summary: Create a user
+      operationId: addUser
       security:
         - OAuth2:
           - admin
@@ -558,18 +744,18 @@ paths:
                 $ref: '#/components/schemas/AddUserResponse'
           links:
             # GET /users/{id}
-            GetUserId:
-              operationId: getUserId
+            GetUser:
+              operationId: getUser
               parameters:
                 id: '$response.body#/user/id'
             # PUT /users/{id}
-            PutUserId:
-              operationId: putUserId
+            PutUser:
+              operationId: putUser
               parameters:
                 id: '$response.body#/user/id'
             # DELETE /users/{id}
-            DelUserId:
-              operationId: delUserId
+            DelUser:
+              operationId: delUser
               parameters:
                 id: '$response.body#/user/id'
         '403':
@@ -579,10 +765,13 @@ paths:
           application/json:
             schema:
               $ref: '#/components/schemas/AddUser'
-        description: User to create
+        description: |
+          If the smtp server is configured, you can leave the password empty and an email will be sent
+          asking the user to set it first.
         required: true
     get:
       summary: List users
+      operationId: getUsers
       security:
         - OAuth2:
           - admin
@@ -603,6 +792,7 @@ paths:
                 type: array
                 items:
                   $ref: '#/components/schemas/User'
+
   '/users/{id}':
     parameters:
       - $ref: '#/components/parameters/id'
@@ -613,7 +803,7 @@ paths:
           - admin
       tags:
         - Users
-      operationId: delUserId
+      operationId: delUser
       responses:
         '204':
           description: successful operation
@@ -623,7 +813,7 @@ paths:
         - OAuth2: []
       tags:
         - Users
-      operationId: getUserId
+      operationId: getUser
       parameters:
         - name: withStats
           in: query
@@ -648,7 +838,7 @@ paths:
         - OAuth2: []
       tags:
         - Users
-      operationId: putUserId
+      operationId: putUser
       responses:
         '204':
           description: successful operation
@@ -658,11 +848,120 @@ paths:
             schema:
               $ref: '#/components/schemas/UpdateUser'
         required: true
+
+  /oauth-clients/local:
+    get:
+      summary: Login prerequisite
+      description: You need to retrieve a client id and secret before [logging in](#operation/getOAuthToken).
+      operationId: getOAuthClient
+      tags:
+        - Session
+      responses:
+        '200':
+          description: successful operation
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/OAuthClient'
+          links:
+            UseOAuthClientToLogin:
+              operationId: getOAuthToken
+              parameters:
+                client_id: '$response.body#/client_id'
+                client_secret: '$response.body#/client_secret'
+      x-codeSamples:
+        - lang: Shell
+          source: |
+            API="https://peertube2.cpy.re/api/v1"
+
+            ## AUTH
+            curl -s "$API/oauth-clients/local"
+
+  /users/token:
+    post:
+      summary: Login
+      operationId: getOAuthToken
+      description: With your [client id and secret](#operation/getOAuthClient), you can retrieve an access and refresh tokens.
+      tags:
+        - Session
+      requestBody:
+        content:
+          application/x-www-form-urlencoded:
+            schema:
+              oneOf:
+                - $ref: '#/components/schemas/OAuthToken-password'
+                - $ref: '#/components/schemas/OAuthToken-refresh_token'
+              discriminator:
+                propertyName: grant_type
+                mapping:
+                  password: '#/components/schemas/OAuthToken-password'
+                  refresh_token: '#/components/schemas/OAuthToken-refresh_token'
+      responses:
+        '200':
+          description: successful operation
+          content:
+            application/json:
+              schema:
+                type: object
+                properties:
+                  token_type:
+                    type: string
+                    example: Bearer
+                  access_token:
+                    type: string
+                    example: 90286a0bdf0f7315d9d3fe8dabf9e1d2be9c97d0
+                    description: valid for 1 day
+                  refresh_token:
+                    type: string
+                    example: 2e0d675df9fc96d2e4ec8a3ebbbf45eca9137bb7
+                    description: valid for 2 weeks
+                  expires_in:
+                    type: integer
+                    minimum: 0
+                    example: 14399
+                  refresh_token_expires_in:
+                    type: integer
+                    minimum: 0
+                    example: 1209600
+      x-codeSamples:
+        - lang: Shell
+          source: |
+            ## DEPENDENCIES: jq
+            API="https://peertube2.cpy.re/api/v1"
+            USERNAME="<your_username>"
+            PASSWORD="<your_password>"
+
+            ## AUTH
+            client_id=$(curl -s "$API/oauth-clients/local" | jq -r ".client_id")
+            client_secret=$(curl -s "$API/oauth-clients/local" | jq -r ".client_secret")
+            curl -s "$API/users/token" \
+              --data client_id="$client_id" \
+              --data client_secret="$client_secret" \
+              --data grant_type=password \
+              --data username="$USERNAME" \
+              --data password="$PASSWORD" \
+              | jq -r ".access_token"
+
+  /users/revoke-token:
+    post:
+      summary: Logout
+      description: Revokes your access token and its associated refresh token, destroying your current session.
+      operationId: revokeOAuthToken
+      tags:
+        - Session
+      security:
+        - OAuth2: []
+      responses:
+        '200':
+          description: successful operation
+
   /users/register:
     post:
       summary: Register a user
+      operationId: registerUser
       tags:
         - Users
+        - Register
       responses:
         '204':
           description: successful operation
@@ -672,9 +971,55 @@ paths:
             schema:
               $ref: '#/components/schemas/RegisterUser'
         required: true
+
+  /users/{id}/verify-email:
+    post:
+      summary: Verify a user
+      operationId: verifyUser
+      description: |
+        Following a user registration, the new user will receive an email asking to click a link
+        containing a secret.
+      tags:
+        - Users
+        - Register
+      parameters:
+        - $ref: '#/components/parameters/id'
+      requestBody:
+        content:
+          application/json:
+            schema:
+              type: object
+              properties:
+                verificationString:
+                  type: string
+                  format: url
+                isPendingEmail:
+                  type: boolean
+              required:
+                - verificationString
+      responses:
+        '204':
+          description: successful operation
+        '403':
+          description: invalid verification string
+        '404':
+          description: user not found
+
+  /users/ask-send-verify-email:
+    post:
+      summary: Resend user verification link
+      operationId: resendEmailToVerifyUser
+      tags:
+        - Users
+        - Register
+      responses:
+        '204':
+          description: successful operation
+
   /users/me:
     get:
       summary: Get my user information
+      operationId: getUserInfo
       security:
         - OAuth2:
           - user
@@ -691,6 +1036,7 @@ paths:
                   $ref: '#/components/schemas/User'
     put:
       summary: Update my user information
+      operationId: putUserInfo
       security:
         - OAuth2:
           - user
@@ -705,6 +1051,7 @@ paths:
             schema:
               $ref: '#/components/schemas/UpdateMe'
         required: true
+
   /users/me/videos/imports:
     get:
       summary: Get video imports of my user
@@ -725,6 +1072,7 @@ paths:
             application/json:
               schema:
                 $ref: '#/components/schemas/VideoImportsList'
+
   /users/me/video-quota-used:
     get:
       summary: Get my user used quota
@@ -743,10 +1091,13 @@ paths:
                 properties:
                   videoQuotaUsed:
                     type: number
+                    description: The user video quota used so far in bytes
                     example: 16810141515
                   videoQuotaUsedDaily:
                     type: number
+                    description: The user video quota used today in bytes
                     example: 1681014151
+
   '/users/me/videos/{videoId}/rating':
     get:
       summary: Get rate of my user for a video
@@ -759,9 +1110,9 @@ paths:
         - name: videoId
           in: path
           required: true
-          description: 'The video id '
+          description: The video id
           schema:
-            type: string
+            $ref: '#/components/schemas/Video/properties/id'
       responses:
         '200':
           description: successful operation
@@ -769,6 +1120,7 @@ paths:
             application/json:
               schema:
                 $ref: '#/components/schemas/GetMeVideoRating'
+
   /users/me/videos:
     get:
       summary: Get videos of my user
@@ -789,6 +1141,7 @@ paths:
             application/json:
               schema:
                 $ref: '#/components/schemas/VideoListResponse'
+
   /users/me/subscriptions:
     get:
       summary: Get my user subscriptions
@@ -834,6 +1187,7 @@ paths:
       responses:
         '200':
           description: successful operation
+
   /users/me/subscriptions/exist:
     get:
       summary: Get if subscriptions exist for my user
@@ -851,6 +1205,7 @@ paths:
             application/json:
               schema:
                 type: object
+
   /users/me/subscriptions/videos:
     get:
       summary: List videos of subscriptions of my user
@@ -880,6 +1235,7 @@ paths:
             application/json:
               schema:
                 $ref: '#/components/schemas/VideoListResponse'
+
   '/users/me/subscriptions/{subscriptionHandle}':
     get:
       summary: Get subscription of my user
@@ -909,6 +1265,7 @@ paths:
       responses:
         '200':
           description: successful operation
+
   /users/me/notifications:
     get:
       summary: List my notifications
@@ -932,6 +1289,7 @@ paths:
             application/json:
               schema:
                 $ref: '#/components/schemas/NotificationListResponse'
+
   /users/me/notifications/read:
     post:
       summary: Mark notifications as read by their id
@@ -955,6 +1313,7 @@ paths:
       responses:
         '204':
           description: successful operation
+
   /users/me/notifications/read-all:
     post:
       summary: Mark all my notification as read
@@ -965,6 +1324,7 @@ paths:
       responses:
         '204':
           description: successful operation
+
   /users/me/notification-settings:
     put:
       summary: Update my notification settings
@@ -1005,6 +1365,7 @@ paths:
       responses:
         '204':
           description: successful operation
+
   /users/me/history/videos:
     get:
       summary: List watched videos history
@@ -1023,6 +1384,7 @@ paths:
             application/json:
               schema:
                 $ref: '#/components/schemas/VideoListResponse'
+
   /users/me/history/videos/remove:
     post:
       summary: Clear video history
@@ -1043,6 +1405,7 @@ paths:
       responses:
         '204':
           description: successful operation
+
   /users/me/avatar/pick:
     post:
       summary: Update my user avatar
@@ -1075,12 +1438,13 @@ paths:
               type: object
               properties:
                 avatarfile:
-                  description: The file to upload.
+                  description: The file to upload
                   type: string
                   format: binary
             encoding:
               avatarfile:
                 contentType: image/png, image/jpeg
+
   /users/me/avatar:
     delete:
       summary: Delete my avatar
@@ -1102,6 +1466,7 @@ paths:
       responses:
         '200':
           description: successful operation
+
   '/videos/ownership/{id}/accept':
     post:
       summary: Accept ownership change request
@@ -1118,6 +1483,7 @@ paths:
           description: cannot terminate an ownership change of another user
         '404':
           description: video owneship change not found
+
   '/videos/ownership/{id}/refuse':
     post:
       summary: Refuse ownership change request
@@ -1134,6 +1500,7 @@ paths:
           description: cannot terminate an ownership change of another user
         '404':
           description: video owneship change not found
+
   '/videos/{id}/give-ownership':
     post:
       summary: Request ownership change
@@ -1161,9 +1528,11 @@ paths:
           description: changing video ownership to a remote account is not supported yet
         '404':
           description: video not found
+
   /videos:
     get:
       summary: List videos
+      operationId: getVideos
       tags:
         - Video
       parameters:
@@ -1186,6 +1555,7 @@ paths:
             application/json:
               schema:
                 $ref: '#/components/schemas/VideoListResponse'
+
   /videos/categories:
     get:
       summary: List available video categories
@@ -1204,6 +1574,7 @@ paths:
               examples:
                 nightly:
                   externalValue: https://peertube2.cpy.re/api/v1/videos/categories
+
   /videos/licences:
     get:
       summary: List available video licences
@@ -1222,6 +1593,7 @@ paths:
               examples:
                 nightly:
                   externalValue: https://peertube2.cpy.re/api/v1/videos/licences
+
   /videos/languages:
     get:
       summary: List available video languages
@@ -1240,6 +1612,7 @@ paths:
               examples:
                 nightly:
                   externalValue: https://peertube2.cpy.re/api/v1/videos/languages
+
   /videos/privacies:
     get:
       summary: List available video privacy policies
@@ -1258,9 +1631,11 @@ paths:
               examples:
                 nightly:
                   externalValue: https://peertube2.cpy.re/api/v1/videos/privacies
+
   '/videos/{id}':
     put:
       summary: Update a video
+      operationId: putVideo
       security:
         - OAuth2: []
       tags:
@@ -1300,7 +1675,7 @@ paths:
                   type: string
                 support:
                   description: A text tell the audience how to support the video creator
-                  example: Please support my work on <insert crowdfunding plateform>! <3
+                  example: Please support our work on https://soutenir.framasoft.org/en/ <3
                   type: string
                 nsfw:
                   description: Whether or not this video contains sensitive content
@@ -1335,6 +1710,7 @@ paths:
                 contentType: image/jpeg
     get:
       summary: Get a video
+      operationId: getVideo
       tags:
         - Video
       parameters:
@@ -1348,6 +1724,7 @@ paths:
                 $ref: '#/components/schemas/VideoDetails'
     delete:
       summary: Delete a video
+      operationId: delVideo
       security:
         - OAuth2: []
       tags:
@@ -1357,9 +1734,11 @@ paths:
       responses:
         '204':
           description: successful operation
+
   '/videos/{id}/description':
     get:
       summary: Get complete video description
+      operationId: getVideoDesc
       tags:
         - Video
       parameters:
@@ -1370,7 +1749,13 @@ paths:
           content:
             application/json:
               schema:
+                nullable: true
                 type: string
+                minLength: 3
+                maxLength: 10000
+                example: |
+                  **[Want to help to translate this video?](https://weblate.framasoft.org/projects/what-is-peertube-video/)**\r\n\r\n**Take back the control of your videos! [#JoinPeertube](https://joinpeertube.org)**
+
   '/videos/{id}/views':
     post:
       summary: Add a view to a video
@@ -1381,6 +1766,7 @@ paths:
       responses:
         '204':
           description: successful operation
+
   '/videos/{id}/watching':
     put:
       summary: Set watching progress of a video
@@ -1399,6 +1785,7 @@ paths:
       responses:
         '204':
           description: successful operation
+
   /videos/upload:
     post:
       summary: Upload a video
@@ -1455,26 +1842,27 @@ paths:
             FILE_PATH="<your_file_path>"
             CHANNEL_ID="<your_channel_id>"
             NAME="<video_name>"
+            API="https://peertube2.cpy.re/api/v1"
 
-            API_PATH="https://peertube2.cpy.re/api/v1"
             ## AUTH
-            client_id=$(curl -s "$API_PATH/oauth-clients/local" | jq -r ".client_id")
-            client_secret=$(curl -s "$API_PATH/oauth-clients/local" | jq -r ".client_secret")
-            token=$(curl -s "$API_PATH/users/token" \
+            client_id=$(curl -s "$API/oauth-clients/local" | jq -r ".client_id")
+            client_secret=$(curl -s "$API/oauth-clients/local" | jq -r ".client_secret")
+            token=$(curl -s "$API/users/token" \
               --data client_id="$client_id" \
               --data client_secret="$client_secret" \
               --data grant_type=password \
-              --data response_type=code \
               --data username="$USERNAME" \
               --data password="$PASSWORD" \
               | jq -r ".access_token")
+
             ## VIDEO UPLOAD
-            curl -s "$API_PATH/videos/upload" \
+            curl -s "$API/videos/upload" \
               -H "Authorization: Bearer $token" \
               --max-time 600 \
               --form videofile=@"$FILE_PATH" \
               --form channelId=$CHANNEL_ID \
               --form name="$NAME"
+
   /videos/upload-resumable:
     post:
       summary: Initialize the resumable upload of a video
@@ -1636,6 +2024,7 @@ paths:
               schema:
                 type: number
                 example: 0
+
   /videos/imports:
     post:
       summary: Import a video
@@ -1650,75 +2039,7 @@ paths:
         content:
           multipart/form-data:
             schema:
-              type: object
-              properties:
-                torrentfile:
-                  description: Torrent File
-                  type: string
-                  format: binary
-                targetUrl:
-                  description: HTTP target URL
-                  type: string
-                magnetUri:
-                  description: Magnet URI
-                  type: string
-                channelId:
-                  description: Channel id that will contain this video
-                  type: integer
-                thumbnailfile:
-                  description: Video thumbnail file
-                  type: string
-                  format: binary
-                previewfile:
-                  description: Video preview file
-                  type: string
-                  format: binary
-                privacy:
-                  $ref: '#/components/schemas/VideoPrivacySet'
-                category:
-                  $ref: '#/components/schemas/VideoCategorySet'
-                licence:
-                  $ref: '#/components/schemas/VideoLicenceSet'
-                language:
-                  $ref: '#/components/schemas/VideoLanguageSet'
-                description:
-                  description: Video description
-                  type: string
-                waitTranscoding:
-                  description: Whether or not we wait transcoding before publish the video
-                  type: boolean
-                support:
-                  description: A text tell the audience how to support the video creator
-                  example: Please support my work on <insert crowdfunding plateform>! <3
-                  type: string
-                nsfw:
-                  description: Whether or not this video contains sensitive content
-                  type: boolean
-                name:
-                  description: Video name
-                  type: string
-                  minLength: 3
-                  maxLength: 120
-                tags:
-                  description: Video tags (maximum 5 tags each between 2 and 30 characters)
-                  type: array
-                  minItems: 1
-                  maxItems: 5
-                  items:
-                    type: string
-                    minLength: 2
-                    maxLength: 30
-                commentsEnabled:
-                  description: Enable or disable comments for this video
-                  type: boolean
-                downloadEnabled:
-                  description: Enable or disable downloading for this video
-                  type: boolean
-                scheduleUpdate:
-                  $ref: '#/components/schemas/VideoScheduledUpdate'
-              required:
-                - channelId
-                - name
+              $ref: '#/components/schemas/VideoCreateImport'
             encoding:
               torrentfile:
                 contentType: application/x-bittorrent
@@ -1743,7 +2064,7 @@ paths:
   /videos/live:
     post:
       summary: Create a live
-      operationId: createLive
+      operationId: addLive
       security:
         - OAuth2: []
       tags:
@@ -1757,7 +2078,7 @@ paths:
               schema:
                 $ref: '#/components/schemas/VideoUploadResponse'
         '403':
-          description: Live is not enabled, allow replay is not enabled, or max instance/user live videos limit is exceeded
+          description: live is not enabled, allow replay is not enabled, or max instance/user live videos limit is exceeded
       requestBody:
         content:
           multipart/form-data:
@@ -1793,7 +2114,7 @@ paths:
                   type: string
                 support:
                   description: A text tell the audience how to support the creator
-                  example: Please support my work on <insert crowdfunding plateform>! <3
+                  example: Please support our work on https://soutenir.framasoft.org/en/ <3
                   type: string
                 nsfw:
                   description: Whether or not this live video/replay contains sensitive content
@@ -1862,11 +2183,11 @@ paths:
               $ref: '#/components/schemas/LiveVideoUpdate'
       responses:
         '204':
-          description: Successful operation
+          description: successful operation
         '400':
-          description: Bad parameters or trying to update a live that has already started
+          description: bad parameters or trying to update a live that has already started
         '403':
-          description: Trying to save replay of the live but saving replay is not enabled on the instance
+          description: trying to save replay of the live but saving replay is not enabled on the instance
 
   /users/me/abuses:
     get:
@@ -1991,7 +2312,6 @@ paths:
                     type: array
                     items:
                       $ref: '#/components/schemas/Abuse'
-
     post:
       summary: Report an abuse
       security:
@@ -2017,13 +2337,16 @@ paths:
                   properties:
                     id:
                       description: Video id to report
-                      type: number
+                      allOf:
+                        - $ref: '#/components/schemas/Video/properties/id'
                     startAt:
                       type: integer
+                      format: seconds
                       description: Timestamp in the video that marks the beginning of the report
                       minimum: 0
                     endAt:
                       type: integer
+                      format: seconds
                       description: Timestamp in the video that marks the ending of the report
                       minimum: 0
                 comment:
@@ -2031,20 +2354,32 @@ paths:
                   properties:
                     id:
                       description: Comment id to report
-                      type: number
+                      allOf:
+                        - $ref: '#/components/schemas/VideoComment/properties/id'
                 account:
                   type: object
                   properties:
                     id:
                       description: Account id to report
-                      type: number
+                      type: integer
               required:
                 - reason
       responses:
-        '204':
+        '200':
           description: successful operation
+          content:
+            application/json:
+              schema:
+                type: object
+                properties:
+                  abuse:
+                    type: object
+                    properties:
+                      id:
+                        $ref: '#/components/schemas/id'
         '400':
           description: incorrect request parameters
+
   '/abuses/{abuseId}':
     put:
       summary: Update an abuse
@@ -2089,6 +2424,7 @@ paths:
           description: successful operation
         '404':
           description: block not found
+
   '/abuses/{abuseId}/messages':
     get:
       summary: List messages of an abuse
@@ -2104,10 +2440,15 @@ paths:
           content:
             application/json:
               schema:
-                type: array
-                items:
-                  $ref: '#/components/schemas/AbuseMessage'
-
+                type: object
+                properties:
+                  total:
+                    type: integer
+                    example: 1
+                  data:
+                    type: array
+                    items:
+                      $ref: '#/components/schemas/AbuseMessage'
     post:
       summary: Add message to an abuse
       security:
@@ -2135,6 +2476,7 @@ paths:
           description: successful operation
         '400':
           description: incorrect request parameters
+
   '/abuses/{abuseId}/messages/{abuseMessageId}':
     delete:
       summary: Delete an abuse message
@@ -2152,6 +2494,7 @@ paths:
   '/videos/{id}/blacklist':
     post:
       summary: Block a video
+      operationId: addVideoBlock
       security:
         - OAuth2:
           - admin
@@ -2165,6 +2508,7 @@ paths:
           description: successful operation
     delete:
       summary: Unblock a video by its id
+      operationId: delVideoBlock
       security:
         - OAuth2:
           - admin
@@ -2178,11 +2522,13 @@ paths:
           description: successful operation
         '404':
           description: block not found
+
   /videos/blacklist:
     get:
       tags:
         - Video Blocks
       summary: List video blocks
+      operationId: getVideoBlocks
       security:
         - OAuth2:
           - admin
@@ -2224,9 +2570,11 @@ paths:
                     type: array
                     items:
                       $ref: '#/components/schemas/VideoBlacklist'
+
   /videos/{id}/captions:
     get:
       summary: List captions of a video
+      operationId: getVideoCaptions
       tags:
         - Video Captions
       parameters:
@@ -2246,9 +2594,11 @@ paths:
                     type: array
                     items:
                       $ref: '#/components/schemas/VideoCaption'
+
   /videos/{id}/captions/{captionLanguage}:
     put:
       summary: Add or replace a video caption
+      operationId: addVideoCaption
       security:
         - OAuth2:
           - user
@@ -2277,6 +2627,7 @@ paths:
           description: video or language not found
     delete:
       summary: Delete a video caption
+      operationId: delVideoCaption
       security:
         - OAuth2:
           - user
@@ -2290,9 +2641,11 @@ paths:
           description: successful operation
         '404':
           description: video or language or caption for that language not found
+
   /video-channels:
     get:
       summary: List video channels
+      operationId: getVideoChannels
       tags:
         - Video Channels
       parameters:
@@ -2308,6 +2661,7 @@ paths:
                 $ref: '#/components/schemas/VideoChannelList'
     post:
       summary: Create a video channel
+      operationId: addVideoChannel
       security:
         - OAuth2: []
       tags:
@@ -2315,14 +2669,26 @@ paths:
       responses:
         '204':
           description: successful operation
+          content:
+            application/json:
+              schema:
+                type: object
+                properties:
+                  videoChannel:
+                    type: object
+                    properties:
+                      id:
+                        $ref: '#/components/schemas/VideoChannel/properties/id'
       requestBody:
         content:
           application/json:
             schema:
               $ref: '#/components/schemas/VideoChannelCreate'
+
   '/video-channels/{channelHandle}':
     get:
       summary: Get a video channel
+      operationId: getVideoChannel
       tags:
         - Video Channels
       parameters:
@@ -2336,6 +2702,7 @@ paths:
                 $ref: '#/components/schemas/VideoChannel'
     put:
       summary: Update a video channel
+      operationId: putVideoChannel
       security:
         - OAuth2: []
       tags:
@@ -2352,6 +2719,7 @@ paths:
               $ref: '#/components/schemas/VideoChannelUpdate'
     delete:
       summary: Delete a video channel
+      operationId: delVideoChannel
       security:
         - OAuth2: []
       tags:
@@ -2361,9 +2729,11 @@ paths:
       responses:
         '204':
           description: successful operation
+
   '/video-channels/{channelHandle}/videos':
     get:
       summary: List videos of a video channel
+      operationId: getVideoChannelVideos
       tags:
         - Video
         - Video Channels
@@ -2388,6 +2758,7 @@ paths:
             application/json:
               schema:
                 $ref: '#/components/schemas/VideoListResponse'
+
   '/video-channels/{channelHandle}/avatar/pick':
     post:
       summary: Update channel avatar
@@ -2428,6 +2799,7 @@ paths:
             encoding:
               avatarfile:
                 contentType: image/png, image/jpeg
+
   '/video-channels/{channelHandle}/avatar':
     delete:
       summary: Delete channel avatar
@@ -2441,7 +2813,6 @@ paths:
         '204':
           description: successful operation
 
-
   '/video-channels/{channelHandle}/banner/pick':
     post:
       summary: Update channel banner
@@ -2482,6 +2853,7 @@ paths:
             encoding:
               bannerfile:
                 contentType: image/png, image/jpeg
+
   '/video-channels/{channelHandle}/banner':
     delete:
       summary: Delete channel banner
@@ -2541,8 +2913,8 @@ paths:
                       $ref: '#/components/schemas/VideoPlaylist'
     post:
       summary: Create a video playlist
-      description: 'If the video playlist is set as public, the videoChannelId is mandatory.'
-      operationId: createPlaylist
+      description: If the video playlist is set as public, `videoChannelId` is mandatory.
+      operationId: addPlaylist
       security:
         - OAuth2: []
       tags:
@@ -2559,9 +2931,9 @@ paths:
                     type: object
                     properties:
                       id:
-                        type: integer
+                        $ref: '#/components/schemas/VideoPlaylist/properties/id'
                       uuid:
-                        $ref: '#/components/schemas/UUIDv4'
+                        $ref: '#/components/schemas/VideoPlaylist/properties/uuid'
       requestBody:
         content:
           multipart/form-data:
@@ -2582,22 +2954,25 @@ paths:
                 description:
                   description: Video playlist description
                   type: string
+                  minLength: 3
+                  maxLength: 1000
                 videoChannelId:
+                  allOf:
+                    - $ref: '#/components/schemas/id'
                   description: Video channel in which the playlist will be published
-                  type: integer
               required:
                 - displayName
             encoding:
               thumbnailfile:
                 contentType: image/jpeg
 
-  /video-playlists/{id}:
+  /video-playlists/{playlistId}:
     get:
       summary: Get a video playlist
       tags:
         - Video Playlists
       parameters:
-        - $ref: '#/components/parameters/idOrUUID'
+        - $ref: '#/components/parameters/playlistId'
       responses:
         '200':
           description: successful operation
@@ -2616,7 +2991,7 @@ paths:
         '204':
           description: successful operation
       parameters:
-        - $ref: '#/components/parameters/idOrUUID'
+        - $ref: '#/components/parameters/playlistId'
       requestBody:
         content:
           multipart/form-data:
@@ -2638,8 +3013,9 @@ paths:
                   description: Video playlist description
                   type: string
                 videoChannelId:
+                  allOf:
+                    - $ref: '#/components/schemas/id'
                   description: Video channel in which the playlist will be published
-                  type: integer
             encoding:
               thumbnailfile:
                 contentType: image/jpeg
@@ -2650,19 +3026,20 @@ paths:
       tags:
         - Video Playlists
       parameters:
-        - $ref: '#/components/parameters/idOrUUID'
+        - $ref: '#/components/parameters/playlistId'
       responses:
         '204':
           description: successful operation
 
-  /video-playlists/{id}/videos:
+  /video-playlists/{playlistId}/videos:
     get:
       summary: 'List videos of a playlist'
+      operationId: getVideoPlaylistVideos
       tags:
         - Videos
         - Video Playlists
       parameters:
-        - $ref: '#/components/parameters/idOrUUID'
+        - $ref: '#/components/parameters/playlistId'
       responses:
         '200':
           description: successful operation
@@ -2671,14 +3048,15 @@ paths:
               schema:
                 $ref: '#/components/schemas/VideoListResponse'
     post:
-      summary: 'Add a video in a playlist'
+      summary: Add a video in a playlist
+      operationId: addVideoPlaylistVideo
       security:
         - OAuth2: []
       tags:
         - Videos
         - Video Playlists
       parameters:
-        - $ref: '#/components/parameters/idOrUUID'
+        - $ref: '#/components/parameters/playlistId'
       responses:
         '200':
           description: successful operation
@@ -2692,6 +3070,7 @@ paths:
                     properties:
                       id:
                         type: integer
+                        example: 2
       requestBody:
         content:
           application/json:
@@ -2699,26 +3078,31 @@ paths:
               type: object
               properties:
                 videoId:
-                  type: integer
-                  description: 'Video to add in the playlist'
+                  oneOf:
+                    - $ref: '#/components/schemas/Video/properties/uuid'
+                    - $ref: '#/components/schemas/Video/properties/id'
+                  description: Video to add in the playlist
                 startTimestamp:
                   type: integer
-                  description: 'Start the video at this specific timestamp (in seconds)'
+                  format: seconds
+                  description: Start the video at this specific timestamp
                 stopTimestamp:
                   type: integer
-                  description: 'Stop the video at this specific timestamp (in seconds)'
+                  format: seconds
+                  description: Stop the video at this specific timestamp
               required:
                 - videoId
 
-  /video-playlists/{id}/videos/reorder:
+  /video-playlists/{playlistId}/videos/reorder:
     post:
       summary: 'Reorder a playlist'
+      operationId: reorderVideoPlaylist
       security:
         - OAuth2: []
       tags:
         - Video Playlists
       parameters:
-        - $ref: '#/components/parameters/idOrUUID'
+        - $ref: '#/components/parameters/playlistId'
       responses:
         '204':
           description: successful operation
@@ -2744,15 +3128,16 @@ paths:
                 - startPosition
                 - insertAfterPosition
 
-  /video-playlists/{id}/videos/{playlistElementId}:
+  /video-playlists/{playlistId}/videos/{playlistElementId}:
     put:
-      summary: 'Update a playlist element'
+      summary: Update a playlist element
+      operationId: putVideoPlaylistVideo
       security:
         - OAuth2: []
       tags:
         - Video Playlists
       parameters:
-        - $ref: '#/components/parameters/idOrUUID'
+        - $ref: '#/components/parameters/playlistId'
         - $ref: '#/components/parameters/playlistElementId'
       responses:
         '204':
@@ -2765,18 +3150,21 @@ paths:
               properties:
                 startTimestamp:
                   type: integer
-                  description: 'Start the video at this specific timestamp (in seconds)'
+                  format: seconds
+                  description: Start the video at this specific timestamp
                 stopTimestamp:
                   type: integer
-                  description: 'Stop the video at this specific timestamp (in seconds)'
+                  format: seconds
+                  description: Stop the video at this specific timestamp
     delete:
-      summary: 'Delete an element from a playlist'
+      summary: Delete an element from a playlist
+      operationId: delVideoPlaylistVideo
       security:
         - OAuth2: []
       tags:
         - Video Playlists
       parameters:
-        - $ref: '#/components/parameters/idOrUUID'
+        - $ref: '#/components/parameters/playlistId'
         - $ref: '#/components/parameters/playlistElementId'
       responses:
         '204':
@@ -2784,7 +3172,7 @@ paths:
 
   '/users/me/video-playlists/videos-exist':
     get:
-      summary: 'Check video exists in my playlists'
+      summary: Check video exists in my playlists
       security:
         - OAuth2: []
       tags:
@@ -2797,7 +3185,7 @@ paths:
           schema:
             type: array
             items:
-              type: integer
+              $ref: '#/components/schemas/Video/properties/id'
       responses:
         '200':
           description: successful operation
@@ -2817,8 +3205,10 @@ paths:
                           type: integer
                         startTimestamp:
                           type: integer
+                          format: seconds
                         stopTimestamp:
                           type: integer
+                          format: seconds
 
   '/accounts/{name}/video-channels':
     get:
@@ -2843,6 +3233,7 @@ paths:
             application/json:
               schema:
                 $ref: '#/components/schemas/VideoChannelList'
+
   '/accounts/{name}/ratings':
     get:
       summary: List ratings of an account
@@ -2873,6 +3264,7 @@ paths:
                 type: array
                 items:
                   $ref: '#/components/schemas/VideoRating'
+
   '/videos/{id}/comment-threads':
     get:
       summary: List threads of a video
@@ -2914,8 +3306,10 @@ paths:
               type: object
               properties:
                 text:
-                  type: string
-                  description: 'Text comment'
+                  allOf:
+                    - $ref: '#/components/schemas/VideoComment/properties/text'
+                  format: markdown
+                  maxLength: 10000
               required:
                 - text
 
@@ -2934,6 +3328,7 @@ paths:
             application/json:
               schema:
                 $ref: '#/components/schemas/VideoCommentThreadTree'
+
   '/videos/{id}/comments/{commentId}':
     post:
       summary: Reply to a thread of a video
@@ -2960,11 +3355,12 @@ paths:
               type: object
               properties:
                 text:
-                  type: string
-                  description: 'Text comment'
+                  allOf:
+                    - $ref: '#/components/schemas/VideoComment/properties/text'
+                  format: markdown
+                  maxLength: 10000
               required:
                 - text
-
     delete:
       summary: Delete a comment or a reply
       security:
@@ -2983,6 +3379,7 @@ paths:
           description: comment or video does not exist
         '409':
           description: comment is already deleted
+
   '/videos/{id}/rate':
     put:
       summary: Like/dislike a video
@@ -2992,16 +3389,31 @@ paths:
         - Video Rates
       parameters:
         - $ref: '#/components/parameters/idOrUUID'
+      requestBody:
+        content:
+          application/json:
+            schema:
+              type: object
+              properties:
+                rating:
+                  type: string
+                  enum:
+                    - like
+                    - dislike
+              required:
+                - rating
       responses:
         '204':
           description: successful operation
         '404':
           description: video does not exist
+
   /search/videos:
     get:
       tags:
         - Search
       summary: Search videos
+      operationId: searchVideos
       parameters:
         - name: search
           in: query
@@ -3072,11 +3484,13 @@ paths:
                 $ref: '#/components/schemas/VideoListResponse'
         '500':
           description: search index unavailable
+
   /search/video-channels:
     get:
       tags:
         - Search
       summary: Search channels
+      operationId: searchChannels
       parameters:
         - name: search
           in: query
@@ -3103,7 +3517,8 @@ paths:
                 $ref: '#/components/schemas/VideoChannelList'
         '500':
           description: search index unavailable
-  /blocklist/accounts:
+
+  /server/blocklist/accounts:
     get:
       tags:
         - Account Blocks
@@ -3142,7 +3557,8 @@ paths:
           description: successful operation
         '409':
           description: self-blocking forbidden
-  '/blocklist/accounts/{accountName}':
+
+  '/server/blocklist/accounts/{accountName}':
     delete:
       tags:
         - Account Blocks
@@ -3162,7 +3578,8 @@ paths:
           description: successful operation
         '404':
           description: account or account block does not exist
-  /blocklist/servers:
+
+  /server/blocklist/servers:
     get:
       tags:
         - Server Blocks
@@ -3197,11 +3614,12 @@ paths:
               required:
                 - host
       responses:
-        '200':
+        '204':
           description: successful operation
         '409':
           description: self-blocking forbidden
-  '/blocklist/servers/{host}':
+
+  '/server/blocklist/servers/{host}':
     delete:
       tags:
         - Server Blocks
@@ -3218,11 +3636,12 @@ paths:
             type: string
             format: hostname
       responses:
-        '201':
+        '204':
           description: successful operation
         '404':
           description: account block does not exist
-  /redundancy/{host}:
+
+  /server/redundancy/{host}:
     put:
       tags:
         - Instance Redundancy
@@ -3254,11 +3673,13 @@ paths:
           description: successful operation
         '404':
           description: server is not already known
-  /redundancy/videos:
+
+  /server/redundancy/videos:
     get:
       tags:
         - Video Mirroring
       summary: List videos being mirrored
+      operationId: getMirroredVideos
       security:
         - OAuth2:
           - admin
@@ -3288,6 +3709,7 @@ paths:
       tags:
         - Video Mirroring
       summary: Mirror a video
+      operationId: putMirroredVideo
       security:
         - OAuth2:
           - admin
@@ -3298,7 +3720,7 @@ paths:
               type: object
               properties:
                 videoId:
-                  type: integer
+                  $ref: '#/components/schemas/Video/properties/id'
               required:
                 - videoId
       responses:
@@ -3310,11 +3732,13 @@ paths:
           description: video does not exist
         '409':
           description: video is already mirrored
-  /redundancy/videos/{redundancyId}:
+
+  /server/redundancy/videos/{redundancyId}:
     delete:
       tags:
         - Video Mirroring
       summary: Delete a mirror done on a video
+      operationId: delMirroredVideo
       security:
         - OAuth2:
           - admin
@@ -3330,11 +3754,13 @@ paths:
           description: successful operation
         '404':
           description: video redundancy not found
+
   '/feeds/video-comments.{format}':
     get:
       tags:
         - Feeds
       summary: List comments on videos
+      operationId: getSyndicatedComments
       parameters:
         - name: format
           in: path
@@ -3423,11 +3849,13 @@ paths:
           description: video, video channel or account not found
         '406':
           description: accept header unsupported
+
   '/feeds/videos.{format}':
     get:
       tags:
         - Feeds
       summary: List videos
+      operationId: getSyndicatedVideos
       parameters:
         - name: format
           in: path
@@ -3509,12 +3937,14 @@ paths:
           description: video channel or account not found
         '406':
           description: accept header unsupported
+
   '/feeds/subscriptions.{format}':
     get:
       tags:
         - Feeds
         - Account
       summary: List videos of subscriptions tied to a token
+      operationId: getSyndicatedSubscriptionVideos
       parameters:
         - name: format
           in: path
@@ -3571,11 +4001,13 @@ paths:
                 type: object
         '406':
           description: accept header unsupported
+
   /plugins:
     get:
       tags:
         - Plugins
       summary: List plugins
+      operationId: getPlugins
       security:
         - OAuth2:
           - admin
@@ -3598,11 +4030,13 @@ paths:
             application/json:
               schema:
                 $ref: '#/components/schemas/PluginResponse'
+
   /plugins/available:
     get:
       tags:
         - Plugins
       summary: List available plugins
+      operationId: getAvailablePlugins
       security:
         - OAuth2:
           - admin
@@ -3631,11 +4065,13 @@ paths:
                 $ref: '#/components/schemas/PluginResponse'
         '503':
           description: plugin index unavailable
+
   /plugins/install:
     post:
       tags:
         - Plugins
       summary: Install a plugin
+      operationId: addPlugin
       security:
         - OAuth2:
           - admin
@@ -3664,11 +4100,13 @@ paths:
           description: successful operation
         '400':
           description: should have either `npmName` or `path` set
+
   /plugins/update:
     post:
       tags:
         - Plugins
       summary: Update a plugin
+      operationId: updatePlugin
       security:
         - OAuth2:
           - admin
@@ -3699,11 +4137,13 @@ paths:
           description: should have either `npmName` or `path` set
         '404':
           description: existing plugin not found
+
   /plugins/uninstall:
     post:
       tags:
         - Plugins
       summary: Uninstall a plugin
+      operationId: uninstallPlugin
       security:
         - OAuth2:
           - admin
@@ -3724,11 +4164,13 @@ paths:
           description: successful operation
         '404':
           description: existing plugin not found
+
   /plugins/{npmName}:
     get:
       tags:
         - Plugins
       summary: Get a plugin
+      operationId: getPlugin
       security:
         - OAuth2:
           - admin
@@ -3743,6 +4185,7 @@ paths:
                 $ref: '#/components/schemas/Plugin'
         '404':
           description: plugin not found
+
   /plugins/{npmName}/settings:
     put:
       tags:
@@ -3767,6 +4210,7 @@ paths:
           description: successful operation
         '404':
           description: plugin not found
+
   /plugins/{npmName}/public-settings:
     get:
       tags:
@@ -3784,6 +4228,7 @@ paths:
                 additionalProperties: true
         '404':
           description: plugin not found
+
   /plugins/{npmName}/registered-settings:
     get:
       tags:
@@ -3804,6 +4249,7 @@ paths:
                 additionalProperties: true
         '404':
           description: plugin not found
+
 servers:
   - url: 'https://peertube2.cpy.re/api/v1'
     description: Live Test Server (live data - latest nightly version)
@@ -3982,9 +4428,7 @@ components:
       required: true
       description: The user id
       schema:
-        type: integer
-        minimum: 0
-        example: 42
+        $ref: '#/components/schemas/id'
     idOrUUID:
       name: id
       in: path
@@ -3992,38 +4436,43 @@ components:
       description: The object id or uuid
       schema:
         oneOf:
-          - type: integer
-            minimum: 0
-            example: 42
+          - $ref: '#/components/schemas/id'
           - $ref: '#/components/schemas/UUIDv4'
+    playlistId:
+      name: playlistId
+      in: path
+      required: true
+      description: Playlist id
+      schema:
+        $ref: '#/components/schemas/VideoPlaylist/properties/id'
     playlistElementId:
       name: playlistElementId
       in: path
       required: true
       description: Playlist element id
       schema:
-        type: integer
+        $ref: '#/components/schemas/id'
     abuseId:
       name: abuseId
       in: path
       required: true
       description: Abuse id
       schema:
-        type: integer
+        $ref: '#/components/schemas/Abuse/properties/id'
     abuseMessageId:
       name: abuseMessageId
       in: path
       required: true
       description: Abuse message id
       schema:
-        type: integer
+        $ref: '#/components/schemas/AbuseMessage/properties/id'
     captionLanguage:
       name: captionLanguage
       in: path
       required: true
       description: The caption language
       schema:
-        type: string
+        $ref: '#/components/schemas/VideoLanguageSet'
     channelHandle:
       name: channelHandle
       in: path
@@ -4053,7 +4502,7 @@ components:
       required: true
       description: The comment id
       schema:
-        type: integer
+        $ref: '#/components/schemas/VideoComment/properties/id'
     isLive:
       name: isLive
       in: query
@@ -4068,10 +4517,10 @@ components:
       description: category id of the video (see [/videos/categories](#operation/getCategories))
       schema:
         oneOf:
-        - type: integer
+        - $ref: '#/components/schemas/VideoCategorySet'
         - type: array
           items:
-            type: integer
+            $ref: '#/components/schemas/VideoCategorySet'
       style: form
       explode: false
     tagsOneOf:
@@ -4108,10 +4557,10 @@ components:
       description: language id of the video (see [/videos/languages](#operation/getLanguages)). Use `_unknown` to filter on videos that don't have a video language
       schema:
         oneOf:
-        - type: string
+        - $ref: '#/components/schemas/VideoLanguageSet'
         - type: array
           items:
-            type: string
+            $ref: '#/components/schemas/VideoLanguageSet'
       style: form
       explode: false
     licenceOneOf:
@@ -4121,10 +4570,10 @@ components:
       description: licence id of the video (see [/videos/licences](#operation/getLicences))
       schema:
         oneOf:
-        - type: integer
+        - $ref: '#/components/schemas/VideoLicenceSet'
         - type: array
           items:
-            type: integer
+            $ref: '#/components/schemas/VideoLicenceSet'
       style: form
       explode: false
     skipCount:
@@ -4200,66 +4649,114 @@ components:
           - activitypub-refresher
           - video-redundancy
           - video-live-ending
+    followState:
+      name: state
+      in: query
+      schema:
+        type: string
+        enum:
+          - pending
+          - accepted
+    actorType:
+      name: actorType
+      in: query
+      schema:
+        type: string
+        enum:
+          - Person
+          - Application
+          - Group
+          - Service
+          - Organization
   securitySchemes:
     OAuth2:
       description: |
         Authenticating via OAuth requires the following steps:
         - Have an activated account
-        - [Generate](https://docs.joinpeertube.org/api-rest-getting-started) a
-        Bearer Token for that account at `/api/v1/users/token`
-        - Make authenticated requests, putting *Authorization: Bearer <token\>*
+        - [Generate] an access token for that account at `/api/v1/users/token`.
+        - Make requests with the *Authorization: Bearer <token\>* header
         - Profit, depending on the role assigned to the account
 
-        Note that the __access token is valid for 1 day__ and, and is given
+        Note that the __access token is valid for 1 day__ and is given
         along with a __refresh token valid for 2 weeks__.
+
+        [Generate]: https://docs.joinpeertube.org/api-rest-getting-started
       type: oauth2
       flows:
         password:
-          tokenUrl: 'https://peertube.example.com/api/v1/users/token'
+          tokenUrl: /api/v1/users/token
           scopes:
             admin: Admin scope
             moderator: Moderator scope
             user: User scope
   schemas:
+    # Resuable core properties
+    id:
+      type: integer
+      minimum: 1
+      example: 42
     UUIDv4:
       type: string
       format: uuid
       example: 9c9de5e8-0a1e-484a-b099-e80766180a6d
       pattern: '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$'
-      # the regex above limits the length;
-      # however, some tools might require explicit settings:
       minLength: 36
       maxLength: 36
+    username:
+      type: string
+      description: immutable name of the user, used to find or mention its actor
+      example: chocobozzz
+      pattern: '/^[a-z0-9._]+$/'
+      minLength: 1
+      maxLength: 50
+    usernameChannel:
+      type: string
+      description: immutable name of the channel, used to interact with its actor
+      example: framasoft_videos
+      pattern: '/^[a-zA-Z0-9\\-_.:]+$/'
+      minLength: 1
+      maxLength: 50
+    password:
+      type: string
+      format: password
+      minLength: 6
+      maxLength: 255
 
     VideoCategorySet:
       type: integer
       description: category id of the video (see [/videos/categories](#operation/getCategories))
+      example: 15
     VideoConstantNumber-Category:
       properties:
         id:
           $ref: '#/components/schemas/VideoCategorySet'
         label:
           type: string
+          example: Science & Technology
 
     VideoLicenceSet:
       type: integer
       description: licence id of the video (see [/videos/licences](#operation/getLicences))
+      example: 2
     VideoConstantNumber-Licence:
       properties:
         id:
           $ref: '#/components/schemas/VideoLicenceSet'
         label:
           type: string
-    
+          example: Attribution - Share Alike
+
     VideoLanguageSet:
       type: string
       description: language id of the video (see [/videos/languages](#operation/getLanguages))
+      example: en
     VideoConstantString-Language:
       properties:
         id:
           $ref: '#/components/schemas/VideoLanguageSet'
         label:
           type: string
+          example: English
 
     VideoPlaylistPrivacySet:
       type: integer
@@ -4374,6 +4871,7 @@ components:
         `0` is used as a special value for stillimage videos dedicated to audio, a.k.a. audio-only videos.
       example: 240
     VideoResolutionConstant:
+      description: resolutions and their labels for the video
       properties:
         id:
           $ref: '#/components/schemas/VideoResolutionSet'
@@ -4411,7 +4909,7 @@ components:
     VideoChannelSummary:
       properties:
         id:
-          type: integer
+          $ref: '#/components/schemas/id'
         name:
           type: string
         displayName:
@@ -4432,21 +4930,28 @@ components:
           type: integer
         startTimestamp:
           type: integer
+          format: seconds
         stopTimestamp:
           type: integer
+          format: seconds
         video:
           nullable: true
           allOf:
             - $ref: '#/components/schemas/Video'
     VideoFile:
+      readOnly: true
       properties:
         magnetUri:
           type: string
+          format: uri
+          description: magnet URI allowing to resolve the video via BitTorrent without a metainfo file
+          example: magnet:?xs=https%3A%2F%2Fframatube.org%2Fstatic%2Ftorrents%2F9c9de5e8-0a1e-484a-b099-e80766180a6d-240.torrent&xt=urn:btih:38b4747ff788b30bf61f59d1965cd38f9e48e01f&dn=What+is+PeerTube%3F&tr=wss%3A%2F%2Fframatube.org%2Ftracker%2Fsocket&tr=https%3A%2F%2Fframatube.org%2Ftracker%2Fannounce&ws=https%3A%2F%2Fframatube.org%2Fstatic%2Fwebseed%2F9c9de5e8-0a1e-484a-b099-e80766180a6d-240.mp4
+          pattern: /magnet:\?xt=urn:[a-z0-9]+:[a-z0-9]{32}/i
         resolution:
           $ref: '#/components/schemas/VideoResolutionConstant'
         size:
           type: integer
-          description: 'Video file size in bytes'
+          description: Video file size in bytes
         torrentUrl:
           type: string
           description: Direct URL of the torrent file
@@ -4465,15 +4970,17 @@ components:
           format: url
         fps:
           type: number
+          description: Frames per second of the video file
         metadataUrl:
           type: string
           format: url
+          description: URL dereferencing the output of ffprobe on the file
     VideoStreamingPlaylists:
       allOf:
         - type: object
           properties:
             id:
-              type: integer
+              $ref: '#/components/schemas/id'
             type:
               type: integer
               enum:
@@ -4509,20 +5016,21 @@ components:
     VideoInfo:
       properties:
         id:
-          type: integer
+          $ref: '#/components/schemas/Video/properties/id'
         uuid:
-          $ref: '#/components/schemas/UUIDv4'
+          $ref: '#/components/schemas/Video/properties/uuid'
         name:
-          type: string
-          minLength: 3
-          maxLength: 120
+          $ref: '#/components/schemas/Video/properties/name'
     Video:
       properties:
         id:
-          type: integer
-          example: 8
+          description: object id for the video
+          allOf:
+            - $ref: '#/components/schemas/id'
         uuid:
-          $ref: '#/components/schemas/UUIDv4'
+          description: universal identifier for the video, that can be used across instances
+          allOf:
+            - $ref: '#/components/schemas/UUIDv4'
         isLive:
           type: boolean
         createdAt:
@@ -4546,13 +5054,21 @@ components:
           example: 2010-10-01T10:52:46.396Z
           description: used to represent a date of first publication, prior to the practical publication date of `publishedAt`
         category:
-          $ref: '#/components/schemas/VideoConstantNumber-Category'
+          allOf:
+            - $ref: '#/components/schemas/VideoConstantNumber-Category'
+          description: category in which the video is classified
         licence:
-          $ref: '#/components/schemas/VideoConstantNumber-Licence'
+          allOf:
+            - $ref: '#/components/schemas/VideoConstantNumber-Licence'
+          description: licence under which the video is distributed
         language:
-          $ref: '#/components/schemas/VideoConstantString-Language'
+          allOf:
+            - $ref: '#/components/schemas/VideoConstantString-Language'
+          description: main language used in the video
         privacy:
-          $ref: '#/components/schemas/VideoPrivacyConstant'
+          allOf:
+            - $ref: '#/components/schemas/VideoPrivacyConstant'
+          description: privacy policy used to distribute the video
         description:
           type: string
           example: |
@@ -4566,11 +5082,13 @@ components:
         duration:
           type: integer
           example: 1419
+          format: seconds
           description: duration of the video in seconds
         isLocal:
           type: boolean
         name:
           type: string
+          description: title of the video
           example: What is PeerTube?
           minLength: 3
           maxLength: 120
@@ -4598,7 +5116,9 @@ components:
           type: boolean
           nullable: true
         state:
-          $ref: '#/components/schemas/VideoStateConstant'
+          allOf:
+            - $ref: '#/components/schemas/VideoStateConstant'
+          description: represents the internal state of the video processing within the PeerTube instance
         scheduledUpdate:
           nullable: true
           allOf:
@@ -4631,7 +5151,7 @@ components:
             support:
               type: string
               description: A text tell the audience how to support the video creator
-              example: Please support my work on <insert crowdfunding plateform>! <3
+              example: Please support our work on https://soutenir.framasoft.org/en/ <3
               minLength: 3
               maxLength: 1000
             channel:
@@ -4656,6 +5176,9 @@ components:
               items:
                 type: string
                 format: url
+              example:
+                - https://peertube2.cpy.re/tracker/announce
+                - wss://peertube2.cpy.re/tracker/socket
             files:
               type: array
               items:
@@ -4677,7 +5200,7 @@ components:
     FileRedundancyInformation:
       properties:
         id:
-          type: integer
+          $ref: '#/components/schemas/id'
         fileUrl:
           type: string
           format: url
@@ -4702,7 +5225,7 @@ components:
     VideoRedundancy:
       properties:
         id:
-          type: integer
+          $ref: '#/components/schemas/id'
         name:
           type: string
         url:
@@ -4733,33 +5256,72 @@ components:
         label:
           type: string
           example: Pending
+    VideoCreateImport:
+      allOf:
+        - type: object
+          additionalProperties: false
+          oneOf:
+            - properties:
+                targetUrl:
+                  $ref: '#/components/schemas/VideoImport/properties/targetUrl'
+              required: [targetUrl]
+            - properties:
+                magnetUri:
+                  $ref: '#/components/schemas/VideoImport/properties/magnetUri'
+              required: [magnetUri]
+            - properties:
+                torrentfile:
+                  $ref: '#/components/schemas/VideoImport/properties/torrentfile'
+              required: [torrentfile]
+        - $ref: '#/components/schemas/VideoUploadRequestCommon'
+      required:
+        - channelId
+        - name
     VideoImport:
       properties:
         id:
-          type: integer
-          example: 2
+          readOnly: true
+          allOf:
+            - $ref: '#/components/schemas/id'
         targetUrl:
           type: string
           format: url
+          description: remote URL where to find the import's source video
           example: https://framatube.org/videos/watch/9c9de5e8-0a1e-484a-b099-e80766180a6d
         magnetUri:
           type: string
           format: uri
+          description: magnet URI allowing to resolve the import's source video
           example: magnet:?xs=https%3A%2F%2Fframatube.org%2Fstatic%2Ftorrents%2F9c9de5e8-0a1e-484a-b099-e80766180a6d-240.torrent&xt=urn:btih:38b4747ff788b30bf61f59d1965cd38f9e48e01f&dn=What+is+PeerTube%3F&tr=wss%3A%2F%2Fframatube.org%2Ftracker%2Fsocket&tr=https%3A%2F%2Fframatube.org%2Ftracker%2Fannounce&ws=https%3A%2F%2Fframatube.org%2Fstatic%2Fwebseed%2F9c9de5e8-0a1e-484a-b099-e80766180a6d-240.mp4
+          pattern: /magnet:\?xt=urn:[a-z0-9]+:[a-z0-9]{32}/i
+        torrentfile:
+          writeOnly: true
+          type: string
+          format: binary
+          description: Torrent file containing only the video file
         torrentName:
+          readOnly: true
           type: string
         state:
-          $ref: '#/components/schemas/VideoImportStateConstant'
+          readOnly: true
+          allOf:
+            - $ref: '#/components/schemas/VideoImportStateConstant'
         error:
+          readOnly: true
           type: string
         createdAt:
+          readOnly: true
           type: string
           format: date-time
         updatedAt:
+          readOnly: true
           type: string
           format: date-time
         video:
-          $ref: '#/components/schemas/Video'
+          readOnly: true
+          nullable: true
+          allOf:
+            - $ref: '#/components/schemas/Video'
     VideoImportsList:
       properties:
         total:
@@ -4773,8 +5335,7 @@ components:
     Abuse:
       properties:
         id:
-          type: integer
-          example: 7
+          $ref: '#/components/schemas/id'
         reason:
           type: string
           example: The video is a spam
@@ -4799,7 +5360,7 @@ components:
     AbuseMessage:
       properties:
         id:
-          type: integer
+          $ref: '#/components/schemas/id'
         message:
           type: string
           minLength: 2
@@ -4814,9 +5375,9 @@ components:
     VideoBlacklist:
       properties:
         id:
-          type: integer
+          $ref: '#/components/schemas/id'
         videoId:
-          type: integer
+          $ref: '#/components/schemas/Video/properties/id'
         createdAt:
           type: string
           format: date-time
@@ -4843,29 +5404,12 @@ components:
           type: integer
         nsfw:
           type: boolean
-    VideoChannel:
-      properties:
-        displayName:
-          type: string
-          minLength: 1
-          maxLength: 120
-        description:
-          type: string
-          minLength: 3
-          maxLength: 1000
-        isLocal:
-          type: boolean
-        ownerAccount:
-          type: object
-          properties:
-            id:
-              type: integer
-            uuid:
-              $ref: '#/components/schemas/UUIDv4'
     VideoPlaylist:
       properties:
         id:
-          type: integer
+          $ref: '#/components/schemas/id'
+        uuid:
+          $ref: '#/components/schemas/UUIDv4'
         createdAt:
           type: string
           format: date-time
@@ -4876,8 +5420,6 @@ components:
           type: string
           minLength: 3
           maxLength: 1000
-        uuid:
-          $ref: '#/components/schemas/UUIDv4'
         displayName:
           type: string
           minLength: 1
@@ -4886,6 +5428,7 @@ components:
           type: boolean
         videoLength:
           type: integer
+          minimum: 0
         thumbnailPath:
           type: string
         privacy:
@@ -4899,30 +5442,44 @@ components:
     VideoComment:
       properties:
         id:
-          type: integer
+          $ref: '#/components/schemas/id'
         url:
           type: string
           format: url
         text:
           type: string
+          format: html
+          description: Text of the comment
           minLength: 1
-          maxLength: 10000
+          example: This video is wonderful!
         threadId:
-          type: integer
+          $ref: '#/components/schemas/id'
         inReplyToCommentId:
-          type: integer
+          nullable: true
+          allOf:
+            - $ref: '#/components/schemas/id'
         videoId:
-          type: integer
+          $ref: '#/components/schemas/Video/properties/id'
         createdAt:
           type: string
           format: date-time
         updatedAt:
           type: string
           format: date-time
+        deletedAt:
+          nullable: true
+          type: string
+          format: date-time
+          default: null
+        isDeleted:
+          type: boolean
+          default: false
         totalRepliesFromVideoAuthor:
           type: integer
+          minimum: 0
         totalReplies:
           type: integer
+          minimum: 0
         account:
           $ref: '#/components/schemas/Account'
     VideoCommentThreadTree:
@@ -4952,8 +5509,7 @@ components:
     ActorInfo:
       properties:
         id:
-          type: integer
-          example: 11
+          $ref: '#/components/schemas/id'
         name:
           type: string
         displayName:
@@ -4970,22 +5526,29 @@ components:
     Actor:
       properties:
         id:
-          type: integer
-          example: 11
+          $ref: '#/components/schemas/id'
         url:
           type: string
           format: url
         name:
-          type: string
+          description: immutable name of the actor, used to find or mention it
+          allOf:
+            - $ref: '#/components/schemas/username'
         host:
           type: string
           format: hostname
+          description: server on which the actor is resident
         hostRedundancyAllowed:
           type: boolean
+          description: whether this actor's host allows redundancy of its videos
         followingCount:
           type: integer
+          minimum: 0
+          description: number of actors subscribed to by this actor, as seen by this instance
         followersCount:
           type: integer
+          minimum: 0
+          description: number of followers of this actor, as seen by this instance
         createdAt:
           type: string
           format: date-time
@@ -4999,16 +5562,22 @@ components:
         - $ref: '#/components/schemas/Actor'
         - properties:
             userId:
-              type: string
-              example: 2
+              description: object id for the user tied to this account
+              allOf:
+                - $ref: '#/components/schemas/User/properties/id'
             displayName:
               type: string
+              description: editable name of the account, displayed in its representations
+              minLength: 3
+              maxLength: 120
             description:
               type: string
+              description: text or bio displayed on the account's profile
     UserWatchingVideo:
       properties:
         currentTime:
           type: integer
+          format: seconds
           description: timestamp within the video, in seconds
           example: 5
     ServerConfig:
@@ -5181,8 +5750,10 @@ components:
           properties:
             videoQuota:
               type: integer
+              example: 16810141515
             videoQuotaDaily:
               type: integer
+              example: 1681014151
         trending:
           type: object
           properties:
@@ -5208,6 +5779,12 @@ components:
                     indexUrl:
                       type: string
                       format: url
+        homepage:
+          type: object
+          properties:
+            enabled:
+              type: boolean
+
     ServerConfigAbout:
       properties:
         instance:
@@ -5301,8 +5878,10 @@ components:
           properties:
             videoQuota:
               type: integer
+              example: 16810141515
             videoQuotaDaily:
               type: integer
+              example: 1681014151
         transcoding:
           type: object
           description: Settings pertaining to transcoding jobs
@@ -5396,10 +5975,16 @@ components:
                   type: boolean
                 manualApproval:
                   type: boolean
+
+    CustomHomepage:
+      properties:
+        content:
+          type: string
+
     Follow:
       properties:
         id:
-          type: integer
+          $ref: '#/components/schemas/id'
         follower:
           $ref: '#/components/schemas/Actor'
         following:
@@ -5438,9 +6023,7 @@ components:
     Job:
       properties:
         id:
-          type: integer
-          minimum: 0
-          example: 42
+          $ref: '#/components/schemas/id'
         state:
           type: string
           enum:
@@ -5484,22 +6067,25 @@ components:
           type: object
           properties:
             id:
-              type: integer
-              example: 8
+              $ref: '#/components/schemas/id'
             account:
               type: object
               properties:
                 id:
-                  type: integer
-                  example: 37
+                  $ref: '#/components/schemas/id'
     VideoUploadRequestCommon:
       properties:
         name:
           description: Video name
           type: string
+          example: What is PeerTube?
+          minLength: 3
+          maxLength: 120
         channelId:
           description: Channel id that will contain this video
           type: integer
+          example: 3
+          minimum: 1
         privacy:
           $ref: '#/components/schemas/VideoPrivacySet'
         category:
@@ -5511,12 +6097,14 @@ components:
         description:
           description: Video description
           type: string
+          example: |
+            **[Want to help to translate this video?](https://weblate.framasoft.org/projects/what-is-peertube-video/)**\r\n\r\n**Take back the control of your videos! [#JoinPeertube](https://joinpeertube.org)**
         waitTranscoding:
           description: Whether or not we wait transcoding before publish the video
           type: boolean
         support:
           description: A text tell the audience how to support the video creator
-          example: Please support my work on <insert crowdfunding plateform>! <3
+          example: Please support our work on https://soutenir.framasoft.org/en/ <3
           type: string
         nsfw:
           description: Whether or not this video contains sensitive content
@@ -5527,6 +6115,9 @@ components:
           minItems: 1
           maxItems: 5
           uniqueItems: true
+          example:
+            - framasoft
+            - peertube
           items:
             type: string
             minLength: 2
@@ -5576,6 +6167,7 @@ components:
               description: Video filename including extension
               type: string
               format: filename
+              example: what_is_peertube.mp4
             thumbnailfile:
               description: Video thumbnail file
               type: string
@@ -5590,10 +6182,9 @@ components:
           type: object
           properties:
             id:
-              type: integer
-              example: 8
+              $ref: '#/components/schemas/Video/properties/id'
             uuid:
-              $ref: '#/components/schemas/UUIDv4'
+              $ref: '#/components/schemas/Video/properties/uuid'
     CommentThreadResponse:
       properties:
         total:
@@ -5645,7 +6236,8 @@ components:
           type: boolean
           description: Has the user confirmed their email address?
         id:
-          type: integer
+          allOf:
+            - $ref: '#/components/schemas/id'
           readOnly: true
         pluginAuth:
           type: string
@@ -5671,10 +6263,7 @@ components:
           type: string
           description: Theme enabled by this user
         username:
-          type: string
-          description: The user username
-          minLength: 1
-          maxLength: 50
+          $ref: '#/components/schemas/username'
         videoChannels:
           type: array
           items:
@@ -5697,7 +6286,7 @@ components:
             # optionally present fields: they require WITH_STATS scope
             videosCount:
               type: integer
-              description: Count of videos published 
+              description: Count of videos published
             abusesCount:
               type: integer
               description: Count of reports/abuses of which the user is a target
@@ -5713,31 +6302,23 @@ components:
     AddUser:
       properties:
         username:
-          type: string
-          description: The user username
-          minLength: 1
-          maxLength: 50
-          pattern: '/^[a-z0-9._]{1,50}$/'
+          $ref: '#/components/schemas/username'
         password:
-          type: string
-          format: password
-          description: The user password. If the smtp server is configured, you can leave empty and an email will be sent
-          minLength: 6
-          maxLength: 255
+          $ref: '#/components/schemas/password'
         email:
           type: string
           format: email
           description: The user email
         videoQuota:
           type: integer
-          description: The user video quota
+          description: The user video quota in bytes
+          example: -1
         videoQuotaDaily:
           type: integer
-          description: The user daily video quota
+          description: The user daily video quota in bytes
+          example: -1
         channelName:
-          type: string
-          description: The user default channel username
-          pattern: '/^[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\\-_.:]+$/'
+          $ref: '#/components/schemas/usernameChannel'
         role:
           $ref: '#/components/schemas/UserRole'
         adminFlags:
@@ -5751,22 +6332,19 @@ components:
         - role
     UpdateUser:
       properties:
-        id:
-          type: string
-          description: The user id
         email:
-          type: string
-          format: email
           description: The updated email of the user
+          allOf:
+            - $ref: '#/components/schemas/User/properties/email'
         emailVerified:
           type: boolean
           description: Set the email as verified
         videoQuota:
           type: integer
-          description: The updated video quota of the user
+          description: The updated video quota of the user in bytes
         videoQuotaDaily:
           type: integer
-          description: The updated daily video quota of the user
+          description: The updated daily video quota of the user in bytes
         pluginAuth:
           type: string
           nullable: true
@@ -5776,40 +6354,59 @@ components:
           $ref: '#/components/schemas/UserRole'
         adminFlags:
           $ref: '#/components/schemas/UserAdminFlags'
-      required:
-        - id
     UpdateMe:
+      # see shared/models/users/user-update-me.model.ts:
       properties:
         password:
-          type: string
-          format: password
-          description: Your new password
-          minLength: 6
-          maxLength: 255
+          $ref: '#/components/schemas/password'
+        currentPassword:
+          $ref: '#/components/schemas/password'
         email:
+          description: new email used for login and service communications
+          allOf:
+            - $ref: '#/components/schemas/User/properties/email'
+        displayName:
           type: string
-          format: email
-          description: Your new email
+          description: new name of the user in its representations
+          minLength: 3
+          maxLength: 120
         displayNSFW:
           type: string
-          description: Your new displayNSFW
+          description: new NSFW display policy
           enum:
             - 'true'
             - 'false'
             - both
+        webTorrentEnabled:
+          type: boolean
+          description: whether to enable P2P in the player or not
         autoPlayVideo:
           type: boolean
-          description: Your new autoPlayVideo
-      required:
-        - password
-        - email
-        - displayNSFW
-        - autoPlayVideo
+          description: new preference regarding playing videos automatically
+        autoPlayNextVideo:
+          type: boolean
+          description: new preference regarding playing following videos automatically
+        autoPlayNextVideoPlaylist:
+          type: boolean
+          description: new preference regarding playing following playlist videos automatically
+        videosHistoryEnabled:
+          type: boolean
+          description: whether to keep track of watched history or not
+        videoLanguages:
+          type: array
+          items:
+            type: string
+          description: list of languages to filter videos down to
+        theme:
+          type: string
+        noInstanceConfigWarningModal:
+          type: boolean
+        noWelcomeModal:
+          type: boolean
     GetMeVideoRating:
       properties:
         id:
-          type: string
-          description: Id of the video
+          $ref: '#/components/schemas/id'
         rating:
           type: string
           enum:
@@ -5837,77 +6434,147 @@ components:
     RegisterUser:
       properties:
         username:
-          type: string
-          description: The username of the user
-          minLength: 1
-          maxLength: 50
-          pattern: '/^[a-z0-9._]{1,50}$/'
+          description: immutable name of the user, used to find or mention its actor
+          allOf:
+            - $ref: '#/components/schemas/username'
         password:
-          type: string
-          format: password
-          description: The password of the user
-          minLength: 6
-          maxLength: 255
+          $ref: '#/components/schemas/password'
         email:
           type: string
           format: email
-          description: The email of the user
+          description: email of the user, used for login or service communications
         displayName:
           type: string
-          description: The user display name
+          description: editable name of the user, displayed in its representations
           minLength: 1
           maxLength: 120
         channel:
           type: object
+          description: channel base information used to create the first channel of the user
           properties:
             name:
-              type: string
-              description: The username for the default channel
-              pattern: '/^[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\\-_.:]+$/'
+              $ref: '#/components/schemas/usernameChannel'
             displayName:
-              type: string
-              description: The display name for the default channel
-              minLength: 1
-              maxLength: 120
+              $ref: '#/components/schemas/VideoChannel/properties/displayName'
       required:
         - username
         - password
         - email
 
-    VideoChannelCommon:
+    OAuthClient:
+      properties:
+        client_id:
+          type: string
+          pattern: /^[a-z0-9]$/
+          maxLength: 32
+          minLength: 32
+          example: v1ikx5hnfop4mdpnci8nsqh93c45rldf
+        client_secret:
+          type: string
+          pattern: /^[a-zA-Z0-9]$/
+          maxLength: 32
+          minLength: 32
+          example: AjWiOapPltI6EnsWQwlFarRtLh4u8tDt
+    OAuthToken-password:
+      allOf:
+        - $ref: '#/components/schemas/OAuthClient'
+        - type: object
+          properties:
+            grant_type:
+              type: string
+              enum:
+                - password
+                - refresh_token
+              default: password
+            username:
+              $ref: '#/components/schemas/User/properties/username'
+            password:
+              $ref: '#/components/schemas/password'
+      required:
+        - client_id
+        - client_secret
+        - grant_type
+        - username
+        - password
+    OAuthToken-refresh_token:
+      allOf:
+        - $ref: '#/components/schemas/OAuthClient'
+        - type: object
+          properties:
+            grant_type:
+              type: string
+              enum:
+                - password
+                - refresh_token
+              default: password
+            refresh_token:
+              type: string
+              example: 2e0d675df9fc96d2e4ec8a3ebbbf45eca9137bb7
+      required:
+        - client_id
+        - client_secret
+        - grant_type
+        - refresh_token
+
+    VideoChannel:
       properties:
+        # GET/POST/PUT properties
         displayName:
           type: string
+          description: editable name of the channel, displayed in its representations
+          example: Videos of Framasoft
           minLength: 1
           maxLength: 120
         description:
           type: string
+          example: Videos made with <3 by Framasoft
           minLength: 3
           maxLength: 1000
         support:
           type: string
-          description: 'A text shown by default on all videos of this channel, to tell the audience how to support it'
-          example: Please support my work on <insert crowdfunding plateform>! <3
+          description: text shown by default on all videos of this channel, to tell the audience how to support it
+          example: Please support our work on https://soutenir.framasoft.org/en/ <3
           minLength: 3
           maxLength: 1000
+        # GET-only properties
+        id:
+          readOnly: true
+          allOf:
+            - $ref: '#/components/schemas/id'
+        isLocal:
+          readOnly: true
+          type: boolean
+        updatedAt:
+          readOnly: true
+          type: string
+          format: date-time
+        ownerAccount:
+          readOnly: true
+          nullable: true
+          type: object
+          properties:
+            id:
+              type: integer
+            uuid:
+              $ref: '#/components/schemas/UUIDv4'
     VideoChannelCreate:
       allOf:
-        - $ref: '#/components/schemas/VideoChannelCommon'
+        - $ref: '#/components/schemas/VideoChannel'
         - properties:
             name:
-              type: string
-              minLength: 1
-              maxLength: 120
+              description: username of the channel to create
+              allOf:
+                - $ref: '#/components/schemas/usernameChannel'
       required:
         - name
         - displayName
     VideoChannelUpdate:
       allOf:
-        - $ref: '#/components/schemas/VideoChannelCommon'
+        - $ref: '#/components/schemas/VideoChannel'
         - properties:
             bulkVideosSupportUpdate:
               type: boolean
-              description: 'Update the support field for all videos of this channel'
+              description: Update the support field for all videos of this channel
     VideoChannelList:
       properties:
         total:
@@ -6123,7 +6790,7 @@ components:
     Notification:
       properties:
         id:
-          type: integer
+          $ref: '#/components/schemas/id'
         type:
           type: integer
           description: >
@@ -6171,7 +6838,7 @@ components:
           type: object
           properties:
             id:
-              type: integer
+              $ref: '#/components/schemas/id'
             video:
               nullable: true
               $ref: '#/components/schemas/VideoInfo'
@@ -6179,9 +6846,7 @@ components:
               type: string
               nullable: true
             magnetUri:
-              type: string
-              format: uri
-              nullable: true
+              $ref: '#/components/schemas/VideoImport/properties/magnetUri'
             targetUri:
               type: string
               format: uri
@@ -6191,7 +6856,7 @@ components:
           type: object
           properties:
             id:
-              type: integer
+              $ref: '#/components/schemas/id'
             threadId:
               type: integer
             video:
@@ -6203,7 +6868,7 @@ components:
           type: object
           properties:
             id:
-              type: integer
+              $ref: '#/components/schemas/id'
             video:
               allOf:
                 - $ref: '#/components/schemas/VideoInfo'
@@ -6212,7 +6877,7 @@ components:
           type: object
           properties:
             id:
-              type: integer
+              $ref: '#/components/schemas/id'
             video:
               allOf:
                 - $ref: '#/components/schemas/VideoInfo'
@@ -6225,7 +6890,7 @@ components:
           nullable: true
           properties:
             id:
-              type: integer
+              $ref: '#/components/schemas/id'
             follower:
               $ref: '#/components/schemas/ActorInfo'
             state: