PeerTube Documentation

ActivityPub-federated video streaming platform using P2P directly in your web browser

15,376 stars TypeScript TypeScript 1 file ยท ~138,315 tokens #activitypub#angular#decentralized#p2p#video
RAW Doc

Technical Documentation: Chocobozzz/PeerTube

โ„น๏ธ Provenance: Multi-Tier Ingestion ยท CodeWiki Reference

Overview (`README.md`)

Website
| Join an instance
| Create an instance
| Chat with us
| Donate

Introduction

PeerTube is a free, decentralized and federated video platform developed as an alternative to other platforms that centralize our data and attention, such as YouTube, Dailymotion or Vimeo. :clapper:

To learn more:

:sparkles: Features

All features for viewers
| All features for content creators
| All features for administrators

Video streaming, even in live!

Just upload your videos, and be sure they will stream anywhere. Add a description, some tags and your video will be discoverable by the entire video fediverse, not just your instance. You can even embed a player on your favorite website!

You are used to hosting live events? We got you covered too! Start livestreaming from your favorite client, and even host permanent streams!


Keep in touch with video creators

Follow your favorite channels from PeerTube or really any other place. No need to have an account on the instance you watched a video to follow its author, you can do all of that from the Fediverse (Mastodon, Pleroma, and plenty others), or just with good ol' RSS.


An interface to call home

Be it as a user or an instance administrator, you can decide what your experience will be like. Don't like the colors? They are easy to change. Don't want to list videos of an instance but let your users subscribe to them? Don't like the regular web client? All of that can be changed, and much more. No UX dark pattern, no mining your data, no video recommendation bullshitโ„ข.


Communities that help each other

In addition to visitors using P2P with WebRTC to share the load among them, instances can help each other by caching one another's videos. This way even small instances have a way to show content to a wider audience, as they will be shouldered by friend instances (more about that in our redundancy guide).

Content creators can get help from their viewers in the simplest way possible: a support button showing a message linking to their donation accounts or really anything else. No more pay-per-view and advertisements that hurt visitors and alter creativity (more about that in our FAQ).

:raised_hands: Contributing

You don't need to be a programmer to help!

You can give us your feedback, report bugs, help us translate PeerTube, write documentation, and more. Check out the contributing
guide
to know how, it takes less than 2 minutes to get started. :wink:

You can also join the cheerful bunch that makes our community:

Feel free to reach out if you have any questions or ideas! :speech_balloon:

:package: Create your own instance

See the production guide, which is the recommended way to install or upgrade PeerTube. For hardware requirements, see Should I have a big server to run PeerTube? in the FAQ.

See the community packages, which cover various platforms (including YunoHost and Docker).

:book: Documentation

If you have a question, please try to find the answer in the FAQ first.

User documentation

See the user documentation.

Admin documentation

See how to create your own instance.

See the more general admin documentation.

Tools documentation

Learn how to import/upload videos from CLI or admin your PeerTube instance with the tools documentation.

Technical documentation

See the architecture blueprint for a more detailed explanation of the architectural choices.

See our REST API documentation:

See our ActivityPub documentation.

License

CC BY-SA 4.0, by Framasoft

Code

Copyright (C) 2015-2025 PeerTube Contributors (see CREDITS.md)

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program. If not, see https://www.gnu.org/licenses/.


Overview (`apps/peertube-cli/README.md`)

PeerTube CLI

Usage

See https://docs.joinpeertube.org/maintain/tools#remote-tools

Dev

Install dependencies

bash
cd peertube-root
npm run install-node-dependencies

Develop

bash
cd peertube-root
npm run dev:peertube-cli

Build

bash
cd peertube-root
npm run build:peertube-cli

Run

bash
cd peertube-root
node apps/peertube-cli/dist/peertube.js --help

Publish on NPM

bash
cd peertube-root
(cd apps/peertube-cli && npm version patch) && npm run build:peertube-cli && (cd apps/peertube-cli && npm login && npm publish --access=public)

Overview (`apps/peertube-runner/README.md`)

PeerTube runner

Runner program to execute jobs (transcoding...) of remote PeerTube instances.

Commands below has to be run at the root of PeerTube git repository.

Dev

Install dependencies

bash
cd peertube-root
npm run install-node-dependencies

Develop

bash
cd peertube-root
npm run dev:peertube-runner

Build

bash
cd peertube-root
npm run build:peertube-runner

Run

bash
cd peertube-root
node apps/peertube-runner/dist/peertube-runner.mjs --help

Publish on NPM

bash
cd peertube-root
(cd apps/peertube-runner && npm version patch) && npm run build:peertube-runner && (cd apps/peertube-runner && npm login && npm publish --access=public)

Overview (`packages/transcription-devtools/README.md`)

Transcription DevTools

Includes:

  • JiWER CLI NodeJS wrapper
  • Benchmark tool to test multiple transcription engines
  • TypeScript classes to evaluate word-error-rate of files generated by the transcription

Build

sh
npm run build

Benchmark

A benchmark of available transcribers might be run with:

sh
npm run benchmark
text
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚        (index)         โ”‚          WER          โ”‚          CER          โ”‚ duration โ”‚ model  โ”‚        engine         โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ 5yZGBYqojXe7nuhq1TuHvz โ”‚ '28.39506172839506%'  โ”‚  '9.62457337883959%'  โ”‚  '41s'   โ”‚ 'tiny' โ”‚   'openai-whisper'    โ”‚
โ”‚ x6qREJ2AkTU4e5YmvfivQN โ”‚ '29.75206611570248%'  โ”‚ '10.46195652173913%'  โ”‚  '15s'   โ”‚ 'tiny' โ”‚ 'whisper-ctranslate2' โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

The benchmark may be run with multiple model builtin sizes:

sh
MODELS=tiny,small,large npm run benchmark

Jiwer

JiWER is a python tool for computing the word-error-rate of ASR systems.
https://jitsi.github.io/jiwer/cli/

JiWER serves as a reference implementation to calculate errors rates between 2 text files:

  • WER (Word Error Rate)
  • CER (Character Error Rate)

Usage

typescript
const jiwerCLI = new JiwerClI('./reference.txt', './hypothesis.txt')

// WER as a percentage, ex: 0.03 -> 3%
console.log(await jiwerCLI.wer())

// CER as a percentage: 0.01 -> 1%
console.log(await jiwerCLI.cer())

// Detailed comparison report
console.log(await jiwerCLI.alignment())

Resources


Overview (`packages/transcription/README.md`)

Transcription

Video transcription consists in transcribing the audio content of a video to a text.

This process might be called Automatic Speech Recognition or Speech to Text in more general context.

Provide a common API to many transcription backend, currently:

  • openai-whisper CLI
  • faster-whisper (via whisper-ctranslate2 CLI)

Potential candidates could be: whisper-cpp, vosk, ...

Requirements

  • Python 3
  • PIP

And at least one of the following transcription backend:

  • Python:
    • openai-whisper
    • whisper-ctranslate2>=0.4.3

Usage

Create a transcriber manually:

typescript
import { OpenaiTranscriber } from '@peertube/peertube-transcription'

(async () => {
  // Optional if you want to use a local installation of transcribe engines
  const binDirectory = 'local/pip/path/bin'

  // Create a transcriber powered by OpenAI Whisper CLI
  const transcriber = new OpenaiTranscriber({
    name: 'openai-whisper',
    command: 'whisper',
    languageDetection: true,
    binDirectory
  });

  // If not installed globally, install the transcriber engine (use pip under the hood)
  await transcriber.install('local/pip/path')

  // Transcribe
  const transcriptFile = await transcriber.transcribe({
    mediaFilePath: './myVideo.mp4',
    model: 'tiny',
    format: 'txt'
  });

  console.log(transcriptFile.path);
  console.log(await transcriptFile.read());
})();

Using a local model file:

typescript
import { WhisperBuiltinModel } from '@peertube/peertube-transcription/dist'

const transcriptFile = await transcriber.transcribe({
  mediaFilePath: './myVideo.mp4',
  model: await WhisperBuiltinModel.fromPath('./models/large.pt'),
  format: 'txt'
});

You may use the builtin Factory if you're happy with the default configuration:

typescript
import { transcriberFactory } from '@peertube/peertube-transcription'

transcriberFactory.createFromEngineName({
  engineName: transcriberName,
  logger: compatibleWinstonLogger,
  transcriptDirectory: '/tmp/transcription'
})

For further usage ../tests/src/transcription/whisper/transcriber/openai-transcriber.spec.ts

Lexicon

  • ONNX: Open Neural Network eXchange. A specification, the ONNX Runtime run these models.
  • GPTs: Generative Pre-Trained Transformers
  • LLM: Large Language Models
  • NLP: Natural Language Processing
  • MLP: Multilayer Perceptron
  • ASR: Automatic Speech Recognition
  • WER: Word Error Rate
  • CER: Character Error Rate

Overview (`packages/types-generator/README.md`)

PeerTube typings

These Typescript types are mainly used to write PeerTube plugins.

Installation

Npm:

text
npm install --save-dev @peertube/peertube-types

Usage

See contribute-plugins Typescript section of the doc.


Overview (`client/src/standalone/embed-player-api/README.md`)

@peertube/embed-api

See https://docs.joinpeertube.org/api/embed-player


Support Doc Api Quickstart (`support/doc/api/quickstart.md`)

REST API quick start

Detect a PeerTube instance

There are several ways to know if a website uses the PeerTube software:

  • The server exposes NodeInfo information: https://peertube2.cpy.re/nodeinfo/2.0.json
  • The server sends a x-powered-by: PeerTube header response to API requests
  • HTML pages include a <meta property="og:platform" content="PeerTube"> tag

Authentication

Get client

Some endpoints need authentication. We use OAuth 2.0 so first fetch the client tokens:

::: code-group

bash [curl]
curl https://peertube.example.com/api/v1/oauth-clients/local
js [js]
const { client_id, client_secret } = await fetch('https://peertube.example.com/api/v1/oauth-clients/local', {
  headers: { 'Content-Type': 'application/json' }
}).then(res => res.json())

:::

Response example:

json
{
  "client_id": "v1ikx5hnfop4mdpnci8nsqh93c45rldf",
  "client_secret": "AjWiOapPltI6EnsWQwlFarRtLh4u8tDt"
}

Get user token

Now you can fetch the user token:

::: code-group

bash [curl]
curl -X POST \
 -d "client_id=v1ikx5hnfop4mdpnci8nsqh93c45rldf&client_secret=AjWiOapPltI6EnsWQwlFarRtLh4u8tDt&grant_type=password&response_type=code&username=your_user&password=your_password" \
  https://peertube.example.com/api/v1/users/token
js [js]
const { access_token } = await fetch('https://peertube.example.com/api/v1/users/token', {
  contentType: 'application/x-www-form-urlencoded',
  method: 'POST',
  body: new URLSearchParams({
    client_id: '...',
    client_secret: '...',
    username: '...',
    password: '...',
    grant_type: 'password'
  })
}).then(res => res.json())

:::

Response example:

json
{
  "access_token": "90286a0bdf0f7315d9d3fe8dabf9e1d2be9c97d0",
  "token_type": "Bearer",
  "expires_in": 14399,
  "refresh_token": "2e0d675df9fc96d2e4ec8a3ebbbf45eca9137bb7"
}

Just use the access_token in the Authorization header:

bash
curl -H 'Authorization: Bearer 90286a0bdf0f7315d9d3fe8dabf9e1d2be9c97d0' https://peertube.example.com/api/v1/jobs/completed

List videos

bash
curl https://peertube.example.com/api/v1/videos

Libraries

Convenience libraries can be generated automatically from the OpenAPI specification for languages supported by the OpenAPI generator.


Support Doc Dependencies (`support/doc/dependencies.md`)

Dependencies

:warning: Warning: dependencies guide is maintained by the community. Some parts may be outdated! :warning:

Main dependencies supported by PeerTube:

  • node LTS (>= 22.12 and <25)
  • pnpm >= 12.x
  • postgres >=14.x
  • redis-server >=6.2
  • ffmpeg >=4.3 (using a ffmpeg static build is not recommended)
  • python >=3.8
  • pip

note: only LTS versions of external dependencies are supported. If no LTS version matching the version constraint is available, only release versions are supported.

note: some distributions still ship a PostgreSQL older than 14 in their default repositories. Check with psql --version after
installing, and if it is too old, install a supported release from the
PostgreSQL official repositories instead of the distribution package.

[[toc]]

Debian / Ubuntu and derivatives

  1. On a fresh Debian/Ubuntu, as root user, install basic utility programs needed for the installation

    sh
    sudo apt-get install curl sudo unzip vim
  2. It would be wise to disable root access and to continue this tutorial with a user with sudoers group access. You can see a guide for how to do this in Debian/Ubuntu here.

  3. Install NodeJS 22.x: https://nodesource.com/products/distributions

  4. Install PNPM:

    sh
    sudo npm install pnpm
  5. Install Python:

    sh
    sudo apt update
    sudo apt install python3-dev python3-pip python-is-python3
    python --version # Should be >= 3.8
  6. Install common dependencies:

    sh
    sudo apt update
    sudo apt install certbot nginx ffmpeg postgresql postgresql-contrib openssl g++ make redis-server git cron wget
    ffmpeg -version # Should be >= 4.1
    g++ -v # Should be >= 5.x
    redis-server --version # Should be >= 6.x
    psql --version # Should be >= 14

    Debian 11 (bullseye) and Ubuntu 20.04 ship PostgreSQL 13 or older: on these releases install PostgreSQL from the
    PostgreSQL APT repository instead.

Now that dependencies are installed, before running PeerTube you should start PostgreSQL and Redis:

sh
sudo systemctl start redis postgresql

Arch Linux

Run:

sh
sudo pacman -S nodejs-lts-iron ffmpeg postgresql openssl redis git wget unzip python python-pip base-devel npm nginx pnpm

Now that dependencies are installed, before running PeerTube you should start PostgreSQL and Redis:

sh
sudo systemctl start redis postgresql

CentOS 7

  1. Install NodeJS 22.x: https://nodesource.com/products/distributions

  2. Install PNPM:

    sh
    sudo npm install pnpm
  3. Install or compile ffmpeg:

  4. Install Packages:

    sh
    sudo yum update
    sudo yum install epel-release centos-release-scl
    sudo yum update
    sudo yum install nginx postgresql postgresql-server postgresql-contrib openssl gcc-c++ make wget redis git devtoolset-7

    :warning: The CentOS 7 base repository provides PostgreSQL 9.2, which is too old for PeerTube. Install PostgreSQL >= 14 from
    the PostgreSQL Yum repository instead of the postgresql* packages above.

  5. You need to use a more up to date version of G++ in order to run the npm run install-node-dependencies command, hence the installation of devtoolset-7.

    sh
    sudo scl enable devtoolset-7 bash

    Later when you invoke any node command, please prefix them with CC=/opt/rh/devtoolset-7/root/usr/bin/gcc CXX=/opt/rh/devtoolset-7/root/usr/bin/g++, such as with:

    sh
    sudo -H -u peertube CC=/opt/rh/devtoolset-7/root/usr/bin/gcc CXX=/opt/rh/devtoolset-7/root/usr/bin/g++ npm run install-node-dependencies -- --production
  6. Initialize the PostgreSQL database:

    sh
    sudo PGSETUP_INITDB_OPTIONS='--auth-host=md5' postgresql-setup --initdb --unit postgresql

Now that dependencies are installed, before running PeerTube you should enable and start PostgreSQL and Redis:

sh
sudo systemctl enable --now redis
sudo systemctl enable --now postgresql

Centos 8

  1. Install NodeJS 22.x: https://nodesource.com/products/distributions

  2. Install PNPM:

    sh
    sudo npm install pnpm
  3. Install or compile ffmpeg:

    sh
    sudo dnf install epel-release dnf-utils
    sudo yum-config-manager --set-enabled powertools
    sudo yum-config-manager --add-repo=https://negativo17.org/repos/epel-multimedia.repo
    sudo dnf install ffmpeg
  4. Install packages:

    sh
    sudo dnf update
    sudo dnf install epel-release
    sudo dnf update
    sudo dnf module enable postgresql:16 # Default stream is PostgreSQL 10, too old for PeerTube
    sudo dnf install nginx postgresql postgresql-server postgresql-contrib openssl gcc-c++ make wget redis git unzip
    psql --version # Should be >= 14

    Use sudo dnf module list postgresql to see the streams available on your release, and pick the most recent one >= 14.

  5. You'll need a symlink for python3 to python for youtube-dl to work

    sh
    sudo ln -s /usr/bin/python3 /usr/bin/python
  6. Initialize the PostgreSQL database:

    sh
    sudo PGSETUP_INITDB_OPTIONS='--auth-host=md5' postgresql-setup --initdb --unit postgresql

Now that dependencies are installed, before running PeerTube you should enable and start PostgreSQL and Redis:

sh
sudo systemctl enable --now redis
sudo systemctl enable --now postgresql

Rocky Linux 8.4

  1. Pull the latest updates:

    sh
    sudo dnf update -y
  2. Install NodeJS 22.x:

    sh
    sudo dnf module install -y nodejs:22
  3. Install PNPM:

    sh
    sudo npm install pnpm
  4. Install or compile ffmpeg (if you want to compile... enjoy):

    sh
    sudo dnf install -y epel-release
    sudo dnf --enablerepo=powertools install -y SDL2 SDL2-devel
    sudo dnf install -y --nogpgcheck https://download1.rpmfusion.org/free/el/rpmfusion-free-release-8.noarch.rpm https://download1.rpmfusion.org/nonfree/el/rpmfusion-nonfree-release-8.noarch.rpm
    sudo dnf install -y ffmpeg
    sudo dnf update -y
  5. Install PostgreSQL and Python3 and other stuff:

    sh
    sudo dnf module enable -y postgresql:16 # Default stream is PostgreSQL 10, too old for PeerTube
    sudo dnf install -y nginx postgresql postgresql-server postgresql-contrib openssl gcc-c++ make wget redis git python3 python3-pip
    psql --version # Should be >= 14
    sudo ln -s /usr/bin/python3 /usr/bin/python
    sudo PGSETUP_INITDB_OPTIONS='--auth-host=md5' postgresql-setup --initdb --unit postgresql
    sudo systemctl enable --now redis
    sudo systemctl enable --now postgresql
  6. Unknown missing steps:

    • Steps missing here... these were adapted from the CentOS 8 steps which abruptly ended.
    • /var/www/peertube does not exist yet (expected? done in future steps? documentation?).
    • Nothing about Certbot, NGINX, Firewall settings, and etc.
    • Hopefully someone can suggest what is missing here with some hints so I can add it?

Fedora

  1. Upgrade your packages:

    sh
    dnf upgrade
  2. (Optional) Install certbot (choose instructions for your distribution):
    https://certbot.eff.org/all-instructions

  3. Install NodeJS 22.x: https://nodesource.com/products/distributions

  4. Install PNPM:

    sh
    sudo npm install pnpm
  5. Enable RPM Fusion for Fedora (available for x86, x86_64, armhfp)

    sh
    sudo dnf install https://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm

    This is necessary because ffmpeg is not in the Fedora repos.

  6. Run:

    sh
    sudo dnf install nginx ffmpeg postgresql-server postgresql-contrib openssl gcc-c++ make redis git vim
    ffmpeg -version # Should be >= 4.1
    g++ -v # Should be >= 5.x
    redis-server --version # Should be >= 6.x
  7. Configure nginx

    sh
    sudo mkdir /etc/nginx/sites-available
    sudo mkdir /etc/nginx/sites-enabled
    sudo ln -s /etc/nginx/sites-enabled/peertube /etc/nginx/conf.d/peertube.conf
  8. Post-installation

    from PostgreSQL documentation:

    Due to policies for Red Hat family distributions, the PostgreSQL installation will not be enabled for automatic start or have the database initialized automatically.

    sh
    # PostgreSQL
    sudo PGSETUP_INITDB_OPTIONS='--auth-host=md5' postgresql-setup --initdb --unit postgresql
    sudo systemctl enable postgresql.service
    sudo systemctl start postgresql.service
    # Nginx
    sudo systemctl enable nginx.service
    sudo systemctl start nginx.service
    # Redis
    sudo systemctl enable redis.service
    sudo systemctl start redis.service
  9. Firewall

    By default, you cannot access your server via public IP. To do so, you must configure the firewall.

    Ports used by peertube dev setup:

    sh
    sudo firewall-cmd --permanent --zone=public --add-port=3000/tcp
    sudo firewall-cmd --permanent --zone=public --add-port=9000/tcp
    • Optional
    sh
    sudo firewall-cmd --permanent --zone=public --add-service=http
    sudo firewall-cmd --permanent --zone=public --add-service=https
    • Reload firewall
    sh
    sudo firewall-cmd --reload
  10. Configure max ports

    This is necessary if you are running dev setup, otherwise you will have errors with nodemon

    sh
    echo fs.inotify.max_user_watches=582222 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p

    More info

Red Hat Enterprise Linux 8

  1. Register system as root user to Red Hat Subscription Management (create a free Red Hat account if you don't have one yet).

    sh
    subscription-manager register --username <username> --password <password> --auto-attach
    dnf upgrade
    reboot
  2. Install NodeJS

    sh
    sudo dnf module install nodejs:22
  3. Install PNPM:

    sh
    sudo npm install pnpm
  4. Install FFmpeg

    sh
    sudo subscription-manager repos --enable "codeready-builder-for-rhel-8-$(arch)-rpms"
    sudo dnf install --nogpgcheck https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm
    sudo dnf install --nogpgcheck https://mirrors.rpmfusion.org/free/el/rpmfusion-free-release-8.noarch.rpm
    sudo dnf upgrade
    sudo dnf install ffmpeg
  5. Run:

    sh
    sudo dnf module enable postgresql:16 # Default stream is PostgreSQL 10, too old for PeerTube
    sudo dnf install nginx postgresql postgresql-server postgresql-contrib openssl gcc-c++ make wget redis git
    psql --version # Should be >= 14
  6. You'll need a symlink for python3 to python for youtube-dl to work

    sh
    sudo alternatives --set python3 /usr/bin/python
  7. Initialize the PostgreSQL database:

    sh
    sudo PGSETUP_INITDB_OPTIONS='--auth-host=md5' postgresql-setup --initdb --unit postgresql

    Now that dependencies are installed, before running PeerTube you should enable and start PostgreSQL and Redis:

    sh
    sudo systemctl enable --now redis
    sudo systemctl enable --now postgresql

    If you are running the production guide, you also need to slightly pre-configure nginx, because nginx is packaged differently in the Red Hat family distributions:

  8. Configure nginx

    sh
    sudo mkdir /etc/nginx/sites-available
    sudo mkdir /etc/nginx/sites-enabled
    sudo ln -s /etc/nginx/sites-enabled/peertube /etc/nginx/conf.d/peertube.conf
    sudo systemctl enable --now nginx
  9. Firewall

    By default, you cannot access your server via public IP. To do so, you must configure firewall:

    • Ports used by peertube dev setup:
    sh
    sudo firewall-cmd --permanent --zone=public --add-port=3000/tcp
    sudo firewall-cmd --permanent --zone=public --add-port=9000/tcp
    • Optional
    sh
    sudo firewall-cmd --permanent --zone=public --add-service=http
    sudo firewall-cmd --permanent --zone=public --add-service=https
    • Reload firewall
    sh
    sudo firewall-cmd --reload
  10. Configure max ports

    This is necessary if you are running dev setup, otherwise you will have errors with nodemon

    sh
    echo fs.inotify.max_user_watches=582222 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p

    More info

FreeBSD

On a fresh install of FreeBSD, new system or new jail:

  1. bootstrap pkg, initialize db and install peertube's dependencies, always as root (sudo not yet installed):

    sh
    pkg
    pkg update
    pkg install -y sudo bash wget git python nginx pkgconf postgresql16-server postgresql16-contrib redis openssl node npm ffmpeg unzip
  2. install sharp build dependencies: https://sharp.pixelplumbing.com/install/#building-from-source

  3. Install PNPM:

    sh
    sudo npm install pnpm
  4. Allow users in the wheel group (hope you don't forgot to add your user on wheel group!) to use sudo.

    sh
    visudo

    Uncomment the line 90

    text
    %wheel ALL=(ALL) ALL
  5. Enable nginx, redis, postgresql services and initialize database.

    sh
    sysrc postgresql_enable="YES"
    sysrc redis_enable="YES"
    sysrc nginx_enable="YES"

    Initialize database and start services

    sh
    service postgresql initdb
    service postgresql start
    service redis start
    service nginx start

macOS

  1. Add the packages:

    sh
    brew install ffmpeg nginx postgresql@16 openssl gcc make redis git
    brew install pnpm
  2. Run the services:

    sh
    brew services run postgresql@16
    brew services run redis

    On macOS, the postgresql user can be _postgres instead of postgres.
    If sudo -u postgres createuser -P peertube gives you an unknown user: postgres error, you can try sudo -u _postgres createuser -U peertube.

Gentoo

  1. Add this to /etc/portage/sets/peertube:

    text
    net-libs/nodejs
    sys-apps/pnpm
    media-video/ffmpeg[x264] # Optionally add vorbis,vpx
    dev-db/postgresql:16 # Any slot >= 14 works
    dev-db/redis
    dev-vcs/git
    app-arch/unzip
    dev-lang/python
    dev-lang/python-exec
    www-servers/nginx
    
    # Optional, client for Letโ€™s Encrypt:
    # app-crypt/certbot
  2. If you are on a "stable" Gentoo you need to accept the testing keyword ~amd64 pnpm:

    sh
    mkdir -p /etc/portage/package.keywords
    cat << EOF >> /etc/portage/package.keywords/peertube
    # required by pnpm (argument) for PeerTube
    sys-apps/pnpm ~amd64
    EOF
  3. Compile the peertube set:

    sh
    emerge -a @peertube
  4. Initialize the PostgreSQL database if you just merged it:

    sh
    emerge --config postgresql
  5. (For OpenRC) Enable and then start the services (replace with the correct PostgreSQL slot):

    sh
    rc-update add redis
    rc-update add postgresql-16
    rc-service redis start
    rc-service postgresql-16 start
  6. Create Python version symlink for youtube-dl:

    sh
    emerge -1 python-exec

OpenBSD

  1. Install Packages:

    sh
    pkg_add sudo bash wget git python nginx pkgconf postgresql-server postgresql-contrib redis openssl
  2. Install PNPM:

    sh
    sudo npm install pnpm
  3. Allow users in the wheel group to use sudo

    sh
    visudo

    Uncomment line #43:

    text
    %wheel ALL=(ALL) ALL
  4. Enable services:

    sh
    rcctl enable postgresql redis nginx

Other distributions

Feel free to update this file in a pull request!


Support Doc Docker (`support/doc/docker.md`)

Docker guide

This guide requires docker and
docker-compose V2.

shell
docker compose version # Must be > 2.x.x

Install

PeerTube does not support webserver host change. Keep in mind your domain
name is definitive after your first PeerTube start.

Go to your workdir

:::info
The guide that follows assumes an empty workdir, but you can also clone the repository, use the master branch and cd support/docker/production.
:::

shell
cd /your/peertube/directory

Get the latest Compose file

shell
curl https://raw.githubusercontent.com/chocobozzz/PeerTube/master/support/docker/production/docker-compose.yml > docker-compose.yml

View the source of the file you're about to download: docker-compose.yml

Get the latest env_file

shell
curl https://raw.githubusercontent.com/Chocobozzz/PeerTube/master/support/docker/production/.env > .env

View the source of the file you're about to download: .env

Tweak the `docker-compose.yml` file there according to your needs

shell
sudo nano docker-compose.yml

Then tweak the `.env` file to change the environment variables settings

shell
sudo nano .env

In the downloaded example .env, you must replace:

  • <MY POSTGRES USERNAME>
  • <MY POSTGRES PASSWORD>
  • <MY DOMAIN> without 'https://'
  • <MY EMAIL ADDRESS>
  • <MY PEERTUBE SECRET>

Other environment variables are used in
/support/docker/production/config/custom-environment-variables.yaml and can be
intuited from usage.

Webserver

::: info
The docker compose file includes a configured web server. You can skip this part and comment the appropriate section in the docker compose if you use another webserver/proxy.
:::

Install the template that the nginx container will use.
The container will generate the configuration by replacing ${WEBSERVER_HOST} and ${PEERTUBE_HOST} using your docker compose env file.

shell
mkdir -p docker-volume/nginx docker-volume/nginx-logs
curl https://raw.githubusercontent.com/Chocobozzz/PeerTube/master/support/nginx/peertube > docker-volume/nginx/peertube

You need to manually generate the first SSL/TLS certificate using Let's Encrypt:

shell
mkdir -p docker-volume/certbot
docker run -it --rm --name certbot -p 80:80 -v "$(pwd)/docker-volume/certbot/conf:/etc/letsencrypt" certbot/certbot certonly --standalone

A dedicated container in the docker-compose will automatically renew this certificate and reload nginx.

Test your setup

note: Newer versions of compose are called with docker compose instead of docker-compose, so remove the dash in all steps that use this command if you are getting errors.

Run your containers:

shell
docker compose up

Obtaining your automatically-generated admin credentials

You can change the automatically created password for user root by running this command from peertube's root directory:

shell
docker compose exec -u peertube peertube npm run reset-password -- -u root

You can also grep your peertube container's logs for the default root password. You're going to want to run docker-compose logs peertube | grep -A1 root to search the log output for your new PeerTube's instance admin credentials which will look something like this.

bash
docker compose logs peertube | grep -A1 root

peertube_1  | [example.com:443] 2019-11-16 04:26:06.082 info: Username: root
peertube_1  | [example.com:443] 2019-11-16 04:26:06.083 info: User password: abcdefghijklmnop

Obtaining Your Automatically Generated DKIM DNS TXT Record

DKIM signature sending and RSA keys generation are enabled by the default Postfix image mwader/postfix-relay with OpenDKIM.

Run cat ./docker-volume/opendkim/keys/*/*.txt to display your DKIM DNS TXT Record containing the public key to configure to your domain :

bash
cat ./docker-volume/opendkim/keys/*/*.txt

peertube._domainkey.mydomain.tld.	IN	TXT	( "v=DKIM1; h=sha256; k=rsa; "
	  "p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0Dx7wLGPFVaxVQ4TGym/eF89aQ8oMxS9v5BCc26Hij91t2Ci8Fl12DHNVqZoIPGm+9tTIoDVDFEFrlPhMOZl8i4jU9pcFjjaIISaV2+qTa8uV1j3MyByogG8pu4o5Ill7zaySYFsYB++cHJ9pjbFSC42dddCYMfuVgrBsLNrvEi3dLDMjJF5l92Uu8YeswFe26PuHX3Avr261n"
	  "j5joTnYwat4387VEUyGUnZ0aZxCERi+ndXv2/wMJ0tizq+a9+EgqIb+7lkUc2XciQPNuTujM25GhrQBEKznvHyPA6fHsFheymOuB763QpkmnQQLCxyLygAY9mE/5RY+5Q6J9oDOQIDAQAB" )  ; ----- DKIM key peertube for mydomain.tld

Administrator password

See the production guide "Administrator" section

What now?

See the production guide "What now" section.

Upgrade

::: warning
Check the changelog (in particular the IMPORTANT NOTES section): https://github.com/Chocobozzz/PeerTube/blob/develop/CHANGELOG.md
:::

Pull the latest images:

shell
cd /your/peertube/directory
docker compose pull

Stop, delete the containers and internal volumes (to invalidate static client files shared by peertube and webserver containers):

shell
docker compose down -v

Update the nginx configuration:

shell
mv docker-volume/nginx/peertube docker-volume/nginx/peertube.bak
curl https://raw.githubusercontent.com/Chocobozzz/PeerTube/master/support/nginx/peertube > docker-volume/nginx/peertube

Rerun PeerTube:

shell
docker compose up -d

Upgrade PostgreSQL container

If you want to upgrade your PostgreSQL container version (for example because your current version is about to no longer be supported),
you need to plan downtime (to export current cluster and re-import data in new one).

When you're ready, go inside your PeerTube docker compose directory:

sh
cd /docker-compose/directory

Prepare the backups directory and stop all containers except the database:

sh
mkdir -p backups
docker compose stop peertube webserver certbot

Go inside the database container:

sh
docker compose exec -it postgres /bin/bash

And export the database (you don't need to replace $POSTGRES_* variables, they are automatically set by your env file from docker compose):

sh
export PGUSER="$POSTGRES_USER"
export PGDATABASE="$POSTGRES_DB"
export PGPASSWORD="$POSTGRES_PASSWORD"
pg_dumpall > "/tmp/pg.dump"

Exit the container:

sh
exit

Copy the dump from the container:

sh
docker compose cp postgres:/tmp/pg.dump backups/pg.dump

Stop the database container and prepare the data for the new cluster:

sh
docker compose stop postgres
mv ./docker-volume/db ./docker-volume/db.bak
mkdir ./docker-volume/db && chmod 700 ./docker-volume/db

Upgrade your PostgreSQL container version (for example replace postgres:13-alpine by postgres:17-alpine):

sh
vim docker-compose.yml

Pull new PostgreSQL Docker image:

sh
docker compose pull

Restart PostgreSQL only container and wait until you see: database system is ready to accept connections

sh
docker compose up -d postgres
docker compose logs -f postgres

Copy the database dump inside the container:

sh
docker compose cp "backups/pg.dump" postgres:/tmp/pg.dump

Go inside the container

sh
docker compose exec -it postgres /bin/bash

Check the PostgreSQL version and re-import database data.
Then, reset the PeerTube database user password to fix a potential authentication issue if the old password hash algorithm has been deprecated.

sh
export PGUSER="$POSTGRES_USER"
export PGDATABASE="$POSTGRES_DB"
export PGPASSWORD="$POSTGRES_PASSWORD"
psql -U "$POSTGRES_USER" -c "SELECT version();"
psql -U "$POSTGRES_USER" -f /tmp/pg.dump
psql -U "$POSTGRES_USER" -c "ALTER USER $POSTGRES_USER WITH PASSWORD '$POSTGRES_PASSWORD';"

Exit the container:

sh
exit

Restart other services and check everything is fine:

sh
docker compose up -d peertube webserver certbot
docker compose logs -f peertube

If you're happy with the results, you can remove backups directory and old data directories:

sh
rm -rf ./docker-volume/db.bak backups

Build

Production

shell
git clone https://github.com/chocobozzz/PeerTube /tmp/peertube
cd /tmp/peertube
docker build . -f ./support/docker/production/Dockerfile

Development

We don't have a Docker image for development. See the CONTRIBUTING guide for more information on how you can hack PeerTube!


Support Doc Production (`support/doc/production.md`)

Production guide

Installation

Please don't install PeerTube for production on a device behind a low bandwidth connection (example: your ADSL link).
If you want information about the appropriate hardware to run PeerTube, please see the FAQ.

:hammer: Dependencies

Follow the steps of the dependencies guide.

:construction_worker: PeerTube user

Create a peertube user with /var/www/peertube home:

::: code-group

bash [gnu/linux]
sudo useradd -m -d /var/www/peertube -s /usr/sbin/nologin peertube
bash [freebsd]
sudo pw useradd -n peertube -d /var/www/peertube -s /usr/sbin/nologin -m

:::

Ensure the peertube root directory is traversable by nginx:

bash
sudo chmod 755 /var/www/peertube

:card_file_box: Database

Create the production database and a peertube user inside PostgreSQL:

bash
cd /var/www/peertube
sudo -u postgres createuser -P peertube

Here you should enter a password for PostgreSQL peertube user, that should be copied in production.yaml file.
Don't just hit enter else it will be empty.

bash
sudo -u postgres createdb -O peertube -E UTF8 -T template0 peertube_prod

Then enable extensions PeerTube needs:

bash
sudo -u postgres psql -c "CREATE EXTENSION pg_trgm;" peertube_prod
sudo -u postgres psql -c "CREATE EXTENSION unaccent;" peertube_prod

:page_facing_up: Prepare PeerTube directory

Fetch the latest tagged version of Peertube:

bash
VERSION=$(curl -s https://api.github.com/repos/chocobozzz/peertube/releases/latest | grep tag_name | cut -d '"' -f 4) && echo "Latest Peertube version is $VERSION"

Open the peertube directory, create a few required directories:

bash
cd /var/www/peertube
sudo -u peertube mkdir config storage versions
sudo -u peertube chmod 750 config/

Download the latest version of the Peertube client, unzip it and remove the zip:

bash
cd /var/www/peertube/versions
# Releases are also available on https://builds.joinpeertube.org/release
sudo -u peertube wget -q "https://github.com/Chocobozzz/PeerTube/releases/download/${VERSION}/peertube-${VERSION}.zip"
sudo -u peertube unzip -q peertube-${VERSION}.zip && sudo -u peertube rm peertube-${VERSION}.zip

Install Peertube:

::: code-group

bash [gnu/linux]
cd /var/www/peertube
sudo -u peertube ln -s versions/peertube-${VERSION} ./peertube-latest
cd ./peertube-latest && sudo -H -u peertube npm run install-node-dependencies -- --production
bash [freebsd]
cd /var/www/peertube
sudo -u peertube ln -s versions/peertube-${VERSION} ./peertube-latest
cd ./peertube-latest && sudo -H -u peertube npm run install-node-dependencies -- --production
sudo -u peertube pnpm add --workspace-root --no-lockfile --prod node-addon-api node-gyp
sudo -u peertube SHARP_FORCE_GLOBAL_LIBVIPS=1 npm explore sharp -- npm run build

:::

:wrench: PeerTube configuration

Copy the default configuration file that contains the default configuration provided by PeerTube.
You must not update this file.

bash
cd /var/www/peertube
sudo -u peertube cp peertube-latest/config/default.yaml config/default.yaml

Now copy the production example configuration:

bash
cd /var/www/peertube
sudo -u peertube cp peertube-latest/config/production.yaml.example config/production.yaml

Then edit the config/production.yaml file according to your webserver and database configuration. In particular:

  • webserver: Reverse proxy public information
  • secrets: Secret strings you must generate manually (PeerTube version >= 5.0)
  • database: PostgreSQL settings
  • redis: Redis settings
  • smtp: If you want to use emails
  • admin.email: To correctly fill root user email

Keys defined in config/production.yaml will override keys defined in config/default.yaml.

PeerTube does not support webserver host change. Even though PeerTube CLI can help you to switch hostname there's no official support for that since it is a risky operation that might result in unforeseen errors.

:truck: Webserver

We only provide official configuration files for Nginx.

Copy the nginx configuration template:

bash
sudo cp /var/www/peertube/peertube-latest/support/nginx/peertube /etc/nginx/sites-available/peertube

Set the domain for the webserver configuration file by replacing [peertube-domain] with the domain for the peertube server:

bash
sudo sed -i 's/${WEBSERVER_HOST}/[peertube-domain]/g' /etc/nginx/sites-available/peertube
sudo sed -i 's/${PEERTUBE_HOST}/127.0.0.1:9000/g' /etc/nginx/sites-available/peertube

Then modify the webserver configuration file. Please pay attention to:

  • the alias and root directives paths, the paths must correspond to your PeerTube filesystem location
  • the proxy_limit_rate and limit_rate directives if you plan to stream high bitrate videos (like 4K at 60FPS)
bash
sudo vim /etc/nginx/sites-available/peertube

Activate the configuration file:

bash
sudo ln -s /etc/nginx/sites-available/peertube /etc/nginx/sites-enabled/peertube

To generate the certificate for your domain as required to make https work you can use Let's Encrypt:

bash
sudo systemctl stop nginx
sudo certbot certonly --standalone --post-hook "systemctl restart nginx"
sudo systemctl restart nginx

Certbot should have installed a cron to automatically renew your certificate.
Since our nginx template supports webroot renewal, we suggest you to update the renewal config file to use the webroot authenticator:

bash
# Replace authenticator = standalone by authenticator = webroot
# Add webroot_path = /var/www/certbot
sudo vim /etc/letsencrypt/renewal/your-domain.com.conf

If you plan to have many concurrent viewers on your PeerTube instance, consider increasing worker_connections value: https://nginx.org/en/docs/ngx_core_module.html#worker_connections.

If using FreeBSD

On FreeBSD you can use Dehydrated security/dehydrated for Let's Encrypt

bash
sudo pkg install dehydrated

:alembic: Linux TCP/IP Tuning

bash
sudo cp /var/www/peertube/peertube-latest/support/sysctl.d/30-peertube-tcp.conf /etc/sysctl.d/
sudo sysctl -p /etc/sysctl.d/30-peertube-tcp.conf

Your distro may enable this by default, but at least Debian 9 does not, and the default FIFO
scheduler is quite prone to "Buffer Bloat" and extreme latency when dealing with slower client
links as we often encounter in a video server.

:bricks: systemd

If your OS uses systemd, copy the configuration template:

bash
sudo cp /var/www/peertube/peertube-latest/support/systemd/peertube.service /etc/systemd/system/

Check the service file (PeerTube paths and security directives):

bash
sudo vim /etc/systemd/system/peertube.service

Tell systemd to reload its config:

bash
sudo systemctl daemon-reload

If you want to start PeerTube on boot:

bash
sudo systemctl enable peertube

Run:

bash
sudo systemctl start peertube
sudo journalctl -feu peertube

If using FreeBSD

On FreeBSD, copy the startup script and update rc.conf:

bash
sudo install -m 0555 /var/www/peertube/peertube-latest/support/freebsd/peertube /usr/local/etc/rc.d/
sudo sysrc peertube_enable="YES"

Run:

bash
sudo service peertube start

If using OpenRC

If your OS uses OpenRC, copy the service script:

bash
sudo cp /var/www/peertube/peertube-latest/support/init.d/peertube /etc/init.d/
sudo cp /var/www/peertube/peertube-latest/support/conf.d/peertube /etc/conf.d/

If you want to start PeerTube on boot:

bash
sudo rc-update add peertube default

Run and print last logs:

bash
sudo /etc/init.d/peertube start
tail -f /var/log/peertube/peertube.log

:technologist: Administrator

The administrator username is root and the password is automatically generated. It can be found in PeerTube
logs (path defined in production.yaml). You can also set another password with:

bash
cd /var/www/peertube/peertube-latest && sudo -u peertube NODE_CONFIG_DIR=/var/www/peertube/config NODE_ENV=production npm run reset-password -- -u root

Alternatively you can set the environment variable PT_INITIAL_ROOT_PASSWORD,
to your own administrator password, although it must be 6 characters or more.

:tada: What now?

Now your instance is up you can:

Upgrade

PeerTube instance

Check the changelog (in particular the IMPORTANT NOTES section): https://github.com/Chocobozzz/PeerTube/blob/develop/CHANGELOG.md

Run the upgrade script (the password it asks is PeerTube's database user password):

::: code-group

bash [gnu/linux]
cd /var/www/peertube/peertube-latest/scripts && sudo -H -u peertube ./upgrade.sh
bash [freebsd]
cd /var/www/peertube/peertube-latest/scripts && sudo -H -u peertube ./upgrade.sh
sudo -u peertube pnpm add --workspace-root --no-lockfile --prod node-addon-api node-gyp
sudo -u peertube SHARP_FORCE_GLOBAL_LIBVIPS=1 npm explore sharp -- npm run build

:::

If you have git installed on your system, the upgrade will create a production.yaml.new file with differences marked as merge conflicts.
Review this file and replace your existing production.yaml with it before restarting.

bash
# Make sure you first updated your configuration per the note above
sudo systemctl restart peertube # Or use your OS command to restart PeerTube if you don't use systemd

You may want to run sudo -u peertube pnpm store prune after several upgrades to free up disk space.

Prefer manual upgrade?

Make a SQL backup

bash
SQL_BACKUP_PATH="backup/sql-peertube_prod-$(date -Im).bak" && \
    cd /var/www/peertube && sudo -u peertube mkdir -p backup && \
    sudo -u postgres pg_dump -F c peertube_prod | sudo -u peertube tee "$SQL_BACKUP_PATH" >/dev/null

Fetch the latest tagged version of Peertube:

bash
VERSION=$(curl -s https://api.github.com/repos/chocobozzz/peertube/releases/latest | grep tag_name | cut -d '"' -f 4) && echo "Latest Peertube version is $VERSION"

Download the new version and unzip it:

bash
cd /var/www/peertube/versions && \
    sudo -u peertube wget -q "https://github.com/Chocobozzz/PeerTube/releases/download/${VERSION}/peertube-${VERSION}.zip" && \
    sudo -u peertube unzip -o peertube-${VERSION}.zip && \
    sudo -u peertube rm peertube-${VERSION}.zip

Install node dependencies:

bash
cd /var/www/peertube/versions/peertube-${VERSION} && \
    sudo -H -u peertube npm run install-node-dependencies -- --production

Copy new configuration defaults values and update your configuration file:

bash
sudo -u peertube cp /var/www/peertube/versions/peertube-${VERSION}/config/default.yaml /var/www/peertube/config/default.yaml
diff -u /var/www/peertube/versions/peertube-${VERSION}/config/production.yaml.example /var/www/peertube/config/production.yaml

Change the link to point to the latest version:

bash
cd /var/www/peertube && \
    sudo unlink ./peertube-latest && \
    sudo -u peertube ln -s versions/peertube-${VERSION} ./peertube-latest

Update PeerTube configuration

If your system has git installed, the auto upgrade script should have created a config/production.yaml.new file that merges your current configuration file with the new configuration keys introduced by the new PeerTube version.

Review the file, check and fix any potential conflicts:

bash
cd /var/www/peertube && sudo -u peertube diff config/production.yaml config/production.yaml.new

Then replace your current configuration file by the new one:

bash
cd /var/www/peertube && sudo -u peertube cp config/production.yaml.new config/production.yaml

Update nginx configuration

Check changes in nginx configuration:

bash
cd /var/www/peertube/versions
diff -u "$(ls -t | head -2 | tail -1)/support/nginx/peertube" "$(ls -t | head -1)/support/nginx/peertube"

Update systemd service

Check changes in systemd configuration:

bash
cd /var/www/peertube/versions
diff -u "$(ls -t | head -2 | tail -1)/support/systemd/peertube.service" "$(ls -t | head -1)/support/systemd/peertube.service"

If using OpenRC

bash
cd /var/www/peertube/versions
diff -u "$(ls -t | head -2 | tail -1)/support/init.d/peertube" "$(ls -t | head -1)/support/init.d/peertube"
diff -u "$(ls -t | head -2 | tail -1)/support/conf.d/peertube" "$(ls -t | head -1)/support/conf.d/peertube"

Restart PeerTube

If you changed your nginx configuration:

bash
sudo systemctl reload nginx

If you changed your systemd configuration:

bash
sudo systemctl daemon-reload

Restart PeerTube and check the logs:

bash
sudo systemctl restart peertube && sudo journalctl -fu peertube

Things went wrong?

Change peertube-latest destination to the previous version and restore your SQL backup:

bash
OLD_VERSION="v0.42.42" && SQL_BACKUP_PATH="backup/sql-peertube_prod-20180119-1018.bak" && \
  cd /var/www/peertube && sudo -u peertube unlink ./peertube-latest && \
  sudo -u peertube ln -s "versions/peertube-$OLD_VERSION" peertube-latest && \
  sudo -u postgres pg_restore -c -C -d peertube_prod "$SQL_BACKUP_PATH" && \
  sudo systemctl restart peertube

Support Doc Tools (`support/doc/tools.md`)

CLI tools guide

[[toc]]

Remote PeerTube CLI

peertube-cli is a tool that communicates with a PeerTube instance using its REST API.
It can be launched from a remote server/computer to easily upload videos, manage plugins, redundancies etc.

Installation

Ensure you have node installed on your system:

bash
node --version # Should be >= 22.x

Then install the CLI:

bash
sudo npm install @peertube/peertube-cli

CLI wrapper

The wrapper provides a convenient interface to the following sub-commands.

text
Usage: peertube-cli [command] [options]

Options:
  -v, --version                     output the version number
  -h, --help                        display help for command

Commands:
  auth                              Register your accounts on remote instances to use them with other commands
  upload|up [options]               Upload a video on a PeerTube instance
  redundancy|r                      Manage instance redundancies
  plugins|p                         Manage instance plugins/themes
  get-access-token|token [options]  Get a peertube access token
  help [command]                    display help for command

The wrapper can keep track of instances you have an account on. We limit to one account per instance for now.

bash
peertube-cli auth add -u 'PEERTUBE_URL' -U 'PEERTUBE_USER' --password 'PEERTUBE_PASSWORD'

Now list the account(s) you've created

bash
peertube-cli auth list
text
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ instance                     โ”‚ login                        โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ 'PEERTUBE_URL'               โ”‚ 'PEERTUBE_USER'              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

You can now use that account to execute sub-commands without feeding the --url, --username and --password parameters:

bash
peertube-cli upload <videoFile>
bash
peertube-cli plugins list
...

peertube-cli upload

You can use this script to upload videos directly from the CLI.

Videos will be publicly available after transcoding (you can see them before that in your account on the web interface).

bash
cd ${CLONE}
peertube-cli upload --help

peertube-cli plugins

Install/update/uninstall or list local or NPM PeerTube plugins:

bash
cd ${CLONE}
peertube-cli plugins --help
peertube-cli plugins list --help
peertube-cli plugins install --help
peertube-cli plugins update --help
peertube-cli plugins uninstall --help

peertube-cli plugins install --path /my/plugin/path
peertube-cli plugins install --npm-name peertube-theme-example

peertube-cli redundancy

Manage (list/add/remove) video redundancies:

To list your videos that are duplicated by remote instances:

bash
peertube-cli redundancy list-remote-redundancies

To list remote videos that your instance duplicated:

bash
peertube-cli redundancy list-my-redundancies

To duplicate a specific video in your redundancy system:

bash
peertube-cli redundancy add --video 823

To remove a video redundancy:

bash
peertube-cli redundancy remove --video 823

PeerTube runner

PeerTube supports VOD/Live transcoding and VOD transcription (PeerTube >= 6.2) by a remote PeerTube runner.

The runner communicates with the PeerTube instance using HTTP and WebSocket and doesn't need to have a public IP.
So you can run a runner on a classic server, a non-public server or even on your own computer!

You can read the admin documentation on how to use PeerTube runners on https://docs.joinpeertube.org/admin/remote-runners

Runner installation

Ensure you have node, ffmpeg and ffprobe installed on your system:

bash
node --version # Should be >= 22.x
ffprobe -version # Should be >= 4.3
ffmpeg -version # Should be >= 4.3

If you want to use video transcription:

bash
pip install whisper-ctranslate2 # or pipx install whisper-ctranslate2 depending on your distribution

Then install the CLI:

bash
sudo npm install @peertube/peertube-runner

Configuration

The runner uses env paths like ~/.config, ~/.cache and ~/.local/share directories to store runner configuration or temporary files.

Multiple PeerTube runners can run on the same OS by using the --id CLI option (each runner uses its own config/tmp directories):

bash
peertube-runner [commands] --id instance-1
peertube-runner [commands] --id instance-2
peertube-runner [commands] --id instance-3

You can change the runner configuration (jobs concurrency, ffmpeg threads/nice, whisper engines/models, etc.) by editing ~/.config/peertube-runner-nodejs/[id]/config.toml.

The runner TOML config template consists of:

toml
[jobs]
# How much concurrent jobs the runner can execute in parallel
concurrency = 2

[ffmpeg]
# How much threads a ffmpeg process can use
# 0 -> let ffmpeg automatically choose
threads = 0
nice = 20

[transcription]
# Choose between "openai-whisper" or "whisper-ctranslate2"
# Engine binary has to be installed manually (unlike the PeerTube instance that can install whisper automatically)
engine = "whisper-ctranslate2"
# Optional whisper binary path if not available in global path
enginePath = "/var/prunner/.local/pipx/venvs/whisper-ctranslate2/bin/whisper-ctranslate2"
# Whisper model: "tiny", "base", "small", "medium", "large-v2" or "large-v3"
model = "large-v2"

# Registered instances are saved in the config file
[[registeredInstances]]
url = "..." # URL of the instance
runnerToken = "..." # Shared runner token secret
runnerName = "..." # Runner name declared to the PeerTube instance

[[registeredInstances]]
url = "..."
runnerToken = "..."
runnerName = "..."

Run the server

In a shell

You need to run the runner in server mode first so it can run transcoding jobs of registered PeerTube instances:

bash
peertube-runner server

You can also decide which kind of job the runner can execute with --enable-job <type> option.
This way you can have one dedicated runner for transcription tasks (on a GPU machine for example) and another one for transcoding tasks.

Only transcription tasks

bash
peertube-runner server --enable-job video-transcription

Only VOD transcoding tasks

bash
peertube-runner server --enable-job vod-web-video-transcoding --enable-job vod-hls-transcoding --enable-job vod-audio-merge-transcoding

Only "studio" transcoding

bash
peertube-runner server --enable-job video-studio-transcoding

Only "live" transcoding

bash
peertube-runner server --enable-job live-rtmp-hls-transcoding

As a Systemd service

If your OS uses systemd, you can also configure a service so that the runner starts automatically.

To do so, first create a dedicated user. Here, we are calling it prunner, but you can choose whatever name you want.
We are using /srv/prunner as his home dir, but you can choose any other path.

bash
useradd -m -d /srv/prunner -s /usr/sbin/nologin prunner

::: info Note
If you want to use /home/prunner, you have to set ProtectHome=false in the systemd configuration (see below).
:::

Now, you can create the /etc/systemd/system/prunner.service file (don't forget to adapt path and user/group names if you changed it):

systemd
[Unit]
Description=PeerTube runner daemon
After=network.target

[Service]
Type=simple
Environment=NODE_ENV=production
User=prunner
Group=prunner
ExecStart=peertube-runner server
WorkingDirectory=/srv/prunner
SyslogIdentifier=prunner
Restart=always

; Some security directives.
; Mount /usr, /boot, and /etc as read-only for processes invoked by this service.
ProtectSystem=full
; Sets up a new /dev mount for the process and only adds API pseudo devices
; like /dev/null, /dev/zero or /dev/random but not physical devices. Disabled
; by default because it may not work on devices like the Raspberry Pi.
PrivateDevices=false
; Ensures that the service process and all its children can never gain new
; privileges through execve().
NoNewPrivileges=true
; This makes /home, /root, and /run/user inaccessible and empty for processes invoked
; by this unit. Make sure that you do not depend on data inside these folders.
ProtectHome=true
; Drops the sys admin capability from the daemon.
CapabilityBoundingSet=~CAP_SYS_ADMIN

[Install]
WantedBy=multi-user.target

:::info Note
You can add the parameter --id instance-1 on the ExecStart line, if you want to have multiple instances.
You can then create multiple separate services. They can use the same user and path.
:::

Finally, to enable the service for the first time:

bash
systemctl daemon-reload
systemctl enable prunner.service
systemctl restart prunner.service

Next time, if you need to start/stop/restart the service:

bash
systemctl stop prunner.service
systemctl start prunner.service
systemctl restart prunner.service

You can also check the status (and last logs):

bash
systemctl status prunner.service

To edit the runner configuration: juste edit the /srv/prunner/.config/peertube-runner-nodejs/default/config.toml file,
and restart the service (this file will be created when the runner starts for the first time).

If you are using the --id parameter, you can change specific configuration by editing the file /srv/prunner/.config/peertube-runner-nodejs/[id]/config.toml.

::: info
For every peertube-runner commands described below, you have to run them as the prunner user.
So for example, to call the list-registered command: sudo -u prunner peertube-runner list-registered.
Otherwise the script will read the wrong configuration and cache files, and won't work as expected.
:::

Register

Then, you can register the runner to process transcoding job of a remote PeerTube instance:

::: code-group

bash [shell]
peertube-runner register --url http://peertube.example.com --registration-token ptrrt-... --runner-name my-runner-name
bash [systemd]
sudo -u prunner peertube-runner register --url http://peertube.example.com --registration-token ptrrt-... --runner-name my-runner-name

:::

The runner will then use a websocket connection with the PeerTube instance to be notified about new available transcoding jobs.

Unregister

To unregister a PeerTube instance:

::: code-group

bash [shell]
peertube-runner unregister --url http://peertube.example.com --runner-name my-runner-name
bash [systemd]
sudo -u prunner peertube-runner unregister --url http://peertube.example.com --runner-name my-runner-name

:::

List registered instances

::: code-group

bash [shell]
peertube-runner list-registered
bash [systemd]
sudo -u prunner peertube-runner list-registered

:::

List jobs

Runner >= 0.1.0

To list jobs that are processed by the runner:

::: code-group

bash [shell]
peertube-runner list-jobs
peertube-runner list-jobs --include-payload
bash [systemd]
sudo -u prunner peertube-runner list-jobs
sudo -u prunner peertube-runner list-jobs --include-payload

:::

Graceful shutdown

Ask the runner to shutdown when it has finished all of its current tasks:

::: code-group

bash [shell]
peertube-runner graceful-shutdown
bash [systemd]
sudo -u prunner peertube-runner graceful-shutdown

:::

Update the runner package

You can check if there is a new runner version using:

bash
sudo npm outdated -g @peertube/peertube-runner
text
Package                    Current  Wanted  Latest  Location                                Depended by
@peertube/peertube-runner    0.0.6   0.0.7   0.0.7  node_modules/@peertube/peertube-runner  lib

To update the runner:

Update the package

bash
sudo npm update -g @peertube/peertube-runner

Check that the version changed (optional)

bash
sudo npm list -g @peertube/peertube-runner

Restart the service (if you are using systemd)

bash
sudo systemctl restart prunner.service

Server tools

Server tools are scripts that interact directly with the code of your PeerTube instance.
They must be run on the server, in peertube-latest directory.

Parse logs

To parse PeerTube last log file:

::: code-group

bash [classic installation]
cd /var/www/peertube/peertube-latest; \
    sudo -u peertube NODE_CONFIG_DIR=/var/www/peertube/config NODE_ENV=production npm run parse-log -- --level info
bash [docker]
cd /var/www/peertube-docker; \
    docker compose exec -u peertube peertube npm run parse-log -- --level info

:::

--level is optional and could be info/warn/error

You can also remove SQL or HTTP logs using --not-tags:

::: code-group

bash [classic installation]
cd /var/www/peertube/peertube-latest; \
    sudo -u peertube NODE_CONFIG_DIR=/var/www/peertube/config NODE_ENV=production npm run parse-log -- --level debug --not-tags http sql
bash [docker]
cd /var/www/peertube-docker; \
    docker compose exec -u peertube peertube npm run parse-log -- --level debug --not-tags http sql

:::

Regenerate video and playlist thumbnails

Regenerating local video and playlist thumbnails could be useful because new PeerTube releases may increase thumbnail sizes:

::: code-group

bash [classic installation]
cd /var/www/peertube/peertube-latest; \
    sudo -u peertube NODE_CONFIG_DIR=/var/www/peertube/config NODE_ENV=production npm run regenerate-thumbnails
bash [docker]
cd /var/www/peertube-docker; \
    docker compose exec -u peertube peertube npm run regenerate-thumbnails

:::

Add or replace specific video file

You can use this script to import a video file to replace an already uploaded file or to add a new web compatible resolution to a video. PeerTube needs to be running.
You can then create a transcoding job using the web interface if you need to optimize your file or create an HLS version of it.

::: code-group

bash [classic installation]
cd /var/www/peertube/peertube-latest; \
    sudo -u peertube NODE_CONFIG_DIR=/var/www/peertube/config NODE_ENV=production npm run create-import-video-file-job -- -v [videoUUID] -i [videoFile]
bash [docker]
cd /var/www/peertube-docker; \
    docker compose exec -u peertube peertube npm run create-import-video-file-job -- -v [videoUUID] -i [videoFile]

:::

Move video files from filesystem to object storage

Use this script to move video related files (video files, original video file, captions, etc.) to object storage.

::: code-group

bash [classic installation]
cd /var/www/peertube/peertube-latest; \
    sudo -u peertube NODE_CONFIG_DIR=/var/www/peertube/config NODE_ENV=production npm run create-move-video-storage-job -- --to-object-storage -v [videoUUID]
bash [docker]
cd /var/www/peertube-docker; \
    docker compose exec -u peertube peertube npm run create-move-video-storage-job -- --to-object-storage -v [videoUUID]

:::

The script can also move all video related files that are not already in object storage:

::: code-group

bash [classic installation]
cd /var/www/peertube/peertube-latest; \
    sudo -u peertube NODE_CONFIG_DIR=/var/www/peertube/config NODE_ENV=production npm run create-move-video-storage-job -- --to-object-storage --all-videos
bash [docker]
cd /var/www/peertube-docker; \
    docker compose exec -u peertube peertube npm run create-move-video-storage-job -- --to-object-storage --all-videos

:::

Move video files from object storage to filesystem

PeerTube >= 6.0

Use this script to move video related files (video files, original video file, captions, etc.) from object storage to the PeerTube instance filesystem.

::: code-group

bash [classic installation]
cd /var/www/peertube/peertube-latest; \
    sudo -u peertube NODE_CONFIG_DIR=/var/www/peertube/config NODE_ENV=production npm run create-move-video-storage-job -- --to-file-system -v [videoUUID]
bash [docker]
cd /var/www/peertube-docker; \
    docker compose exec -u peertube peertube npm run create-move-video-storage-job -- --to-file-system -v [videoUUID]

:::

The script can also move all video related files that are not already on the filesystem:

::: code-group

bash [classic installation]
cd /var/www/peertube/peertube-latest; \
    sudo -u peertube NODE_CONFIG_DIR=/var/www/peertube/config NODE_ENV=production npm run create-move-video-storage-job -- --to-file-system --all-videos
bash [docker]
cd /var/www/peertube-docker; \
    docker compose exec -u peertube peertube npm run create-move-video-storage-job -- --to-file-system --all-videos

:::

Cleanup remote files

PeerTube >= 6.2

Use this script to recover disk space by removing remote files (thumbnails, avatars...) that can be re-fetched later by your PeerTube instance on-demand.

Restart PeerTube after running this script.

::: code-group

bash [classic installation]
cd /var/www/peertube/peertube-latest; \
    sudo -u peertube NODE_CONFIG_DIR=/var/www/peertube/config NODE_ENV=production npm run house-keeping -- --delete-remote-files
bash [docker]
cd /var/www/peertube-docker; \
    docker compose exec -u peertube peertube npm run house-keeping -- --delete-remote-files

:::

Generate storyboard

PeerTube >= 6.0

Use this script to generate storyboard of a specific video:

::: code-group

bash [classic installation]
cd /var/www/peertube/peertube-latest; \
    sudo -u peertube NODE_CONFIG_DIR=/var/www/peertube/config NODE_ENV=production npm run create-generate-storyboard-job -- -v [videoUUID]
bash [docker]
cd /var/www/peertube-docker; \
    docker compose exec -u peertube peertube npm run create-generate-storyboard-job -- -v [videoUUID]

:::

The script can also generate all missing storyboards of local videos:

::: code-group

bash [classic installation]
cd /var/www/peertube/peertube-latest; \
    sudo -u peertube NODE_CONFIG_DIR=/var/www/peertube/config NODE_ENV=production npm run create-generate-storyboard-job -- --all-videos
bash [docker]
cd /var/www/peertube-docker; \
    docker compose exec -u peertube peertube npm run create-generate-storyboard-job -- --all-videos

:::

Prune filesystem/object storage

Some transcoded videos or shutdown at a bad time can leave some unused files on your storage.
To delete these files (a confirmation will be demanded first):

::: code-group

bash [classic installation]
cd /var/www/peertube/peertube-latest; \
    sudo -u peertube NODE_CONFIG_DIR=/var/www/peertube/config NODE_ENV=production npm run prune-storage
bash [docker]
cd /var/www/peertube-docker; \
    docker compose exec -u peertube peertube npm run prune-storage

:::

It's also possible to remove more local files if your stop PeerTube using the --offline option:

::: code-group

bash [classic installation]
cd /var/www/peertube/peertube-latest; \
    sudo -u peertube NODE_CONFIG_DIR=/var/www/peertube/config NODE_ENV=production npm run prune-storage -- --offline
bash [docker]
cd /var/www/peertube-docker; \
    docker compose exec -u peertube peertube npm run prune-storage -- --offline

:::

Update PeerTube instance domain name

Changing the hostname is unsupported and may be a risky operation, especially if you have already federated.
If you started PeerTube with a domain, and then changed it you will have
invalid torrent files and invalid URLs in your database. To fix this, you have
to run the command below (keep in mind your follower instances will NOT update their URLs).

::: code-group

bash [classic installation]
cd /var/www/peertube/peertube-latest; \
    sudo -u peertube NODE_CONFIG_DIR=/var/www/peertube/config NODE_ENV=production npm run update-host
bash [docker]
cd /var/www/peertube-docker; \
    docker compose exec -u peertube peertube npm run update-host

:::

Reset user password

To reset a user password from CLI, run:

::: code-group

bash [classic installation]
cd /var/www/peertube/peertube-latest; \
    sudo -u peertube NODE_CONFIG_DIR=/var/www/peertube/config NODE_ENV=production npm run reset-password -- -u target_username
bash [docker]
cd /var/www/peertube-docker; \
    docker compose exec -u peertube peertube npm run reset-password -- -u target_username

:::

Install or uninstall plugins

The difference with peertube plugins CLI is that these scripts can be used even if PeerTube is not running.
If PeerTube is running, you need to restart it for the changes to take effect (whereas with peertube plugins CLI, plugins/themes are dynamically loaded on the server).

To install/update a plugin or a theme from the disk:

::: code-group

bash [classic installation]
cd /var/www/peertube/peertube-latest; \
    sudo -u peertube NODE_CONFIG_DIR=/var/www/peertube/config NODE_ENV=production npm run plugin:install -- --plugin-path /local/plugin/path
bash [docker]
cd /var/www/peertube-docker; \
    docker compose exec -u peertube peertube npm run plugin:install -- --plugin-path /local/plugin/path

:::

From NPM:

::: code-group

bash
cd /var/www/peertube/peertube-latest; \
    sudo -u peertube NODE_CONFIG_DIR=/var/www/peertube/config NODE_ENV=production npm run plugin:install -- --npm-name peertube-plugin-myplugin
bash [docker]
cd /var/www/peertube-docker; \
    docker compose exec -u peertube peertube npm run plugin:install -- --npm-name peertube-plugin-myplugin

:::

To uninstall a plugin or a theme:

::: code-group

bash [classic installation]
cd /var/www/peertube/peertube-latest; \
    sudo -u peertube NODE_CONFIG_DIR=/var/www/peertube/config NODE_ENV=production npm run plugin:uninstall -- --npm-name peertube-plugin-myplugin
bash [docker]
cd /var/www/peertube-docker; \
    docker compose exec -u peertube peertube npm run plugin:uninstall -- --npm-name peertube-plugin-myplugin

:::


Support Doc Translation (`support/doc/translation.md`)

Translation

We use Weblate as translation platform.
Please do not edit translation files directly from Git, you have to use Weblate!

If you don't see your locale in the platform you can add it directly in the Weblate interface.
Then, if you think there are enough translated strings, please create an issue so we add the new locale in PeerTube!

Translations are manually pulled and merged in PeerTube software and are publicly available in the next official release.
You can get a chance to see translations before the official release by going to https://peertube2.cpy.re which is updated every night with the latest PeerTube changes.

How to

Files

There are 4 files:

  • angular: contains client strings
  • player: contains player strings.
    Most of the strings come from VideoJS, so you can help yourself by using video.js JSON files
  • server: contains server strings clients can fetch in JSON format so they don't have to translate common PeerTube strings themselves (iso639 languages, privacies, licences...)
  • server-internal: contains internal server strings used in the REST API responses or emails

Tips

Special tags

You must not translate special tags like <x id="INTERPOLATION" ... />.

For example:

text
<x id="INTERPOLATION" equiv-text="{{ video.publishedAt | myFromNow }}"/> - <x id="INTERPOLATION_1" equiv-text="{{ video.views | myNumberFormatter }}"/> views

should be in French

text
<x id="INTERPOLATION" equiv-text="{{ video.publishedAt | myFromNow }}"/> - <x id="INTERPOLATION_1" equiv-text="{{ video.views | myNumberFormatter }}"/> vues

Singular/plural

For singular/plural translations, you must translate values inside { and }. Please don't translate the word other

For example:

text
{VAR_PLURAL, plural, =0 {No videos} =1 {1 video} other {<x id="INTERPOLATION" equiv-text="{{ playlist.videosLength }}"/> videos} }

should be in French

text
{VAR_PLURAL, plural, =0 {Aucune vidรฉo} =1 {1 vidรฉo} other {<x id="INTERPOLATION" equiv-text="{{ playlist.videosLength }}"/> vidรฉos} }

Support Doc Api Embeds (`support/doc/api/embeds.md`)

PeerTube Embed API

PeerTube lets you embed videos and programmatically control their playback. This documentation covers how to interact with the PeerTube Embed API.

Playground

Any PeerTube embed URL (ie https://my-instance.example.com/videos/embed/52a10666-3a18-4e73-93da-e8d3c12c305a) can be viewed as an embedding playground which
allows you to test various aspects of PeerTube embeds. Simply replace /embed with /test-embed and visit the URL in a browser.
For instance, the playground URL for the above embed URL is https://my-instance.example.com/videos/test-embed/52a10666-3a18-4e73-93da-e8d3c12c305a.

Quick Start

Given an existing PeerTube embed `` with API enabled (https://my-instance.example.com/videos/embed/52a10666-3a18-4e73-93da-e8d3c12c305a?api=1),
one can use the PeerTube Embed API to control it by first including the library. You can include it via NPM with:

text
npm install @peertube/embed-api

Now just use the PeerTubePlayer class exported by the module:

typescript
import { PeerTubePlayer } from '@peertube/embed-api.js'

...

Or use the minified build from NPM CDN in your HTML file:

text
<script src="https://unpkg.com/@peertube/embed-api/build/player.min.js"></script>

<script>
  const PeerTubePlayer = window['PeerTubePlayer']

  ...
</script>

Then you can instantiate the player:

typescript
let player = new PeerTubePlayer(document.querySelector('iframe'))
await player.ready // wait for the player to be ready

// now you can use it!
player.play()
player.seek(32)
player.pause()

Embed URL parameters

You can customize PeerTube player by specifying URL query parameters.
For example https://my-instance.example.com/videos/embed/52a10666-3a18-4e73-93da-e8d3c12c305a?start=1s&stop=18s&loop=1&autoplay=1&muted=1&warningTitle=0&controlBar=0&peertubeLink=0&p2p=0

start

Start the video at a specific time.
Value must be raw seconds or a duration (3m4s)
Default: starts at 0

stop

Stop the video at a specific time.
Value must be raw seconds or a duration (54s)
Default: ends at content end

controls

Mimics video HTML element controls attribute, meaning that all controls (including big play button, control bar, etc.) will be removed.
It can be useful if you want to have a full control of the PeerTube player.

Value must be 0 or 1.
Default: 1

controlBar

Hide control bar when the video is played.

Value must be 0 or 1.
Default: 1

Hide PeerTube instance link in control bar.

Value must be 0 or 1.
Default: 1

muted

Mute the video by default.

Value must be 0 or 1.
Default: tries to restore the last muted setting set by the user

loop

Automatically start again the video when it ends.

Value must be 0 or 1.
Default: 0

subtitle

Auto select a subtitle by default.

Value must be a valid subtitle ISO code (fr, en, etc.).
Default: no subtitle selected and then tries to restore the last subtitle set by the user

autoplay

Try to automatically play the video.
Most web browsers disable video autoplay if the user did not interact with the video. You can try to bypass this limitation by muting the video.

Value must be 0 or 1.
Default: 0

playbackRate

Force the default playback rate (0.75, 1.5 etc).
Default: 1

title

Show/Hide embed title.

Value must be 0 or 1.
Default: 1

warningTitle

Show/Hide P2P warning title.

Value must be 0 or 1.
Default: 1

p2p

Enable/Disable P2P.

Value must be 0 or 1.
Default: tries to use the user setting and fallbacks to instance setting if user setting is not found

bigPlayBackgroundColor

Customize big play button background color.

Value must be a valid color (red or rgba(100, 100, 100, 0.5)).
Default: rgba(0, 0, 0, 0.8)

foregroundColor

Customize embed font color.

Value must be a valid color (red or rgba(100, 100, 100, 0.5)).

Default: white

mode

Force a specific player engine.

Value must be a valid mode (web-video or p2p-media-loader).

See behaviour description here

Default: p2p-media-loader and fallback to web-video mode.

playlistPosition

If you are embedding a playlist, select the video to play by specifying its position.

Value must be a number.

Default: 1

api

Enable/Disable embed JavaScript API (see methods below).

Value must be 0 or 1.

Default: 0

waitPasswordFromEmbedAPI

PeerTube >= 6.0

If the video requires a password, PeerTube will wait a password provided by setVideoPassword method before loading the video.

Until you provide a password, player.ready is not resolved.

Value must be 0 or 1.

Default: 0

Embed attributes

`ready: Promise`

This promise is resolved when the video is loaded and the player is ready.

Embed methods

`isPlaying(): Promise`

PeerTube >= 7.0

Check if the player is playing the media.

`play(): Promise`

Starts playback, or resumes playback if it is paused.

`pause(): Promise`

Pauses playback.

`getCurrentTime(): Promise`

PeerTube >= 7.0

Get player current time in seconds.

`seek(positionInSeconds : number): Promise`

Seek to the given position, as specified in seconds into the video.

`addEventListener(eventName : string, handler : Function)`

Add a listener for a specific event. See below for the available events.

`removeEventListener(eventName : string, handler : Function)`

Remove a listener.

`getResolutions() : Promise`

Get the available resolutions. A PeerTubeResolution looks like:

json
{
    "id": 3,
    "label": "720p",
    "height": "720",
    "active": true
}

active is true if the resolution is the currently selected resolution.

`setResolution(resolutionId : number): Promise`

Change the current resolution. Pass -1 for automatic resolution (when available).
Otherwise, resolutionId should be the ID of an object returned by getResolutions()

`getPlaybackRates() : Promise`

Get the available playback rates, where 1 represents normal speed, 0.5 is half speed, 2 is double speed, etc.

`getPlaybackRate() : Promise`

Get the current playback rate. See getPlaybackRates() for more information.

`setPlaybackRate(rate: number) : Promise`

Set the current playback rate. The passed rate should be a value as returned by getPlaybackRates().

`setVolume(factor: number) : Promise`

Set the playback volume. Value should be between 0 and 1.

`getVolume(): Promise`

Get the playback volume. Returns a value between 0 and 1.

`setCaption(id: string) : Promise`

Update current caption using the caption id.

`getCaptions(): Promise<{ id: string, label: string, src: string, mode: 'disabled' | 'showing' }>`

Get video captions.

`playNextVideo(): Promise`

Play next video in playlist.

`playPreviousVideo(): Promise`

Play previous video in playlist.

`getCurrentPosition(): Promise`

Get current position in playlist (starts from 1).

`setVideoPassword(): Promise`

PeerTube >= 6.0

Set the video password so the user doesn't have to manually fill it.
waitPasswordFromEmbedAPI=1 is required in embed URL.

`getImageDataUrl(): Promise`

PeerTube >= 6.2

Get the current frame as JPEG image data URL.

Embed events

You can subscribe to events by using addEventListener(). See above for details.

Event `playbackStatusUpdate`

Fired every half second to provide the current status of playback.
The parameter of the callback will resemble:

json
{
  "position": 22.3,
  "volume": 0.9,
  "duration": "171.37499",
  "playbackState": "playing"
}

duration field and ended playbackState are available in PeerTube >= 2.2.

The volume field contains the volume from 0 (silent) to 1 (full volume).
The playbackState can be unstarted, playing, paused or ended. More states may be added later.

Event `playbackStatusChange`

Fired when playback transitions between states, such as paused and playing. More states may be added later.

Event `resolutionUpdate`

Fired when the available resolutions have changed, or when the currently selected resolution has changed. Listener should call getResolutions() to get the updated information.

Event `volumeChange`

Fired when the player volume changed.


Support Doc Api Openapi.Yaml (`support/doc/api/openapi.yaml`)

openapi: 3.0.3
info:
title: PeerTube
version: 8.3.0
contact:
name: PeerTube Community
url: https://joinpeertube.org
license:
name: AGPLv3.0
url: https://github.com/Chocobozzz/PeerTube/blob/master/LICENSE
x-logo:
url: https://joinpeertube.org/img/brand.png
altText: PeerTube Project Homepage
The PeerTube API is built on HTTP(S) and is RESTful. You can use your favorite
HTTP/REST library for your programming language to use PeerTube.

text
See the [REST API quick start](https://docs.joinpeertube.org/api/rest-getting-started) for a few
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 an access token. Only __one
access token can currently be used at a time__.

## Roles

Accounts are given permissions based on their role. There are three roles on
PeerTube: Administrator, Moderator, and User. See the [roles guide](https://docs.joinpeertube.org/admin/managing-users#roles) for a detail of their permissions.

# Errors

The API uses standard HTTP status codes to indicate the success or failure
of the API call, completed by a [RFC7807-compliant](https://tools.ietf.org/html/rfc7807) response body.

```
HTTP 1.1 404 Not Found
Content-Type: application/problem+json; charset=utf-8

{
  "detail": "Video not found",
  "docs": "https://docs.joinpeertube.org/api-rest-reference.html#operation/getVideo",
  "status": 404,
  "title": "Not Found",
  "type": "about:blank"
}
```

We provide error `type` (following RFC7807) and `code` (internal PeerTube code) values for [a growing number of cases](https://github.com/Chocobozzz/PeerTube/blob/develop/packages/models/src/server/server-error-code.enum.ts),
but it is still optional. Types are used to disambiguate errors that bear the same status code
and are non-obvious:

```
HTTP 1.1 403 Forbidden
Content-Type: application/problem+json; charset=utf-8

{
  "detail": "Cannot get this video regarding follow constraints",
  "docs": "https://docs.joinpeertube.org/api-rest-reference.html#operation/getVideo",
  "status": 403,
  "title": "Forbidden",
  "type": "https://docs.joinpeertube.org/api-rest-reference.html#section/Errors/does_not_respect_follow_constraints"
}
```

Here a 403 error could otherwise mean that the video is private or blocklisted.

## Validation errors

Example:

```
HTTP 1.1 400 Bad Request
Content-Type: application/problem+json; charset=utf-8

{
  "detail": "Incorrect request parameters: id",
  "docs": "https://docs.joinpeertube.org/api-rest-reference.html#operation/getVideo",
  "instance": "/api/v1/videos/9c9de5e8-0a1e-484a-b099-e80766180",
  "invalid-params": {
    "id": {
      "location": "params",
      "msg": "Invalid value",
      "param": "id",
      "value": "9c9de5e8-0a1e-484a-b099-e80766180"
    }
  },
  "status": 400,
  "title": "Bad Request",
  "type": "about:blank"
}
```

Where `id` is the name of the field concerned by the error, within the route definition.
`invalid-params.<field>.location` can be either 'params', 'body', 'header', 'query' or 'cookies'.
`invalid-params.<field>.value` reports the value that didn't pass validation whose `invalid-params.<field>.msg` is about.

## max_file_size_reached

The uploaded file exceeds the instance-wide file size limit.

## quota_reached

The uploaded file exceeds the user's storage quota.

## does_not_respect_follow_constraints

The requested remote resource cannot be accessed because the instance does not follow its origin.

## live_not_enabled

Live streaming is not enabled on the instance.

## live_not_allowing_replay

Saving live replays is disabled on this instance, so a live cannot be created or updated with `saveReplay` enabled.

## live_conflicting_permanent_and_save_replay

Not returned by PeerTube anymore: permanent lives can save replays.

## max_instance_lives_limit_reached

The instance has reached its maximum number of simultaneous live streams.

## max_user_lives_limit_reached

The user has reached the maximum number of simultaneous live streams.

## incorrect_files_in_torrent

The torrent does not contain exactly one usable video file.

## comment_not_associated_to_video

The comment is not associated with the requested video.

## invalid_grant

The OAuth grant or refresh token is invalid.

## invalid_client

Client authentication failed.

## invalid_token

The access token is expired, revoked, malformed, or otherwise invalid.

## unauthorized_request

The endpoint requires authentication but no access token was provided.

## invalid_request

The authentication or token request is malformed: missing `grant_type`, malformed `Authorization` header,
access token sent using more than one method, or sent in the query string.

## unsupported_grant_type

The `grant_type` is not supported. PeerTube supports `password` and `refresh_token`.

## unauthorized_client

The OAuth client is not allowed to use the requested `grant_type`.

## server_error

An unexpected error occurred while checking the access token.

## missing_two_factor

The required two-factor authentication header is missing.

## too_long_password

The password exceeds the maximum allowed length.

## invalid_two_factor

The two-factor authentication code is invalid.

## account_blocked

The account is blocked.

## email_not_verified

The account email address has not been verified.

## account_waiting_for_approval

The account is waiting for administrator approval.

## account_approval_rejected

The account approval request was rejected.

## runner_job_not_in_processing_state

The runner job is not in the processing state.

## runner_job_not_in_pending_state

The runner job is not in the pending state.

## unknown_runner_token

The runner token is unknown.

## video_requires_password

A password is required to access the video.

## incorrect_video_password

The password provided for the video is incorrect.

## video_already_being_transcoded

The video is already being transcoded.

## video_already_being_transcribed

The video is already being transcribed.

## video_already_has_captions

The video already has captions.

## max_user_video_quota_exceeded_for_user_export

The user requested an export including video files, but the total size of their videos is above the maximum allowed by the instance for such exports.
Request an export without video files instead.

## current_password_is_invalid

The current password is invalid.

# Rate limits

We are rate-limiting all endpoints of PeerTube's API. Custom values can be set by administrators:

| 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, <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
following headers:

| 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         |

# 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/*`            |
| `/.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
    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
    instead.

  • name: Session
    x-displayName: Login/Logout
    Sessions deal with access tokens over time. Only one session token can currently be used at a time.

  • name: Accounts
    Accounts encompass remote accounts discovered across the federation,
    and correspond to the main Actor, along with video channels a user can create, which
    are also Actors.

    When a comment is posted, it is done with your Account's Actor.

  • name: Users
    Using some features of PeerTube require authentication, for which User
    provide different levels of permission as well as associated user
    information. Each user has a corresponding local Account for federation.

  • name: User Exports
    To create an archive of user data.

  • name: User Imports
    To import an archive of user data.

  • name: My User
    Operations related to your own User, when logged-in.

  • name: My Subscriptions
    Operations related to your subscriptions to video channels, their
    new videos, and how to keep up to date with their latest publications!

  • name: My History
    Operations related to your watch history.

  • name: My Notifications
    Notifications following new videos, follows or reports. They allow you
    to keep track of the interactions and overall important information that
    concerns you. You MAY set per-notification type delivery preference, to
    receive the info either by mail, by in-browser notification or both.

  • name: Config
    Each server exposes public information regarding supported videos and
    options.

  • name: Job
    Jobs are long-running tasks enqueued and processed by the instance
    itself. No additional worker registration is currently available.

  • name: Instance Follows
    Managing servers which the instance interacts with is crucial to the
    concept of federation in PeerTube and external video indexation. The PeerTube
    server then deals with inter-server ActivityPub operations and propagates
    information across its social graph by posting activities to actors' inbox
    endpoints.
    externalDocs:
    url: https://docs.joinpeertube.org/admin/following-instances#instances-follows

  • name: Instance Redundancy
    Redundancy is part of the inter-server solidarity that PeerTube fosters.
    Manage the list of instances you wish to help by seeding their videos according
    to the policy of video selection of your choice. Note that you have a similar functionality
    to mirror individual videos, see video mirroring.
    externalDocs:
    url: https://docs.joinpeertube.org/admin/following-instances#instances-redundancy

  • name: Plugins
    Managing plugins installed from a local path or from NPM, or search for new ones.
    externalDocs:
    url: https://docs.joinpeertube.org/api/plugins

  • name: Abuses
    Abuses deal with reports of local or remote videos/comments/accounts alike.

  • name: Video
    Operations dealing with listing, uploading, fetching or modifying videos.

  • name: Video Upload
    Operations dealing with adding video or audio. PeerTube supports two upload modes, and three import modes.

    Upload

    • legacy, where the video file is sent in a single request
    • resumable, where the video file is sent in chunks

    You can upload videos more reliably by using the resumable variant. Its protocol lets
    you resume an upload operation after a network interruption or other transmission failure,
    saving time and bandwidth in the event of network failures.

    Favor using resumable uploads in any of the following cases:

    • You are transferring large files
    • The likelihood of a network interruption is high
    • Uploads are originating from a device with a low-bandwidth or unstable Internet connection, such as a mobile device

    Import

    • URL-based: where the URL points to any service supported by youtube-dl
    • magnet-based: where the URI resolves to a BitTorrent resource containing a single supported video file
    • torrent-based: where the metainfo file resolves to a BitTorrent resource containing a single supported video file

    The import function is practical when the desired video/audio is available online. It makes PeerTube
    download it for you, saving you as much bandwidth and avoiding any instability or limitation your network might have.

  • name: Video Imports

  • name: Channels Sync

  • name: Video Captions

  • name: Video Chapters

  • name: Video Channels

  • name: Player Settings

  • name: Video Comments
    Operations dealing with comments to a video. Comments are organized in threads: adding a
    comment in response to the video starts a thread, adding a reply to a comment adds it to
    its root comment thread.

  • name: Video Blocks

  • name: Automatic Tags

  • name: Watched Words

  • name: Video Rates

  • name: Video Playlists

  • name: Video Files

  • name: Video Transcoding

  • name: Video Stats

  • name: Video Feeds

  • name: Video Download

  • name: Logs

  • name: Search
    The search helps to find videos or channels from within the instance and beyond.
    Videos from other instances federated by the instance (that is, instances
    followed by the instance) can be found via keywords and other criteria of
    the advanced search.

    Administrators can also enable the use of a remote search system, indexing
    videos and channels that may not be federated by the instance.

  • name: Homepage

  • name: Video Mirroring
    PeerTube instances can mirror videos from one another, and help distribute some videos.

    For importing videos as your own, refer to video imports.

  • name: Stats
    Statistics

  • name: Contact

  • name: Debug

  • name: Runner Registration Token
    Manage runner registration tokens.

  • name: Runner Jobs

  • name: Runners

  • name: Video Passwords

  • name: Client Config
    x-tagGroups:

  • name: Static endpoints
    tags:

    • Static Video Files
  • name: Download
    tags:

    • Video Download
  • name: Feeds
    tags:

    • Video Feeds
  • name: Auth
    tags:

    • Register
    • Session
  • name: Accounts
    tags:

    • Accounts
    • Users
    • User Exports
    • User Imports
    • My User
    • My Subscriptions
    • My Notifications
    • My History
  • name: Videos
    tags:

    • Video
    • Video Upload
    • Video Imports
    • Video Captions
    • Video Chapters
    • Video Channels
    • Video Comments
    • Video Rates
    • Video Playlists
    • Video Stats
    • Ownership Change
    • Video Mirroring
    • Video Files
    • Video Transcoding
    • Live Videos
    • Channels Sync
    • Video Passwords
    • Video Embed Privacy
  • name: Search
    tags:

    • Search
  • name: Moderation
    tags:

    • Abuses
    • Video Blocks
    • Account Blocklist
    • Server Blocklist
    • Automatic Tags
    • Watched Words
  • name: Instance
    tags:

    • Config
    • Client Config
    • Homepage
    • Instance Follows
    • Instance Redundancy
    • Plugins
    • Stats
    • Logs
    • Job
  • name: Remote Jobs
    tags:

    • Runner Registration Token
    • Runner Jobs
    • Runners

paths:
'/static/web-videos/{filename}':
get:
tags:
- Static Video Files
summary: Get public Web Video file
parameters:
- $ref: '#/components/parameters/staticFilename'
responses:
'200':
'404':
'/static/web-videos/private/{filename}':
get:
tags:
- Static Video Files
summary: Get private Web Video file
parameters:
- $ref: '#/components/parameters/staticFilename'
- $ref: '#/components/parameters/videoFileToken'
security:
- OAuth2: []
responses:
'200':
'403':
'404':
'/static/streaming-playlists/hls/{filename}':
get:
tags:
- Static Video Files
summary: Get public HLS video file
parameters:
- $ref: '#/components/parameters/staticFilename'
security:
- OAuth2: []
responses:
'200':
'403':
'404':
'/static/streaming-playlists/hls/private/{filename}':
get:
tags:
- Static Video Files
summary: Get private HLS video file
parameters:
- $ref: '#/components/parameters/staticFilename'
- $ref: '#/components/parameters/videoFileToken'
- $ref: '#/components/parameters/reinjectVideoFileToken'
security:
- OAuth2: []
responses:
'200':
'403':
'404':
'/download/videos/generate/{videoIdOrUUID}':
get:
tags:
- Video Download
summary: Download video file
Mainly used to merge the HLS audio only video file and the HLS video only resolution file.
parameters:
- $ref: '#/components/parameters/videoIdOrUUID'
- name: videoFileIds
in: query
required: true
schema:
type: array
items:
type: integer
- $ref: '#/components/parameters/videoFileToken'
responses:
'200':
'/feeds/video-comments.{format}':
get:
tags:
- Video Feeds
summary: Comments on videos feeds
operationId: getSyndicatedComments
parameters:
- name: format
in: path
required: true
schema:
type: string
enum:
- xml
- rss
- rss2
- atom
- atom1
- json
- json1
- name: videoId
in: query
schema:
type: string
- name: accountId
in: query
schema:
type: string
- name: accountName
in: query
schema:
type: string
- name: videoChannelId
in: query
schema:
type: string
- name: videoChannelName
in: query
schema:
type: string
- name: isLocal
in: query
required: false
schema:
type: boolean
- name: onLocalVideo
in: query
required: false
schema:
type: boolean
responses:
'200':
headers:
Cache-Control:
schema:
type: string
default: 'max-age=900' # 15 min cache
content:
application/xml:
schema:
$ref: '#/components/schemas/VideoCommentsForXML'

text
examples:
            nightly:
              externalValue: https://peertube2.cpy.re/feeds/video-comments.xml?scope=local
        application/rss+xml:
          schema:
            $ref: '#/components/schemas/VideoCommentsForXML'
          examples:
            nightly:
              externalValue: https://peertube2.cpy.re/feeds/video-comments.rss?scope=local
        text/xml:
          schema:
            $ref: '#/components/schemas/VideoCommentsForXML'
          examples:
            nightly:
              externalValue: https://peertube2.cpy.re/feeds/video-comments.xml?scope=local
        application/atom+xml:
          schema:
            $ref: '#/components/schemas/VideoCommentsForXML'
          examples:
            nightly:
              externalValue: https://peertube2.cpy.re/feeds/video-comments.atom?scope=local
        application/json:
          schema:
            type: object
          examples:
            nightly:
              externalValue: https://peertube2.cpy.re/feeds/video-comments.json?scope=local
    '400':
      x-summary: field inconsistencies
        Arises when:
          - videoId filter is mixed with a channel filter
    '404':
    '406':

'/feeds/videos.{format}':
get:
tags:
- Video Feeds
summary: Common videos feeds
operationId: getSyndicatedVideos
parameters:
- name: format
in: path
required: true
schema:
type: string
enum:
- xml
- rss
- rss2
- atom
- atom1
- json
- json1
- name: accountId
in: query
schema:
type: string
- name: accountName
in: query
schema:
type: string
- name: videoChannelId
in: query
schema:
type: string
- name: videoChannelName
in: query
schema:
type: string
- $ref: '#/components/parameters/sort'
- $ref: '#/components/parameters/nsfw'
- $ref: '#/components/parameters/isLocal'
- $ref: '#/components/parameters/include'
- $ref: '#/components/parameters/privacyOneOf'
- $ref: '#/components/parameters/hasHLSFiles'
- $ref: '#/components/parameters/hasWebVideoFiles'
responses:
'200':
headers:
Cache-Control:
schema:
type: string
default: 'max-age=900' # 15 min cache
content:
application/xml:
schema:
$ref: '#/components/schemas/VideosForXML'
examples:
nightly:
externalValue: https://peertube2.cpy.re/feeds/videos.xml?scope=local
application/rss+xml:
schema:
$ref: '#/components/schemas/VideosForXML'
examples:
nightly:
externalValue: https://peertube2.cpy.re/feeds/videos.rss?scope=local
text/xml:
schema:
$ref: '#/components/schemas/VideosForXML'
examples:
nightly:
externalValue: https://peertube2.cpy.re/feeds/videos.xml?scope=local
application/atom+xml:
schema:
$ref: '#/components/schemas/VideosForXML'
examples:
nightly:
externalValue: https://peertube2.cpy.re/feeds/videos.atom?scope=local
application/json:
schema:
type: object
examples:
nightly:
externalValue: https://peertube2.cpy.re/feeds/videos.json?scope=local
'404':
'406':
'/feeds/subscriptions.{format}':
get:
tags:
- Video Feeds
summary: Videos of subscriptions feeds
operationId: getSyndicatedSubscriptionVideos
parameters:
- name: format
in: path
required: true
schema:
type: string
enum:
- xml
- rss
- rss2
- atom
- atom1
- json
- json1
- name: accountId
in: query
schema:
type: string
required: true
- name: token
in: query
schema:
type: string
required: true
- $ref: '#/components/parameters/sort'
- $ref: '#/components/parameters/nsfw'
- $ref: '#/components/parameters/isLocal'
- $ref: '#/components/parameters/include'
- $ref: '#/components/parameters/privacyOneOf'
- $ref: '#/components/parameters/hasHLSFiles'
- $ref: '#/components/parameters/hasWebVideoFiles'
responses:
'200':
headers:
Cache-Control:
schema:
type: string
default: 'max-age=900' # 15 min cache
content:
application/xml:
schema:
$ref: '#/components/schemas/VideosForXML'
application/rss+xml:
schema:
$ref: '#/components/schemas/VideosForXML'
text/xml:
schema:
$ref: '#/components/schemas/VideosForXML'
application/atom+xml:
schema:
$ref: '#/components/schemas/VideosForXML'
application/json:
schema:
type: object
'406':
'/feeds/podcast/videos.xml':
get:
tags:
- Video Feeds
summary: Videos podcast feed
operationId: getVideosPodcastFeed
parameters:
- name: videoChannelId
in: query
required: false
schema:
type: string
- name: playlistId
in: query
required: false
schema:
type: string
- name: enclosurePreference
in: query
required: false
schema:
type: string
enum:
- video-only
- audio-only
responses:
'200':
headers:
Cache-Control:
schema:
type: string
default: 'max-age=900' # 15 min cache
'404':
'/api/v1/accounts/{name}':
get:
tags:
- Accounts
summary: Get an account
operationId: getAccount
parameters:
- $ref: '#/components/parameters/name'
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/Account'
'404':
'/api/v1/accounts/{name}/videos':
get:
tags:
- Accounts
- Video
summary: 'List videos of an account'
operationId: getAccountVideos
parameters:
- $ref: '#/components/parameters/name'
# Common video filter parameters
- $ref: '#/components/parameters/start'
- $ref: '#/components/parameters/count'
- $ref: '#/components/parameters/skipCount'
- $ref: '#/components/parameters/videosSort'
- $ref: '#/components/parameters/nsfw'
- $ref: '#/components/parameters/nsfwFlagsIncluded'
- $ref: '#/components/parameters/nsfwFlagsExcluded'
- $ref: '#/components/parameters/aiUsageOneOf'
- $ref: '#/components/parameters/isLive'
- $ref: '#/components/parameters/includeScheduledLive'
- $ref: '#/components/parameters/categoryOneOf'
- $ref: '#/components/parameters/licenceOneOf'
- $ref: '#/components/parameters/languageOneOf'
- $ref: '#/components/parameters/tagsOneOf'
- $ref: '#/components/parameters/tagsAllOf'
- $ref: '#/components/parameters/isLocal'
- $ref: '#/components/parameters/include'
- $ref: '#/components/parameters/hasHLSFiles'
- $ref: '#/components/parameters/hasWebVideoFiles'
- $ref: '#/components/parameters/host'
- $ref: '#/components/parameters/autoTagOneOfVideo'
- $ref: '#/components/parameters/stateOneOfVideo'
- $ref: '#/components/parameters/privacyOneOf'
- $ref: '#/components/parameters/excludeAlreadyWatched'
- $ref: '#/components/parameters/search'
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/VideoListResponse'
x-codeSamples:
- lang: JavaScript
source: |
fetch('https://peertube2.cpy.re/api/v1/accounts/{name}/videos')
.then(function(response) {
return response.json()
}).then(function(data) {
console.log(data)
})
- lang: Shell
source: |
## DEPENDENCIES: jq
curl -s https://peertube2.cpy.re/api/v1/accounts/{name}/videos | jq
- lang: Ruby
source: |
require 'net/http'
require 'json'

text
uri = URI.parse("https://peertube2.cpy.re/api/v1/accounts/{name}/videos")

        http = Net::HTTP.new(uri.host, uri.port)
        http.use_ssl = true

        response = http.get(uri.request_uri)

        puts JSON.parse(response.read_body)
    - lang: Python
      source: |
        import requests

        r = requests.get("https://peertube2.cpy.re/api/v1//accounts/{name}/videos")
        json = r.json()

        print(json)

'/api/v1/accounts/{name}/followers':
get:
tags:
- Accounts
summary: 'List followers of an account'
security:
- OAuth2: []
operationId: getAccountFollowers
parameters:
- $ref: '#/components/parameters/name'
- $ref: '#/components/parameters/start'
- $ref: '#/components/parameters/count'
- $ref: '#/components/parameters/followersSort'
- $ref: '#/components/parameters/search'
responses:
'200':
content:
application/json:
schema:
type: object
properties:
total:
type: integer
example: 1
data:
type: array
items:
$ref: '#/components/schemas/Follow'

/api/v1/accounts:
get:
tags:
- Accounts
summary: List accounts
operationId: getAccounts
parameters:
- $ref: '#/components/parameters/start'
- $ref: '#/components/parameters/count'
- $ref: '#/components/parameters/sort'
responses:
'200':
content:
'application/json':
schema:
type: object
properties:
total:
type: integer
example: 1
data:
type: array
items:
$ref: '#/components/schemas/Account'

/api/v1/config:
get:
tags:
- Config
summary: Get instance public configuration
operationId: getConfig
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/ServerConfig'
examples:
nightly:
externalValue: https://peertube2.cpy.re/api/v1/config

/api/v1/config/about:
get:
summary: Get instance "About" information
Translatable information is returned in the language of the request, using the x-peertube-language header
or the Accept-Language header. If the instance has no translation for this language, the default information is returned.
operationId: getAbout
tags:
- Config
parameters:
- name: x-peertube-language
in: header
required: false
schema:
type: string
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/ServerConfigAbout'
examples:
nightly:
externalValue: https://peertube2.cpy.re/api/v1/config/about

/api/v1/config/custom:
get:
summary: Get instance runtime configuration
operationId: getCustomConfig
tags:
- Config
security:
- OAuth2:
- admin
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/ServerConfigCustom'
put:
summary: Set instance runtime configuration
operationId: putCustomConfig
tags:
- Config
security:
- OAuth2:
- admin
responses:
'200':
'400':
x-summary: field inconsistencies
Arises when:
- the emailer is disabled and the instance is open to registrations
- web videos and hls are disabled with transcoding enabled - you need at least one enabled
delete:
summary: Delete instance runtime configuration
operationId: delCustomConfig
tags:
- Config
security:
- OAuth2:
- admin
responses:
'200':
/api/v1/config/instance-banner/pick:
post:
summary: Update instance banner
security:
- OAuth2:
- admin
tags:
- Config
responses:
'204':
'413':
headers:
X-File-Maximum-Size:
schema:
type: string
format: Nginx size
requestBody:
content:
multipart/form-data:
schema:
type: object
properties:
bannerfile:
type: string
format: binary
encoding:
bannerfile:
contentType: image/png, image/jpeg

'/api/v1/config/instance-banner':
delete:
summary: Delete instance banner
security:
- OAuth2:
- admin
tags:
- Config
responses:
'204':
/api/v1/config/instance-avatar/pick:
post:
summary: Update instance avatar
security:
- OAuth2:
- admin
tags:
- Config
responses:
'204':
'413':
headers:
X-File-Maximum-Size:
schema:
type: string
format: Nginx size
requestBody:
content:
multipart/form-data:
schema:
type: object
properties:
avatarfile:
type: string
format: binary
encoding:
avatarfile:
contentType: image/png, image/jpeg

'/api/v1/config/instance-avatar':
delete:
summary: Delete instance avatar
security:
- OAuth2:
- admin
tags:
- Config
responses:
'204':
'/api/v1/config/instance-logo/{logoType}/pick':
post:
summary: Update instance logo
security:
- OAuth2:
- admin
tags:
- Config
parameters:
- $ref: '#/components/parameters/logoTypeParam'
responses:
'204':
'413':
headers:
X-File-Maximum-Size:
schema:
type: string
format: Nginx size
requestBody:
content:
multipart/form-data:
schema:
type: object
properties:
logofile:
type: string
format: binary
encoding:
logofile:
contentType: image/png, image/jpeg

'/api/v1/config/instance-logo/{logoType}':
delete:
summary: Delete instance logo
security:
- OAuth2:
- admin
tags:
- Config
parameters:
- $ref: '#/components/parameters/logoTypeParam'
responses:
'204':
/api/v1/custom-pages/homepage/instance:
get:
summary: Get instance custom homepage
tags:
- Homepage
responses:
'404':
'200':
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
responses:
'204':
/api/v1/jobs/pause:
post:
summary: Pause job queue
security:
- OAuth2:
- admin
tags:
- Job
requestBody:
content:
application/json:
schema:
type: object
properties:
processRoles:
type: array
minItems: 1
items:
type: string
enum:
- primary
- secondary
Roles of the PeerTube processes that must pause their job queue.
Defaults to all the roles.
Other processes are notified asynchronously.
responses:
'204':
/api/v1/jobs/resume:
post:
summary: Resume job queue
security:
- OAuth2:
- admin
tags:
- Job
requestBody:
content:
application/json:
schema:
type: object
properties:
processRoles:
type: array
minItems: 1
items:
type: string
enum:
- primary
- secondary
Roles of the PeerTube processes that must resume their job queue.
Defaults to all the roles.
Other processes are notified asynchronously.
responses:
'204':
/api/v1/jobs/{state}:
get:
summary: List instance jobs
operationId: getJobs
security:
- OAuth2:
- admin
tags:
- Job
parameters:
- name: state
in: path
required: true
schema:
type: string
enum:
- ''
- active
- completed
- failed
- waiting
- delayed
- $ref: '#/components/parameters/jobType'
- $ref: '#/components/parameters/start'
- $ref: '#/components/parameters/count'
- $ref: '#/components/parameters/sort'
responses:
'200':
content:
application/json:
schema:
type: object
properties:
total:
type: integer
example: 1
data:
type: array
maxItems: 100
items:
$ref: '#/components/schemas/Job'

/api/v1/jobs/{jobType}/{jobId}/cancel:
post:
summary: Cancel a job
operationId: cancelJob
security:
- OAuth2:
- admin
tags:
- Job
parameters:
- name: jobType
in: path
required: true
schema:
$ref: '#/components/schemas/JobType'
- name: jobId
in: path
required: true
schema:
type: string
responses:
'204':
'404':
'409':
/api/v1/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':
content:
application/json:
schema:
type: object
properties:
total:
type: integer
example: 1
data:
type: array
items:
$ref: '#/components/schemas/Follow'

'/api/v1/server/followers/{handle}':
delete:
summary: Remove or reject a follower to your server
security:
- OAuth2:
- admin
tags:
- Instance Follows
parameters:
- name: handle
in: path
required: true
schema:
type: string
format: email
responses:
'204':
'404':
'/api/v1/server/followers/{handle}/reject':
post:
summary: Reject a pending follower to your server
security:
- OAuth2:
- admin
tags:
- Instance Follows
parameters:
- name: handle
in: path
required: true
schema:
type: string
format: email
responses:
'204':
'404':
'/api/v1/server/followers/{handle}/accept':
post:
summary: Accept a pending follower to your server
security:
- OAuth2:
- admin
tags:
- Instance Follows
parameters:
- name: handle
in: path
required: true
schema:
type: string
format: email
responses:
'204':
'404':
/api/v1/server/following:
get:
tags:
- Instance Follows
summary: List instances followed by 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':
content:
application/json:
schema:
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 list of actors (PeerTube instance, channel or account)
responses:
'204':
'500':
requestBody:
content:
application/json:
schema:
type: object
properties:
hosts:
type: array
items:
type: string
format: hostname
uniqueItems: true
handles:
type: array
items:
type: string
uniqueItems: true

'/api/v1/server/following/{hostOrHandle}':
delete:
summary: Unfollow an actor (PeerTube instance, channel or account)
security:
- OAuth2:
- admin
tags:
- Instance Follows
parameters:
- name: hostOrHandle
in: path
required: true
schema:
type: string
responses:
'204':
'404':
/api/v1/users:
post:
summary: Create a user
operationId: addUser
security:
- OAuth2:
- admin
tags:
- Users
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/AddUserResponse'
links:
# GET /users/{id}
GetUser:
operationId: getUser
parameters:
id: '$response.body#/user/id'
# PUT /users/{id}
PutUser:
operationId: putUser
parameters:
id: '$response.body#/user/id'
# DELETE /users/{id}
DelUser:
operationId: delUser
parameters:
id: '$response.body#/user/id'
'403':
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/AddUser'
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
tags:
- Users
parameters:
- $ref: '#/components/parameters/usersSearch'
- $ref: '#/components/parameters/usersBlocked'
- $ref: '#/components/parameters/usersRole'
- $ref: '#/components/parameters/start'
- $ref: '#/components/parameters/count'
- $ref: '#/components/parameters/usersSort'
responses:
'200':
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/User'

'/api/v1/users/{id}':
parameters:
- $ref: '#/components/parameters/id'
delete:
summary: Delete a user
security:
- OAuth2:
- admin
tags:
- Users
operationId: delUser
responses:
'204':
get:
summary: Get a user
security:
- OAuth2: []
tags:
- Users
operationId: getUser
parameters:
- name: withStats
in: query
schema:
type: boolean
responses:
'200':
x-summary: successful operation
As an admin/moderator, you can request a response augmented with statistics about the user's
moderation relations and videos usage, by using the withStats parameter.
content:
application/json:
schema:
oneOf:
- $ref: '#/components/schemas/User'
- $ref: '#/components/schemas/UserWithStats'
put:
summary: Update a user
security:
- OAuth2: []
tags:
- Users
operationId: putUser
responses:
'204':
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/UpdateUser'
required: true

/api/v1/users/{id}/block:
post:
summary: Block a user
security:
- OAuth2:
- admin
tags:
- Users
parameters:
- $ref: '#/components/parameters/id'
requestBody:
content:
application/json:
schema:
type: object
properties:
reason:
type: string
minLength: 0
maxLength: 500
responses:
'204':
'400':
'403':
'404':
/api/v1/users/{id}/unblock:
post:
summary: Unblock a user
security:
- OAuth2:
- admin
tags:
- Users
parameters:
- $ref: '#/components/parameters/id'
responses:
'204':
'400':
'403':
'404':
/api/v1/oauth-clients/local:
get:
summary: Login prerequisite
operationId: getOAuthClient
tags:
- Session
responses:
'200':
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"

text
## AUTH
        curl -s "$API/oauth-clients/local"

/api/v1/users/token:
post:
summary: Login
operationId: getOAuthToken
tags:
- Session
parameters:
- name: x-peertube-otp
in: header
schema:
type: string
required: false
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':
content:
application/json:
schema:
type: object
properties:
token_type:
type: string
example: Bearer
access_token:
type: string
example: 90286a0bdf0f7315d9d3fe8dabf9e1d2be9c97d0
refresh_token:
type: string
example: 2e0d675df9fc96d2e4ec8a3ebbbf45eca9137bb7
expires_in:
type: integer
minimum: 0
example: 14399
refresh_token_expires_in:
type: integer
minimum: 0
example: 1209600
'400':
x-summary: client or credentials are invalid
Disambiguate via code:
- invalid_client for an unmatched client_id
- invalid_grant for unmatched credentials
'401':
x-summary: token expired or two factor header is missing
Disambiguate via code:
- default value for a regular authentication failure
- invalid_token for an expired token
- missing_two_factor if two factor header is missing
x-codeSamples:
- lang: Shell
source: |
## DEPENDENCIES: jq
API="https://peertube2.cpy.re/api/v1"
USERNAME=""
PASSWORD=""

text
## 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-urlencode password="$PASSWORD" \
          | jq -r ".access_token"

/api/v1/users/revoke-token:
post:
summary: Logout
operationId: revokeOAuthToken
tags:
- Session
security:
- OAuth2: []
responses:
'200':
/api/v1/users/{id}/token-sessions:
get:
summary: List token sessions
parameters:
- $ref: '#/components/parameters/id'
tags:
- Session
security:
- OAuth2: []
responses:
'200':
content:
application/json:
schema:
type: object
properties:
total:
type: integer
example: 1
data:
type: array
items:
$ref: '#/components/schemas/TokenSession'

/api/v1/users/{id}/token-sessions/{tokenSessionId}/revoke:
get:
summary: List token sessions
parameters:
- $ref: '#/components/parameters/id'
- $ref: '#/components/parameters/tokenSessionId'
tags:
- Session
security:
- OAuth2: []
responses:
'200':
/api/v1/users/ask-send-verify-email:
post:
summary: Resend user verification link
operationId: resendEmailToVerifyUser
tags:
- Users
- Register
requestBody:
content:
application/json:
schema:
type: object
properties:
email:
type: string
required:
- email
responses:
'204':
/api/v1/users/registrations/ask-send-verify-email:
post:
summary: Resend verification link to registration request email
operationId: resendEmailToVerifyRegistration
tags:
- Register
requestBody:
content:
application/json:
schema:
type: object
properties:
email:
type: string
required:
- email
responses:
'204':
/api/v1/users/{id}/verify-email:
post:
summary: Verify a user
operationId: verifyUser
Following a user registration, the new user will receive an email asking to click a link
containing a secret.
This endpoint can also be used to verify a new email set in the user account.
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':
'403':
'404':
/api/v1/users/registrations/{registrationId}/verify-email:
post:
summary: Verify a registration email
operationId: verifyRegistrationEmail
Following a user registration request, the user will receive an email asking to click a link
containing a secret.
tags:
- Register
parameters:
- $ref: '#/components/parameters/registrationId'
requestBody:
content:
application/json:
schema:
type: object
properties:
verificationString:
type: string
format: url
required:
- verificationString
responses:
'204':
'403':
'404':
/api/v1/users/ask-reset-password:
post:
summary: Ask to reset password
tags:
- Users
requestBody:
content:
application/json:
schema:
type: object
properties:
email:
type: string
required:
- email
responses:
'204':
/api/v1/users/{id}/reset-password:
post:
summary: Reset password
tags:
- Users
parameters:
- $ref: '#/components/parameters/id'
requestBody:
content:
application/json:
schema:
type: object
properties:
verificationString:
type: string
format: url
password:
type: string
required:
- verificationString
- password
responses:
'204':
'403':
'404':
/api/v1/users/{id}/two-factor/request:
post:
summary: Request two factor auth
operationId: requestTwoFactor
security:
- OAuth2: []
tags:
- Users
parameters:
- $ref: '#/components/parameters/id'
requestBody:
content:
application/json:
schema:
type: object
properties:
currentPassword:
type: string
responses:
'200':
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/RequestTwoFactorResponse'
'403':
'404':
'429':
/api/v1/users/{id}/two-factor/confirm-request:
post:
summary: Confirm two factor auth
operationId: confirmTwoFactorRequest
security:
- OAuth2: []
tags:
- Users
parameters:
- $ref: '#/components/parameters/id'
requestBody:
content:
application/json:
schema:
type: object
properties:
requestToken:
type: string
otpToken:
type: string
required:
- requestToken
- otpToken
responses:
'204':
'403':
'404':
/api/v1/users/{id}/two-factor/disable:
post:
summary: Disable two factor auth
operationId: disableTwoFactor
security:
- OAuth2: []
tags:
- Users
parameters:
- $ref: '#/components/parameters/id'
requestBody:
content:
application/json:
schema:
type: object
properties:
currentPassword:
type: string
responses:
'204':
'403':
'404':
'429':
/api/v1/users/{userId}/imports/import-resumable:
post:
summary: Initialize the resumable user import
operationId: userImportResumableInit
security:
- OAuth2: []
tags:
- User Imports
parameters:
- $ref: '#/components/parameters/userId'
- $ref: '#/components/parameters/resumableUploadInitContentLengthHeader'
- $ref: '#/components/parameters/resumableUploadInitContentTypeHeader'
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/UserImportResumable'
responses:
'201':
headers:
Location:
schema:
type: string
format: url
Content-Length:
schema:
type: number
example: 0
put:
summary: Send chunk for the resumable user import
operationId: userImportResumable
security:
- OAuth2: []
tags:
- User Imports
parameters:
- $ref: '#/components/parameters/userId'
- $ref: '#/components/parameters/resumableUploadId'
- $ref: '#/components/parameters/resumableUploadChunkContentRangeHeader'
- $ref: '#/components/parameters/resumableUploadChunkContentLengthHeader'
requestBody:
content:
application/octet-stream:
schema:
type: string
format: binary
responses:
'204':
'308':
headers:
Range:
schema:
type: string
example: bytes=0-262143
Content-Length:
schema:
type: number
example: 0
'400':
'503':
headers:
'Retry-After':
schema:
type: number
example: 300
delete:
summary: Cancel the resumable user import
operationId: userImportResumableCancel
security:
- OAuth2: []
tags:
- User Imports
parameters:
- $ref: '#/components/parameters/userId'
- $ref: '#/components/parameters/resumableUploadId'
- name: Content-Length
in: header
required: true
schema:
type: number
example: 0
responses:
'204':
headers:
Content-Length:
schema:
type: number
example: 0

/api/v1/users/{userId}/imports/latest:
get:
summary: Get latest user import
operationId: getLatestUserImport
security:
- OAuth2: []
tags:
- User Imports
parameters:
- $ref: '#/components/parameters/userId'
responses:
'200':
content:
application/json:
schema:
type: object
properties:
id:
type: integer
state:
type: object
properties:
id:
$ref: '#/components/schemas/UserImportState'
label:
type: string
createdAt:
type: string
format: date-time

/api/v1/users/{userId}/exports/request:
post:
summary: Request user export
operationId: requestUserExport
security:
- OAuth2: []
tags:
- User Exports
parameters:
- $ref: '#/components/parameters/userId'
requestBody:
content:
application/json:
schema:
type: object
properties:
withVideoFiles:
type: boolean
responses:
'200':
content:
application/json:
schema:
type: object
properties:
export:
type: object
properties:
id:
type: integer

/api/v1/users/{userId}/exports:
get:
summary: List user exports
operationId: listUserExports
security:
- OAuth2: []
tags:
- User Exports
parameters:
- $ref: '#/components/parameters/userId'
responses:
'200':
content:
application/json:
schema:
type: object
properties:
id:
type: integer
state:
type: object
properties:
id:
$ref: '#/components/schemas/UserExportState'
label:
type: string
size:
type: integer
privateDownloadUrl:
type: string
createdAt:
type: string
format: date-time
expiresOn:
type: string
format: date-time
/api/v1/users/{userId}/exports/{id}:
delete:
summary: Delete a user export
operationId: deleteUserExport
security:
- OAuth2: []
tags:
- User Exports
parameters:
- $ref: '#/components/parameters/userId'
- $ref: '#/components/parameters/id'
responses:
'204':
/api/v1/users/me:
get:
summary: Get my user information
operationId: getUserInfo
security:
- OAuth2:
- user
tags:
- My User
responses:
'200':
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/User'
put:
summary: Update my user information
operationId: putUserInfo
security:
- OAuth2:
- user
tags:
- My User
responses:
'204':
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/UpdateMe'
required: true
delete:
summary: Delete my account
operationId: deleteMe
security:
- OAuth2:
- user
tags:
- My User
responses:
'204':
'400':
'401':
'/api/v1/users/me/videos/comments':
get:
summary: List comments on user's videos
security:
- OAuth2: []
tags:
- Video Comments
parameters:
- $ref: '#/components/parameters/search'
- $ref: '#/components/parameters/searchAccountForComments'
- $ref: '#/components/parameters/searchVideoForComments'
- $ref: '#/components/parameters/videoId'
- $ref: '#/components/parameters/videoChannelId'
- $ref: '#/components/parameters/autoTagOneOfComment'
- $ref: '#/components/parameters/isHeldForReview'
- $ref: '#/components/parameters/includeCollaborations'
responses:
'200':
content:
application/json:
schema:
type: object
properties:
total:
type: integer
example: 1
data:
type: array
items:
$ref: '#/components/schemas/VideoCommentForOwnerOrAdmin'

/api/v1/users/me/videos/imports:
get:
summary: Get video imports of my user
security:
- OAuth2:
- user
tags:
- Videos
- My User
parameters:
- $ref: '#/components/parameters/start'
- $ref: '#/components/parameters/count'
- $ref: '#/components/parameters/sort'
- $ref: '#/components/parameters/includeCollaborations'
-
name: videoId
in: query
required: false
schema:
type: integer
-
name: targetUrl
in: query
required: false
schema:
type: string
-
name: videoChannelSyncId
in: query
required: false
schema:
type: number
-
name: search
in: query
required: false
schema:
type: string
-
name: stateOneOf
in: query
required: false
schema:
type: array
items:
$ref: '#/components/schemas/VideoImportStateConstant/properties/id'
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/VideoImportsList'

/api/v1/users/me/video-quota-used:
get:
summary: Get my user used quota
security:
- OAuth2:
- user
tags:
- My User
responses:
'200':
content:
application/json:
schema:
type: object
properties:
videoQuotaUsed:
type: number
example: 16810141515
videoQuotaUsedDaily:
type: number
example: 1681014151

'/api/v1/users/me/videos/{videoIdOrUUID}/rating':
get:
summary: Get rate of my user for a video
security:
- OAuth2: []
tags:
- My User
- Video Rates
parameters:
- $ref: '#/components/parameters/videoIdOrUUID'
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/GetMeVideoRating'

/api/v1/users/me/videos:
get:
summary: List videos of my user
security:
- OAuth2:
- user
tags:
- My User
- Videos
parameters:
- $ref: '#/components/parameters/channelNameOneOf'
# Common video filter parameters
- $ref: '#/components/parameters/start'
- $ref: '#/components/parameters/count'
- $ref: '#/components/parameters/skipCount'
- $ref: '#/components/parameters/videosSort'
- $ref: '#/components/parameters/nsfw'
- $ref: '#/components/parameters/nsfwFlagsIncluded'
- $ref: '#/components/parameters/nsfwFlagsExcluded'
- $ref: '#/components/parameters/aiUsageOneOf'
- $ref: '#/components/parameters/isLive'
- $ref: '#/components/parameters/includeScheduledLive'
- $ref: '#/components/parameters/categoryOneOf'
- $ref: '#/components/parameters/licenceOneOf'
- $ref: '#/components/parameters/languageOneOf'
- $ref: '#/components/parameters/tagsOneOf'
- $ref: '#/components/parameters/tagsAllOf'
- $ref: '#/components/parameters/isLocal'
- $ref: '#/components/parameters/include'
- $ref: '#/components/parameters/hasHLSFiles'
- $ref: '#/components/parameters/hasWebVideoFiles'
- $ref: '#/components/parameters/host'
- $ref: '#/components/parameters/autoTagOneOfVideo'
- $ref: '#/components/parameters/stateOneOfVideo'
- $ref: '#/components/parameters/privacyOneOf'
- $ref: '#/components/parameters/excludeAlreadyWatched'
- $ref: '#/components/parameters/search'
- $ref: '#/components/parameters/includeCollaborations'
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/VideoListResponse'

/api/v1/users/me/subscriptions:
get:
summary: List my user subscriptions
security:
- OAuth2:
- user
tags:
- My Subscriptions
parameters:
- $ref: '#/components/parameters/start'
- $ref: '#/components/parameters/count'
- $ref: '#/components/parameters/mySubscriptionSort'
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/VideoChannelList'
post:
tags:
- My Subscriptions
summary: Add subscription to my user
security:
- OAuth2:
- user
requestBody:
content:
application/json:
schema:
type: object
properties:
uri:
type: string
format: uri
required:
- uri
examples:
default:
value:
uri: [email protected]
responses:
'204':
/api/v1/users/me/subscriptions/exist:
get:
summary: Get if subscriptions exist for my user
security:
- OAuth2:
- user
tags:
- My Subscriptions
parameters:
- $ref: '#/components/parameters/subscriptionsUris'
responses:
'200':
content:
application/json:
schema:
type: object

/api/v1/users/me/subscriptions/videos:
get:
summary: List videos of subscriptions of my user
security:
- OAuth2:
- user
tags:
- My Subscriptions
- Videos
parameters:
# Common video filter parameters
- $ref: '#/components/parameters/start'
- $ref: '#/components/parameters/count'
- $ref: '#/components/parameters/skipCount'
- $ref: '#/components/parameters/videosSort'
- $ref: '#/components/parameters/nsfw'
- $ref: '#/components/parameters/nsfwFlagsIncluded'
- $ref: '#/components/parameters/nsfwFlagsExcluded'
- $ref: '#/components/parameters/aiUsageOneOf'
- $ref: '#/components/parameters/isLive'
- $ref: '#/components/parameters/includeScheduledLive'
- $ref: '#/components/parameters/categoryOneOf'
- $ref: '#/components/parameters/licenceOneOf'
- $ref: '#/components/parameters/languageOneOf'
- $ref: '#/components/parameters/tagsOneOf'
- $ref: '#/components/parameters/tagsAllOf'
- $ref: '#/components/parameters/isLocal'
- $ref: '#/components/parameters/include'
- $ref: '#/components/parameters/hasHLSFiles'
- $ref: '#/components/parameters/hasWebVideoFiles'
- $ref: '#/components/parameters/host'
- $ref: '#/components/parameters/autoTagOneOfVideo'
- $ref: '#/components/parameters/stateOneOfVideo'
- $ref: '#/components/parameters/privacyOneOf'
- $ref: '#/components/parameters/excludeAlreadyWatched'
- $ref: '#/components/parameters/search'
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/VideoListResponse'

'/api/v1/users/me/subscriptions/{subscriptionHandle}':
get:
summary: Get subscription of my user
security:
- OAuth2:
- user
tags:
- My Subscriptions
parameters:
- $ref: '#/components/parameters/subscriptionHandle'
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/VideoChannel'
delete:
summary: Delete subscription of my user
security:
- OAuth2:
- user
tags:
- My Subscriptions
parameters:
- $ref: '#/components/parameters/subscriptionHandle'
responses:
'204':
/api/v1/users/me/notifications:
get:
summary: List my notifications
security:
- OAuth2: []
tags:
- My Notifications
parameters:
- name: typeOneOf
in: query
schema:
type: array
items:
$ref: '#/components/schemas/NotificationType'
- name: unread
in: query
schema:
type: boolean
- $ref: '#/components/parameters/start'
- $ref: '#/components/parameters/count'
- $ref: '#/components/parameters/sort'
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/NotificationListResponse'

/api/v1/users/me/notifications/read:
post:
summary: Mark notifications as read by their id
security:
- OAuth2: []
tags:
- My Notifications
requestBody:
content:
application/json:
schema:
type: object
properties:
ids:
type: array
items:
type: integer
required:
- ids
responses:
'204':
/api/v1/users/me/notifications/read-all:
post:
summary: Mark all my notification as read
security:
- OAuth2: []
tags:
- My Notifications
responses:
'204':
/api/v1/users/me/notification-settings:
put:
summary: Update my notification settings
security:
- OAuth2: []
tags:
- My Notifications
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/UserNotificationSettings'

text
responses:
    '204':

/api/v1/users/me/new-feature-info/read:
post:
tags:
- My User
summary: Mark feature info as read
security:
- OAuth2:
- user
requestBody:
content:
application/json:
schema:
type: object
properties:
feature:
$ref: '#/components/schemas/NewFeatureInfoType'
required:
- feature
responses:
'204':
/api/v1/users/me/history/videos:
get:
summary: List watched videos history
security:
- OAuth2: []
tags:
- My History
parameters:
- $ref: '#/components/parameters/start'
- $ref: '#/components/parameters/count'
- $ref: '#/components/parameters/search'
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/VideoListResponse'

/api/v1/users/me/history/videos/{videoIdOrUUID}:
delete:
summary: Delete history element
security:
- OAuth2: []
tags:
- My History
parameters:
- $ref: '#/components/parameters/videoIdOrUUID'
responses:
'204':
/api/v1/users/me/history/videos/remove:
post:
summary: Clear video history
security:
- OAuth2: []
tags:
- My History
requestBody:
content:
multipart/form-data:
schema:
type: object
properties:
beforeDate:
type: string
format: date-time
responses:
'204':
/api/v1/users/me/avatar/pick:
post:
summary: Update my user avatar
security:
- OAuth2: []
tags:
- My User
responses:
'200':
content:
application/json:
schema:
type: object
properties:
avatars:
type: array
items:
$ref: '#/components/schemas/ActorImage'
'413':
headers:
X-File-Maximum-Size:
schema:
type: string
format: Nginx size
requestBody:
content:
multipart/form-data:
schema:
type: object
properties:
avatarfile:
type: string
format: binary
encoding:
avatarfile:
contentType: image/png, image/jpeg

/api/v1/users/me/avatar:
delete:
summary: Delete my avatar
security:
- OAuth2: []
tags:
- My User
responses:
'204':
/api/v1/users/register:
post:
summary: Register a user
operationId: registerUser
tags:
- Register
responses:
'200':
content:
application/json:
schema:
type: object
properties:
state:
type: object
properties:
id:
$ref: '#/components/schemas/UserRegistrationState'
label:
type: string
'400':
'403':
'409':
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/RegisterUser'
required: true

/api/v1/users/registrations/request:
post:
summary: Request registration
operationId: requestRegistration
tags:
- Register
responses:
'200':
content:
application/json:
schema:
type: object
properties:
state:
type: object
properties:
id:
$ref: '#/components/schemas/UserRegistrationState'
label:
type: string
'400':
'403':
'409':
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/UserRegistrationRequest'

/api/v1/users/registrations/{registrationId}/accept:
post:
security:
- OAuth2:
- admin
- moderator
summary: Accept registration
operationId: acceptRegistration
tags:
- Register
parameters:
- $ref: '#/components/parameters/registrationId'
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/UserRegistrationAcceptOrReject'
responses:
'204':
/api/v1/users/registrations/{registrationId}/reject:
post:
security:
- OAuth2:
- admin
- moderator
summary: Reject registration
operationId: rejectRegistration
tags:
- Register
parameters:
- $ref: '#/components/parameters/registrationId'
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/UserRegistrationAcceptOrReject'
responses:
'204':
/api/v1/users/registrations/{registrationId}:
delete:
security:
- OAuth2:
- admin
- moderator
summary: Delete registration
operationId: deleteRegistration
tags:
- Register
parameters:
- $ref: '#/components/parameters/registrationId'
responses:
'204':
/api/v1/users/registrations:
get:
security:
- OAuth2:
- admin
- moderator
summary: List registrations
operationId: listRegistrations
tags:
- Register
parameters:
- $ref: '#/components/parameters/start'
- $ref: '#/components/parameters/count'
- name: search
in: query
required: false
schema:
type: string
- name: sort
in: query
required: false
schema:
type: string
enum:
- -createdAt
- createdAt
- state
- -state
- name: stateOneOf
in: query
required: false
schema:
type: array
items:
$ref: '#/components/schemas/UserRegistrationState'
responses:
'200':
content:
application/json:
schema:
type: object
properties:
total:
type: integer
example: 1
data:
type: array
items:
$ref: '#/components/schemas/UserRegistration'

/api/v1/videos/ownership:
get:
summary: List video ownership changes
tags:
- Ownership Change
security:
- OAuth2: []
parameters:
- $ref: '#/components/parameters/start'
- $ref: '#/components/parameters/count'
- name: sort
in: query
required: false
schema:
type: string
enum:
- -createdAt
- createdAt
responses:
'200':
content:
'application/json':
schema:
type: object
properties:
total:
type: integer
example: 1
data:
type: array
items:
$ref: '#/components/schemas/ChangeOwnership'
'401':
'/api/v1/videos/ownership/{id}/accept':
post:
summary: Accept ownership change request
tags:
- Ownership Change
security:
- OAuth2: []
parameters:
- $ref: '#/components/parameters/idOrUUID'
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
channelId:
type: integer
required:
- channelId
responses:
'204':
'400':
'403':
'413':
'404':
'/api/v1/videos/ownership/{id}/refuse':
post:
summary: Refuse ownership change request
tags:
- Ownership Change
security:
- OAuth2: []
parameters:
- $ref: '#/components/parameters/idOrUUID'
responses:
'204':
'400':
'403':
'404':
'/api/v1/videos/ownership/{id}':
delete:
summary: Delete ownership change request
tags:
- Ownership Change
security:
- OAuth2: []
parameters:
- $ref: '#/components/parameters/idOrUUID'
responses:
'204':
'400':
'403':
'404':
'/api/v1/videos/{videoIdOrUUID}/ownership':
get:
summary: List ownership change requests for a video
tags:
- Ownership Change
security:
- OAuth2: []
parameters:
- $ref: '#/components/parameters/videoIdOrUUID'
- name: state
in: query
required: false
schema:
$ref: '#/components/schemas/ChangeOwnershipState'
- $ref: '#/components/parameters/start'
- $ref: '#/components/parameters/count'
- name: sort
in: query
required: false
schema:
type: string
enum:
- -createdAt
- createdAt
responses:
'200':
content:
'application/json':
schema:
type: object
properties:
total:
type: integer
example: 1
data:
type: array
items:
$ref: '#/components/schemas/ChangeOwnership'
'403':
'404':
'/api/v1/videos/{videoIdOrUUID}/give-ownership':
post:
summary: Request ownership change
tags:
- Ownership Change
security:
- OAuth2: []
parameters:
- $ref: '#/components/parameters/videoIdOrUUID'
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
username:
type: string
required:
- username
responses:
'204':
'400':
'403':
'404':
/api/v1/video-channels/ownership:
get:
summary: List channel ownership changes
tags:
- Ownership Change
security:
- OAuth2: []
parameters:
- $ref: '#/components/parameters/start'
- $ref: '#/components/parameters/count'
- name: sort
in: query
required: false
schema:
type: string
enum:
- -createdAt
- createdAt
responses:
'200':
content:
application/json:
schema:
type: object
properties:
total:
type: integer
example: 1
data:
type: array
items:
$ref: '#/components/schemas/ChangeOwnership'
'401':
'/api/v1/video-channels/ownership/{id}/accept':
post:
summary: Accept channel ownership change request
tags:
- Ownership Change
security:
- OAuth2: []
parameters:
- $ref: '#/components/parameters/idOrUUID'
responses:
'204':
'400':
'403':
'404':
'409':
'413':
'/api/v1/video-channels/ownership/{id}/refuse':
post:
summary: Refuse channel ownership change request
tags:
- Ownership Change
security:
- OAuth2: []
parameters:
- $ref: '#/components/parameters/idOrUUID'
responses:
'204':
'400':
'403':
'404':
'/api/v1/video-channels/ownership/{id}':
delete:
summary: Delete channel ownership change request
tags:
- Ownership Change
security:
- OAuth2: []
parameters:
- $ref: '#/components/parameters/idOrUUID'
responses:
'204':
'400':
'403':
'404':
'/api/v1/video-channels/{channelHandle}/ownership':
get:
summary: List ownership change requests for a channel
tags:
- Ownership Change
security:
- OAuth2: []
parameters:
- $ref: '#/components/parameters/channelHandle'
- name: state
in: query
required: false
schema:
$ref: '#/components/schemas/ChangeOwnershipState'
- $ref: '#/components/parameters/start'
- $ref: '#/components/parameters/count'
- name: sort
in: query
required: false
schema:
type: string
enum:
- -createdAt
- createdAt
responses:
'200':
content:
application/json:
schema:
type: object
properties:
total:
type: integer
example: 1
data:
type: array
items:
$ref: '#/components/schemas/ChangeOwnership'
'400':
'403':
'404':
'/api/v1/video-channels/{channelHandle}/give-ownership':
post:
summary: Request channel ownership change
tags:
- Ownership Change
security:
- OAuth2: []
parameters:
- $ref: '#/components/parameters/channelHandle'
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
username:
type: string
required:
- username
responses:
'204':
'400':
'403':
'404':
'/api/v1/videos/{id}/token':
post:
summary: Request video token
operationId: requestVideoToken
tags:
- Video
security:
- OAuth2: []
parameters:
- $ref: '#/components/parameters/idOrUUID'
- $ref: '#/components/parameters/videoPasswordHeader'
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/VideoTokenResponse'
'400':
'404':
/api/v1/videos/{id}/studio/edit:
post:
summary: Create a studio task
tags:
- Video Transcoding
- Video
security:
- OAuth2: []
parameters:
- $ref: '#/components/parameters/idOrUUID'
requestBody:
required: true
content:
multipart/form-data:
schema:
$ref: '#/components/schemas/VideoStudioCreateTask'
responses:
'204':
'400':
'404':
/api/v1/videos:
get:
summary: List videos
operationId: getVideos
tags:
- Video
parameters:
# Common video filter parameters
- $ref: '#/components/parameters/start'
- $ref: '#/components/parameters/count'
- $ref: '#/components/parameters/skipCount'
- $ref: '#/components/parameters/videosSort'
- $ref: '#/components/parameters/nsfw'
- $ref: '#/components/parameters/nsfwFlagsIncluded'
- $ref: '#/components/parameters/nsfwFlagsExcluded'
- $ref: '#/components/parameters/aiUsageOneOf'
- $ref: '#/components/parameters/isLive'
- $ref: '#/components/parameters/includeScheduledLive'
- $ref: '#/components/parameters/categoryOneOf'
- $ref: '#/components/parameters/licenceOneOf'
- $ref: '#/components/parameters/languageOneOf'
- $ref: '#/components/parameters/tagsOneOf'
- $ref: '#/components/parameters/tagsAllOf'
- $ref: '#/components/parameters/isLocal'
- $ref: '#/components/parameters/include'
- $ref: '#/components/parameters/hasHLSFiles'
- $ref: '#/components/parameters/hasWebVideoFiles'
- $ref: '#/components/parameters/host'
- $ref: '#/components/parameters/autoTagOneOfVideo'
- $ref: '#/components/parameters/stateOneOfVideo'
- $ref: '#/components/parameters/privacyOneOf'
- $ref: '#/components/parameters/excludeAlreadyWatched'
- $ref: '#/components/parameters/search'
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/VideoListResponse'

/api/v1/recommendations/videos:
get:
summary: List recommended videos
Return videos recommended next to a reference video (or general recommendations if no reference video is given).

text
PeerTube decides the recommendation algorithm: it currently lists videos sharing tags with the reference video
    (excluding videos already watched by the authenticated user), then the latest videos.
    All returned videos are restricted to the `scope`, which defaults to the `recommendationScope` of the reference video.
  operationId: getRecommendationVideos
  tags:
    - Video
  parameters:
    - name: scope
      in: query
      required: false
        Restrict recommended videos. Defaults to the `recommendationScope` of the reference video, or to `1` (all videos) if no reference video is given
      schema:
        $ref: '#/components/schemas/VideoRecommendationScopeSet'
    - name: videoId
      in: query
      required: false
      schema:
        oneOf:
          - $ref: '#/components/schemas/id'
          - $ref: '#/components/schemas/UUIDv4'
          - $ref: '#/components/schemas/shortUUID'
    - name: count
      in: query
      required: false
      schema:
        type: integer
        minimum: 1
        maximum: 30
        default: 10
    - name: excludeVideoIds
      in: query
      required: false
      style: form
      explode: true
      schema:
        type: array
        maxItems: 50
        items:
          $ref: '#/components/schemas/id'
    - $ref: '#/components/parameters/videoPasswordHeader'
    - $ref: '#/components/parameters/nsfw'
    - $ref: '#/components/parameters/nsfwFlagsIncluded'
    - $ref: '#/components/parameters/nsfwFlagsExcluded'
    - $ref: '#/components/parameters/aiUsageOneOf'
  responses:
    '200':
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/VideoListResponse'
    '400':
    '401':
    '403':
    '404':

/api/v1/videos/categories:
get:
summary: List available video categories
operationId: getCategories
tags:
- Video
responses:
'200':
content:
application/json:
schema:
type: array
items:
type: string
examples:
nightly:
externalValue: https://peertube2.cpy.re/api/v1/videos/categories

/api/v1/videos/licences:
get:
summary: List available video licences
operationId: getLicences
tags:
- Video
responses:
'200':
content:
application/json:
schema:
type: array
items:
type: string
examples:
nightly:
externalValue: https://peertube2.cpy.re/api/v1/videos/licences

/api/v1/videos/languages:
get:
summary: List available video languages
operationId: getLanguages
tags:
- Video
parameters:
- name: scope
in: query
required: false
schema:
type: string
enum:
- subtitle
responses:
'200':
content:
application/json:
schema:
type: array
items:
type: string
examples:
nightly:
externalValue: https://peertube2.cpy.re/api/v1/videos/languages

/api/v1/videos/privacies:
get:
summary: List available video privacy policies
operationId: getVideoPrivacyPolicies
tags:
- Video
responses:
'200':
content:
application/json:
schema:
type: array
items:
type: string
examples:
nightly:
externalValue: https://peertube2.cpy.re/api/v1/videos/privacies

'/api/v1/videos/{id}':
put:
summary: Update a video
operationId: putVideo
security:
- OAuth2: []
tags:
- Video
parameters:
- $ref: '#/components/parameters/idOrUUID'
responses:
'204':
requestBody:
content:
multipart/form-data:
schema:
type: object
properties:
channelId:
type: integer
New channel of the video. The channel must be owned by the same account as the previous one.
Use the "change ownership" endpoints to give a video to a channel owned by another account on the local PeerTube instance.
thumbnailfile:
type: string
format: binary
previewfile:
deprecated: true
type: string
format: binary
category:
$ref: '#/components/schemas/VideoCategorySet'
licence:
$ref: '#/components/schemas/VideoLicenceSet'
language:
$ref: '#/components/schemas/VideoLanguageSet'
privacy:
$ref: '#/components/schemas/VideoPrivacySet'
type: string
waitTranscoding:
type: string
support:
example: Please support our work on https://soutenir.framasoft.org/en/ <3
type: string
nsfw:
type: boolean
nsfwSummary:
nsfwFlags:
$ref: '#/components/schemas/NSFWFlag'
name:
type: string
minLength: 3
maxLength: 120
tags:
type: array
minItems: 1
maxItems: 5
items:
type: string
minLength: 2
maxLength: 30
commentsPolicy:
$ref: '#/components/schemas/VideoCommentsPolicySet'
recommendationScope:
$ref: '#/components/schemas/VideoRecommendationScopeSet'
aiUsage:
$ref: '#/components/schemas/VideoAIUsageSet'
commercialContent:
$ref: '#/components/schemas/VideoCommercialContentSet'
downloadEnabled:
type: boolean
originallyPublishedAt:
type: string
format: date-time
nullable: true
scheduleUpdate:
$ref: '#/components/schemas/VideoScheduledUpdate'
videoPasswords:
$ref: '#/components/schemas/AddVideoPasswords'
encoding:
thumbnailfile:
contentType: image/jpeg
previewfile:
contentType: image/jpeg
tags:
style: form
explode: true
get:
summary: Get a video
operationId: getVideo
tags:
- Video
parameters:
- $ref: '#/components/parameters/idOrUUID'
- $ref: '#/components/parameters/videoPasswordHeader'
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/VideoDetails'
'401':
content:
application/json:
schema:
$ref: '#/components/schemas/ServerError'
'403':
content:
application/json:
schema:
$ref: '#/components/schemas/ServerError'
delete:
summary: Delete a video
operationId: delVideo
security:
- OAuth2: []
tags:
- Video
parameters:
- $ref: '#/components/parameters/idOrUUID'
responses:
'204':
'/api/v1/videos/{id}/views':
post:
summary: Notify user is watching a video
operationId: addView
tags:
- Video
parameters:
- $ref: '#/components/parameters/idOrUUID'
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/UserViewingVideo'
required: true
responses:
'204':
'/api/v1/videos/{id}/stats/overall':
get:
summary: Get overall stats of a video
tags:
- Video Stats
security:
- OAuth2: []
parameters:
- $ref: '#/components/parameters/idOrUUID'
- name: startDate
in: query
schema:
type: string
format: date-time
- name: endDate
in: query
schema:
type: string
format: date-time
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/VideoStatsOverall'

'/api/v1/videos/{id}/stats/user-agent':
get:
summary: Get user agent stats of a video
tags:
- Video Stats
security:
- OAuth2: []
parameters:
- $ref: '#/components/parameters/idOrUUID'
- name: startDate
in: query
schema:
type: string
format: date-time
- name: endDate
in: query
schema:
type: string
format: date-time
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/VideoStatsUserAgent'

'/api/v1/videos/{id}/stats/retention':
get:
summary: Get retention stats of a video
tags:
- Video Stats
security:
- OAuth2: []
parameters:
- $ref: '#/components/parameters/idOrUUID'
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/VideoStatsRetention'

'/api/v1/videos/{id}/stats/timeseries/{metric}':
get:
summary: Get timeserie stats of a video
tags:
- Video Stats
security:
- OAuth2: []
parameters:
- $ref: '#/components/parameters/idOrUUID'
-
name: metric
in: path
required: true
schema:
type: string
enum:
- 'viewers'
- 'aggregateWatchTime'
- name: startDate
in: query
schema:
type: string
format: date-time
- name: endDate
in: query
schema:
type: string
format: date-time
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/VideoStatsTimeserie'

/api/v1/videos/upload:
post:
summary: Upload a video
operationId: uploadLegacy
security:
- OAuth2: []
tags:
- Video
- Video Upload
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/VideoUploadResponse'
'403':
'408':
'413':
x-summary: video file too large, due to quota or max body size limit set by the reverse-proxy
If the response has no body, it means the reverse-proxy didn't let it through. Otherwise disambiguate via code:
- quota_reached for quota limits whether daily or global
headers:
X-File-Maximum-Size:
schema:
type: string
format: Nginx size
'415':
'422':
requestBody:
content:
multipart/form-data:
schema:
$ref: '#/components/schemas/VideoUploadRequestLegacy'
encoding:
videofile:
contentType: video/mp4, video/webm, video/ogg, video/avi, video/quicktime, video/x-msvideo, video/x-flv, video/x-matroska, application/octet-stream
thumbnailfile:
contentType: image/jpeg
previewfile:
contentType: image/jpeg
x-codeSamples:
- lang: Shell
source: |
## DEPENDENCIES: jq
USERNAME=""
PASSWORD=""
FILE_PATH=""
CHANNEL_ID=""
NAME=""
API="https://peertube2.cpy.re/api/v1"

text
## 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")
        token=$(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")

        ## VIDEO UPLOAD
        curl -s "$API/videos/upload" \
          -H "Authorization: Bearer $token" \
          --max-time 600 \
          --form videofile=@"$FILE_PATH" \
          --form channelId=$CHANNEL_ID \
          --form name="$NAME"

/api/v1/videos/upload-resumable:
post:
summary: Initialize the resumable upload of a video
operationId: uploadResumableInit
security:
- OAuth2: []
tags:
- Video
- Video Upload
parameters:
- $ref: '#/components/parameters/resumableUploadInitContentLengthHeader'
- $ref: '#/components/parameters/resumableUploadInitContentTypeHeader'
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/VideoUploadRequestResumable'
responses:
'200':
'201':
headers:
Location:
schema:
type: string
format: url
example: /api/v1/videos/upload-resumable?upload_id=471e97554f21dec3b8bb5d4602939c51
Content-Length:
schema:
type: number
example: 0
'413':
x-summary: video file too large, due to quota, absolute max file size or concurrent partial upload limit
Disambiguate via code:
- max_file_size_reached for the absolute file size limit
- quota_reached for quota limits whether daily or global
'415':
put:
summary: Send chunk for the resumable upload of a video
operationId: uploadResumable
security:
- OAuth2: []
tags:
- Video
- Video Upload
parameters:
- $ref: '#/components/parameters/resumableUploadId'
- $ref: '#/components/parameters/resumableUploadChunkContentRangeHeader'
- $ref: '#/components/parameters/resumableUploadChunkContentLengthHeader'
requestBody:
content:
application/octet-stream:
schema:
type: string
format: binary
responses:
'200':
headers:
Content-Length:
schema:
type: number
content:
application/json:
schema:
$ref: '#/components/schemas/VideoUploadResponse'
'308':
headers:
Range:
schema:
type: string
example: bytes=0-262143
Content-Length:
schema:
type: number
example: 0
'400':
'403':
'404':
'409':
'422':
'429':
'503':
headers:
'Retry-After':
schema:
type: number
example: 300
delete:
summary: Cancel the resumable upload of a video, deleting any data uploaded so far
operationId: uploadResumableCancel
security:
- OAuth2: []
tags:
- Video
- Video Upload
parameters:
- $ref: '#/components/parameters/resumableUploadId'
- name: Content-Length
in: header
required: true
schema:
type: number
example: 0
responses:
'204':
headers:
Content-Length:
schema:
type: number
example: 0
'404':
/api/v1/videos/imports:
post:
summary: Import a video
operationId: importVideo
security:
- OAuth2: []
tags:
- Video Imports
- Video Upload
requestBody:
content:
multipart/form-data:
schema:
$ref: '#/components/schemas/VideoCreateImport'
encoding:
torrentfile:
contentType: application/x-bittorrent
thumbnailfile:
contentType: image/jpeg
previewfile:
contentType: image/jpeg
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/VideoUploadResponse'
'400':
'403':
'409':
/api/v1/videos/imports/{id}/cancel:
post:
summary: Cancel video import
security:
- OAuth2: []
tags:
- Video Imports
parameters:
- $ref: '#/components/parameters/id'
responses:
'204':
/api/v1/videos/imports/{id}/retry:
post:
summary: Retry video import
security:
- OAuth2: []
tags:
- Video Imports
parameters:
- $ref: '#/components/parameters/id'
responses:
'204':
/api/v1/videos/imports/{id}:
delete:
summary: Delete video import
security:
- OAuth2: []
tags:
- Video Imports
parameters:
- $ref: '#/components/parameters/id'
responses:
'204':
/api/v1/videos/live:
post:
summary: Create a live
operationId: addLive
security:
- OAuth2: []
tags:
- Live Videos
- Video
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/VideoUploadResponse'
'400':
x-summary: validation error, or conflicting saveReplay and permanentLive parameter set
Disambiguate via code:
- default type for a validation error
- live_conflicting_permanent_and_save_replay for conflicting parameters set
'403':
x-summary: live is not enabled, allow replay is not enabled, or max instance/user live videos limit is exceeded
Disambiguate via code:
- live_not_enabled for a disabled live feature
- live_not_allowing_replay for a disabled replay feature
- max_instance_lives_limit_reached for the absolute concurrent live limit
- max_user_lives_limit_reached for the user concurrent live limit
requestBody:
content:
multipart/form-data:
schema:
type: object
properties:
channelId:
type: integer
saveReplay:
type: boolean
replaySettings:
$ref: '#/components/schemas/LiveVideoReplaySettings'
permanentLive:
type: boolean
latencyMode:
allOf:
- $ref: '#/components/schemas/LiveVideoLatencyMode'
thumbnailfile:
type: string
format: binary
previewfile:
deprecated: true
type: string
format: binary
privacy:
$ref: '#/components/schemas/VideoPrivacySet'
category:
$ref: '#/components/schemas/VideoCategorySet'
licence:
$ref: '#/components/schemas/VideoLicenceSet'
language:
$ref: '#/components/schemas/VideoLanguageSet'
type: string
support:
example: Please support our work on https://soutenir.framasoft.org/en/ <3
type: string
nsfw:
type: boolean
nsfwSummary:
nsfwFlags:
$ref: '#/components/schemas/NSFWFlag'
name:
type: string
minLength: 3
maxLength: 120
tags:
type: array
minItems: 1
maxItems: 5
items:
type: string
minLength: 2
maxLength: 30
commentsPolicy:
$ref: '#/components/schemas/VideoCommentsPolicySet'
recommendationScope:
$ref: '#/components/schemas/VideoRecommendationScopeSet'
aiUsage:
$ref: '#/components/schemas/VideoAIUsageSet'
commercialContent:
$ref: '#/components/schemas/VideoCommercialContentSet'
downloadEnabled:
type: boolean
schedules:
type: array
items:
$ref: '#/components/schemas/LiveSchedule'
required:
- channelId
- name
encoding:
thumbnailfile:
contentType: image/jpeg
previewfile:
contentType: image/jpeg

/api/v1/videos/live/{id}:
get:
summary: Get information about a live
operationId: getLiveId
security:
- OAuth2: []
tags:
- Live Videos
- Video
parameters:
- $ref: '#/components/parameters/idOrUUID'
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/LiveVideoResponse'
put:
summary: Update information about a live
operationId: updateLiveId
security:
- OAuth2: []
tags:
- Live Videos
- Video
parameters:
- $ref: '#/components/parameters/idOrUUID'
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/LiveVideoUpdate'
responses:
'204':
'400':
'403':
/api/v1/videos/live/{id}/sessions:
get:
summary: List live sessions
security:
- OAuth2: []
tags:
- Live Videos
parameters:
- $ref: '#/components/parameters/idOrUUID'
- $ref: '#/components/parameters/sort'
responses:
'200':
content:
application/json:
schema:
type: object
properties:
total:
type: integer
example: 1
data:
type: array
items:
$ref: '#/components/schemas/LiveVideoSessionResponse'
/api/v1/videos/{id}/live-session:
get:
summary: Get live session of a replay
security:
- OAuth2: []
tags:
- Live Videos
parameters:
- $ref: '#/components/parameters/idOrUUID'
- $ref: '#/components/parameters/videoPasswordHeader'
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/LiveVideoSessionResponse'

'/api/v1/videos/{id}/source':
get:
summary: Get video source file metadata
operationId: getVideoSource
security:
- OAuth2: []
tags:
- Video
parameters:
- $ref: '#/components/parameters/idOrUUID'
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/VideoSource'

'/api/v1/videos/{id}/source/file':
delete:
summary: Delete video source file
operationId: deleteVideoSourceFile
tags:
- Video
security:
- OAuth2:
- admin
- moderator
parameters:
- $ref: '#/components/parameters/idOrUUID'
responses:
'204':
'404':
'/api/v1/videos/{id}/source/replace-resumable':
post:
summary: Initialize the resumable replacement of a video
operationId: replaceVideoSourceResumableInit
security:
- OAuth2: []
tags:
- Video
- Video Upload
parameters:
- $ref: '#/components/parameters/idOrUUID'
- $ref: '#/components/parameters/resumableUploadInitContentLengthHeader'
- $ref: '#/components/parameters/resumableUploadInitContentTypeHeader'
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/VideoReplaceSourceRequestResumable'
responses:
'200':
'201':
headers:
Location:
schema:
type: string
format: url
Content-Length:
schema:
type: number
example: 0
'413':
x-summary: video file too large, due to quota, absolute max file size or concurrent partial upload limit
Disambiguate via code:
- max_file_size_reached for the absolute file size limit
- quota_reached for quota limits whether daily or global
'415':
put:
summary: Send chunk for the resumable replacement of a video
operationId: replaceVideoSourceResumable
security:
- OAuth2: []
tags:
- Video
- Video Upload
parameters:
- $ref: '#/components/parameters/idOrUUID'
- $ref: '#/components/parameters/resumableUploadId'
- $ref: '#/components/parameters/resumableUploadChunkContentRangeHeader'
- $ref: '#/components/parameters/resumableUploadChunkContentLengthHeader'
requestBody:
content:
application/octet-stream:
schema:
type: string
format: binary
responses:
'204':
'308':
headers:
Range:
schema:
type: string
example: bytes=0-262143
Content-Length:
schema:
type: number
example: 0
'400':
'403':
'404':
'409':
'422':
'429':
'503':
headers:
'Retry-After':
schema:
type: number
example: 300
delete:
summary: Cancel the resumable replacement of a video
operationId: replaceVideoSourceResumableCancel
security:
- OAuth2: []
tags:
- Video
- Video Upload
parameters:
- $ref: '#/components/parameters/idOrUUID'
- $ref: '#/components/parameters/resumableUploadId'
- name: Content-Length
in: header
required: true
schema:
type: number
example: 0
responses:
'204':
headers:
Content-Length:
schema:
type: number
example: 0
'404':
/api/v1/users/me/abuses:
get:
summary: List my abuses
operationId: getMyAbuses
security:
- OAuth2: []
tags:
- Abuses
- My User
parameters:
- name: id
in: query
schema:
type: integer
- name: state
in: query
schema:
$ref: '#/components/schemas/AbuseStateSet'
- $ref: '#/components/parameters/abusesSort'
- $ref: '#/components/parameters/start'
- $ref: '#/components/parameters/count'
responses:
'200':
content:
application/json:
schema:
type: object
properties:
total:
type: integer
example: 1
data:
type: array
items:
$ref: '#/components/schemas/Abuse'

/api/v1/abuses:
get:
summary: List abuses
operationId: getAbuses
security:
- OAuth2:
- admin
- moderator
tags:
- Abuses
parameters:
- name: id
in: query
schema:
type: integer
- name: predefinedReason
in: query
schema:
$ref: '#/components/schemas/PredefinedAbuseReasons'
- name: search
in: query
schema:
type: string
- name: state
in: query
schema:
$ref: '#/components/schemas/AbuseStateSet'
- name: searchReporter
in: query
schema:
type: string
- name: searchReportee
in: query
schema:
type: string
- name: searchVideo
in: query
schema:
type: string
- name: searchVideoChannel
in: query
schema:
type: string
- name: videoIs
in: query
schema:
type: string
enum:
- 'deleted'
- 'blacklisted'
- name: filter
in: query
schema:
type: string
enum:
- 'video'
- 'comment'
- 'account'
- $ref: '#/components/parameters/start'
- $ref: '#/components/parameters/count'
- $ref: '#/components/parameters/abusesSort'
responses:
'200':
content:
application/json:
schema:
type: object
properties:
total:
type: integer
example: 1
data:
type: array
items:
$ref: '#/components/schemas/Abuse'
post:
summary: Report an abuse
You cannot report a video that you own or on which you are a collaborator (video channel editor).
security:
- OAuth2: []
tags:
- Abuses
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
reason:
type: string
minLength: 2
maxLength: 3000
predefinedReasons:
$ref: '#/components/schemas/PredefinedAbuseReasons'
video:
type: object
properties:
id:
allOf:
- $ref: '#/components/schemas/Video/properties/id'
startAt:
type: integer
format: seconds
minimum: 0
endAt:
type: integer
format: seconds
minimum: 0
comment:
type: object
properties:
id:
allOf:
- $ref: '#/components/schemas/VideoComment/properties/id'
account:
type: object
properties:
id:
type: integer
required:
- reason
responses:
'200':
content:
application/json:
schema:
type: object
properties:
abuse:
type: object
properties:
id:
$ref: '#/components/schemas/id'
'400':
'403':
'/api/v1/abuses/{abuseId}':
put:
summary: Update an abuse
security:
- OAuth2:
- admin
- moderator
tags:
- Abuses
parameters:
- $ref: '#/components/parameters/abuseId'
requestBody:
content:
application/json:
schema:
type: object
properties:
state:
$ref: '#/components/schemas/AbuseStateSet'
moderationComment:
type: string
minLength: 2
maxLength: 3000
responses:
'204':
'404':
delete:
tags:
- Abuses
summary: Delete an abuse
security:
- OAuth2:
- admin
- moderator
parameters:
- $ref: '#/components/parameters/abuseId'
responses:
'204':
'404':
'/api/v1/abuses/{abuseId}/messages':
get:
summary: List messages of an abuse
security:
- OAuth2: []
tags:
- Abuses
parameters:
- $ref: '#/components/parameters/abuseId'
responses:
'200':
content:
application/json:
schema:
type: object
properties:
total:
type: integer
example: 1
data:
type: array
items:
$ref: '#/components/schemas/AbuseMessage'
post:
summary: Add message to an abuse
security:
- OAuth2: []
tags:
- Abuses
parameters:
- $ref: '#/components/parameters/abuseId'
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
message:
type: string
minLength: 2
maxLength: 3000
required:
- message
responses:
'200':
'400':
'/api/v1/abuses/{abuseId}/messages/{abuseMessageId}':
delete:
summary: Delete an abuse message
security:
- OAuth2: []
tags:
- Abuses
parameters:
- $ref: '#/components/parameters/abuseId'
- $ref: '#/components/parameters/abuseMessageId'
responses:
'204':
'/api/v1/videos/{id}/blacklist':
post:
summary: Block a video
operationId: addVideoBlock
security:
- OAuth2:
- admin
- moderator
tags:
- Video Blocks
parameters:
- $ref: '#/components/parameters/idOrUUID'
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/VideoBlacklistCreate'
responses:
'204':
put:
summary: Update a video block
operationId: updateVideoBlock
security:
- OAuth2:
- admin
- moderator
tags:
- Video Blocks
parameters:
- $ref: '#/components/parameters/idOrUUID'
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/VideoBlacklistUpdate'
responses:
'204':
'404':
delete:
summary: Unblock a video by its id
operationId: delVideoBlock
security:
- OAuth2:
- admin
- moderator
tags:
- Video Blocks
parameters:
- $ref: '#/components/parameters/idOrUUID'
responses:
'204':
'404':
/api/v1/videos/blacklist:
get:
tags:
- Video Blocks
summary: List video blocks
operationId: getVideoBlocks
security:
- OAuth2:
- admin
- moderator
parameters:
- name: type
in: query
list only blocks that match this type:

text
- `1`: manual block

        - `2`: automatic block that needs review
      schema:
        type: integer
        enum:
          - 1
          - 2
    - name: search
      in: query
      schema:
        type: string
    - $ref: '#/components/parameters/start'
    - $ref: '#/components/parameters/count'
    - $ref: '#/components/parameters/blacklistsSort'
  responses:
    '200':
      content:
        application/json:
          schema:
            type: object
            properties:
              total:
                type: integer
                example: 1
              data:
                type: array
                items:
                  $ref: '#/components/schemas/VideoBlacklist'

/api/v1/videos/{id}/storyboards:
get:
summary: List storyboards of a video
operationId: listVideoStoryboards
tags:
- Video
parameters:
- $ref: '#/components/parameters/idOrUUID'
responses:
'200':
content:
application/json:
schema:
type: object
properties:
storyboards:
type: array
items:
$ref: '#/components/schemas/Storyboard'

/api/v1/videos/{id}/captions:
get:
summary: List captions of a video
operationId: getVideoCaptions
tags:
- Video Captions
parameters:
- $ref: '#/components/parameters/idOrUUID'
- $ref: '#/components/parameters/videoPasswordHeader'
responses:
'200':
content:
application/json:
schema:
type: object
properties:
total:
type: integer
example: 1
data:
type: array
items:
$ref: '#/components/schemas/VideoCaption'

/api/v1/videos/{id}/captions/generate:
post:
summary: Generate a video caption
operationId: generateVideoCaption
security:
- OAuth2:
- user
tags:
- Video Captions
parameters:
- $ref: '#/components/parameters/idOrUUID'
requestBody:
content:
application/json:
schema:
type: object
properties:
forceTranscription:
type: boolean
default: false
responses:
'204':
'404':
/api/v1/videos/{id}/captions/{captionLanguage}:
put:
summary: Add or replace a video caption
operationId: addVideoCaption
security:
- OAuth2:
- user
tags:
- Video Captions
parameters:
- $ref: '#/components/parameters/idOrUUID'
- $ref: '#/components/parameters/captionLanguage'
requestBody:
content:
multipart/form-data:
schema:
type: object
properties:
captionfile:
type: string
format: binary
encoding:
captionfile:
contentType: text/vtt, application/x-subrip, text/plain
responses:
'204':
'404':
delete:
summary: Delete a video caption
operationId: delVideoCaption
security:
- OAuth2:
- user
tags:
- Video Captions
parameters:
- $ref: '#/components/parameters/idOrUUID'
- $ref: '#/components/parameters/captionLanguage'
responses:
'204':
'404':
/api/v1/videos/{id}/chapters:
get:
summary: Get chapters of a video
operationId: getVideoChapters
tags:
- Video Chapters
parameters:
- $ref: '#/components/parameters/idOrUUID'
- $ref: '#/components/parameters/videoPasswordHeader'
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/VideoChapters'
put:
summary: Replace video chapters
operationId: replaceVideoChapters
security:
- OAuth2:
- user
tags:
- Video Chapters
parameters:
- $ref: '#/components/parameters/idOrUUID'
requestBody:
content:
application/json:
schema:
type: object
properties:
chapters:
type: array
items:
type: object
properties:
title:
type: string
timecode:
type: integer
responses:
'204':
'404':
/api/v1/videos/{id}/embed-privacy:
get:
summary: Get video embed privacy
operationId: getVideoEmbedPrivacy
security:
- OAuth2:
- user
tags:
- Video Embed Privacy
parameters:
- $ref: '#/components/parameters/idOrUUID'
responses:
'200':
content:
application/json:
schema:
type: object
properties:
policy:
type: object
properties:
id:
$ref: '#/components/schemas/VideoEmbedPrivacy'
label:
type: string
example: Allowlist
domains:
type: array
items:
type: string
example: 'example.com'
'400':
put:
summary: Update video embed privacy
operationId: updateVideoEmbedPrivacy
security:
- OAuth2:
- user
tags:
- Video Embed Privacy
parameters:
- $ref: '#/components/parameters/idOrUUID'
requestBody:
content:
application/json:
schema:
type: object
properties:
policy:
$ref: '#/components/schemas/VideoEmbedPrivacy'
domains:
type: array
items:
type: string
example: 'example.com'
responses:
'204':
'400':
/api/v1/videos/{id}/embed-privacy/allowed:
get:
summary: Check if embed is allowed
operationId: isVideoEmbedOnDomainAllowed
security:
- OAuth2:
- user
tags:
- Video Embed Privacy
parameters:
- $ref: '#/components/parameters/idOrUUID'
- name: domain
in: query
required: true
schema:
type: string
responses:
'200':
content:
application/json:
schema:
type: object
properties:
domainAllowed:
type: boolean
userBypassAllowed:
nullable: true
type: boolean
'400':
/api/v1/videos/{id}/passwords:
get:
summary: List video passwords
operationId: listVideoPasswords
security:
- OAuth2:
- user
tags:
- Video Passwords
parameters:
- $ref: '#/components/parameters/idOrUUID'
- $ref: '#/components/parameters/start'
- $ref: '#/components/parameters/count'
- $ref: '#/components/parameters/sort'
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/VideoPasswordList'
'400':
put:
summary: Update video passwords
operationId: updateVideoPasswordList
security:
- OAuth2:
- user
tags:
- Video Passwords
parameters:
- $ref: '#/components/parameters/idOrUUID'
requestBody:
content:
application/json:
schema:
type: object
properties:
passwords:
$ref: '#/components/schemas/AddVideoPasswords'
responses:
'204':
'400':
post:
summary: Add a video password
operationId: addVideoPassword
security:
- OAuth2:
- user
tags:
- Video Passwords
parameters:
- $ref: '#/components/parameters/idOrUUID'
requestBody:
content:
application/json:
schema:
type: object
properties:
password:
type: string
responses:
'204':
'400':
/api/v1/videos/{id}/passwords/{passwordId}:
delete:
summary: Delete a video password
operationId: removeVideoPassword
security:
- OAuth2:
- user
tags:
- Video Passwords
parameters:
- $ref: '#/components/parameters/idOrUUID'
- $ref: '#/components/parameters/passwordId'
responses:
'204':
'403':
'400':
/api/v1/video-channels:
get:
summary: List video channels
operationId: getVideoChannels
tags:
- Video Channels
parameters:
- $ref: '#/components/parameters/start'
- $ref: '#/components/parameters/count'
- $ref: '#/components/parameters/sort'
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/VideoChannelList'
post:
summary: Create a video channel
operationId: addVideoChannel
security:
- OAuth2: []
tags:
- Video Channels
responses:
'200':
content:
application/json:
schema:
type: object
properties:
videoChannel:
type: object
properties:
id:
$ref: '#/components/schemas/id'
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/VideoChannelCreate'

'/api/v1/video-channels/{channelHandle}':
get:
summary: Get a video channel
operationId: getVideoChannel
tags:
- Video Channels
parameters:
- $ref: '#/components/parameters/channelHandle'
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/VideoChannel'
put:
summary: Update a video channel
operationId: putVideoChannel
security:
- OAuth2: []
tags:
- Video Channels
parameters:
- $ref: '#/components/parameters/channelHandle'
responses:
'204':
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/VideoChannelUpdate'
delete:
summary: Delete a video channel
operationId: delVideoChannel
security:
- OAuth2: []
tags:
- Video Channels
parameters:
- $ref: '#/components/parameters/channelHandle'
responses:
'204':
'/api/v1/video-channels/{channelHandle}/videos':
get:
summary: List videos of a video channel
operationId: getVideoChannelVideos
tags:
- Video
- Video Channels
parameters:
- $ref: '#/components/parameters/channelHandle'
# Common video filter parameters
- $ref: '#/components/parameters/start'
- $ref: '#/components/parameters/count'
- $ref: '#/components/parameters/skipCount'
- $ref: '#/components/parameters/videosSort'
- $ref: '#/components/parameters/nsfw'
- $ref: '#/components/parameters/nsfwFlagsIncluded'
- $ref: '#/components/parameters/nsfwFlagsExcluded'
- $ref: '#/components/parameters/aiUsageOneOf'
- $ref: '#/components/parameters/isLive'
- $ref: '#/components/parameters/includeScheduledLive'
- $ref: '#/components/parameters/categoryOneOf'
- $ref: '#/components/parameters/licenceOneOf'
- $ref: '#/components/parameters/languageOneOf'
- $ref: '#/components/parameters/tagsOneOf'
- $ref: '#/components/parameters/tagsAllOf'
- $ref: '#/components/parameters/isLocal'
- $ref: '#/components/parameters/include'
- $ref: '#/components/parameters/hasHLSFiles'
- $ref: '#/components/parameters/hasWebVideoFiles'
- $ref: '#/components/parameters/host'
- $ref: '#/components/parameters/autoTagOneOfVideo'
- $ref: '#/components/parameters/stateOneOfVideo'
- $ref: '#/components/parameters/privacyOneOf'
- $ref: '#/components/parameters/excludeAlreadyWatched'
- $ref: '#/components/parameters/search'
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/VideoListResponse'

'/api/v1/video-channels/{channelHandle}/activities':
get:
summary: List activities of a video channel
operationId: listVideoChannelActivities
tags:
- Video Channels
parameters:
- $ref: '#/components/parameters/channelHandle'
- $ref: '#/components/parameters/start'
- $ref: '#/components/parameters/count'
- $ref: '#/components/parameters/sort'
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/ChannelActivityListResponse'

'/api/v1/video-channels/{channelHandle}/video-playlists':
get:
summary: List playlists of a channel
tags:
- Video Playlists
- Video Channels
parameters:
- $ref: '#/components/parameters/channelHandle'
- $ref: '#/components/parameters/start'
- $ref: '#/components/parameters/count'
- $ref: '#/components/parameters/sort'
- $ref: '#/components/parameters/videoPlaylistType'
responses:
'200':
content:
application/json:
schema:
type: object
properties:
total:
type: integer
example: 1
data:
type: array
items:
$ref: '#/components/schemas/VideoPlaylist'

'/api/v1/video-channels/{channelHandle}/video-playlists/reorder':
post:
summary: Reorder channel playlists
operationId: reorderVideoPlaylistsOfChannel
security:
- OAuth2: []
tags:
- Video Playlists
- Video Channels
parameters:
- $ref: '#/components/parameters/channelHandle'
responses:
'204':
requestBody:
content:
application/json:
schema:
type: object
properties:
startPosition:
type: integer
minimum: 1
insertAfterPosition:
type: integer
minimum: 0
reorderLength:
type: integer
minimum: 1
required:
- startPosition
- insertAfterPosition

'/api/v1/video-channels/{channelHandle}/followers':
get:
tags:
- Video Channels
summary: 'List followers of a video channel'
security:
- OAuth2: []
operationId: getVideoChannelFollowers
parameters:
- $ref: '#/components/parameters/channelHandle'
- $ref: '#/components/parameters/start'
- $ref: '#/components/parameters/count'
- $ref: '#/components/parameters/followersSort'
- $ref: '#/components/parameters/search'
responses:
'200':
content:
application/json:
schema:
type: object
properties:
total:
type: integer
example: 1
data:
type: array
items:
$ref: '#/components/schemas/Follow'

'/api/v1/video-channels/{channelHandle}/avatar/pick':
post:
summary: Update channel avatar
security:
- OAuth2: []
tags:
- Video Channels
parameters:
- $ref: '#/components/parameters/channelHandle'
responses:
'200':
content:
application/json:
schema:
type: object
properties:
avatars:
type: array
items:
$ref: '#/components/schemas/ActorImage'
'413':
headers:
X-File-Maximum-Size:
schema:
type: string
format: Nginx size
requestBody:
content:
multipart/form-data:
schema:
type: object
properties:
avatarfile:
type: string
format: binary
encoding:
avatarfile:
contentType: image/png, image/jpeg

'/api/v1/video-channels/{channelHandle}/avatar':
delete:
summary: Delete channel avatar
security:
- OAuth2: []
tags:
- Video Channels
parameters:
- $ref: '#/components/parameters/channelHandle'
responses:
'204':
'/api/v1/video-channels/{channelHandle}/banner/pick':
post:
summary: Update channel banner
security:
- OAuth2: []
tags:
- Video Channels
parameters:
- $ref: '#/components/parameters/channelHandle'
responses:
'200':
content:
application/json:
schema:
type: object
properties:
banners:
type: array
items:
$ref: '#/components/schemas/ActorImage'
'413':
headers:
X-File-Maximum-Size:
schema:
type: string
format: Nginx size
requestBody:
content:
multipart/form-data:
schema:
type: object
properties:
bannerfile:
type: string
format: binary
encoding:
bannerfile:
contentType: image/png, image/jpeg

'/api/v1/video-channels/{channelHandle}/banner':
delete:
summary: Delete channel banner
security:
- OAuth2: []
tags:
- Video Channels
parameters:
- $ref: '#/components/parameters/channelHandle'
responses:
'204':
'/api/v1/video-channels/{channelHandle}/import-videos':
post:
summary: Import videos in channel
security:
- OAuth2: []
tags:
- Video Channels
- Channels Sync
parameters:
- $ref: '#/components/parameters/channelHandle'
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/ImportVideosInChannelCreate'
responses:
'204':
'/api/v1/video-channel-syncs':
post:
summary: Create a synchronization for a video channel
operationId: addVideoChannelSync
security:
- OAuth2: []
tags:
- Channels Sync
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/VideoChannelSyncCreate'
responses:
'200':
content:
application/json:
schema:
type: object
properties:
videoChannelSync:
$ref: "#/components/schemas/VideoChannelSync"

'/api/v1/video-channel-syncs/{channelSyncId}':
delete:
summary: Delete a video channel synchronization
operationId: delVideoChannelSync
security:
- OAuth2: []
tags:
- Channels Sync
parameters:
- $ref: '#/components/parameters/channelSyncId'
responses:
'204':
'/api/v1/video-channel-syncs/{channelSyncId}/sync':
post:
summary: Triggers the channel synchronization job, fetching all the videos from the remote channel
operationId: triggerVideoChannelSync
security:
- OAuth2: []
tags:
- Channels Sync
parameters:
- $ref: '#/components/parameters/channelSyncId'
responses:
'204':
'/api/v1/player-settings/videos/{id}':
get:
summary: Get video player settings
operationId: getVideoPlayerSettings
tags:
- Player Settings
parameters:
- $ref: '#/components/parameters/idOrUUID'
- name: raw
in: query
required: false
schema:
type: boolean
default: false
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/PlayerVideoSettings'
'404':
put:
summary: Update video player settings
operationId: updateVideoPlayerSettings
security:
- OAuth2: []
tags:
- Player Settings
parameters:
- $ref: '#/components/parameters/idOrUUID'
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/PlayerVideoSettingsUpdate'
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/PlayerVideoSettings'
'404':
'/api/v1/player-settings/video-channels/{channelHandle}':
get:
summary: Get channel player settings
operationId: getChannelPlayerSettings
tags:
- Player Settings
parameters:
- $ref: '#/components/parameters/channelHandle'
- name: raw
in: query
required: false
schema:
type: boolean
default: false
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/PlayerChannelSettings'
'404':
put:
summary: Update channel player settings
operationId: updateChannelPlayerSettings
security:
- OAuth2: []
tags:
- Player Settings
parameters:
- $ref: '#/components/parameters/channelHandle'
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/PlayerChannelSettingsUpdate'
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/PlayerChannelSettings'
'404':
/api/v1/video-playlists/privacies:
get:
summary: List available playlist privacy policies
operationId: getPlaylistPrivacyPolicies
tags:
- Video Playlists
responses:
'200':
content:
application/json:
schema:
type: array
items:
type: string
examples:
nightly:
externalValue: https://peertube2.cpy.re/api/v1/video-playlists/privacies

/api/v1/video-playlists:
get:
summary: List video playlists
operationId: getPlaylists
tags:
- Video Playlists
parameters:
- $ref: '#/components/parameters/start'
- $ref: '#/components/parameters/count'
- $ref: '#/components/parameters/sort'
- $ref: '#/components/parameters/videoPlaylistType'
responses:
'200':
content:
application/json:
schema:
type: object
properties:
total:
type: integer
example: 1
data:
type: array
items:
$ref: '#/components/schemas/VideoPlaylist'
post:
summary: Create a video playlist
operationId: addPlaylist
security:
- OAuth2: []
tags:
- Video Playlists
responses:
'200':
content:
application/json:
schema:
type: object
properties:
videoPlaylist:
type: object
properties:
id:
$ref: '#/components/schemas/VideoPlaylist/properties/id'
uuid:
$ref: '#/components/schemas/VideoPlaylist/properties/uuid'
shortUUID:
$ref: '#/components/schemas/VideoPlaylist/properties/shortUUID'
requestBody:
content:
multipart/form-data:
schema:
type: object
properties:
displayName:
type: string
minLength: 1
maxLength: 120
thumbnailfile:
type: string
format: binary
privacy:
$ref: '#/components/schemas/VideoPlaylistPrivacySet'
type: string
minLength: 3
maxLength: 1000
videoChannelId:
allOf:
- $ref: '#/components/schemas/id'
required:
- displayName
encoding:
thumbnailfile:
contentType: image/jpeg

/api/v1/video-playlists/{playlistId}:
get:
summary: Get a video playlist
tags:
- Video Playlists
parameters:
- $ref: '#/components/parameters/playlistId'
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/VideoPlaylist'
put:
summary: Update a video playlist
security:
- OAuth2: []
tags:
- Video Playlists
responses:
'204':
parameters:
- $ref: '#/components/parameters/playlistId'
requestBody:
content:
multipart/form-data:
schema:
type: object
properties:
displayName:
type: string
minLength: 1
maxLength: 120
thumbnailfile:
type: string
format: binary
privacy:
$ref: '#/components/schemas/VideoPlaylistPrivacySet'
type: string
videoChannelId:
allOf:
- $ref: '#/components/schemas/id'
encoding:
thumbnailfile:
contentType: image/jpeg
delete:
summary: Delete a video playlist
security:
- OAuth2: []
tags:
- Video Playlists
parameters:
- $ref: '#/components/parameters/playlistId'
responses:
'204':
/api/v1/video-playlists/{playlistId}/videos:
get:
summary: 'List videos of a playlist'
operationId: getVideoPlaylistVideos
tags:
- Videos
- Video Playlists
parameters:
- $ref: '#/components/parameters/playlistId'
- $ref: '#/components/parameters/start'
- $ref: '#/components/parameters/count'
responses:
'200':
content:
application/json:
schema:
properties:
total:
type: integer
example: 1
data:
type: array
maxItems: 100
items:

text
type: object
                  properties:
                    id:
                      allOf:
                        - $ref: '#/components/schemas/id'
                    position:
                      type: integer
                      example: 2
                    startTimestamp:
                      type: integer
                      nullable: true
                      example: 10
                      format: seconds
                    stopTimestamp:
                      type: integer
                      nullable: true
                      example: 41
                      format: seconds
                    video:
                      $ref: '#/components/schemas/Video'
post:
  summary: Add a video in a playlist
  operationId: addVideoPlaylistVideo
  security:
    - OAuth2: []
  tags:
    - Videos
    - Video Playlists
  parameters:
    - $ref: '#/components/parameters/playlistId'
  responses:
    '200':
      content:
        application/json:
          schema:
            type: object
            properties:
              videoPlaylistElement:
                type: object
                properties:
                  id:
                    type: integer
                    example: 2
  requestBody:
    content:
      application/json:
        schema:
          type: object
          properties:
            videoId:
              oneOf:
                - $ref: '#/components/schemas/Video/properties/uuid'
                - $ref: '#/components/schemas/Video/properties/id'
            startTimestamp:
              type: integer
              format: seconds
            stopTimestamp:
              type: integer
              format: seconds
          required:
            - videoId

/api/v1/video-playlists/{playlistId}/videos/reorder:
post:
summary: Reorder playlist elements
operationId: reorderVideoPlaylist
security:
- OAuth2: []
tags:
- Video Playlists
parameters:
- $ref: '#/components/parameters/playlistId'
responses:
'204':
requestBody:
content:
application/json:
schema:
type: object
properties:
startPosition:
type: integer
minimum: 1
insertAfterPosition:
type: integer
minimum: 0
reorderLength:
type: integer
minimum: 1
required:
- startPosition
- insertAfterPosition

/api/v1/video-playlists/{playlistId}/videos/{playlistElementId}:
put:
summary: Update a playlist element
operationId: putVideoPlaylistVideo
security:
- OAuth2: []
tags:
- Video Playlists
parameters:
- $ref: '#/components/parameters/playlistId'
- $ref: '#/components/parameters/playlistElementId'
responses:
'204':
requestBody:
content:
application/json:
schema:
type: object
properties:
startTimestamp:
type: integer
format: seconds
stopTimestamp:
type: integer
format: seconds
delete:
summary: Delete an element from a playlist
operationId: delVideoPlaylistVideo
security:
- OAuth2: []
tags:
- Video Playlists
parameters:
- $ref: '#/components/parameters/playlistId'
- $ref: '#/components/parameters/playlistElementId'
responses:
'204':
'/api/v1/users/me/video-playlists/videos-exist':
get:
summary: Check video exists in my playlists
security:
- OAuth2: []
tags:
- Video Playlists
parameters:
- name: videoIds
in: query
required: true
schema:
type: array
items:
$ref: '#/components/schemas/Video/properties/id'
responses:
'200':
content:
application/json:
schema:
type: object
properties:
videoId:
type: array
items:
type: object
properties:
playlistElementId:
type: integer
playlistId:
type: integer
startTimestamp:
type: integer
format: seconds
nullable: true
stopTimestamp:
type: integer
format: seconds
nullable: true

'/api/v1/accounts/{name}/video-playlists':
get:
summary: List playlists of an account
tags:
- Video Playlists
- Accounts
parameters:
- $ref: '#/components/parameters/name'
- $ref: '#/components/parameters/start'
- $ref: '#/components/parameters/count'
- $ref: '#/components/parameters/sort'
- $ref: '#/components/parameters/search'
- $ref: '#/components/parameters/videoPlaylistType'
- $ref: '#/components/parameters/includeCollaborations'
- name: channelNameOneOf
in: query
required: false
schema:
oneOf:
- type: string
- type: array
items:
type: string
style: form
explode: true
responses:
'200':
content:
application/json:
schema:
type: object
properties:
total:
type: integer
example: 1
data:
type: array
items:
$ref: '#/components/schemas/VideoPlaylist'

'/api/v1/accounts/{name}/video-channels':
get:
summary: List video channels of an account
tags:
- Video Channels
- Accounts
parameters:
- $ref: '#/components/parameters/name'
- name: withStats
in: query
schema:
type: boolean
- name: statsDays
in: query
number of days of view statistics to include in viewsPerDay when withStats is true
(only if authenticated as the account user).
0 means all time (since the channel's earliest recorded stat).
viewsPerDay always spans the whole requested range so channels can be compared to each other.
Its bucket size is reported in viewsGroupInterval: it is derived from the requested range,
narrowed to the channel history so that a young channel on a long range is not aggregated
into a single coarse bucket.
totalViews is unaffected by this parameter and always reports lifetime views.
schema:
type: integer
enum: [30, 90, 365, 0]
default: 30
- $ref: '#/components/parameters/start'
- $ref: '#/components/parameters/count'
- $ref: '#/components/parameters/search'
- $ref: '#/components/parameters/sort'
- $ref: '#/components/parameters/includeCollaborations'
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/VideoChannelList'

'/api/v1/accounts/{name}/video-channel-syncs':
get:
summary: List the synchronizations of video channels of an account
tags:
- Video Channels
- Channels Sync
- Accounts
parameters:
- $ref: '#/components/parameters/name'
- $ref: '#/components/parameters/start'
- $ref: '#/components/parameters/count'
- $ref: '#/components/parameters/sort'
- $ref: '#/components/parameters/includeCollaborations'
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/VideoChannelSyncList'

'/api/v1/accounts/{name}/ratings':
get:
summary: List ratings of an account
security:
- OAuth2: []
tags:
- Accounts
parameters:
- $ref: '#/components/parameters/name'
- $ref: '#/components/parameters/start'
- $ref: '#/components/parameters/count'
- $ref: '#/components/parameters/sort'
- name: rating
in: query
required: false
schema:
type: string
enum:
- like
- dislike
responses:
'200':
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/VideoRating'

'/api/v1/videos/{id}/comment-threads':
get:
summary: List threads of a video
tags:
- Video Comments
parameters:
- $ref: '#/components/parameters/idOrUUID'
- $ref: '#/components/parameters/start'
- $ref: '#/components/parameters/count'
- $ref: '#/components/parameters/commentsSort'
- $ref: '#/components/parameters/videoPasswordHeader'
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/CommentThreadResponse'
post:
summary: Create a thread
security:
- OAuth2: []
tags:
- Video Comments
parameters:
- $ref: '#/components/parameters/idOrUUID'
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/CommentThreadPostResponse'
'404':
requestBody:
content:
application/json:
schema:
type: object
properties:
text:
allOf:
- $ref: '#/components/schemas/VideoComment/properties/text'
format: markdown
maxLength: 10000
required:
- text

'/api/v1/videos/{id}/comment-threads/{threadId}':
get:
summary: Get a thread
Since PeerTube 8.3 the returned tree is truncated: only the first replies of each comment are included, and only
down to maxDepth nesting levels. Use GET /api/v1/videos/{id}/comments/{commentId}/replies to fetch the
replies that are missing, comparing children and totalChildren of each node of the tree.
tags:
- Video Comments
parameters:
- $ref: '#/components/parameters/idOrUUID'
- $ref: '#/components/parameters/threadId'
- $ref: '#/components/parameters/commentMaxDepth'
- $ref: '#/components/parameters/commentRepliesPerLevel'
- $ref: '#/components/parameters/videoPasswordHeader'
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/VideoCommentThreadTree'

'/api/v1/videos/{id}/comments/{commentId}/replies':
get:
summary: List replies of a comment
PeerTube >= 8.3 List the direct replies of a comment, each of them nested up to maxDepth levels. Used to unfold the parts of a
thread that GET /api/v1/videos/{id}/comment-threads/{threadId} truncated.
tags:
- Video Comments
parameters:
- $ref: '#/components/parameters/idOrUUID'
- $ref: '#/components/parameters/commentId'
- $ref: '#/components/parameters/start'
- $ref: '#/components/parameters/count'
- $ref: '#/components/parameters/commentRepliesSort'
- $ref: '#/components/parameters/commentMaxDepth'
- $ref: '#/components/parameters/commentRepliesPerLevel'
- $ref: '#/components/parameters/videoPasswordHeader'
responses:
'200':
content:
application/json:
schema:
type: object
properties:
total:
type: integer
example: 13
data:
type: array
items:
$ref: '#/components/schemas/VideoCommentThreadTree'

'/api/v1/videos/comments':
get:
summary: List instance comments
security:
- OAuth2:
- admin
- moderator
tags:
- Video Comments
parameters:
- $ref: '#/components/parameters/search'
- $ref: '#/components/parameters/searchAccountForComments'
- $ref: '#/components/parameters/searchVideoForComments'
- $ref: '#/components/parameters/videoId'
- $ref: '#/components/parameters/videoChannelId'
- $ref: '#/components/parameters/autoTagOneOfComment'
- $ref: '#/components/parameters/isLocal'
- $ref: '#/components/parameters/onLocalVideo'
- $ref: '#/components/parameters/includeMuted'

text
responses:
    '200':
      content:
        application/json:
          schema:
            type: object
            properties:
              total:
                type: integer
                example: 1
              data:
                type: array
                items:
                  $ref: '#/components/schemas/VideoCommentForOwnerOrAdmin'

'/api/v1/videos/{id}/comments/{commentId}':
post:
summary: Reply to a thread of a video
security:
- OAuth2: []
tags:
- Video Comments
parameters:
- $ref: '#/components/parameters/idOrUUID'
- $ref: '#/components/parameters/commentId'
- $ref: '#/components/parameters/videoPasswordHeader'
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/CommentThreadPostResponse'
'404':
requestBody:
content:
application/json:
schema:
type: object
properties:
text:
allOf:
- $ref: '#/components/schemas/VideoComment/properties/text'
format: markdown
maxLength: 10000
required:
- text
delete:
summary: Delete a comment or a reply
security:
- OAuth2: []
tags:
- Video Comments
parameters:
- $ref: '#/components/parameters/idOrUUID'
- $ref: '#/components/parameters/commentId'
responses:
'204':
'403':
'404':
'409':
'/api/v1/videos/{id}/comments/{commentId}/approve':
post:
summary: Approve a comment
security:
- OAuth2: []
tags:
- Video Comments
parameters:
- $ref: '#/components/parameters/idOrUUID'
- $ref: '#/components/parameters/commentId'
responses:
'204':
'/api/v1/videos/{id}/rate':
put:
summary: Like/dislike a video
security:
- OAuth2: []
tags:
- Video Rates
parameters:
- $ref: '#/components/parameters/idOrUUID'
- $ref: '#/components/parameters/videoPasswordHeader'
requestBody:
content:
application/json:
schema:
type: object
properties:
rating:
type: string
enum:
- like
- dislike
required:
- rating
responses:
'204':
'404':
'/api/v1/videos/{id}/hls':
delete:
summary: Delete video HLS files
security:
- OAuth2:
- admin
tags:
- Video Files
operationId: delVideoHLS
parameters:
- $ref: '#/components/parameters/idOrUUID'
responses:
'204':
'404':
'/api/v1/videos/{id}/web-videos':
delete:
summary: Delete video Web Video files
security:
- OAuth2:
- admin
tags:
- Video Files
operationId: delVideoWebVideos
parameters:
- $ref: '#/components/parameters/idOrUUID'
responses:
'204':
'404':
'/api/v1/videos/{id}/transcoding':
post:
summary: Create a transcoding job
security:
- OAuth2:
- admin
tags:
- Video Transcoding
operationId: createVideoTranscoding
parameters:
- $ref: '#/components/parameters/idOrUUID'
requestBody:
content:
application/json:
schema:
type: object
properties:
transcodingType:
type: string
enum:
- hls
- web-video
forceTranscoding:
type: boolean
default: false
required:
- transcodingType
responses:
'204':
'404':
/api/v1/search/videos:
get:
tags:
- Search
- Video
summary: Search videos
operationId: searchVideos
parameters:
- name: search
in: query
required: true
allowEmptyValue: false
String to search. If the user can make a remote URI search, and the string is an URI then the
PeerTube instance will fetch the remote object and add it to its database. Then,
you can use the REST API to fetch the complete video information and interact with it.
schema:
type: string
- $ref: '#/components/parameters/uuids'
- $ref: '#/components/parameters/searchTarget'
# Common video filter parameters
- $ref: '#/components/parameters/start'
- $ref: '#/components/parameters/count'
- $ref: '#/components/parameters/skipCount'
- $ref: '#/components/parameters/videosSort'
- $ref: '#/components/parameters/nsfw'
- $ref: '#/components/parameters/nsfwFlagsIncluded'
- $ref: '#/components/parameters/nsfwFlagsExcluded'
- $ref: '#/components/parameters/aiUsageOneOf'
- $ref: '#/components/parameters/isLive'
- $ref: '#/components/parameters/includeScheduledLive'
- $ref: '#/components/parameters/categoryOneOf'
- $ref: '#/components/parameters/licenceOneOf'
- $ref: '#/components/parameters/languageOneOf'
- $ref: '#/components/parameters/tagsOneOf'
- $ref: '#/components/parameters/tagsAllOf'
- $ref: '#/components/parameters/isLocal'
- $ref: '#/components/parameters/include'
- $ref: '#/components/parameters/hasHLSFiles'
- $ref: '#/components/parameters/hasWebVideoFiles'
- $ref: '#/components/parameters/host'
- $ref: '#/components/parameters/autoTagOneOfVideo'
- $ref: '#/components/parameters/stateOneOfVideo'
- $ref: '#/components/parameters/privacyOneOf'
- $ref: '#/components/parameters/excludeAlreadyWatched'
- name: startDate
in: query
schema:
type: string
format: date-time
- name: endDate
in: query
schema:
type: string
format: date-time
- name: originallyPublishedStartDate
in: query
schema:
type: string
format: date-time
- name: originallyPublishedEndDate
in: query
schema:
type: string
format: date-time
- name: durationMin
in: query
schema:
type: integer
- name: durationMax
in: query
schema:
type: integer
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/VideoListResponse'
'500':
/api/v1/search/video-channels:
get:
tags:
- Search
- Video Channels
summary: Search channels
operationId: searchChannels
parameters:
- name: search
in: query
required: true
String to search. If the user can make a remote URI search, and the string is an URI then the
PeerTube instance will fetch the remote object and add it to its database. Then,
you can use the REST API to fetch the complete channel information and interact with it.
schema:
type: string
- $ref: '#/components/parameters/start'
- $ref: '#/components/parameters/count'
- $ref: '#/components/parameters/searchTarget'
- $ref: '#/components/parameters/sort'
- $ref: '#/components/parameters/host'
- $ref: '#/components/parameters/handles'
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/VideoChannelList'
'500':
/api/v1/search/video-playlists:
get:
tags:
- Search
- Video Playlists
summary: Search playlists
operationId: searchPlaylists
parameters:
- name: search
in: query
required: true
String to search. If the user can make a remote URI search, and the string is an URI then the
PeerTube instance will fetch the remote object and add it to its database. Then,
you can use the REST API to fetch the complete playlist information and interact with it.
schema:
type: string
- $ref: '#/components/parameters/start'
- $ref: '#/components/parameters/count'
- $ref: '#/components/parameters/searchTarget'
- $ref: '#/components/parameters/sort'
- $ref: '#/components/parameters/host'
- $ref: '#/components/parameters/uuids'
responses:
'200':
content:
application/json:
schema:
type: object
properties:
total:
type: integer
example: 1
data:
type: array
items:
$ref: '#/components/schemas/VideoPlaylist'
'500':
/api/v1/blocklist/status:
get:
tags:
- Account Blocklist
- Server Blocklist
summary: Get block status of accounts/hosts
parameters:
-
name: 'accounts'
in: query
example: [ '[email protected]', '[email protected]' ]
schema:
type: array
items:
type: string
-
name: 'hosts'
in: query
example: [ 'example.com' ]
schema:
type: array
items:
type: string
responses:
'200':
content:
'application/json':
schema:
$ref: '#/components/schemas/BlockStatus'

/api/v1/users/me/blocklist/accounts:
get:
summary: List accounts blocked by my account
operationId: getMyBlockedAccounts
security:
- OAuth2:
- user
tags:
- Account Blocklist
parameters:
- $ref: '#/components/parameters/start'
- $ref: '#/components/parameters/count'
- $ref: '#/components/parameters/sort'
- name: search
in: query
required: false
schema:
type: string
responses:
'200':
content:
application/json:
schema:
type: object
properties:
total:
type: integer
example: 1
data:
type: array
items:
$ref: '#/components/schemas/AccountBlock'
'401':
post:
summary: Block an account by my account
operationId: blockAccount
security:
- OAuth2:
- user
tags:
- Account Blocklist
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
accountName:
type: string
example: '[email protected]'
required:
- accountName
responses:
'204':
'400':
'401':
'404':
/api/v1/users/me/blocklist/accounts/{accountName}:
delete:
summary: Unblock an account by my account
operationId: unblockAccount
security:
- OAuth2:
- user
tags:
- Account Blocklist
parameters:
- name: accountName
in: path
required: true
schema:
type: string
example: '[email protected]'
responses:
'204':
'400':
'401':
'404':
/api/v1/users/me/blocklist/servers:
get:
summary: List servers blocked by my account
operationId: getMyBlockedServers
security:
- OAuth2:
- user
tags:
- Account Blocklist
parameters:
- $ref: '#/components/parameters/start'
- $ref: '#/components/parameters/count'
- $ref: '#/components/parameters/sort'
- name: search
in: query
required: false
schema:
type: string
responses:
'200':
content:
application/json:
schema:
type: object
properties:
total:
type: integer
example: 1
data:
type: array
items:
$ref: '#/components/schemas/ServerBlock'
'401':
post:
summary: Block a server by my account
operationId: blockServer
security:
- OAuth2:
- user
tags:
- Account Blocklist
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
host:
type: string
example: 'example.com'
required:
- host
responses:
'204':
'400':
'401':
'404':
/api/v1/users/me/blocklist/servers/{host}:
delete:
summary: Unblock a server by my account
operationId: unblockServer
security:
- OAuth2:
- user
tags:
- Account Blocklist
parameters:
- name: host
in: path
required: true
schema:
type: string
example: 'example.com'
responses:
'204':
'400':
'401':
'404':
/api/v1/server/blocklist/accounts:
get:
tags:
- Server Blocklist
summary: List blocked accounts by server
security:
- OAuth2:
- admin
parameters:
- $ref: '#/components/parameters/start'
- $ref: '#/components/parameters/count'
- $ref: '#/components/parameters/sort'
-
name: subscriptionName
in: query
required: false
schema:
type: string
responses:
'200':
content:
application/json:
schema:
type: object
properties:
total:
type: integer
example: 1
data:
type: array
items:
$ref: '#/components/schemas/AccountBlock'
post:
tags:
- Server Blocklist
summary: Block an account by server
security:
- OAuth2:
- admin
requestBody:
content:
application/json:
schema:
type: object
properties:
accountName:
type: string
example: [email protected]
required:
- accountName
responses:
'200':
'409':
'/api/v1/server/blocklist/accounts/{accountName}':
delete:
tags:
- Server Blocklist
summary: Unblock an account by server
security:
- OAuth2:
- admin
parameters:
- name: accountName
in: path
required: true
schema:
type: string
responses:
'201':
'404':
/api/v1/server/blocklist/servers:
get:
tags:
- Server Blocklist
summary: List blocked servers by server
security:
- OAuth2:
- admin
parameters:
- $ref: '#/components/parameters/start'
- $ref: '#/components/parameters/count'
- $ref: '#/components/parameters/sort'
-
name: subscriptionName
in: query
required: false
schema:
type: string
responses:
'200':
content:
application/json:
schema:
type: object
properties:
total:
type: integer
example: 1
data:
type: array
items:
$ref: '#/components/schemas/ServerBlock'
post:
tags:
- Server Blocklist
summary: Block a server by server
security:
- OAuth2:
- admin
requestBody:
content:
application/json:
schema:
type: object
properties:
host:
type: string
format: hostname
required:
- host
responses:
'204':
'409':
'/api/v1/server/blocklist/servers/{host}':
delete:
tags:
- Server Blocklist
summary: Unblock a server by server
security:
- OAuth2:
- admin
parameters:
- name: host
in: path
required: true
schema:
type: string
format: hostname
responses:
'204':
'404':
/api/v1/server/blocklist/subscriptions:
get:
tags:
- Server Blocklist
summary: List server blocklist subscriptions
security:
- OAuth2:
- admin
parameters:
- $ref: '#/components/parameters/start'
- $ref: '#/components/parameters/count'
- $ref: '#/components/parameters/sort'
- $ref: '#/components/parameters/search'
responses:
'200':
content:
application/json:
schema:
type: object
properties:
total:
type: integer
example: 1
data:
type: array
items:
$ref: '#/components/schemas/BlocklistSubscription'
post:
tags:
- Server Blocklist
summary: Add a server blocklist subscription
security:
- OAuth2:
- admin
requestBody:
content:
application/json:
schema:
type: object
properties:
url:
type: string
format: url
required:
- url
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/BlocklistSubscription'
'409':
'/api/v1/server/blocklist/subscriptions/{id}':
delete:
tags:
- Server Blocklist
summary: Delete a server blocklist subscription
security:
- OAuth2:
- admin
parameters:
- name: id
in: path
required: true
schema:
type: integer
responses:
'204':
'404':
/api/v1/server/blocklist/public-log:
get:
tags:
- Server Blocklist
summary: List publicly shared server blocklist log entries
parameters:
- name: startDate
in: query
required: true
schema:
type: string
format: date-time
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/AutoMuteList'
'403':
/api/v1/server/redundancy/{host}:
put:
tags:
- Instance Redundancy
summary: Update a server redundancy policy
security:
- OAuth2:
- admin
parameters:
- name: host
in: path
required: true
schema:
type: string
format: hostname
requestBody:
content:
application/json:
schema:
type: object
properties:
redundancyAllowed:
type: boolean
required:
- redundancyAllowed
responses:
'204':
'404':
/api/v1/server/redundancy/videos:
get:
tags:
- Video Mirroring
summary: List videos being mirrored
operationId: getMirroredVideos
security:
- OAuth2:
- admin
parameters:
- name: target
in: query
required: true
schema:
type: string
enum:
- my-videos
- remote-videos
- $ref: '#/components/parameters/start'
- $ref: '#/components/parameters/count'
- $ref: '#/components/parameters/videoRedundanciesSort'
responses:
'200':
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/VideoRedundancy'
post:
tags:
- Video Mirroring
summary: Mirror a video
operationId: putMirroredVideo
security:
- OAuth2:
- admin
requestBody:
content:
application/json:
schema:
type: object
properties:
videoId:
$ref: '#/components/schemas/Video/properties/id'
required:
- videoId
responses:
'204':
'400':
'404':
'409':
/api/v1/server/redundancy/videos/{redundancyId}:
delete:
tags:
- Video Mirroring
summary: Delete a mirror done on a video
operationId: delMirroredVideo
security:
- OAuth2:
- admin
parameters:
- name: redundancyId
in: path
required: true
schema:
type: string
responses:
'204':
'404':
/api/v1/server/stats:
get:
tags:
- Stats
summary: Get instance stats
operationId: getInstanceStats
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/ServerStats'

/api/v1/server/contact:
post:
tags:
- Contact
summary: Contact the instance administrators
operationId: contactAdministrator
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
fromName:
type: string
fromEmail:
type: string
format: email
subject:
type: string
body:
type: string
required:
- fromName
- fromEmail
- body
responses:
'204':
'403':
'409':
/api/v1/server/debug:
get:
tags:
- Debug
summary: Get debug information
operationId: getDebug
security:
- OAuth2:
- admin
responses:
'200':
content:
application/json:
schema:
type: object
properties:
ip:
type: string
activityPubMessagesWaiting:
type: integer
secondariesUp:
type: integer
processes:
type: array
items:
type: object
properties:
id:
type: string
role:
type: string
enum:
- primary
- secondary
hostname:
type: string
pid:
type: integer
version:
type: string
startedAt:
type: string
format: date-time
lastSeenAt:
type: string
format: date-time

/api/v1/server/debug/run-command:
post:
tags:
- Debug
summary: Run a debug command
operationId: runDebugCommand
security:
- OAuth2:
- admin
requestBody:
required: true
content:
application/json:
schema:
oneOf:
- type: object
properties:
command:
type: string
enum:
- remove-dandling-resumable-uploads
- remove-expired-user-exports
- process-video-stats-buffer
- process-video-viewers
- process-update-videos-scheduler
- process-video-channel-sync-latest
- process-remove-old-stats
- process-video-files-lifecycle
required:
- command
- type: object
properties:
command:
type: string
enum:
- test-emails
email:
type: string
format: email
required:
- command
- email
responses:
'204':
'400':
/api/v1/server/logs/client:
post:
tags:
- Logs
summary: Send client log
operationId: sendClientLog
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/SendClientLog'
responses:
'204':
/api/v1/server/logs:
get:
tags:
- Logs
summary: Get instance logs
operationId: getInstanceLogs
security:
- OAuth2:
- admin
responses:
'200':
content:
application/json:
schema:
type: array
items:
type: string

/api/v1/server/audit-logs:
get:
tags:
- Logs
summary: Get instance audit logs
User, administration and moderation actions recorded by all the PeerTube processes of the instance.

text
By default (`format=array`), returns an array of at most the 10,000 most recent entries of the requested date range, oldest first.
    `startDate` is then required and pagination parameters are ignored.

    With `format=list`, returns a paginated list.
  operationId: getInstanceAuditLogs
  security:
    - OAuth2:
      - admin
  parameters:
    - name: format
      in: query
      required: false
      schema:
        type: string
        default: array
        enum:
        - array
        - list
    - $ref: '#/components/parameters/start'
    - $ref: '#/components/parameters/count'
    - name: sort
      in: query
      required: false
      schema:
        type: string
        enum:
        - -createdAt
        - createdAt
    - name: search
      in: query
      required: false
      schema:
        type: string
    - name: entityType
      in: query
      required: false
      schema:
        $ref: '#/components/schemas/AuditLogEntityType'
    - name: entityId
      in: query
      required: false
      schema:
        type: integer
    - name: action
      in: query
      required: false
      schema:
        $ref: '#/components/schemas/AuditLogAction'
    - name: startDate
      in: query
      required: false
      schema:
        type: string
        format: date-time
    - name: endDate
      in: query
      required: false
      schema:
        type: string
        format: date-time
  responses:
    '200':
      content:
        application/json:
          schema:
            oneOf:
              - type: array
                items:
                  $ref: '#/components/schemas/AuditLog'
              - type: object
                properties:
                  total:
                    type: integer
                    example: 1
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/AuditLog'
    '403':

/api/v1/plugins:
get:
tags:
- Plugins
summary: List plugins
operationId: getPlugins
security:
- OAuth2:
- admin
parameters:
- name: pluginType
in: query
schema:
type: integer
- name: uninstalled
in: query
schema:
type: boolean
- $ref: '#/components/parameters/start'
- $ref: '#/components/parameters/count'
- $ref: '#/components/parameters/sort'
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/PluginResponse'

/api/v1/plugins/available:
get:
tags:
- Plugins
summary: List available plugins
operationId: getAvailablePlugins
security:
- OAuth2:
- admin
parameters:
- name: search
in: query
schema:
type: string
- name: pluginType
in: query
schema:
type: integer
- name: currentPeerTubeEngine
in: query
schema:
type: string
- $ref: '#/components/parameters/start'
- $ref: '#/components/parameters/count'
- $ref: '#/components/parameters/sort'
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/PluginResponse'
'503':
/api/v1/plugins/install:
post:
tags:
- Plugins
summary: Install a plugin
operationId: addPlugin
security:
- OAuth2:
- admin
requestBody:
content:
application/json:
schema:
oneOf:
- type: object
properties:
npmName:
type: string
example: peertube-plugin-auth-ldap
required:
- npmName
additionalProperties: false
- type: object
properties:
path:
type: string
required:
- path
additionalProperties: false
responses:
'204':
'400':
/api/v1/plugins/update:
post:
tags:
- Plugins
summary: Update a plugin
operationId: updatePlugin
security:
- OAuth2:
- admin
requestBody:
content:
application/json:
schema:
oneOf:
- type: object
properties:
npmName:
type: string
example: peertube-plugin-auth-ldap
required:
- npmName
additionalProperties: false
- type: object
properties:
path:
type: string
required:
- path
additionalProperties: false
responses:
'204':
'400':
'404':
/api/v1/plugins/uninstall:
post:
tags:
- Plugins
summary: Uninstall a plugin
operationId: uninstallPlugin
security:
- OAuth2:
- admin
requestBody:
content:
application/json:
schema:
type: object
properties:
npmName:
type: string
example: peertube-plugin-auth-ldap
required:
- npmName
responses:
'204':
'404':
/api/v1/plugins/{npmName}:
get:
tags:
- Plugins
summary: Get a plugin
operationId: getPlugin
security:
- OAuth2:
- admin
parameters:
- $ref: '#/components/parameters/npmName'
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/Plugin'
'404':
/api/v1/plugins/{npmName}/settings:
put:
tags:
- Plugins
summary: Set a plugin's settings
security:
- OAuth2:
- admin
parameters:
- $ref: '#/components/parameters/npmName'
requestBody:
content:
application/json:
schema:
type: object
properties:
settings:
type: object
additionalProperties: true
responses:
'204':
'404':
/api/v1/plugins/{npmName}/public-settings:
get:
tags:
- Plugins
summary: Get a plugin's public settings
parameters:
- $ref: '#/components/parameters/npmName'
responses:
'200':
content:
application/json:
schema:
type: object
additionalProperties: true
'404':
/api/v1/plugins/{npmName}/registered-settings:
get:
tags:
- Plugins
summary: Get a plugin's registered settings
security:
- OAuth2:
- admin
parameters:
- $ref: '#/components/parameters/npmName'
responses:
'200':
content:
application/json:
schema:
type: object
additionalProperties: true
'404':
/api/v1/metrics/playback:
post:
summary: Create playback metrics
tags:
- Stats
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/PlaybackMetricCreate'
responses:
'204':
/api/v1/runners/registration-tokens/generate:
post:
summary: Generate registration token
security:
- OAuth2:
- admin
tags:
- Runner Registration Token
responses:
'204':
/api/v1/runners/registration-tokens/{registrationTokenId}:
delete:
summary: Remove registration token
security:
- OAuth2:
- admin
tags:
- Runner Registration Token
parameters:
- $ref: '#/components/parameters/registrationTokenId'
responses:
'204':
/api/v1/runners/registration-tokens:
get:
summary: List registration tokens
security:
- OAuth2:
- admin
tags:
- Runner Registration Token
parameters:
- $ref: '#/components/parameters/start'
- $ref: '#/components/parameters/count'
- $ref: '#/components/parameters/registrationTokenSort'
responses:
'200':
content:
application/json:
schema:
type: object
properties:
total:
type: integer
example: 1
data:
type: array
items:
$ref: '#/components/schemas/RunnerRegistrationToken'

/api/v1/runners/register:
post:
summary: Register a new runner
tags:
- Runners
requestBody:
content:
application/json:
schema:
type: object
properties:
registrationToken:
type: string
name:
type: string
type: string
required:
- registrationToken
- name
responses:
'200':
content:
application/json:
schema:
type: object
properties:
id:
type: integer
runnerToken:
type: string

/api/v1/runners/unregister:
post:
summary: Unregister a runner
tags:
- Runners
requestBody:
content:
application/json:
schema:
type: object
properties:
runnerToken:
type: string
required:
- runnerToken
responses:
'204':
/api/v1/runners/{runnerId}:
delete:
summary: Delete a runner
security:
- OAuth2:
- admin
tags:
- Runners
parameters:
- $ref: '#/components/parameters/runnerId'
requestBody:
content:
application/json:
schema:
type: object
properties:
runnerToken:
type: string
required:
- runnerToken
responses:
'204':
/api/v1/runners:
get:
summary: List runners
security:
- OAuth2:
- admin
tags:
- Runners
parameters:
- $ref: '#/components/parameters/start'
- $ref: '#/components/parameters/count'
- $ref: '#/components/parameters/runnerSort'
responses:
'200':
content:
application/json:
schema:
type: object
properties:
total:
type: integer
example: 1
data:
type: array
items:
$ref: '#/components/schemas/Runner'

/api/v1/runners/jobs/request:
post:
summary: Request a new job
tags:
- Runner Jobs
requestBody:
content:
application/json:
schema:
type: object
properties:
runnerToken:
type: string
jobTypes:
type: array
items:
type: string
required:
- runnerToken
responses:
'200':
content:
application/json:
schema:
type: object
properties:
availableJobs:
type: array
items:
type: object
properties:
uuid:
$ref: '#/components/schemas/UUIDv4'
type:
$ref: '#/components/schemas/RunnerJobType'
payload:
$ref: '#/components/schemas/RunnerJobPayload'

/api/v1/runners/jobs/{jobUUID}/accept:
post:
summary: Accept job
tags:
- Runner Jobs
parameters:
- $ref: '#/components/parameters/jobUUID'
requestBody:
content:
application/json:
schema:
type: object
properties:
runnerToken:
type: string
required:
- runnerToken
responses:
'200':
content:
application/json:
schema:
type: object
properties:
job:
allOf:
- $ref: '#/components/schemas/RunnerJob'
- type: object
properties:
jobToken:
type: string

/api/v1/runners/jobs/{jobUUID}/abort:
post:
summary: Abort job
tags:
- Runner Jobs
parameters:
- $ref: '#/components/parameters/jobUUID'
requestBody:
content:
application/json:
schema:
type: object
properties:
runnerToken:
type: string
jobToken:
type: string
reason:
type: string
required:
- runnerToken
- jobToken
- reason
responses:
'204':
/api/v1/runners/jobs/{jobUUID}/update:
post:
summary: Update job
tags:
- Runner Jobs
parameters:
- $ref: '#/components/parameters/jobUUID'
requestBody:
content:
application/json:
schema:
type: object
properties:
runnerToken:
type: string
jobToken:
type: string
progress:
type: integer
payload:
anyOf:
- type: object
properties:
type:
type: string
enum:
- 'add-chunk'
- 'remove-chunk'
masterPlaylistFile:
type: string
format: binary
resolutionPlaylistFile:
type: string
format: binary
resolutionPlaylistFilename:
type: string
videoChunkFile:
type: string
format: binary
videoChunkFilename:
type: string
required:
- runnerToken
- jobToken
responses:
'204':
/api/v1/runners/jobs/{jobUUID}/error:
post:
summary: Post job error
tags:
- Runner Jobs
parameters:
- $ref: '#/components/parameters/jobUUID'
requestBody:
content:
application/json:
schema:
type: object
properties:
runnerToken:
type: string
jobToken:
type: string
message:
type: string
required:
- runnerToken
- jobToken
- message
responses:
'204':
/api/v1/runners/jobs/{jobUUID}/success:
post:
summary: Post job success
tags:
- Runner Jobs
parameters:
- $ref: '#/components/parameters/jobUUID'
requestBody:
content:
application/json:
schema:
type: object
properties:
runnerToken:
type: string
jobToken:
type: string
payload:
anyOf:
- type: object
title: VOD web video transcoding
properties:
videoFile:
type: string
format: binary
- type: object
title: VOD HLS transcoding
properties:
videoFile:
type: string
format: binary
resolutionPlaylistFile:
type: string
format: binary
- type: object
title: VOD audio merge transcoding
properties:
videoFile:
type: string
format: binary
- type: object
title: Live RTMP to HLS transcoding
required:
- runnerToken
- jobToken
- payload
responses:
'204':
/api/v1/runners/jobs/{jobUUID}/files/videos/{videoIdOrUUID}/max-quality/audio:
post:
summary: Download the max-quality audio file for a job video
tags:
- Runner Jobs
parameters:
- $ref: '#/components/parameters/jobUUID'
- $ref: '#/components/parameters/videoIdOrUUID'
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
runnerToken:
type: string
jobToken:
type: string
required:
- runnerToken
- jobToken
responses:
'200':
content:
application/octet-stream:
schema:
type: string
format: binary
'403':
/api/v1/runners/jobs/{jobUUID}/files/videos/{videoIdOrUUID}/max-quality:
post:
summary: Download the max-quality video file for a job video
tags:
- Runner Jobs
parameters:
- $ref: '#/components/parameters/jobUUID'
- $ref: '#/components/parameters/videoIdOrUUID'
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
runnerToken:
type: string
jobToken:
type: string
required:
- runnerToken
- jobToken
responses:
'200':
content:
application/octet-stream:
schema:
type: string
format: binary
'403':
/api/v1/runners/jobs/{jobUUID}/files/videos/{videoIdOrUUID}/thumbnails/max-quality:
post:
summary: Download the max-quality thumbnail for a job video
tags:
- Runner Jobs
parameters:
- $ref: '#/components/parameters/jobUUID'
- $ref: '#/components/parameters/videoIdOrUUID'
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
runnerToken:
type: string
jobToken:
type: string
required:
- runnerToken
- jobToken
responses:
'200':
content:
application/octet-stream:
schema:
type: string
format: binary
'403':
/api/v1/runners/jobs/{jobUUID}/files/videos/{videoIdOrUUID}/previews/max-quality:
post:
summary: Download the max-quality preview for a job video
tags:
- Runner Jobs
parameters:
- $ref: '#/components/parameters/jobUUID'
- $ref: '#/components/parameters/videoIdOrUUID'
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
runnerToken:
type: string
jobToken:
type: string
required:
- runnerToken
- jobToken
responses:
'200':
content:
application/octet-stream:
schema:
type: string
format: binary
'403':
/api/v1/runners/jobs/{jobUUID}/files/videos/{videoIdOrUUID}/studio/task-files/{filename}:
post:
summary: Download a video studio task file for a job video
tags:
- Runner Jobs
parameters:
- $ref: '#/components/parameters/jobUUID'
- $ref: '#/components/parameters/videoIdOrUUID'
- name: filename
in: path
required: true
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
runnerToken:
type: string
jobToken:
type: string
required:
- runnerToken
- jobToken
responses:
'200':
content:
application/octet-stream:
schema:
type: string
format: binary
'400':
'403':
/api/v1/runners/jobs/{jobUUID}/cancel:
post:
summary: Cancel a job
security:
- OAuth2:
- admin
tags:
- Runner Jobs
parameters:
- $ref: '#/components/parameters/jobUUID'
responses:
'204':
/api/v1/runners/jobs/{jobUUID}:
delete:
summary: Delete a job
security:
- OAuth2:
- admin
tags:
- Runner Jobs
parameters:
- $ref: '#/components/parameters/jobUUID'
responses:
'204':
/api/v1/runners/jobs:
get:
summary: List jobs
security:
- OAuth2:
- admin
tags:
- Runner Jobs
parameters:
- $ref: '#/components/parameters/start'
- $ref: '#/components/parameters/count'
- $ref: '#/components/parameters/runnerJobSort'
- $ref: '#/components/parameters/search'
- name: stateOneOf
in: query
required: false
schema:
type: array
items:
$ref: '#/components/schemas/RunnerJobState'
- name: typeOneOf
in: query
required: false
schema:
type: array
items:
$ref: '#/components/schemas/RunnerJobType'
responses:
'200':
content:
application/json:
schema:
type: object
properties:
total:
type: integer
example: 1
data:
type: array
items:
$ref: '#/components/schemas/RunnerJobAdmin'

/api/v1/automatic-tags/policies/accounts/{accountName}/comments:
get:
tags:
- Automatic Tags
summary: Get account auto tag policies on comments
security:
- OAuth2: []
parameters:
- name: accountName
in: path
required: true
schema:
type: string
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/CommentAutoTagPolicies'
put:
tags:
- Automatic Tags
summary: Update account auto tag policies on comments
security:
- OAuth2: []
parameters:
- name: accountName
in: path
required: true
schema:
type: string
requestBody:
content:
application/json:
schema:
type: object
properties:
review:
type: array
items:
type: string
responses:
'204':
/api/v1/automatic-tags/accounts/{accountName}/available:
get:
tags:
- Automatic Tags
summary: Get account available auto tags
security:
- OAuth2: []
parameters:
- name: accountName
in: path
required: true
schema:
type: string
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/AutomaticTagAvailable'
/api/v1/automatic-tags/server/available:
get:
tags:
- Automatic Tags
summary: Get server available auto tags
security:
- OAuth2:
- admin
- moderator
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/AutomaticTagAvailable'

/api/v1/automatic-tags/policies/server/videos:
get:
tags:
- Automatic Tags
summary: Get server auto tag policies for videos
security:
- OAuth2:
- admin
- moderator
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/VideoAutoTagPolicies'
put:
tags:
- Automatic Tags
summary: Update server auto tag policies for videos
security:
- OAuth2:
- admin
- moderator
requestBody:
content:
application/json:
schema:
type: object
properties:
autoBlock:
type: array
items:
type: string
responses:
'204':
/api/v1/watched-words/accounts/{accountName}/lists:
get:
tags:
- Watched Words
summary: List account watched words
security:
- OAuth2: []
parameters:
- name: accountName
in: path
required: true
schema:
type: string
responses:
'200':
content:
application/json:
schema:
properties:
total:
type: integer
example: 1
data:
type: array
items:
$ref: '#/components/schemas/WatchedWordsLists'
post:
tags:
- Watched Words
summary: Add account watched words
security:
- OAuth2: []
parameters:
- name: accountName
in: path
required: true
schema:
type: string
requestBody:
content:
application/json:
schema:
type: object
properties:
listName:
type: string
words:
type: array
items:
type: string
responses:
'200':
content:
application/json:
schema:
type: object
properties:
watchedWordsList:
type: object
properties:
id:
type: integer

/api/v1/watched-words/accounts/{accountName}/lists/{listId}:
put:
tags:
- Watched Words
summary: Update account watched words
security:
- OAuth2: []
parameters:
- name: accountName
in: path
required: true
schema:
type: string
- name: listId
in: path
required: true
schema:
type: string
requestBody:
content:
application/json:
schema:
type: object
properties:
listName:
type: string
words:
type: array
items:
type: string
responses:
'204':
delete:
tags:
- Watched Words
summary: Delete account watched words
security:
- OAuth2: []
parameters:
- name: accountName
in: path
required: true
schema:
type: string
- name: listId
in: path
required: true
schema:
type: string
responses:
'204':
/api/v1/watched-words/server/lists:
get:
tags:
- Watched Words
summary: List server watched words
security:
- OAuth2:
- admin
- moderator
responses:
'200':
content:
application/json:
schema:
properties:
total:
type: integer
example: 1
data:
type: array
items:
$ref: '#/components/schemas/WatchedWordsLists'
post:
tags:
- Watched Words
summary: Add server watched words
security:
- OAuth2:
- admin
- moderator
requestBody:
content:
application/json:
schema:
type: object
properties:
listName:
type: string
words:
type: array
items:
type: string
responses:
'200':
content:
application/json:
schema:
type: object
properties:
watchedWordsList:
type: object
properties:
id:
type: integer

/api/v1/watched-words/server/lists/{listId}:
put:
tags:
- Watched Words
summary: Update server watched words
security:
- OAuth2:
- admin
- moderator
parameters:
- name: listId
in: path
required: true
schema:
type: string
requestBody:
content:
application/json:
schema:
type: object
properties:
listName:
type: string
words:
type: array
items:
type: string
responses:
'204':
delete:
tags:
- Watched Words
summary: Delete server watched words
security:
- OAuth2:
- admin
- moderator
parameters:
- name: listId
in: path
required: true
schema:
type: string
responses:
'204':
/api/v1/watched-words/accounts/{accountName}/subscriptions:
get:
tags:
- Watched Words
summary: List account watched words subscriptions
security:
- OAuth2: []
parameters:
- name: accountName
in: path
required: true
schema:
type: string
- $ref: '#/components/parameters/start'
- $ref: '#/components/parameters/count'
- $ref: '#/components/parameters/sort'
- $ref: '#/components/parameters/search'
responses:
'200':
content:
application/json:
schema:
type: object
properties:
total:
type: integer
example: 1
data:
type: array
items:
$ref: '#/components/schemas/WatchedWordsSubscription'
post:
tags:
- Watched Words
summary: Add account watched words subscription
security:
- OAuth2: []
parameters:
- name: accountName
in: path
required: true
schema:
type: string
requestBody:
content:
application/json:
schema:
type: object
properties:
url:
type: string
format: url
required:
- url
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/WatchedWordsSubscription'
'400':
'409':
/api/v1/watched-words/accounts/{accountName}/subscriptions/{id}:
delete:
tags:
- Watched Words
summary: Delete account watched words subscription
security:
- OAuth2: []
parameters:
- name: accountName
in: path
required: true
schema:
type: string
- name: id
in: path
required: true
schema:
type: integer
responses:
'204':
'404':
/api/v1/watched-words/server/subscriptions:
get:
tags:
- Watched Words
summary: List server watched words subscriptions
security:
- OAuth2:
- admin
- moderator
parameters:
- $ref: '#/components/parameters/start'
- $ref: '#/components/parameters/count'
- $ref: '#/components/parameters/sort'
- $ref: '#/components/parameters/search'
responses:
'200':
content:
application/json:
schema:
type: object
properties:
total:
type: integer
example: 1
data:
type: array
items:
$ref: '#/components/schemas/WatchedWordsSubscription'
post:
tags:
- Watched Words
summary: Add server watched words subscription
security:
- OAuth2:
- admin
- moderator
requestBody:
content:
application/json:
schema:
type: object
properties:
url:
type: string
format: url
required:
- url
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/WatchedWordsSubscription'
'400':
'409':
/api/v1/watched-words/server/subscriptions/{id}:
delete:
tags:
- Watched Words
summary: Delete server watched words subscription
security:
- OAuth2:
- admin
- moderator
parameters:
- name: id
in: path
required: true
schema:
type: integer
responses:
'204':
'404':
/api/v1/client-config/update-language:
post:
tags:
- Client Config
summary: Update client language
operationId: updateClientLanguage
deprecated: true
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
language:
type: string
nullable: true
example: 'en-US'
required:
- language
responses:
'204':
/api/v1/client-config/update-interface-language:
post:
tags:
- Client Config
summary: Update client language
operationId: updateClientInterfaceLanguage
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
language:
type: string
nullable: true
example: 'en-US'
required:
- language
responses:
'204':
/api/v1/video-channels/{channelHandle}/collaborators:
get:
tags:
- Video Channels
summary: List channel collaborators
operationId: listVideoChannelCollaborators
security:
- OAuth2: []
parameters:
- $ref: '#/components/parameters/channelHandle'
responses:
'200':
content:
application/json:
schema:
type: object
properties:
total:
type: integer
example: 1
data:
type: array
items:
$ref: '#/components/schemas/VideoChannelCollaborator'

/api/v1/video-channels/{channelHandle}/collaborators/invite:
post:
tags:
- Video Channels
summary: Invite a collaborator
operationId: inviteVideoChannelCollaborator
security:
- OAuth2: []
parameters:
- $ref: '#/components/parameters/channelHandle'
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
accountHandle:
type: string
responses:
'200':
content:
application/json:
schema:
type: object
properties:
collaborator:
$ref: '#/components/schemas/VideoChannelCollaborator'

/api/v1/video-channels/{channelHandle}/collaborators/{collaboratorId}/accept:
post:
tags:
- Video Channels
summary: Accept a collaboration invitation
operationId: acceptVideoChannelCollaborator
security:
- OAuth2: []
parameters:
- $ref: '#/components/parameters/channelHandle'
- $ref: '#/components/parameters/collaboratorId'
responses:
'204':
/api/v1/video-channels/{channelHandle}/collaborators/{collaboratorId}/reject:
post:
tags:
- Video Channels
summary: Reject a collaboration invitation
operationId: rejectVideoChannelCollaborator
security:
- OAuth2: []
parameters:
- $ref: '#/components/parameters/channelHandle'
- $ref: '#/components/parameters/collaboratorId'
responses:
'204':
/api/v1/video-channels/{channelHandle}/collaborators/{collaboratorId}:
delete:
tags:
- Video Channels
summary: Remove a channel collaborator
operationId: removeVideoChannelCollaborator
security:
- OAuth2: []
parameters:
- $ref: '#/components/parameters/channelHandle'
- $ref: '#/components/parameters/collaboratorId'
responses:
'204':
servers:

  • url: 'https://peertube2.cpy.re'

  • url: 'https://peertube3.cpy.re'

  • url: 'https://peertube.cpy.re'
    components:
    parameters:
    start:
    name: start
    in: query
    required: false
    schema:
    type: integer
    minimum: 0

    count:
    name: count
    in: query
    required: false
    schema:
    type: integer
    default: 15
    maximum: 100
    minimum: 1

    sort:
    name: sort
    in: query
    required: false
    schema:
    type: string
    example: -createdAt

    search:
    name: search
    in: query
    required: false
    schema:
    type: string

    searchTarget:
    name: searchTarget
    in: query
    required: false
    If the administrator enabled search index support, you can override the default search target.


    Warning: If you choose to make an index search, PeerTube will get results from a third party service.
    It means the instance may not yet know the objects you fetched. If you want to load video/channel information:
    * If the current user has the ability to make a remote URI search (this information is available in the config endpoint),
    then reuse the search API to make a search using the object URI so PeerTube instance fetches the remote object and fill its database.
    After that, you can use the classic REST API endpoints to fetch the complete object or interact with it
    * If the current user doesn't have the ability to make a remote URI search, then redirect the user on the origin instance or fetch
    the data from the origin instance API

    schema:
    type: string
    enum:
    - 'local'
    - 'search-index'

    mySubscriptionSort:
    name: sort
    in: query
    required: false
    schema:
    type: string
    enum:
    - -id
    - -createdAt
    - -channelUpdatedAt

    videosSort:
    name: sort
    in: query
    required: false
    schema:
    type: string
    enum:
    - name
    - -duration
    - -createdAt
    - -publishedAt
    - -views
    - -likes
    - -comments
    - -trending
    - -hot
    - -best
    Sort videos by criteria (prefixing with - means DESC order):
    * hot - Adaptation of Reddit "hot" algorithm taking into account video views, likes, dislikes and comments and publication date
    * best - Same than hot, but also takes into account user video history
    * trending - Sort videos by recent views ("recent" is defined by the admin)
    * views - Sort videos using their views counter
    * publishedAt - Sort by video publication date (when it became publicly available)

    videosSearchSort:
    name: sort
    in: query
    required: false
    Sort videos by criteria (prefixing with - means DESC order):

    schema:
    type: string
    enum:
    - name
    - -duration
    - -createdAt
    - -publishedAt
    - -views
    - -likes
    - -match

    commentsSort:
    name: sort
    in: query
    required: false
    schema:
    type: string
    enum:
    - -createdAt
    - -totalReplies

    blacklistsSort:
    name: sort
    in: query
    required: false
    schema:
    type: string
    enum:
    - -id
    - name
    - -duration
    - -views
    - -likes
    - -dislikes
    - -uuid
    - -createdAt

    usersSearch:
    name: search
    in: query
    required: false
    schema:
    type: string

    usersBlocked:
    name: blocked
    in: query
    required: false
    schema:
    type: boolean

    usersRole:
    name: role
    in: query
    required: false
    schema:
    $ref: '#/components/schemas/UserRole'

    usersSort:
    name: sort
    in: query
    required: false
    schema:
    type: string
    enum:
    - -id
    - -username
    - -createdAt

    abusesSort:
    name: sort
    in: query
    required: false
    schema:
    type: string
    enum:
    - -id
    - -createdAt
    - -state

    videoRedundanciesSort:
    name: sort
    in: query
    required: false
    schema:
    type: string
    enum:
    - name

    followersSort:
    name: sort
    in: query
    required: false
    schema:
    type: string
    enum:
    - createdAt

    registrationTokenSort:
    name: sort
    in: query
    required: false
    schema:
    type: string
    enum:
    - createdAt

    runnerSort:
    name: sort
    in: query
    required: false
    schema:
    type: string
    enum:
    - createdAt

    runnerJobSort:
    name: sort
    in: query
    required: false
    schema:
    type: string
    enum:
    - updatedAt
    - createdAt
    - priority
    - state
    - progress

    name:
    name: name
    in: path
    required: true
    schema:
    type: string
    example: chocobozzz | [email protected]

    id:
    name: id
    in: path
    required: true
    schema:
    $ref: '#/components/schemas/id'

    tokenSessionId:
    name: tokenSessionId
    in: path
    required: true
    schema:
    $ref: '#/components/schemas/id'

    userId:
    name: userId
    in: path
    required: true
    schema:
    $ref: '#/components/schemas/id'

    registrationId:
    name: registrationId
    in: path
    required: true
    schema:
    $ref: '#/components/schemas/id'

    idOrUUID:
    name: id
    in: path
    required: true
    schema:
    oneOf:
    - $ref: '#/components/schemas/id'
    - $ref: '#/components/schemas/UUIDv4'
    - $ref: '#/components/schemas/shortUUID'

    playlistId:
    name: playlistId
    in: path
    required: true
    schema:
    $ref: '#/components/schemas/VideoPlaylist/properties/id'

    videoIdOrUUID:
    name: videoIdOrUUID
    in: path
    required: true
    schema:
    oneOf:
    - $ref: '#/components/schemas/id'
    - $ref: '#/components/schemas/UUIDv4'
    - $ref: '#/components/schemas/shortUUID'

    playlistElementId:
    name: playlistElementId
    in: path
    required: true
    schema:
    $ref: '#/components/schemas/id'

    abuseId:
    name: abuseId
    in: path
    required: true
    schema:
    $ref: '#/components/schemas/Abuse/properties/id'

    abuseMessageId:
    name: abuseMessageId
    in: path
    required: true
    schema:
    $ref: '#/components/schemas/AbuseMessage/properties/id'

    captionLanguage:
    name: captionLanguage
    in: path
    required: true
    schema:
    $ref: '#/components/schemas/VideoLanguageSet'

    channelHandle:
    name: channelHandle
    in: path
    required: true
    schema:
    type: string
    example: my_username | [email protected]

    channelSyncId:
    name: channelSyncId
    in: path
    required: true
    schema:
    $ref: '#/components/schemas/Abuse/properties/id'

    subscriptionHandle:
    name: subscriptionHandle
    in: path
    required: true
    schema:
    type: string
    example: my_username | [email protected]

    threadId:
    name: threadId
    in: path
    required: true
    schema:
    type: integer

    commentId:
    name: commentId
    in: path
    required: true
    schema:
    $ref: '#/components/schemas/VideoComment/properties/id'

    commentMaxDepth:
    name: maxDepth
    in: query
    required: false
    Number of nesting levels to include below the requested comment.

    Bounded by repliesPerLevel and count, see the note on repliesPerLevel

    schema:
    type: integer
    minimum: 1
    maximum: 10
    default: 5

    commentRepliesPerLevel:
    name: repliesPerLevel
    in: query
    required: false
    Number of direct replies to include for each comment of the tree. Does not apply to the first level of
    GET /api/v1/videos/{id}/comments/{commentId}/replies, which is paginated using start and count.

    A tree can make the server walk through
    count * (repliesPerLevel ^ maxDepth - 1) / (repliesPerLevel - 1) comments, which grows exponentially.
    Combinations above 2000000 are rejected
    A deep tree has to be narrow and a wide tree has to be shallow.

    schema:
    type: integer
    minimum: 1
    maximum: 30
    default: 10

    commentRepliesSort:
    name: sort
    in: query
    required: false
    Sort the direct replies of the comment. Deeper levels of the tree are always sorted the same way.

    Defaults to createdAt so the replies are appended to the thread tree in the order it was built

    schema:
    type: string
    default: createdAt
    enum:
    - createdAt
    - -createdAt

    isLive:
    name: isLive
    in: query
    required: false
    schema:
    type: boolean

    includeScheduledLive:
    name: includeScheduledLive
    in: query
    required: false
    schema:
    type: boolean

    categoryOneOf:
    name: categoryOneOf
    in: query
    required: false
    schema:
    oneOf:
    - $ref: '#/components/schemas/VideoCategorySet'
    - type: array
    items:
    $ref: '#/components/schemas/VideoCategorySet'

    style: form
    explode: true
    tagsOneOf:
    name: tagsOneOf
    in: query
    required: false
    schema:
    oneOf:
    - type: string
    - type: array
    maxItems: 5
    items:
    type: string

    style: form
    explode: true
    tagsAllOf:
    name: tagsAllOf
    in: query
    required: false
    schema:
    oneOf:
    - type: string
    - type: array
    items:
    type: string

    style: form
    explode: true
    languageOneOf:
    name: languageOneOf
    in: query
    required: false
    schema:
    oneOf:
    - $ref: '#/components/schemas/VideoLanguageSet'
    - type: array
    items:
    $ref: '#/components/schemas/VideoLanguageSet'

    style: form
    explode: true
    autoTagOneOfVideo:
    name: autoTagOneOf
    in: query
    required: false
    schema:
    oneOf:
    - type: string
    - type: array
    items:
    type: string

    style: form
    explode: true
    stateOneOfVideo:
    name: stateOneOf
    in: query
    required: false
    schema:
    oneOf:
    - $ref: '#/components/schemas/VideoStateConstant/properties/id'
    - type: array
    items:
    $ref: '#/components/schemas/VideoStateConstant/properties/id'

    style: form
    explode: true
    channelNameOneOf:
    name: channelNameOneOf
    in: query
    required: false
    schema:
    oneOf:
    - type: string
    - type: array
    items:
    type: string

    style: form
    explode: true
    autoTagOneOfComment:
    name: autoTagOneOf
    in: query
    required: false
    schema:
    oneOf:
    - type: string
    - type: array
    items:
    type: string

    style: form
    explode: true
    isHeldForReview:
    name: isHeldForReview
    in: query
    required: false
    schema:
    type: boolean

    licenceOneOf:
    name: licenceOneOf
    in: query
    required: false
    schema:
    oneOf:
    - $ref: '#/components/schemas/VideoLicenceSet'
    - type: array
    items:
    $ref: '#/components/schemas/VideoLicenceSet'

    style: form
    explode: true
    skipCount:
    name: skipCount
    in: query
    required: false
    schema:
    type: string
    enum:
    - 'true'
    - 'false'
    default: 'false'

    nsfw:
    name: nsfw
    in: query
    required: false
    schema:
    type: string
    enum:
    - 'true'
    - 'false'

    nsfwFlagsIncluded:
    name: nsfwFlagsIncluded
    in: query
    required: false
    schema:
    $ref: '#/components/schemas/NSFWFlag'

    nsfwFlagsExcluded:
    name: nsfwFlagsExcluded
    in: query
    required: false
    schema:
    $ref: '#/components/schemas/NSFWFlag'

    aiUsageOneOf:
    name: aiUsageOneOf
    in: query
    required: false
    PeerTube >= 9.0 Only list videos with one of these AI usages, declared by video creators.
    If not provided, the preference of the authenticated user (aiUsagesHidden) is used

    schema:
    oneOf:
    - $ref: '#/components/schemas/VideoAIUsageSet'
    - type: array
    items:
    $ref: '#/components/schemas/VideoAIUsageSet'

    style: form
    explode: true
    isLocal:
    name: isLocal
    in: query
    required: false
    schema:
    type: boolean

    hasHLSFiles:
    name: hasHLSFiles
    in: query
    required: false
    schema:
    type: boolean

    hasWebVideoFiles:
    name: hasWebVideoFiles
    in: query
    required: false
    schema:
    type: boolean

    privacyOneOf:
    name: privacyOneOf
    in: query
    required: false
    schema:
    $ref: '#/components/schemas/VideoPrivacySet'

    excludeAlreadyWatched:
    name: excludeAlreadyWatched
    in: query
    schema:
    type: boolean

    uuids:
    name: uuids
    in: query
    required: false
    schema:
    items:
    type: string

    host:
    name: host
    in: query
    required: false
    schema:
    type: string

    handles:
    name: handles
    in: query
    required: false
    schema:
    items:
    type: string

    include:
    name: include
    in: query
    required: false
    schema:
    type: integer
    enum:
    - 0
    - 1
    - 2
    - 4
    - 8
    - 16
    - 32
    Only administrators and moderators can use this parameter


    Include additional videos in results (can be combined using bitwise or operator)

    - 0 NONE

    - 1 NOT_PUBLISHED_STATE

    - 2 BLACKLISTED

    - 4 BLOCKED_OWNER

    - 8 FILES

    - 16 CAPTIONS

    - 32 VIDEO SOURCE

    subscriptionsUris:
    name: uris
    in: query
    required: true
    schema:
    type: array
    items:
    type: string
    format: uri

    npmName:
    name: npmName
    in: path
    required: true
    schema:
    type: string
    example: peertube-plugin-auth-ldap

    jobType:
    name: jobType
    in: query
    required: false
    schema:
    $ref: '#/components/schemas/JobType'

    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

    staticFilename:
    name: filename
    in: path
    required: true
    schema:
    type: string

    videoFileToken:
    name: videoFileToken
    in: query
    required: false
    schema:
    type: string

    reinjectVideoFileToken:
    name: reinjectVideoFileToken
    in: query
    required: false
    schema:
    type: boolean

    videoPlaylistType:
    name: playlistType
    in: query
    required: false
    schema:
    $ref: '#/components/schemas/VideoPlaylistTypeSet'

    registrationTokenId:
    name: registrationTokenId
    in: path
    required: true
    schema:
    type: integer

    runnerId:
    name: runnerId
    in: path
    required: true
    schema:
    type: integer

    jobUUID:
    name: jobUUID
    in: path
    required: true
    schema:
    $ref: '#/components/schemas/UUIDv4'

    passwordId:
    name: passwordId
    in: path
    required: true
    schema:
    $ref: '#/components/schemas/id'

    onLocalVideo:
    name: onLocalVideo
    in: query
    required: false
    schema:
    type: boolean

    includeMuted:
    name: includeMuted
    in: query
    required: false
    schema:
    type: boolean

    videoChannelId:
    name: videoChannelId
    in: query
    required: false
    schema:
    type: integer

    videoId:
    name: videoId
    in: query
    required: false
    schema:
    type: integer

    searchVideoForComments:
    name: searchVideo
    in: query
    required: false
    schema:
    type: string

    searchAccountForComments:
    name: searchAccount
    in: query
    required: false
    schema:
    type: string

    videoPasswordHeader:
    name: x-peertube-video-password
    in: header
    required: false
    schema:
    type: string

    resumableUploadInitContentLengthHeader:
    name: X-Upload-Content-Length
    in: header
    schema:
    type: number
    example: 2469036
    required: true

    resumableUploadInitContentTypeHeader:
    name: X-Upload-Content-Type
    in: header
    schema:
    type: string
    format: mimetype
    example: video/mp4

    required: true
    resumableUploadChunkContentRangeHeader:
    name: Content-Range
    in: header
    schema:
    type: string
    example: bytes 0-262143/2469036

    required: true
    Specifies the bytes in the file that the request is uploading.

    For example, a value of bytes 0-262143/1000000 shows that the request is sending the first
    262144 bytes (256 x 1024) in a 2,469,036 byte file.

    When the server config client.videos.resumableUpload.minChunkSize (video uploads) or
    import.users.resumableUpload.minChunkSize (user archive imports) is not 0,
    every chunk except the last one must be at least that big. It must also be at least 1/10,000 of the file size
    (the maximum number of object storage multipart upload parts).

    resumableUploadChunkContentLengthHeader:
    name: Content-Length
    in: header
    schema:
    type: number
    example: 262144

    required: true
    Size of the chunk that the request is sending.

    Remember that larger chunks are more efficient. PeerTube's web client uses chunks varying from
    1048576 bytes (~1MB) and increases or reduces size depending on connection health.

    resumableUploadId:
    name: upload_id
    in: query
    required: true
    Created session id to proceed with. If you didn't send chunks in the last hour, it is
    not valid anymore and you need to initialize a new upload.

    schema:
    type: string

    logoTypeParam:
    name: logoType
    in: path
    required: true
    schema:
    type: string
    enum:
    - 'favicon'
    - 'header-wide'
    - 'header-square'
    - 'opengraph'

    includeCollaborations:
    name: includeCollaborations
    in: query
    required: false
    schema:
    type: boolean

    collaboratorId:
    name: collaboratorId
    in: path
    required: true
    schema:
    $ref: '#/components/schemas/id'

securitySchemes:
OAuth2:
Authenticating via OAuth requires the following steps:
- Have an activated account
- [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

text
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: /api/v1/users/token
      scopes:
        admin: Admin scope
        moderator: Moderator scope
        user: User scope

schemas:
# Reusable 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}$'
minLength: 36
maxLength: 36
shortUUID:
type: string
example: 2y84q2MQUMWPbiEcxNXMgC
username:
type: string
example: chocobozzz
pattern: '/^[a-z0-9.]+$/'
minLength: 1
maxLength: 50
usernameChannel:
type: string
example: framasoft_videos
pattern: '/^[a-zA-Z0-9\-
.:]+$/'
minLength: 1
maxLength: 50
password:
type: string
format: password
minLength: 6
maxLength: 50

text
VideoCategorySet:
  type: integer
  example: 15
VideoConstantNumber-Category:
  properties:
    id:
      $ref: '#/components/schemas/VideoCategorySet'
    label:
      type: string
      example: Science & Technology

VideoLicenceSet:
  type: integer
  example: 2
VideoConstantNumber-Licence:
  properties:
    id:
      $ref: '#/components/schemas/VideoLicenceSet'
    label:
      type: string
      example: Attribution - Share Alike

VideoLanguageSet:
  type: string
  example: en
VideoConstantString-Language:
  properties:
    id:
      $ref: '#/components/schemas/VideoLanguageSet'
    label:
      type: string
      example: English

VideoPlaylistPrivacySet:
  type: integer
  enum:
    - 1
    - 2
    - 3
VideoPlaylistPrivacyConstant:
  properties:
    id:
      $ref: '#/components/schemas/VideoPlaylistPrivacySet'
    label:
      type: string

VideoPlaylistTypeSet:
  type: integer
  enum:
    - 1
    - 2
VideoPlaylistTypeConstant:
  properties:
    id:
      $ref: '#/components/schemas/VideoPlaylistTypeSet'
    label:
      type: string

VideoPrivacySet:
  type: integer
  enum:
    - 1
    - 2
    - 3
    - 4
    - 5
VideoPrivacyConstant:
  properties:
    id:
      $ref: '#/components/schemas/VideoPrivacySet'
    label:
      type: string

VideoCommentsPolicySet:
  type: integer
  enum:
    - 1
    - 2
    - 3
VideoCommentsPolicyConstant:
  properties:
    id:
      $ref: '#/components/schemas/VideoCommentsPolicySet'
    label:
      type: string

VideoRecommendationScopeSet:
  type: integer
  enum:
    - 1
    - 2
    - 3
    - 4
    Videos that can be recommended next to a video:
      - `1` All videos
      - `2` Only videos of the platform that owns the reference video (or of the current platform if no video is given)
      - `3` Only videos of the account that owns the reference video
      - `4` Only videos of the channel of the reference video

    This is a preference of the video owner: applications displaying recommendations may not apply it
VideoRecommendationScopeConstant:
  properties:
    id:
      $ref: '#/components/schemas/VideoRecommendationScopeSet'
    label:
      type: string

VideoAIUsageSet:
  type: integer
  enum:
    - 1
    - 2
    - 3
    - 4
    **PeerTube >= 9.0** Use of AI in the video, declared by the video creator:
      - `1` Not specified
      - `2` No AI-generated content: nothing seen or heard in the video has been generated by AI
      - `3` Contains AI-generated content: some parts of the video have been generated by AI
      - `4` AI-generated: the whole video, or most of it, has been generated by AI
VideoAIUsageConstant:
  properties:
    id:
      $ref: '#/components/schemas/VideoAIUsageSet'
    label:
      type: string
VideoCommercialContentSet:
  type: integer
  enum:
    - 1
    - 2
    - 3
    **PeerTube >= 9.0** Commercial content in the video, declared by the video creator:
      - `1` None
      - `2` Promotional content: the creator promotes their own products, services or business
      - `3` Paid partnership: a third party paid, or provided goods or services, in exchange for the promotion
VideoCommercialContentConstant:
  properties:
    id:
      $ref: '#/components/schemas/VideoCommercialContentSet'
    label:
      type: string

BlockStatus:
  properties:
    accounts:
      type: object
      additionalProperties:
        x-additionalPropertiesName: account
        type: object
        properties:
          blockedByServer:
            type: boolean
          blockedByServerSubscription:
            type: string
          blockedByUser:
            type: boolean
    hosts:
      type: object
      additionalProperties:
        x-additionalPropertiesName: host
        type: object
        properties:
          blockedByServer:
            type: boolean
          blockedByServerSubscription:
            type: string
          blockedByUser:
            type: boolean

NSFWPolicy:
  type: string
  enum:
    - display
    - warn
    - do_not_list

NSFWFlag:
  type: integer
  enum:
    - 0
    - 1
    - 2
    - 4
    NSFW flags (can be combined using bitwise or operator)

    - `0` NONE

    - `1` VIOLENT

    - `2` EXPLICIT_SEX

UserRole:
  type: integer
  enum:
    - 0
    - 1
    - 2
  example: 2
UserAdminFlags:
  type: integer
  enum:
    - 0
    - 1
  example: 1

LiveVideoLatencyMode:
  type: integer
  enum:
    - 1
    - 2
    - 3
LiveVideoReplaySettings:
  type: object
  properties:
    privacy:
      # description: Video playlist privacy policy (see [../video-playlists/privacies])
      $ref: '#/components/schemas/VideoPrivacySet'

VideoChannelActivityAction:
  type: integer
  enum:
    - 1
    - 2
    - 3
    - 4
    - 5
    - 6
    - 7
    - 8
    - 9
    - 10
    - 11
    The activity action:
      - CREATE: 1
      - UPDATE: 2
      - DELETE: 3
      - UPDATE_CAPTIONS: 4
      - UPDATE_CHAPTERS: 5
      - UPDATE_PASSWORDS: 6
      - CREATE_STUDIO_TASKS: 7
      - UPDATE_SOURCE_FILE: 8
      - UPDATE_ELEMENTS: 9
      - REMOVE_CHANNEL_OWNERSHIP: 10
      - CREATE_CHANNEL_OWNERSHIP: 11

VideoChannelActivityTarget:
  type: integer
  enum:
    - 1
    - 2
    - 3
    - 4
    - 5
    The activity target:
      - VIDEO: 1,
      - PLAYLIST: 2,
      - CHANNEL: 3,
      - CHANNEL_SYNC: 4,
      - VIDEO_IMPORT: 5

VideoStateConstant:
  properties:
    id:
      type: integer
      enum:
        - 1
        - 2
        - 3
        - 4
        - 5
        - 6
        - 7
        - 8
        - 9
        The video state:
        - `1`: Published
        - `2`: To transcode
        - `3`: To import
        - `4`: Waiting for live stream
        - `5`: Live ended
        - `6`: To move to an external storage (object storage...)
        - `7`: Transcoding failed
        - `8`: Moving to an external storage failed
        - `9`: To edit using studio edition feature
    label:
      type: string

UserExportState:
  type: integer
  enum:
    - 1
    - 2
    - 3
    - 4
    The user export state:
      - `1`: Pending
      - `2`: Processing
      - `3`: Completed
      - `4`: Errored

UserImportState:
  type: integer
  enum:
    - 1
    - 2
    - 3
    - 4
    The user import state:
      - `1`: Pending
      - `2`: Processing
      - `3`: Completed
      - `4`: Errored

AbuseStateSet:
  type: integer
  enum:
    - 1
    - 2
    - 3
AbuseStateConstant:
  properties:
    id:
      $ref: '#/components/schemas/AbuseStateSet'
    label:
      type: string
AbusePredefinedReasons:
  type: array
  items:
    type: string
    enum:
    - violentOrAbusive
    - hatefulOrAbusive
    - spamOrMisleading
    - privacy
    - rights
    - serverRules
    - thumbnails
    - captions
  example: [spamOrMisleading]

VideoResolutionSet:
  type: integer
    Video resolution (`0`, `240`, `360`, `720`, `1080`, `1440` or `2160`)

    `0` is used as a special value for stillimage videos dedicated to audio, a.k.a. audio-only videos.
  example: 240
VideoResolutionConstant:
  properties:
    id:
      $ref: '#/components/schemas/VideoResolutionSet'
    label:
      type: string
      example: 240p
VideoScheduledUpdate:
  properties:
    privacy:
      $ref: '#/components/schemas/VideoPrivacySet'
    updateAt:
      type: string
      format: date-time
  required:
    - updateAt
AccountSummary:
  properties:
    id:
      type: integer
    name:
      type: string
    displayName:
      type: string
    url:
      type: string
      format: url
    host:
      type: string
      format: hostname
    avatars:
      type: array
      items:
        $ref: '#/components/schemas/ActorImage'

VideoSummary:
  properties:
    id:
      allOf:
        - $ref: '#/components/schemas/id'
    uuid:
      allOf:
        - $ref: '#/components/schemas/UUIDv4'
    shortUUID:
      allOf:
        - $ref: '#/components/schemas/shortUUID'
    name:
      type: string
    isLive:
      type: boolean
    nsfw:
      type: boolean
    publishedAt:
      type: string
      format: date-time
    thumbnails:
      type: array
      items:
        $ref: '#/components/schemas/Thumbnail'
    channel:
      $ref: '#/components/schemas/VideoChannelSummary'

VideoChannelSummary:
  properties:
    id:
      $ref: '#/components/schemas/id'
    name:
      type: string
    displayName:
      type: string
    url:
      type: string
      format: url
    host:
      type: string
      format: hostname
    avatars:
      type: array
      items:
        $ref: '#/components/schemas/ActorImage'
PlaylistElement:
  properties:
    position:
      type: integer
    startTimestamp:
      type: integer
      format: seconds
    stopTimestamp:
      type: integer
      format: seconds
    video:
      nullable: true
      allOf:
        - $ref: '#/components/schemas/Video'
Thumbnail:
  properties:
    fileUrl:
      type: string
    width:
      type: integer
    height:
      type: integer
    aspectRatio:
      type: string
      example: '16:9'
VideoFile:
  properties:
    id:
      $ref: '#/components/schemas/id'
    magnetUri:
      type: string
      format: uri
      pattern: /magnet:\?xt=urn:[a-z0-9]+:[a-z0-9]{32}/i
    resolution:
      $ref: '#/components/schemas/VideoResolutionConstant'
    size:
      type: integer
    torrentUrl:
      type: string
      format: url
    torrentDownloadUrl:
      type: string
      format: url
    fileUrl:
      type: string
      format: url
    playlistUrl:
      type: string
      format: url
    fileDownloadUrl:
      type: string
      format: url
    fps:
      type: number
    width:
      type: number
    height:
      type: number
    metadataUrl:
      type: string
      format: url
    hasAudio:
      type: boolean
    hasVideo:
      type: boolean
    storage:
      $ref: '#/components/schemas/FileStorage'

VideoStreamingPlaylists:
  allOf:
    - type: object
      properties:
        id:
          $ref: '#/components/schemas/id'
        type:
          type: integer
          enum:
            - 1
            Playlist type:
            - `1`: HLS
    - $ref: '#/components/schemas/VideoStreamingPlaylists-HLS'
VideoStreamingPlaylists-HLS:
  properties:
    playlistUrl:
      type: string
      format: url
    segmentsSha256Url:
      type: string
      format: url
    files:
      type: array
        Video files associated to this playlist.

        The difference with the root `files` property is that these files are fragmented, so they can be used in this streaming playlist (HLS, etc.)
      items:
        $ref: '#/components/schemas/VideoFile'
    redundancies:
      type: array
      items:
        type: object
        properties:
          baseUrl:
            type: string
            format: url
VideoInfo:
  properties:
    id:
      $ref: '#/components/schemas/Video/properties/id'
    uuid:
      $ref: '#/components/schemas/Video/properties/uuid'
    name:
      $ref: '#/components/schemas/Video/properties/name'
    state:
      $ref: '#/components/schemas/Video/properties/state'
Video:
  properties:
    id:
      allOf:
        - $ref: '#/components/schemas/id'
    uuid:
      allOf:
        - $ref: '#/components/schemas/UUIDv4'
    shortUUID:
      allOf:
        - $ref: '#/components/schemas/shortUUID'
    isLive:
      type: boolean
    liveSchedules:
      type: array
      items:
        $ref: '#/components/schemas/LiveSchedule'
    createdAt:
      type: string
      format: date-time
      example: 2017-10-01T10:52:46.396Z
    publishedAt:
      type: string
      format: date-time
      example: 2018-10-01T10:52:46.396Z
    updatedAt:
      type: string
      format: date-time
      example: 2021-05-04T08:01:01.502Z
    originallyPublishedAt:
      type: string
      nullable: true
      format: date-time
      example: 2010-10-01T10:52:46.396Z
    category:
      allOf:
        - $ref: '#/components/schemas/VideoConstantNumber-Category'
    licence:
      allOf:
        - $ref: '#/components/schemas/VideoConstantNumber-Licence'
    language:
      allOf:
        - $ref: '#/components/schemas/VideoConstantString-Language'
    privacy:
      allOf:
        - $ref: '#/components/schemas/VideoPrivacyConstant'
    truncatedDescription:
      type: string
      nullable: true
      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)**\r\n*A decentralized video hosting network, based on fr...
      minLength: 3
      maxLength: 250
        truncated description of the video, written in Markdown.
    duration:
      type: integer
      example: 1419
      format: seconds
    aspectRatio:
      type: number
      nullable: true
      format: float
      example: 1.778
    isLocal:
      type: boolean
    name:
      type: string
      example: What is PeerTube?
      minLength: 3
      maxLength: 120
    thumbnailPath:
      deprecated: true
      nullable: true
      type: string
    previewPath:
      deprecated: true
      nullable: true
      type: string
    thumbnails:
      type: array
      items:
        $ref: '#/components/schemas/Thumbnail'
    embedPath:
      type: string
      example: /videos/embed/a65bc12f-9383-462e-81ae-8207e8b434ee
    views:
      type: integer
      example: 1337
    likes:
      type: integer
      example: 42
    dislikes:
      type: integer
      example: 7
    comments:
      type: integer
    nsfw:
      type: boolean
    nsfwFlags:
      allOf:
        - $ref: '#/components/schemas/NSFWFlag'
    nsfwSummary:
      type: string
    aiUsage:
      $ref: '#/components/schemas/VideoAIUsageConstant'
    commercialContent:
      $ref: '#/components/schemas/VideoCommercialContentConstant'
    recommendationScope:
      $ref: '#/components/schemas/VideoRecommendationScopeConstant'
    waitTranscoding:
      type: boolean
      nullable: true
    state:
      allOf:
        - $ref: '#/components/schemas/VideoStateConstant'
    scheduledUpdate:
      nullable: true
      allOf:
        - $ref: '#/components/schemas/VideoScheduledUpdate'
    blacklisted:
      nullable: true
      type: boolean
    blacklistedReason:
      nullable: true
      type: string
    account:
      $ref: '#/components/schemas/AccountSummary'
    channel:
      $ref: '#/components/schemas/VideoChannelSummary'
    userHistory:
      nullable: true
      type: object
      properties:
        currentTime:
          type: integer
ServerError:
  properties:
    type:
      type: string
      format: uri-reference
        URI identifying the error type. `about:blank` when the error has no specific type.
        Otherwise it links to the corresponding section of the [Errors](#section/Errors) documentation;
        the type name itself is also available in `code`.
      example: 'https://docs.joinpeertube.org/api-rest-reference.html#section/Errors/video_requires_password'
    detail:
      type: string
      example: 'Please provide a password to access this password protected video'
    status:
      type: integer
      example: 403
    code:
      type: string
      example: video_requires_password
VideoDetails:
  allOf:
    - $ref: '#/components/schemas/Video'
    - type: object
      properties:
        viewers:
          type: integer
          type: string
          nullable: true
          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)**\r\n*A decentralized video hosting network,
            based on free/libre software!*\r\n\r\n**Animation Produced by:** [LILA](https://libreart.info) - [ZeMarmot Team](https://film.zemarmot.net)\r\n
            *Directed by* Aryeom\r\n*Assistant* Jehan\r\n**Licence**: [CC-By-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/)\r\n\r\n
            **Sponsored by** [Framasoft](https://framasoft.org)\r\n\r\n**Music**: [Red Step Forward](http://play.dogmazic.net/song.php?song_id=52491) - CC-By Ken Bushima\r\n\r\n
            **Movie Clip**: [Caminades 3: Llamigos](http://www.caminandes.com/) CC-By Blender Institute\r\n\r\n**Video sources**: https://gitlab.gnome.org/Jehan/what-is-peertube/"
          minLength: 3
          maxLength: 1000
            full description of the video, written in Markdown.
        support:
          type: string
          nullable: true
          example: Please support our work on https://soutenir.framasoft.org/en/ <3
          minLength: 3
          maxLength: 1000
        channel:
          $ref: '#/components/schemas/VideoChannel'
        account:
          $ref: '#/components/schemas/Account'
        tags:
          example: [flowers, gardening]
          type: array
          minItems: 1
          maxItems: 5
          items:
            type: string
            minLength: 2
            maxLength: 30
        commentsPolicy:
          $ref: '#/components/schemas/VideoCommentsPolicyConstant'
        downloadEnabled:
          type: boolean
        inputFileUpdatedAt:
          type: string
          format: date-time
          nullable: true
        trackerUrls:
          type: array
            WebTorrent (`ws://` or `wss://`) and BitTorrent (`http://` or `https://`) trackers of the video
          items:
            type: string
            format: url
          example:
            - https://peertube2.cpy.re/tracker/announce
            - wss://peertube2.cpy.re/tracker/socket
        files:
          type: array
          items:
            $ref: '#/components/schemas/VideoFile'
            Web compatible video files. If Web Video is disabled on the server:

            - field will be empty
            - video files will be found in `streamingPlaylists[].files` field
        streamingPlaylists:
          type: array
          items:
            $ref: '#/components/schemas/VideoStreamingPlaylists'
            HLS playlists/manifest files. If HLS is disabled on the server:

            - field will be empty
            - video files will be found in `files` field
FileRedundancyInformation:
  properties:
    id:
      $ref: '#/components/schemas/id'
    fileUrl:
      type: string
      format: url
    strategy:
      type: string
      enum:
        - manual
        - most-views
        - trending
        - recently-added
    size:
      type: integer
    createdAt:
      type: string
      format: date-time
    updatedAt:
      type: string
      format: date-time
    expiresOn:
      type: string
      format: date-time
VideoRedundancy:
  properties:
    id:
      $ref: '#/components/schemas/id'
    name:
      type: string
    url:
      type: string
      format: url
    uuid:
      $ref: '#/components/schemas/UUIDv4'
    redundancies:
      type: object
      properties:
        streamingPlaylists:
          type: array
          items:
            $ref: '#/components/schemas/FileRedundancyInformation'
AccountBlock:
  properties:
    byAccount:
      $ref: '#/components/schemas/Account'
    blockedAccount:
      $ref: '#/components/schemas/Account'
      type: boolean
    blocklistSubscription:
      $ref: '#/components/schemas/BlocklistSubscriptionSummary'
      nullable: true
    createdAt:
      type: string
      format: date-time
ServerBlock:
  properties:
    byAccount:
      $ref: '#/components/schemas/Account'
    blockedServer:
      type: object
      properties:
        host:
          type: string
          format: hostname
    blocklistSubscription:
      $ref: '#/components/schemas/BlocklistSubscriptionSummary'
      nullable: true
    createdAt:
      type: string
      format: date-time
BlocklistSubscription:
  properties:
    id:
      $ref: '#/components/schemas/id'
    name:
      type: string
    url:
      type: string
      format: url
    mutedAccountsCount:
      type: integer
      minimum: 0
    mutedServersCount:
      type: integer
      minimum: 0
    lastSyncAt:
      type: string
      format: date-time
    createdAt:
      type: string
      format: date-time
    updatedAt:
      type: string
      format: date-time
BlocklistSubscriptionSummary:
  properties:
    id:
      $ref: '#/components/schemas/id'
    name:
      type: string
    url:
      type: string
      format: url
BlocklistLog:
  properties:
    id:
      $ref: '#/components/schemas/id'
    action:
      type: string
      enum:
        - add
        - delete
    target:
      type: string
    createdAt:
      type: string
      format: date-time
AutoMuteList:
  properties:
    name:
      type: string
    actions:
      type: array
      items:
        type: object
        properties:
          type:
            type: string
            enum:
              - block
              - unblock
          target:
            type: string
          createdAt:
            type: string
            format: date-time
CommentAutoTagPolicies:
  properties:
    review:
      type: array
      items:
        type: string
VideoAutoTagPolicies:
  properties:
    autoBlock:
      type: array
      items:
        type: string
AutomaticTagAvailable:
  properties:
    available:
      type: array
      items:
        type: object
        properties:
          name:
            type: string
          type:
            type: string
            enum:
              - 'core'
              - 'watched-words-list'

VideoImportStateConstant:
  properties:
    id:
      type: integer
      enum:
        - 1
        - 2
        - 3
        - 4
        - 5
        - 6
        The video import state (Pending = `1`, Success = `2`, Failed = `3`, Rejected = `4`, Cancelled = `5`,
        Processing = `6`)
    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:
      $ref: '#/components/schemas/id'
    targetUrl:
      type: string
      format: url
      example: https://framatube.org/videos/watch/9c9de5e8-0a1e-484a-b099-e80766180a6d
    magnetUri:
      type: string
      format: uri
      pattern: /magnet:\?xt=urn:[a-z0-9]+:[a-z0-9]{32}/i
    torrentfile:
      type: string
      format: binary
    torrentName:
      type: string
    state:
      allOf:
        - $ref: '#/components/schemas/VideoImportStateConstant'
    error:
      type: string
    createdAt:
      type: string
      format: date-time
    updatedAt:
      type: string
      format: date-time
    video:
      nullable: true
      allOf:
        - $ref: '#/components/schemas/Video'
VideoImportsList:
  properties:
    total:
      type: integer
      example: 1
    data:
      type: array
      maxItems: 100
      items:
        $ref: '#/components/schemas/VideoImport'
Abuse:
  properties:
    id:
      $ref: '#/components/schemas/id'
    reason:
      type: string
      example: The video is a spam
      minLength: 2
      maxLength: 3000
    predefinedReasons:
      $ref: '#/components/schemas/AbusePredefinedReasons'
    reporterAccount:
      $ref: '#/components/schemas/Account'
    state:
      $ref: '#/components/schemas/AbuseStateConstant'
    moderationComment:
      type: string
      example: Decided to ban the server since it spams us regularly
      minLength: 2
      maxLength: 3000
    video:
      type: object
      properties:
        id:
          type: integer
        uuid:
          $ref: '#/components/schemas/UUIDv4'
        shortUUID:
          $ref: '#/components/schemas/shortUUID'
        name:
          type: string
        nsfw:
          type: boolean
        startAt:
          type: string
          format: date-time
        endAt:
          type: string
          format: date-time
        deleted:
          type: boolean
        blacklisted:
          type: boolean
        thumbnailPath:
          deprecated: true
          nullable: true
          type: string
        thumbnails:
          type: array
          items:
            $ref: '#/components/schemas/Thumbnail'
        channel:
          $ref: '#/components/schemas/VideoChannel'
    createdAt:
      type: string
      format: date-time
AbuseMessage:
  properties:
    id:
      $ref: '#/components/schemas/id'
    message:
      type: string
      minLength: 2
      maxLength: 3000
    byModerator:
      type: boolean
    createdAt:
      type: string
      format: date-time
    account:
      $ref: '#/components/schemas/AccountSummary'
VideoBlacklist:
  type: object
  properties:
    id:
      $ref: '#/components/schemas/id'
    reason:
      type: string
    internalNote:
      type: string
    unfederated:
      type: boolean
    type:
      type: integer
        - `1`: manual block
        - `2`: automatic block by instance policy
        - `3`: automatic block by auto-tag policy
    video:
      $ref: '#/components/schemas/Video'
    createdAt:
      type: string
      format: date-time
    updatedAt:
      type: string
      format: date-time
VideoBlacklistCreate:
  type: object
  properties:
    reason:
      type: string
    unfederate:
      type: boolean
    internalNote:
      type: string
VideoBlacklistUpdate:
  type: object
  properties:
    reason:
      type: string
    internalNote:
      type: string
ChangeOwnership:
  type: object
  properties:
    id:
      $ref: '#/components/schemas/id'
    state:
      properties:
        id:
          $ref: '#/components/schemas/ChangeOwnershipState'
        label:
          type: string
    initiatorAccount:
      $ref: '#/components/schemas/Account'
    nextOwnerAccount:
      $ref: '#/components/schemas/Account'
    video:
      $ref: '#/components/schemas/VideoSummary'
    videoChannel:
      $ref: '#/components/schemas/VideoChannelSummary'
    createdAt:
      type: string
      format: date-time
VideoPlaylist:
  properties:
    id:
      $ref: '#/components/schemas/id'
    uuid:
      $ref: '#/components/schemas/UUIDv4'
    shortUUID:
      allOf:
        - $ref: '#/components/schemas/shortUUID'
    createdAt:
      type: string
      format: date-time
    updatedAt:
      type: string
      format: date-time
      type: string
      minLength: 3
      maxLength: 1000
    displayName:
      type: string
      minLength: 1
      maxLength: 120
    isLocal:
      type: boolean
    videoLength:
      type: integer
      minimum: 0
    thumbnailPath:
      deprecated: true
      nullable: true
      type: string
    thumbnails:
      type: array
      items:
        $ref: '#/components/schemas/Thumbnail'
    privacy:
      $ref: '#/components/schemas/VideoPlaylistPrivacyConstant'
    type:
      $ref: '#/components/schemas/VideoPlaylistTypeConstant'
    ownerAccount:
      $ref: '#/components/schemas/AccountSummary'
    videoChannel:
      $ref: '#/components/schemas/VideoChannelSummary'
    videoChannelPosition:
      type: integer
      minimum: 1
VideoComment:
  properties:
    id:
      $ref: '#/components/schemas/id'
    url:
      type: string
      format: url
    text:
      type: string
      format: html
      minLength: 1
      example: This video is wonderful!
    threadId:
      $ref: '#/components/schemas/id'
    inReplyToCommentId:
      nullable: true
      allOf:
        - $ref: '#/components/schemas/id'
    videoId:
      $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
    heldForReview:
      type: boolean
    totalRepliesFromVideoAuthor:
      type: integer
      minimum: 0
    totalReplies:
      type: integer
      minimum: 0
    account:
      $ref: '#/components/schemas/Account'
VideoCommentThreadTree:
  properties:
    comment:
      $ref: '#/components/schemas/VideoComment'
    children:
      type: array
        Direct replies of `comment`. The server truncates the tree in depth (see the `maxDepth` parameter) and in
        width, so this array may contain less elements than `totalChildren`. Missing replies can be fetched using
        `GET /api/v1/videos/{id}/comments/{commentId}/replies`
      items:
        $ref: '#/components/schemas/VideoCommentThreadTree'
    totalChildren:
      type: integer
      minimum: 0
VideoCommentForOwnerOrAdmin:
  properties:
    id:
      $ref: '#/components/schemas/id'
    url:
      $ref: '#/components/schemas/VideoComment/properties/url'
    text:
      $ref: '#/components/schemas/VideoComment/properties/text'
    heldForReview:
      $ref: '#/components/schemas/VideoComment/properties/heldForReview'
    threadId:
      $ref: '#/components/schemas/VideoComment/properties/threadId'
    inReplyToCommentId:
      $ref: '#/components/schemas/VideoComment/properties/inReplyToCommentId'
    createdAt:
      $ref: '#/components/schemas/VideoComment/properties/createdAt'
    updatedAt:
      $ref: '#/components/schemas/VideoComment/properties/updatedAt'
    account:
      $ref: '#/components/schemas/VideoComment/properties/account'
    video:
      $ref: '#/components/schemas/VideoInfo'
    automaticTags:
      type: array
      items:
        type: string

Storyboard:
  properties:
    storyboardPath:
      deprecated: true
      nullable: true
      type: string
    fileUrl:
      type: string
    totalHeight:
      type: integer
    totalWidth:
      type: integer
    spriteHeight:
      type: integer
    spriteWidth:
      type: integer
    spriteDuration:
      type: integer

VideoCaption:
  properties:
    language:
      $ref: '#/components/schemas/VideoConstantString-Language'
    automaticallyGenerated:
      type: boolean
    captionPath:
      type: string
      deprecated: true
      nullable: true
    fileUrl:
      type: string
    m3u8Url:
      type: string
    updatedAt:
      type: string
      format: date-time

VideoChapters:
  properties:
    chapters:
      type: object
      properties:
        title:
          type: string
        timecode:
          type: integer
VideoSource:
  properties:
    inputFilename:
      type: string
    fileDownloadUrl:
      type: string
    resolution:
      allOf:
       - $ref: '#/components/schemas/VideoResolutionConstant'
    size:
      type: integer
    fps:
      type: number
    width:
      type: integer
    height:
      type: integer
    createdAt:
      type: string
      format: date-time
ActorImage:
  properties:
    path:
      deprecated: true
      nullable: true
      type: string
    fileUrl:
      type: string
    width:
      type: integer
    height:
      type: integer
    createdAt:
      type: string
      format: date-time
    updatedAt:
      type: string
      format: date-time
ActorInfo:
  properties:
    id:
      $ref: '#/components/schemas/id'
    name:
      type: string
    displayName:
      type: string
    host:
      type: string
      format: hostname
    avatars:
      type: array
      items:
        $ref: '#/components/schemas/ActorImage'
Actor:
  properties:
    id:
      $ref: '#/components/schemas/id'
    url:
      type: string
      format: url
    name:
      allOf:
        - $ref: '#/components/schemas/username'
    avatars:
      type: array
      items:
        $ref: '#/components/schemas/ActorImage'
    host:
      type: string
      format: hostname
    hostRedundancyAllowed:
      type: boolean
      nullable: true
    followingCount:
      type: integer
      minimum: 0
    followersCount:
      type: integer
      minimum: 0
    createdAt:
      type: string
      format: date-time
    updatedAt:
      type: string
      format: date-time
Account:
  allOf:
    - $ref: '#/components/schemas/Actor'
    - properties:
        userId:
          nullable: true
          allOf:
            - $ref: '#/components/schemas/User/properties/id'
        displayName:
          type: string
          minLength: 3
          maxLength: 120
          type: string
          nullable: true
UserViewingVideo:
  required:
    - currentTime
  properties:
    currentTime:
      type: integer
      format: seconds
      example: 5
    viewEvent:
      type: string
      enum:
        - seek
        Event since last viewing call:
         * `seek` - If the user seeked the video
    sessionId:
      type: string
        Optional param to represent the current viewer session.
        Used by the backend to properly count one view per session per video.
        PeerTube admin can configure the server to not trust this `sessionId` parameter but use the request IP address instead to identify a viewer.
    client:
      type: string
        Client software used to watch the video. For example "Firefox", "PeerTube Approval Android", etc.
    device:
        Device used to watch the video. For example "desktop", "mobile", "smarttv", etc.
      allOf:
        - $ref: '#/components/schemas/VideoStatsUserAgentDevice'
    operatingSystem:
      type: string
        Operating system used to watch the video. For example "Windows", "Ubuntu", etc.

VideoStatsOverall:
  properties:
    averageWatchTime:
      type: number
    totalWatchTime:
      type: number
    viewersPeak:
      type: number
    totalViewers:
      type: number
    viewersPeakDate:
      type: string
      format: date-time
    countries:
      type: array
      items:
        type: object
        properties:
          isoCode:
            type: string
          viewers:
            type: number
    subdivisions:
      type: array
      items:
        type: object
        properties:
          name:
            type: string
          viewers:
            type: number

VideoStatsUserAgentDevice:
  enum:
    - 'console'
    - 'embedded'
    - 'mobile'
    - 'smarttv'
    - 'tablet'
    - 'wearable'
    - 'xr'
    - 'desktop'

VideoStatsUserAgent:
  properties:
    clients:
      type: array
      items:
        type: object
        properties:
          name:
            type: string
          viewers:
            type: number
    devices:
      type: array
      items:
        type: object
        properties:
          name:
            $ref: '#/components/schemas/VideoStatsUserAgentDevice'
          viewers:
            type: number
    operatingSystem:
      type: array
      items:
        type: object
        properties:
          name:
            type: string
          viewers:
            type: number

VideoStatsRetention:
  properties:
    data:
      type: array
      items:
        type: object
        properties:
          second:
            type: number
          retentionPercent:
            type: number

VideoStatsTimeserie:
  properties:
    data:
      type: array
      items:
        type: object
        properties:
          date:
            type: string
          value:
            type: number

ServerConfig:
  properties:
    instance:
      type: object
      properties:
        name:
          type: string
        shortDescription:
          type: string
        defaultClientRoute:
          type: string
        isNSFW:
          type: boolean
        defaultNSFWPolicy:
          type: string
        serverCountry:
          type: string
        defaultLanguage:
          type: string
        support:
          type: object
          properties:
            text:
              type: string
        social:
          type: object
          properties:
            externalLink:
              type: string
            mastodonLink:
              type: string
            blueskyLink:
              type: string
            xLink:
              type: string
        customizations:
          type: object
          properties:
            javascript:
              type: string
            css:
              type: string
        avatars:
          type: array
          items:
            $ref: '#/components/schemas/ActorImage'
        banners:
          type: array
          items:
            $ref: '#/components/schemas/ActorImage'
    search:
      type: object
      properties:
        remoteUri:
          type: object
          properties:
            users:
              type: boolean
            anonymous:
              type: boolean
    plugin:
      type: object
      properties:
        registered:
          type: array
          items:
            type: string
    theme:
      type: object
      properties:
        registered:
          type: array
          items:
            type: string
    email:
      type: object
      properties:
        enabled:
          type: boolean
    contactForm:
      type: object
      properties:
        enabled:
          type: boolean
    serverVersion:
      type: string
    serverCommit:
      type: string
    signup:
      type: object
      properties:
        allowed:
          type: boolean
        allowedForCurrentIP:
          type: boolean
        requiresEmailVerification:
          type: boolean
    transcoding:
      type: object
      properties:
        hls:
          type: object
          properties:
            enabled:
              type: boolean
        web_videos:
          type: object
          properties:
            enabled:
              type: boolean
        enabledResolutions:
          type: array
          items:
            $ref: '#/components/schemas/VideoResolutionSet'
    import:
      type: object
      properties:
        videos:
          type: object
          properties:
            http:
              type: object
              properties:
                enabled:
                  type: boolean
            torrent:
              type: object
              properties:
                enabled:
                  type: boolean
        videoChannelSynchronization:
          type: object
          properties:
            enabled:
              type: boolean
        users:
          type: object
          properties:
            enabled:
              type: boolean
            resumableUpload:
              type: object
              properties:
                minChunkSize:
                  type: number
    export:
      type: object
      properties:
        users:
          type: object
          properties:
            enabled:
              type: boolean
            exportExpiration:
              type: number
            maxUserVideoQuota:
              type: number
    autoBlacklist:
      type: object
      properties:
        videos:
          type: object
          properties:
            ofUsers:
              type: object
              properties:
                enabled:
                  type: boolean
    blocklist:
      type: object
      properties:
        publicLog:
          type: object
          properties:
            enabled:
              type: boolean
    avatar:
      type: object
      properties:
        file:
          type: object
          properties:
            size:
              type: object
              properties:
                max:
                  type: integer
        extensions:
          type: array
          items:
            type: string
    video:
      type: object
      properties:
        image:
          type: object
          properties:
            extensions:
              type: array
              items:
                type: string
            size:
              type: object
              properties:
                max:
                  type: integer
        file:
          type: object
          properties:
            extensions:
              type: array
              items:
                type: string
    videoCaption:
      type: object
      properties:
        file:
          type: object
          properties:
            size:
              type: object
              properties:
                max:
                  type: integer
            extensions:
              type: array
              items:
                type: string
    user:
      type: object
      properties:
        videoQuota:
          type: integer
          example: 16810141515
        videoQuotaDaily:
          type: integer
          example: 1681014151
    trending:
      type: object
      properties:
        videos:
          type: object
          properties:
            intervalDays:
              type: integer
    tracker:
      type: object
      properties:
        enabled:
          type: boolean
    followings:
      type: object
      properties:
        instance:
          type: object
          properties:
            autoFollowIndex:
              type: object
              properties:
                indexUrl:
                  type: string
                  format: url
    federation:
      type: object
      properties:
        enabled:
          type: boolean
    homepage:
      type: object
      properties:
        enabled:
          type: boolean

    openTelemetry:
      type: object
      properties:
        metrics:
          type: object
          properties:
            enabled:
              type: boolean
            playbackStatsInterval:
              type: number
    views:
      type: object
      properties:
        videos:
          type: object
          properties:
            countViewAfter:
              type: number
            watchingInterval:
              type: object
              properties:
                anonymous:
                  type: number
                users:
                  type: number
SendClientLog:
  properties:
    message:
      type: string
    url:
      type: string
    level:
      enum:
        - error
        - warn
    stackTrace:
      type: string
    userAgent:
      type: string
    meta:
      type: string
  required:
    - message
    - url
    - level

ServerStats:
  properties:
    totalUsers:
      type: number
    totalDailyActiveUsers:
      type: number
    totalWeeklyActiveUsers:
      type: number
    totalMonthlyActiveUsers:
      type: number
    totalModerators:
      type: number
    totalAdmins:
      type: number
    totalLocalVideos:
      type: number
    totalLocalVideoViews:
      type: number
    totalLocalVideoDownloads:
      type: number
    totalLocalVideoComments:
      type: number
    totalLocalVideoFilesSize:
      type: number
    totalVideos:
      type: number
    totalVideoComments:
      type: number
    totalLocalVideoChannels:
      type: number
    totalLocalDailyActiveVideoChannels:
      type: number
    totalLocalWeeklyActiveVideoChannels:
      type: number
    totalLocalMonthlyActiveVideoChannels:
      type: number
    totalLocalPlaylists:
      type: number
    totalInstanceFollowers:
      type: number
    totalInstanceFollowing:
      type: number
    videosRedundancy:
      type: array
      items:
        type: object
        properties:
            strategy:
              type: string
            totalSize:
              type: number
            totalUsed:
              type: number
            totalVideoFiles:
              type: number
            totalVideos:
              type: number
    totalActivityPubMessagesProcessed:
      type: number
    totalActivityPubMessagesSuccesses:
      type: number
    totalActivityPubMessagesErrors:
      type: number

    activityPubMessagesProcessedPerSecond:
      type: number
    totalActivityPubMessagesWaiting:
      type: number

    averageRegistrationRequestResponseTimeMs:
      type: number
    totalRegistrationRequestsProcessed:
      type: number
    totalRegistrationRequests:
      type: number
    averageAbuseResponseTimeMs:
      type: number
    totalAbusesProcessed:
      type: number
    totalAbuses:
      type: number
ServerConfigAbout:
  properties:
    instance:
      type: object
      properties:
        name:
          type: string
        shortDescription:
          type: string
          type: string
        terms:
          type: string
        codeOfConduct:
          type: string
        hardwareInformation:
          type: string
        creationReason:
          type: string
        moderationInformation:
          type: string
        administrator:
          type: string
        maintenanceLifetime:
          type: string
        businessModel:
          type: string
        support:
          type: object
          properties:
            text:
              type: string
        languages:
          type: array
          items:
              type: string
        categories:
          type: array
          items:
            type: integer
        avatars:
          type: array
          items:
            $ref: '#/components/schemas/ActorImage'
        banners:
          type: array
          items:
            $ref: '#/components/schemas/ActorImage'
InstanceTranslation:
  properties:
    language:
      type: string
      example: fr-FR
    shortDescription:
      type: string
      type: string
    terms:
      type: string
    codeOfConduct:
      type: string
    moderationInformation:
      type: string
    administrator:
      type: string
    creationReason:
      type: string
    maintenanceLifetime:
      type: string
    businessModel:
      type: string
    hardwareInformation:
      type: string
    supportText:
      type: string
ServerConfigCustom:
  properties:
    instance:
      type: object
      properties:
        name:
          type: string
        shortDescription:
          type: string
          type: string
        terms:
          type: string
        codeOfConduct:
          type: string
        creationReason:
          type: string
        moderationInformation:
          type: string
        administrator:
          type: string
        maintenanceLifetime:
          type: string
        businessModel:
          type: string
        hardwareInformation:
          type: string
        translations:
          type: array
          items:
            $ref: '#/components/schemas/InstanceTranslation'
        languages:
          type: array
          items:
            type: string
        categories:
          type: array
          items:
            type: number
        isNSFW:
          type: boolean
        defaultNSFWPolicy:
          type: string
        serverCountry:
          type: string
        support:
          type: object
          properties:
            text:
              type: string
        social:
          type: object
          properties:
            externalLink:
              type: string
            mastodonLink:
              type: string
            blueskyLink:
              type: string
            xLink:
              type: string
        defaultClientRoute:
          type: string
        customizations:
          type: object
          properties:
            javascript:
              type: string
            css:
              type: string
    theme:
      type: object
      properties:
        default:
          type: string
    services:
      type: object
      properties:
        twitter:
          type: object
          properties:
            username:
              type: string
    cache:
      type: object
      properties:
        previews:
          type: object
          properties:
            size:
              type: integer
        captions:
          type: object
          properties:
            size:
              type: integer
    signup:
      type: object
      properties:
        enabled:
          type: boolean
        limit:
          type: integer
        requiresEmailVerification:
          type: boolean
    admin:
      type: object
      properties:
        email:
          type: string
          format: email
    contactForm:
      type: object
      properties:
        enabled:
          type: boolean
    user:
      type: object
      properties:
        videoQuota:
          type: integer
          example: 16810141515
        videoQuotaDaily:
          type: integer
          example: 1681014151
    transcoding:
      type: object
      properties:
        enabled:
          type: boolean
        originalFile:
          type: object
          properties:
            keep:
              type: boolean
        allowAdditionalExtensions:
          type: boolean
        allowAudioFiles:
          type: boolean
        threads:
          type: integer
        concurrency:
          type: number
        profile:
          type: string
          enum:
            - default
            New profiles can be added by plugins ; available in core PeerTube: 'default'.
        resolutions:
          type: object
          properties:
            0p:
              type: boolean
            144p:
              type: boolean
            240p:
              type: boolean
            360p:
              type: boolean
            480p:
              type: boolean
            720p:
              type: boolean
            1080p:
              type: boolean
            1440p:
              type: boolean
            2160p:
              type: boolean
        web_videos:
          type: object
          properties:
            enabled:
              type: boolean
        hls:
          type: object
          properties:
            enabled:
              type: boolean
            splitAudioAndVideo:
              type: boolean
    import:
      type: object
      properties:
        videos:
          type: object
          properties:
            http:
              type: object
              properties:
                enabled:
                  type: boolean
            torrent:
              type: object
              properties:
                enabled:
                  type: boolean
        video_channel_synchronization:
          type: object
          properties:
            enabled:
              type: boolean
    autoBlacklist:
      type: object
      properties:
        videos:
          type: object
          properties:
            ofUsers:
              type: object
              properties:
                enabled:
                  type: boolean
    blocklist:
      type: object
      properties:
        publicLog:
          type: object
          properties:
            enabled:
              type: boolean
    followers:
      type: object
      properties:
        instance:
          type: object
          properties:
            enabled:
              type: boolean
            manualApproval:
              type: boolean
    storyboard:
      type: object
      properties:
        enabled:
          type: boolean
    defaults:
      type: object
      properties:
        publish:
          type: object
          properties:
            downloadEnabled:
              type: boolean
            commentsPolicy:
              $ref: '#/components/schemas/VideoCommentsPolicySet'
            recommendationScope:
              $ref: '#/components/schemas/VideoRecommendationScopeSet'
            privacy:
              $ref: '#/components/schemas/VideoPrivacySet'
            licence:
              $ref: '#/components/schemas/VideoLicenceSet'
        p2p:
          type: object
          properties:
            webapp:
              type: object
              properties:
                enabled:
                  type: boolean
            embed:
              type: object
              properties:
                enabled:
                  type: boolean
        player:
          type: object
          properties:
            autoPlay:
              type: boolean

CustomHomepage:
  properties:
    content:
      type: string

Follow:
  properties:
    id:
      $ref: '#/components/schemas/id'
    follower:
      $ref: '#/components/schemas/Actor'
    following:
      $ref: '#/components/schemas/Actor'
    score:
      type: number
    state:
      type: string
      enum:
        - pending
        - accepted
    createdAt:
      type: string
      format: date-time
    updatedAt:
      type: string
      format: date-time

PredefinedAbuseReasons:
  type: array
  maxItems: 8
  items:
    type: string
    enum:
    - violentOrAbusive
    - hatefulOrAbusive
    - spamOrMisleading
    - privacy
    - rights
    - serverRules
    - thumbnails
    - captions

JobType:
  type: string
  enum:
    - activitypub-cleaner
    - activitypub-follow
    - activitypub-http-broadcast
    - activitypub-http-broadcast-parallel
    - activitypub-http-fetcher
    - activitypub-http-unicast
    - activitypub-refresher
    - actor-keys
    - after-video-channel-import
    - build-automatic-tags
    - build-object-automatic-tags
    - create-user-export
    - email
    - federate-video
    - generate-video-storyboard
    - import-user-archive
    - manage-video-torrent
    - move-to-file-system
    - move-to-object-storage
    - notify
    - transcoding-job-builder
    - video-channel-import
    - video-file-import
    - video-files-lifecycle
    - video-import
    - video-live-ending
    - video-redundancy
    - video-studio-edition
    - video-transcoding
    - video-transcription
    - videos-stats

Job:
  properties:
    id:
      $ref: '#/components/schemas/id'
    state:
      type: string
      enum:
        - active
        - completed
        - failed
        - waiting
        - delayed
    type:
      $ref: '#/components/schemas/JobType'
    data:
      type: object
      additionalProperties: true
    error:
      type: object
      additionalProperties: true
    createdAt:
      type: string
      format: date-time
    finishedOn:
      type: string
      format: date-time
    processedOn:
      type: string
      format: date-time
    canCancel:
      type: boolean
AddUserResponse:
  properties:
    user:
      type: object
      properties:
        id:
          $ref: '#/components/schemas/id'
        account:
          type: object
          properties:
            id:
              $ref: '#/components/schemas/id'

VideoUploadRequestCommon:
  properties:
    name:
      type: string
      example: What is PeerTube?
      minLength: 3
      maxLength: 120
    channelId:
      type: integer
      example: 3
      minimum: 1
    privacy:
      $ref: '#/components/schemas/VideoPrivacySet'
    category:
      $ref: '#/components/schemas/VideoCategorySet'
    licence:
      $ref: '#/components/schemas/VideoLicenceSet'
    language:
      $ref: '#/components/schemas/VideoLanguageSet'
      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:
      type: boolean
    generateTranscription:
      type: boolean
    support:
      example: Please support our work on https://soutenir.framasoft.org/en/ <3
      type: string
    nsfw:
      type: boolean
    nsfwSummary:
    nsfwFlags:
      $ref: '#/components/schemas/NSFWFlag'
    tags:
      type: array
      minItems: 1
      maxItems: 5
      uniqueItems: true
      example:
        - framasoft
        - peertube
      items:
        type: string
        minLength: 2
        maxLength: 30
    commentsPolicy:
      $ref: '#/components/schemas/VideoCommentsPolicySet'
    recommendationScope:
      $ref: '#/components/schemas/VideoRecommendationScopeSet'
    aiUsage:
      $ref: '#/components/schemas/VideoAIUsageSet'
    commercialContent:
      $ref: '#/components/schemas/VideoCommercialContentSet'
    downloadEnabled:
      type: boolean
    originallyPublishedAt:
      type: string
      format: date-time
    scheduleUpdate:
      $ref: '#/components/schemas/VideoScheduledUpdate'
    thumbnailfile:
      type: string
      format: binary
    previewfile:
      deprecated: true
      type: string
      format: binary
    videoPasswords:
      $ref: '#/components/schemas/AddVideoPasswords'
  required:
    - channelId
    - name
VideoUploadRequestLegacy:
  allOf:
    - $ref: '#/components/schemas/VideoUploadRequestCommon'
    - type: object
      required:
        - videofile
      properties:
        videofile:
          type: string
          format: binary
VideoUploadRequestResumable:
  allOf:
    - $ref: '#/components/schemas/VideoUploadRequestCommon'
    - type: object
      required:
        - filename
      properties:
        filename:
          type: string
          format: filename
          example: what_is_peertube.mp4
        thumbnailfile:
          type: string
          format: binary
        previewfile:
          deprecated: true
          type: string
          format: binary
VideoUploadResponse:
  properties:
    video:
      type: object
      properties:
        id:
          $ref: '#/components/schemas/Video/properties/id'
        uuid:
          $ref: '#/components/schemas/Video/properties/uuid'
        shortUUID:
          $ref: '#/components/schemas/Video/properties/shortUUID'
VideoReplaceSourceRequestResumable:
  properties:
    filename:
      type: string
      format: filename
      example: what_is_peertube.mp4
UserImportResumable:
  properties:
    filename:
      type: string
      format: filename
      example: "user-export-6-2024-02-09T10_12_11.682Z"
CommentThreadResponse:
  properties:
    total:
      type: integer
    totalNotDeletedComments:
      type: integer
    data:
      type: array
      maxItems: 100
      items:
        $ref: '#/components/schemas/VideoComment'
CommentThreadPostResponse:
  properties:
    comment:
      $ref: '#/components/schemas/VideoComment'
VideoTokenResponse:
  properties:
    files:
      type: object
      properties:
        token:
          type: string
        expires:
          type: string
          format: date-time
VideoListResponse:
  properties:
    total:
      type: integer
      example: 1
    data:
      type: array
      maxItems: 100
      items:
        $ref: '#/components/schemas/Video'

ChannelActivityListResponse:
  properties:
    total:
      type: integer
      example: 1
    data:
      type: array
      items:
        type: object
        properties:
          id:
            type: integer
          account:
            nullable: true
            $ref: '#/components/schemas/AccountSummary'
          action:
            type: object
            properties:
              id:
                $ref: '#/components/schemas/VideoChannelActivityAction'
              label:
                type: string
          targetType:
            type: object
            properties:
              id:
                $ref: '#/components/schemas/VideoChannelActivityTarget'
              label:
                type: string
          details:
            type: object
            additionalProperties: true
          createdAt:
            type: string
            format: date-time
          channel:
            type: object
            properties:
              id:
                $ref: '#/components/schemas/id'
              name:
                type: string
              displayName:
                type: string
              url:
                type: string
                format: url
          video:
            nullable: true
            type: object
            properties:
              id:
                $ref: '#/components/schemas/id'
              name:
                type: string
              uuid:
                $ref: '#/components/schemas/UUIDv4'
              shortUUID:
                $ref: '#/components/schemas/shortUUID'
              url:
                type: string
                format: url
              isLive:
                type: boolean
          videoImport:
            nullable: true
            type: object
            properties:
              id:
                $ref: '#/components/schemas/id'
              name:
                type: string
              uuid:
                $ref: '#/components/schemas/UUIDv4'
              shortUUID:
                $ref: '#/components/schemas/shortUUID'
              url:
                type: string
                format: url
              targetUrl:
                type: string
                format: uri
          playlist:
            nullable: true
            type: object
            properties:
              id:
                $ref: '#/components/schemas/id'
              name:
                type: string
              uuid:
                $ref: '#/components/schemas/UUIDv4'
              shortUUID:
                $ref: '#/components/schemas/shortUUID'
              url:
                type: string
                format: url
          channelSync:
            nullable: true
            type: object
            properties:
              id:
                $ref: '#/components/schemas/id'
              externalChannelUrl:
                type: string
                format: uri

UserNotificationSettings:
  properties:
    abuseAsModerator:
      $ref: '#/components/schemas/NotificationSettingValue'
    videoAutoBlacklistAsModerator:
      $ref: '#/components/schemas/NotificationSettingValue'
    newUserRegistration:
      $ref: '#/components/schemas/NotificationSettingValue'

    newVideoFromSubscription:
      $ref: '#/components/schemas/NotificationSettingValue'

    blacklistOnMyVideo:
      $ref: '#/components/schemas/NotificationSettingValue'
    myVideoPublished:
      $ref: '#/components/schemas/NotificationSettingValue'
    myVideoImportFinished:
      $ref: '#/components/schemas/NotificationSettingValue'

    commentMention:
      $ref: '#/components/schemas/NotificationSettingValue'
    newCommentOnMyVideo:
      $ref: '#/components/schemas/NotificationSettingValue'

    newFollow:
      $ref: '#/components/schemas/NotificationSettingValue'
    newInstanceFollower:
      $ref: '#/components/schemas/NotificationSettingValue'
    autoInstanceFollowing:
      $ref: '#/components/schemas/NotificationSettingValue'

    abuseStateChange:
      $ref: '#/components/schemas/NotificationSettingValue'
    abuseNewMessage:
      $ref: '#/components/schemas/NotificationSettingValue'

    newPeerTubeVersion:
      $ref: '#/components/schemas/NotificationSettingValue'
    newPluginVersion:
      $ref: '#/components/schemas/NotificationSettingValue'

    myVideoStudioEditionFinished:
      $ref: '#/components/schemas/NotificationSettingValue'

    myVideoTranscriptionGenerated:
      $ref: '#/components/schemas/NotificationSettingValue'

User:
  properties:
    id:
      $ref: '#/components/schemas/id'
    username:
      $ref: '#/components/schemas/username'
    email:
      type: string
      format: email
    emailVerified:
      type: boolean
    nsfwPolicy:
      $ref: '#/components/schemas/NSFWPolicy'
    nsfwFlagsDisplayed:
      $ref: '#/components/schemas/NSFWFlag'
    nsfwFlagsHidden:
      $ref: '#/components/schemas/NSFWFlag'
    nsfwFlagsWarned:
      $ref: '#/components/schemas/NSFWFlag'
    nsfwFlagsBlurred:
      $ref: '#/components/schemas/NSFWFlag'
    aiUsagesHidden:
      type: array
      items:
        $ref: '#/components/schemas/VideoAIUsageSet'

    adminFlags:
      $ref: '#/components/schemas/UserAdminFlags'

    autoPlayNextVideo:
      type: boolean
    autoPlayNextVideoPlaylist:
      type: boolean
    autoPlayVideo:
      type: boolean
    p2pEnabled:
      type: boolean