diff --git a/dev.yml b/dev.yml
index c22689304a1f05ce201cf05ebbd15af93af17390..c6d48c78ab7cba45d5dfc7c874b1eba5f1f14506 100644
--- a/dev.yml
+++ b/dev.yml
@@ -161,6 +161,7 @@ services:
       - "8002:8080"
     volumes:
       - "./docs/swagger.yml:/usr/share/nginx/html/swagger.yml"
+      - "./docs/api:/usr/share/nginx/html/api"
 
   # minio:
   #   image: minio/minio
diff --git a/docs/api/definitions.yml b/docs/api/definitions.yml
new file mode 100644
index 0000000000000000000000000000000000000000..4903b2c390cf46eb2f0cdc7b40efe5382659b06f
--- /dev/null
+++ b/docs/api/definitions.yml
@@ -0,0 +1,897 @@
+
+
+OAuthApplication:
+  type: "object"
+  properties:
+    client_id:
+      type: "string"
+      example: "VKIZWv7FwBq56UMfUtbCSIgSxzUTv1b6nMyOkJvP"
+    created:
+      type: "string"
+      format: "date-time"
+    updated:
+      type: "string"
+      format: "date-time"
+    scopes:
+      type: "string"
+      description: "Coma-separated list of scopes requested by the app"
+
+OAuthApplicationCreation:
+  type: "object"
+  properties:
+    client_secret:
+      type: "string"
+      example: "qnKDX8zjIfC0BG4tUreKlqk3tNtuCfJdGsaEt5MIWrTv0YLLhGI6SGqCjs9kn12gyXtIg4FWfZqWMEckJmolCi7a6qew4LawPWMfnLDii4mQlY1eQG4BJbwPANOrDiTZ"
+    redirect_uris:
+      type: "string"
+      format: "uri"
+      description: "Coma-separated list of redirect uris allowed for the app"
+
+
+ResultPage:
+  type: "object"
+  properties:
+    count:
+      type: "integer"
+      format: "int64"
+      example: 42
+      description: "The total number of results (all pages included)"
+    next:
+      type: "string"
+      format: "uri"
+      description: "Link to the next page of results"
+    previous:
+      type: "string"
+      format: "uri"
+      description: "Link to the previous page of results"
+
+Attachment:
+  type: "object"
+  properties:
+    uuid:
+      type: string
+      format: uuid
+    size:
+      type: "integer"
+      format: "int64"
+      example: 2787000
+      description: "Size of the file, in bytes"
+    mimetype:
+      $ref: "./properties.yml#image_mimetype"
+    creation_date:
+      type: "string"
+      format: "date-time"
+    urls:
+      type: "object"
+      properties:
+        original:
+          type: "string"
+          description: "URL to the original image"
+          example: "https://mydomain/media/attachments/ec2c53aeaac6.jpg"
+        medium_square_crop:
+          type: "string"
+          description: "URL to a medium, squared thumbnail of the image"
+          example: "https://mydomain/media/__sized__/attachments/ec2c53aeaac6-crop-c0-5__0-5-200x200-70.jpg"
+
+Actor:
+  type: object
+  description: "A federation/ ActivityPub actor"
+  properties:
+    fid:
+      type: string
+      format: uri
+      description: "The actor Federation ID (unique accross federation)"
+    uuid:
+      type: string
+      format: uuid
+      description: "Local ID of the library"
+    creation_date:
+      type: "string"
+      format: "date-time"
+    preferred_username:
+      type: "string"
+      example: "alice"
+    name:
+      type: string
+      example: "Alice Unicorn"
+    last_fetch_date:
+      type: "string"
+      format: "date-time"
+      description: "Last time the actor profile was fetched on its origin server"
+    domain:
+      type: "string"
+      format: "hostname"
+      example: "open.audio"
+    type:
+      type: "string"
+      example: "Person"
+      enum:
+        - Person
+        - Application
+        - Group
+        - Organization
+    manually_approves_followers:
+      type: "boolean"
+    full_username:
+      type: string
+      example: "alice@open.audio"
+
+BaseArtist:
+  type: "object"
+  properties:
+    mbid:
+      required: false
+      $ref: "./properties.yml#mbid"
+    id:
+      type: "integer"
+      format: "int64"
+      example: 42
+    fid:
+      type: string
+      format: uri
+      description: "The artist Federation ID (unique accross federation)"
+    name:
+      type: "string"
+      example: "System of a Down"
+    creation_date:
+      type: "string"
+      format: "date-time"
+    is_local:
+      type: "boolean"
+      description: "Indicates if the object was initally created locally or on another server"
+
+Artist:
+  type: "object"
+  allOf:
+    - $ref: "#/BaseArtist"
+    - type: "object"
+      properties:
+        tracks_count:
+          type: "integer"
+          format: "int64"
+          example: 42
+        albums:
+          type: "array"
+          items:
+            $ref: "#/ArtistAlbum"
+
+BaseAlbum:
+  type: "object"
+  properties:
+    mbid:
+      required: false
+      $ref: "./properties.yml#mbid"
+    id:
+      type: "integer"
+      format: "int64"
+      example: 16
+    fid:
+      type: string
+      format: uri
+      description: "The album Federation ID (unique accross federation)"
+    artist:
+      type: "integer"
+      format: "int64"
+      example: 42
+    title:
+      type: "string"
+      example: "Toxicity"
+    creation_date:
+      type: "string"
+      format: "date-time"
+    release_date:
+      type: "string"
+      required: false
+      format: "date"
+      example: "2001-01-01"
+    is_playable:
+      type: "boolean"
+    cover:
+      $ref: "#/Attachment"
+    is_local:
+      type: "boolean"
+      description: "Indicates if the object was initally created locally or on another server"
+
+Album:
+  type: "object"
+  allOf:
+    - $ref: "#/BaseAlbum"
+    - type: "object"
+      properties:
+        tracks:
+          type: "array"
+          items:
+            $ref: "#/AlbumTrack"
+
+ArtistAlbum:
+  type: "object"
+  allOf:
+    - $ref: "#/BaseAlbum"
+    - type: "object"
+      properties:
+        tracks_count:
+          type: "integer"
+          format: "int64"
+          example: 16
+
+ChannelMetadata:
+  type: "object"
+  properties:
+    itunes_category:
+      type: string
+      example: Comedy
+      description: Itunes category (see `/api/v1/channels/metadata-choices`) for allowed values
+    itunes_subcategory:
+      type: string
+      example: Improv
+      description: Itunes subcategory (see `/api/v1/channels/metadata-choices`) for allowed values
+    language:
+      type: string
+      example: en
+      description: Language of the content, in ISO 639 format (see `/api/v1/channels/metadata-choices`) for allowed values
+    owner_name:
+      type: string
+      example: "Alice"
+      description: Used to make the channel compatible with other platforms (iTunes, Spotify, etc.)
+    owner_email:
+      type: string
+      example: "alice@example.com"
+      description: Used to make the channel compatible with other platforms (iTunes, Spotify, etc.)
+
+ChannelCreate:
+  type: "object"
+  properties:
+    name:
+      type: "string"
+      example: "A short, public name for the channel"
+      maxLength: 255
+    username:
+      type: "string"
+      example: "aliceandbob"
+      description: "The username to associate with the channel, for use over federation. This cannot be changed afterwards."
+    description:
+      $ref: "./properties.yml#description"
+    tags:
+      $ref: "./properties.yml#tags"
+    content_category:
+      $ref: "./properties.yml#content_category"
+    cover:
+      type: string
+      format: uuid
+    metadata:
+      $ref: "#ChannelMetadata"
+ChannelUpdate:
+  type: "object"
+  properties:
+    name:
+      type: "string"
+      example: "A short, public name for the channel"
+      maxLength: 255
+    description:
+      $ref: "./properties.yml#description"
+    tags:
+      $ref: "./properties.yml#tags"
+    cover:
+      type: string
+      format: uuid
+    metadata:
+      $ref: "#/ChannelMetadata"
+
+Channel:
+  type: "object"
+  properties:
+    uuid:
+      type: "string"
+      format: "uuid"
+    creation_date:
+      $ref: "./properties.yml#creation_date"
+    artist:
+      $ref: "#/BaseArtist"
+    attributed_to:
+      $ref: "#/Actor"
+      description: User account owning the channel
+    actor:
+      $ref: "#/Actor"
+      description: Actor representing the channel over federation
+
+Subscription:
+  type: "object"
+  properties:
+    approved:
+      type: "string"
+    fid:
+      $ref: "./properties.yml#fid"
+    uuid:
+      type: "string"
+      format: "uuid"
+    creation_date:
+      $ref: "./properties.yml#creation_date"
+    channel:
+      $ref: "#/Channel"
+
+SubscriptionsAll:
+  type: "object"
+  properties:
+    uuid:
+      type: "string"
+      format: "uuid"
+    channel:
+      type: "string"
+      format: "uuid"
+
+Library:
+  type: "object"
+  properties:
+    fid:
+      type: string
+      format: uri
+      description: "The library Federation ID (unique accross federation)"
+    uuid:
+      type: string
+      format: uuid
+      description: "Local ID of the library"
+    name:
+      type: string
+      example: "My awesome library"
+    description:
+      type: string
+      nullable: true
+      example: "This library contains all the stuff I love!"
+    uploads_count:
+      type: "integer"
+      format: "int64"
+      example: 687
+    privacy_level:
+      type: string
+      example: "me"
+      enum:
+        - "me"
+        - "instance"
+        - "everyone"
+    actor:
+      $ref: "#/Actor"
+LibraryPage:
+  allOf:
+    - $ref: "#/ResultPage"
+    - type: "object"
+      properties:
+        results:
+          type: "array"
+          items:
+            $ref: "#/Library"
+
+License:
+  type: "object"
+  properties:
+    id:
+      type: string
+      format: uri
+      example: http://creativecommons.org/publicdomain/zero/1.0/
+      description: "The license ID"
+    url:
+      type: string
+      format: uri
+      example: http://creativecommons.org/publicdomain/zero/1.0/
+      description: "The license url (can be different than the ID)"
+    code:
+      type: string
+      description: "A unique code to identify the license"
+      example: cc0-1.0
+    redistribute:
+      type: boolean
+      example: true
+      description: "Does the license allow free redistribution?"
+    derivative:
+      type: boolean
+      example: true
+      description: "Does the license allow the creation of derivative work?"
+    commercial:
+      type: boolean
+      example: true
+      description: "Does the license allow commercial use?"
+    attribution:
+      type: boolean
+      example: false
+      description: "Does the license requires crediting the author?"
+    copyleft:
+      type: boolean
+      example: false
+      description: "Does the license enforce a similar license of derivative work?"
+
+BaseTrack:
+  type: "object"
+  properties:
+    mbid:
+      required: false
+      $ref: "./properties.yml#mbid"
+    id:
+      type: "integer"
+      format: "int64"
+      example: 66
+    fid:
+      type: string
+      format: uri
+      description: "The track Federation ID (unique accross federation)"
+    artist:
+      type: "integer"
+      format: "int64"
+      example: 42
+    album:
+      type: "integer"
+      format: "int64"
+      example: 16
+    title:
+      type: "string"
+      example: "Chop Suey!"
+    position:
+      required: false
+      description: "Position of the track in the album"
+      type: "number"
+      minimum: 1
+      example: 1
+    disc_number:
+      required: false
+      type: "number"
+      minimum: 1
+      example: 1
+    listen_url:
+      type: "string"
+      format: "uri"
+      description: "URL to stream the track"
+    copyright:
+      type: "string"
+      example: "Creative Commons Attribution-NonCommercial-NoDerivatives 4.0: http://creativecommons.org/licenses/by-nc-nd/4.0/"
+      description: "Copyright information as extracted from upload tags"
+    license:
+      type: "string"
+      description: "Identifier of the license that is linked to the track"
+      example: "cc-by-nc-nd-4.0"
+    is_local:
+      type: "boolean"
+      description: "Indicates if the object was initally created locally or on another server"
+
+AlbumTrack:
+  type: "object"
+  allOf:
+    - $ref: "#/BaseTrack"
+    - type: "object"
+      properties:
+        artist:
+          $ref: "#/BaseArtist"
+        uploads:
+          type: "array"
+          description: "List of uploads associated with this track"
+          items:
+            $ref: "#/Upload"
+Track:
+  type: "object"
+  allOf:
+    - $ref: "#/BaseTrack"
+    - type: "object"
+      properties:
+        album:
+          $ref: "#/Album"
+        artist:
+          $ref: "#/BaseArtist"
+        uploads:
+          type: "array"
+          description: "List of uploads associated with this track"
+          items:
+            $ref: "#/Upload"
+Upload:
+  type: "object"
+  properties:
+    uuid:
+      type: string
+      format: uuid
+    size:size:
+      type: "integer"
+      format: "int64"
+      example: 278987000
+      description: "Size of the file, in bytes"
+    duration:
+      type: "integer"
+      format: "int64"
+      example: 184
+      description: "Duration of the audio, in seconds"
+    bitrate:
+      type: "integer"
+      format: "int64"
+      example: 128000
+      description: "Bitrate of the file, in bytes/s"
+    mimetype:
+      $ref: "./properties.yml#audio_mimetype"
+    extension:
+      type: string
+      example: "ogg"
+      description: "File extension of the upload"
+    filename:
+      type: "string"
+      example: "Myfile.mp3"
+    listen_url:
+      type: "string"
+      format: "uri"
+      description: "URL to stream the upload"
+
+OwnedLibraryCreate:
+  type: "object"
+  properties:
+    name:
+      type: "string"
+      example: "My new library"
+    description:
+      required: false
+      type: "string"
+      example: "Lots of interesting content"
+    privacy_level:
+      $ref: "./properties.yml#privacy_level"
+
+OwnedLibrary:
+  type: "object"
+  properties:
+    uuid:
+      type: string
+      format: uuid
+    fid:
+      $ref: "./properties.yml#fid"
+    name:
+      type: "string"
+      example: "My Creative Commons library"
+    description:
+      type: "string"
+      example: "All content is under CC-BY"
+    creation_date:
+      $ref: "./properties.yml#creation_date"
+    privacy_level:
+      $ref: "./properties.yml#privacy_level"
+    uploads_count:
+      type: "integer"
+      format: "int64"
+      example: 34
+    size:
+      type: "integer"
+      format: "int64"
+      example: 678917000
+      description: "Total size of uploads in the library, in bytes"
+
+OwnedUpload:
+  type: "object"
+  allOf:
+    - $ref: "#/Upload"
+    - type: "object"
+      properties:
+        import_status:
+          $ref: "./properties.yml#import_status"
+        track:
+          $ref: "#/Track"
+        library:
+          $ref: "#/OwnedLibrary"
+        source:
+          type: "string"
+          example: "upload://myfile.mp3"
+        import_reference:
+          type: "string"
+          example: "Import launched via web UI on 03/18"
+        import_metadata:
+          $ref: "#/ImportMetadata"
+
+Playlist:
+  type: "object"
+  properties:
+    id:
+      type: "integer"
+      format: "int64"
+      example: 42
+    name:
+      type: "string"
+      description: Name of the playlist
+      example: "Move your body"
+    duration:
+      type: "integer"
+      format: "int64"
+      description: Duration of the playlist, in seconds
+      example: 3600
+    tracks_count:
+      type: "integer"
+      format: "int64"
+      description: Number of tracks in the playlist
+      example: 76
+    privacy_level:
+      $ref: "./properties.yml#privacy_level"
+    actor:
+      $ref: "#/Actor"
+      description: Actor owning the playlist
+    creation_date:
+      $ref: "./properties.yml#creation_date"
+    modification_date:
+      $ref: "./properties.yml#modification_date"
+
+
+PlaylistCreate:
+  type: "object"
+  properties:
+    name:
+      type: "string"
+      description: Name of the playlist
+      example: "Move your body"
+    privacy_level:
+      $ref: "./properties.yml#privacy_level"
+
+PlaylistTrack:
+  type: "object"
+  properties:
+    id:
+      type: "integer"
+      format: "int64"
+      example: 42
+    index:
+      type: "integer"
+      format: "int64"
+      example: 16
+      description: Position of the track in the playlist
+    creation_date:
+      $ref: "./properties.yml#creation_date"
+    track:
+      $ref: "#/Track"
+
+ImportMetadata:
+  type: "object"
+  description: "Import metadata to override values from ID3/embedded audio tags"
+  properties:
+    title:
+      type: "string"
+      example: "My Track"
+      required: true
+    mbid:
+      $ref: "./properties.yml#mbid"
+      required: false
+    copyright:
+      type: "string"
+      example: "Alice, 2018"
+      description: "Copyright information"
+      required: false
+    license:
+      type: "string"
+      example: "cc-by-sa-4.0"
+      required: false
+      description: A license code, as returned by /api/v1/licenses
+    tags:
+      $ref: "./properties.yml#tags"
+      required: false
+    position:
+      description: "Position of the track in the album or channel"
+      type: "number"
+      minimum: 1
+      example: 1
+
+TrackFavorite:
+  type: "object"
+  properties:
+    id:
+      type: "integer"
+      format: "int64"
+      example: 876
+    track:
+      $ref: "#/Track"
+    user:
+      $ref: "#/User"
+    creation_date:
+      $ref: "./properties.yml#creation_date"
+User:
+  type: "object"
+  properties:
+    id:
+      type: "integer"
+      format: "int64"
+      example: 23
+    username:
+      type: "string"
+      example: "alice"
+    name:
+      type: "string"
+      example: "Alice Kingsley"
+    avatar:
+      $ref: "#/Avatar"
+
+Me:
+  type: "object"
+  allOf:
+    - $ref: "#/User"
+    - type: "object"
+      properties:
+        full_username:
+          type: "string"
+          description: Full username, for use on federation
+          example: "alice@yourdomain.com"
+        email:
+          type: "string"
+          format: "email"
+          description: Email address associated with the account
+          example: "alice@email.provider"
+        is_staff:
+          type: "boolean"
+          example: false
+        is_superuser:
+          type: "boolean"
+          example: false
+        date_joined:
+          type: "string"
+          format: "date-time"
+        privacy_level:
+          $ref: "./properties.yml#privacy_level"
+          description: Default privacy-level associated with the user account
+        quota_status:
+          $ref: "#/QuotaStatus"
+        permissions:
+          $ref: "#/Permissions"
+        tokens:
+          type: object
+          properties:
+            listen:
+              type: string
+              description: |
+                A token that can be passed in the querystring, when playing
+                a file from the /api/v1/listen endpoint. Example:
+                  /api/v1/listen/uuid/?token=foo
+
+                This is especially useful in situations where authentication
+                via request headers isn't possible.
+
+                The token expires after 3 days by default.
+Avatar:
+  type: "object"
+  properties:
+    original:
+      type: "string"
+      format: "uri"
+      description: "Original image URL"
+      example: "http://yourinstance/media/users/avatars/92/49/60/b3c-4736-43b3-bb5c-ed7a99ac6996.jpg"
+    square_crop:
+      type: "string"
+      format: "uri"
+      description: "400x400 thumbnail URL"
+      example: "http://yourinstance/media/__sized__/users/avatars/92/49/60/b3c-4736-43b3-bb5c-ed7a99ac6996-crop-c0-5__0-5-400x400-70.jpg"
+    small_square_crop:
+      type: "string"
+      format: "uri"
+      description: "50x50 thumbnail URL"
+      example: "http://yourinstance/media/__sized__/users/avatars/92/49/60/b3c-4736-43b3-bb5c-ed7a99ac6996-crop-c0-5__0-5-50x50-70.jpg"
+    medium_square_crop:
+      type: "string"
+      format: "uri"
+      description: "200x200 thumbnail URL"
+      example: "http://yourinstance/media/__sized__/users/avatars/92/49/60/b3c-4736-43b3-bb5c-ed7a99ac6996-crop-c0-5__0-5-200x200-70.jpg"
+QuotaStatus:
+  type: "object"
+  properties:
+    max:
+      type: "integer"
+      format: "int64"
+      description: Storage space allocated to this user, in MB
+      example: 5000
+    remaining:
+      type: "integer"
+      format: "int64"
+      description: Remaining storage space for this user, in MB
+      example: 4600
+    current:
+      type: "integer"
+      format: "int64"
+      description: Storage space used by this user, in MB
+      example: 400
+    skipped:
+      type: "integer"
+      format: "int64"
+      description: Storage space occupied by uploads with "skipped" import status, in MB
+      example: 30
+    finished:
+      type: "integer"
+      format: "int64"
+      description: Storage space occupied by uploads with "finished" import status, in MB
+      example: 350
+    pending:
+      type: "integer"
+      format: "int64"
+      description: Storage space occupied by uploads with "pending" import status, in MB
+      example: 15
+    draft:
+      type: "integer"
+      format: "int64"
+      description: Storage space occupied by uploads with "draft" import status, in MB
+      example: 8
+    errored:
+      type: "integer"
+      format: "int64"
+      description: Storage space occupied by uploads with "errored" import status, in MB
+      example: 5
+Permissions:
+  type: "object"
+  properties:
+    library:
+      type: "boolean"
+      example: false
+      description: A boolean indicating if the user can manage the instance library
+    moderation:
+      type: "boolean"
+      example: false
+      description: A boolean indicating if the user has moderation permission
+    settings:
+      type: "boolean"
+      example: false
+      description: A boolean indicating if the user can manage instance settings and users
+RateLimitStatus:
+  type: "object"
+  properties:
+    enabled:
+      type: "boolean"
+      example: true
+      description: A boolean indicating if rate-limiting is enabled on the server
+    ident:
+      type: "object"
+      description: Client-related data
+      properties:
+        type:
+          type: string
+          example: "anonymous"
+          enum:
+            - "authenticated"
+            - "anonymous"
+        id:
+          type: string
+          example: "92.143.42"
+          description: An address IP or user ID identifying the client
+    scopes:
+      type: "array"
+      items:
+        type: "object"
+        description: Rate-limit scope configuration and usage
+        properties:
+          id:
+            type: string
+            example: "password-reset"
+          description:
+            type: string
+            example: "Password reset request"
+          rate:
+            type: string
+            example: "30/day"
+          limit:
+            type: "integer"
+            format: "int64"
+            example: 30
+          duration:
+            type: "integer"
+            format: "int64"
+            example: 86400
+          remaining:
+            type: "integer"
+            format: "int64"
+            example: 28
+            description: How many requests can be sent with the same scope before the limit applies
+          reset:
+            type: "integer"
+            format: "int64"
+            example: 1568126189
+            description: A timestamp indicating when <code>remaining</code> will return to its higher possible value
+          reset_seconds:
+            type: "integer"
+            format: "int64"
+            example: 86267
+            description: How many seconds to wait before <code>remaining</code> returns to its higher possible value
+          available:
+            type: "integer"
+            format: "int64"
+            example: 1568126089
+            description: A timestamp indicating when the client can retry
+          available_seconds:
+            type: "integer"
+            format: "int64"
+            example: 54
+            description: How many seconds to wait before a retry
+
+ResourceNotFound:
+  type: "object"
+  properties:
+    detail:
+      type: "string"
+      example: "Not found."
diff --git a/docs/api/parameters.yml b/docs/api/parameters.yml
new file mode 100644
index 0000000000000000000000000000000000000000..3562845872d3a52433cc2b796831c9f3af39ce2d
--- /dev/null
+++ b/docs/api/parameters.yml
@@ -0,0 +1,136 @@
+ChannelOrdering:
+  - $ref: "#/parameters/Ordering"
+  - default: "-creation_date"
+    schema:
+      required: false
+      type: "string"
+      example: "-creation_date"
+      enum:
+        - creation_date
+        - artist__modification_date
+
+External:
+  name: "external"
+  in: "query"
+  default: null
+  description: "Filter/exclude channels created from a third-party, non-Funkwhale RSS feed"
+  schema:
+    required: false
+    type: "boolean"
+
+
+Library:
+  name: library
+  in: query
+  description: Restrict to results contained in the given library
+  schema:
+    type: string
+    format: uuid
+  
+ObjectId:
+  name: id
+  in: path
+  description: Object ID
+  required: true
+  schema:
+    type: integer
+    format: int64
+Ordering:
+  name: "ordering"
+  in: "query"
+  description: "Ordering for the results, prefix with - for DESC ordering"
+
+PageNumber:
+  in: query
+  name: page
+  schema:
+    type: "integer"
+    format: "int64"
+    example: 1
+    default: 1
+    minimum: 1
+PageSize:
+  in: query
+  name: page_size
+  schema:
+    type: "integer"
+    format: "int64"
+    example: 16
+    default: 25
+    minimum: 1
+    maximum: 25
+Playable:
+  name: "playable"
+  in: "query"
+  default: null
+  description: "Filter/exclude resources with playable tracks"
+  schema:
+    required: false
+    type: "boolean"
+Refresh:
+  name: "refresh"
+  in: "query"
+  default: false
+  description: "Trigger an ActivityPub fetch to refresh local data"
+  schema:
+    required: false
+    type: "boolean"
+
+
+Related:
+  name: related
+  in: query
+  description: Restrict to results similar to the given object (based on tags)
+  schema:
+    type: integer
+    format: int64
+
+    
+Scope:
+  name: "scope"
+  in: "query"
+  default: "all"
+  description: |
+    Limit the results to a given user or pod:
+      - Use `all` (or do not specify the property to disable scope filtering)
+      - Use `me` to retrieve content relative to the current user
+      - Use `actor:alice@example.com` to retrieve content relative to the account `alice@example.com
+      - Use `domain:example.com` to retrieve content relative to the domain `example.com
+  schema:
+    required: false
+    type: "string"
+    enum:
+    - "me"
+    - "all"
+    - "actor:alice@example.com"
+    - "domain:example.com"
+
+Search:
+  name: "q"
+  in: "query"
+  default: "all"
+  description: "Limit the results to the corresponding search query"
+  schema:
+    required: false
+    type: "string"
+    example: "Bonobo"
+
+Subscribed:
+  name: "subscribed"
+  in: "query"
+  description: "Limit or exclude results with a matching subsription from the current user"
+  schema:
+    required: false
+    type: boolean
+
+Tags:
+  name: "tag"
+  in: "query"
+  description: "Limit the results to the corresponding tags. May be used multiple times, to retrieve objects matching al provided tags"
+  schema:
+    required: false
+    type: array
+    collectionFormat: csv
+    example:
+      - rock
+      - metal
\ No newline at end of file
diff --git a/docs/api/properties.yml b/docs/api/properties.yml
new file mode 100644
index 0000000000000000000000000000000000000000..1133a0937e33373d5a24fce8535dccfbb4a37ae3
--- /dev/null
+++ b/docs/api/properties.yml
@@ -0,0 +1,100 @@
+
+description:
+  type: object
+  description: Text content associated with another resource, like and artist or channel.
+  properties:
+    text:
+      type: string
+      example: "This is **me**"
+      description: "The raw user input"
+    content_type:
+      type: string
+      enum:
+        - text/markdown
+        - text/plain
+        - text/html
+      description: "The raw user input"
+    html:
+      type: string
+      description: "HTML output based on user input"
+      readOnly: true
+
+mbid:
+  type: "string"
+  format: "uuid"
+  description: "A musicbrainz ID"
+creation_date:
+  type: "string"
+  format: "date-time"
+  description: "Creation date of the resource"
+
+modification_date:
+  type: "string"
+  format: "date-time"
+  description: "Last modification date of th resource"
+privacy_level:
+  type: string
+  example: "me"
+  description: |
+    * `me`: private
+    * `instance`: accessible by local users
+    * `everyone`: public (including over federation)
+  enum:
+    - "me"
+    - "instance"
+    - "everyone"
+fid:
+  type: "string"
+  format: "uri"
+  description: "Federation ID"
+  example: "https://my.instance/federation/music/libraries/3fa85f64-5717-4562-b3fc-2c963f66afa6"
+audio_mimetype:
+  type: string
+  example: "audio/ogg"
+  enum:
+    - "audio/ogg"
+    - "audio/mpeg"
+    - "audio/x-flac"
+    - "audio/flac"
+image_mimetype:
+  type: string
+  example: "image/png"
+  enum:
+    - "image/png"
+    - "image/jpeg"
+import_status:
+  type: string
+  example: "finished"
+  enum:
+    - "draft"
+    - "pending"
+    - "finished"
+    - "errored"
+    - "skipped"
+  description: |
+    * `draft`: waiting for further modifications from the owner
+    * `pending`: waiting to be processed by the server
+    * `finished`: successfully processed by the server
+    * `errored`: couldn't be processed by the server (e.g because of a tagging issue)
+    * `skipped`: processed by the server but skipped, because considered as a duplicate of an existing upload
+
+transcode_options:
+  type: string
+  enum:
+    - "ogg"
+    - "mp3"
+
+tags:
+  type: array
+  description: A list of hashtags associated with a resource
+  items:
+    type: string
+    example: "Rock"
+
+content_category:
+  type: "string"
+  description: Used to what kind of content is published in a chanel
+  enum:
+    - music
+    - podcast
+    - other
diff --git a/docs/build_swagger.sh b/docs/build_swagger.sh
index 13ae21b065856e864f3798f9498afd897e3ef265..8c0d32e55315f2bf52c39d1c0b9eb7afc0313ce8 100755
--- a/docs/build_swagger.sh
+++ b/docs/build_swagger.sh
@@ -6,4 +6,5 @@ rm -rf $TARGET_PATH /tmp/swagger-ui
 git clone --branch="v$SWAGGER_VERSION" --depth=1 "https://github.com/swagger-api/swagger-ui.git" /tmp/swagger-ui
 mv /tmp/swagger-ui/dist $TARGET_PATH
 cp swagger.yml $TARGET_PATH
+cp -r api $TARGET_PATH/api
 sed -i "s,http://petstore.swagger.io/v2/swagger.json,swagger.yml,g" $TARGET_PATH/index.html
diff --git a/docs/swagger.yml b/docs/swagger.yml
index 7460b9e6430f60175da3678c4cf5c79a39603af5..0f002bda1366dc368afef60c6bdd2b611bb5c966 100644
--- a/docs/swagger.yml
+++ b/docs/swagger.yml
@@ -1,7 +1,6 @@
 # Undocumented endpoints:
 #  /api/v1/settings
 #  /api/v1/activity
-#  /api/v1/playlists
 #  /api/v1/playlist-tracks
 #  /api/v1/search
 #  /api/v1/radios
@@ -205,8 +204,8 @@ paths:
             application/json:
               schema:
                 allOf:
-                  - $ref: "#/definitions/OAuthApplication"
-                  - $ref: "#/definitions/OAuthApplicationCreation"
+                  - $ref: "./api/definitions.yml#OAuthApplication"
+                  - $ref: "./api/definitions.yml#OAuthApplicationCreation"
       requestBody:
         required: true
         content:
@@ -323,7 +322,7 @@ paths:
           content:
             application/json:
               schema:
-                $ref: "#/definitions/Me"
+                $ref: "./api/definitions.yml#Me"
 
   /api/v1/rate-limit/:
     get:
@@ -336,7 +335,7 @@ paths:
           content:
             application/json:
               schema:
-                $ref: "#/definitions/RateLimitStatus"
+                $ref: "./api/definitions.yml#RateLimitStatus"
 
   /api/v1/artists/:
     get:
@@ -348,9 +347,9 @@ paths:
           - "read:libraries"
       parameters:
 
-        - $ref: "#/parameters/Search"
+        - $ref: "./api/parameters.yml#Search"
         - allOf:
-            - $ref: "#/parameters/Ordering"
+            - $ref: "./api/parameters.yml#Ordering"
             - default: "-creation_date"
               schema:
                 required: false
@@ -361,32 +360,31 @@ paths:
                   - id
                   - name
                   - random
-        - $ref: "#/parameters/Playable"
-        - $ref: "#/parameters/Library"
-        - $ref: "#/parameters/PageNumber"
-        - $ref: "#/parameters/PageSize"
-        - $ref: "#/parameters/Related"
-        - $ref: "#/parameters/Scope"
-
+        - $ref: "./api/parameters/Playable"
+        - $ref: "./api/parameters/Library"
+        - $ref: "./api/parameters/PageNumber"
+        - $ref: "./api/parameters/PageSize"
+        - $ref: "./api/parameters/Related"
+        - $ref: "./api/parameters/Scope"
       responses:
         200:
           content:
             application/json:
               schema:
                 allOf:
-                  - $ref: "#/definitions/ResultPage"
+                  - $ref: "./api/definitions.yml#ResultPage"
                   - type: "object"
                     properties:
                       results:
                         type: "array"
                         items:
-                          $ref: "#/definitions/Artist"
+                          $ref: "./api/definitions.yml#Artist"
   /api/v1/artists/{id}/:
     get:
       summary: Retrieve a single artist
       parameters:
-        - $ref: "#/parameters/ObjectId"
-        - $ref: "#/parameters/Refresh"
+        - $ref: "./api/parameters.yml#ObjectId"
+        - $ref: "./api/parameters.yml#Refresh"
       security:
         - oauth2:
           - "read:libraries"
@@ -397,12 +395,12 @@ paths:
           content:
             application/json:
               schema:
-                $ref: "#/definitions/Artist"
+                $ref: "./api/definitions.yml#Artist"
         404:
           content:
             application/json:
               schema:
-                $ref: "#/definitions/ResourceNotFound"
+                $ref: "./api/definitions.yml#ResourceNotFound"
   /api/v1/artists/{id}/libraries/:
     get:
       summary: List available user libraries containing work from this artist
@@ -410,9 +408,9 @@ paths:
         - oauth2:
           - "read:libraries"
       parameters:
-        - $ref: "#/parameters/ObjectId"
-        - $ref: "#/parameters/PageNumber"
-        - $ref: "#/parameters/PageSize"
+        - $ref: "./api/parameters.yml#ObjectId"
+        - $ref: "./api/parameters.yml#PageNumber"
+        - $ref: "./api/parameters.yml#PageSize"
 
       tags:
         - "Library and metadata"
@@ -421,12 +419,12 @@ paths:
           content:
             application/json:
               schema:
-                $ref: "#/definitions/LibraryPage"
+                $ref: "./api/definitions.yml#LibraryPage"
         404:
           content:
             application/json:
               schema:
-                $ref: "#/definitions/ResourceNotFound"
+                $ref: "./api/definitions.yml#ResourceNotFound"
 
   /api/v1/albums/:
     get:
@@ -439,7 +437,7 @@ paths:
           - "read:libraries"
       parameters:
 
-        - $ref: "#/parameters/Search"
+        - $ref: "./api/parameters.yml#Search"
         - name: "artist"
           in: "query"
           default: null
@@ -449,7 +447,7 @@ paths:
             type: "integer"
             format: "int64"
         - allOf:
-            - $ref: "#/parameters/Ordering"
+            - $ref: "./api/parameters.yml#Ordering"
             - default: "-creation_date"
               schema:
                 required: false
@@ -460,12 +458,12 @@ paths:
                   - release_date
                   - title
                   - random
-        - $ref: "#/parameters/Library"
-        - $ref: "#/parameters/Playable"
-        - $ref: "#/parameters/PageNumber"
-        - $ref: "#/parameters/PageSize"
-        - $ref: "#/parameters/Related"
-        - $ref: "#/parameters/Scope"
+        - $ref: "./api/parameters/Library"
+        - $ref: "./api/parameters/Playable"
+        - $ref: "./api/parameters/PageNumber"
+        - $ref: "./api/parameters/PageSize"
+        - $ref: "./api/parameters/Related"
+        - $ref: "./api/parameters/Scope"
 
       responses:
         200:
@@ -473,19 +471,19 @@ paths:
             application/json:
               schema:
                 allOf:
-                  - $ref: "#/definitions/ResultPage"
+                  - $ref: "./api/definitions.yml#ResultPage"
                   - type: "object"
                     properties:
                       results:
                         type: "array"
                         items:
-                          $ref: "#/definitions/Album"
+                          $ref: "./api/definitions.yml#Album"
   /api/v1/albums/{id}/:
     get:
       summary: Retrieve a single album
       parameters:
-        - $ref: "#/parameters/ObjectId"
-        - $ref: "#/parameters/Refresh"
+        - $ref: "./api/parameters.yml#ObjectId"
+        - $ref: "./api/parameters.yml#Refresh"
 
       security:
         - oauth2:
@@ -497,20 +495,20 @@ paths:
           content:
             application/json:
               schema:
-                $ref: "#/definitions/Album"
+                $ref: "./api/definitions.yml#Album"
         404:
           content:
             application/json:
               schema:
-                $ref: "#/definitions/ResourceNotFound"
+                $ref: "./api/definitions.yml#ResourceNotFound"
 
   /api/v1/albums/{id}/libraries/:
     get:
       summary: List available user libraries containing tracks from this album
       parameters:
-        - $ref: "#/parameters/ObjectId"
-        - $ref: "#/parameters/PageNumber"
-        - $ref: "#/parameters/PageSize"
+        - $ref: "./api/parameters.yml#ObjectId"
+        - $ref: "./api/parameters.yml#PageNumber"
+        - $ref: "./api/parameters.yml#PageSize"
 
       security:
         - oauth2:
@@ -522,12 +520,12 @@ paths:
           content:
             application/json:
               schema:
-                $ref: "#/definitions/LibraryPage"
+                $ref: "./api/definitions.yml#LibraryPage"
         404:
           content:
             application/json:
               schema:
-                $ref: "#/definitions/ResourceNotFound"
+                $ref: "./api/definitions.yml#ResourceNotFound"
 
   /api/v1/tracks/:
     get:
@@ -540,7 +538,7 @@ paths:
           - "read:libraries"
       parameters:
 
-        - $ref: "#/parameters/Search"
+        - $ref: "./api/parameters.yml#Search"
         - name: "artist"
           in: "query"
           default: null
@@ -573,7 +571,7 @@ paths:
             required: false
             type: "string"
         - allOf:
-            - $ref: "#/parameters/Ordering"
+            - $ref: "./api/parameters.yml#Ordering"
             - default: "-creation_date"
               schema:
                 required: false
@@ -584,12 +582,12 @@ paths:
                   - release_date
                   - title
                   - random
-        - $ref: "#/parameters/Library"
-        - $ref: "#/parameters/Playable"
-        - $ref: "#/parameters/PageNumber"
-        - $ref: "#/parameters/PageSize"
-        - $ref: "#/parameters/Related"
-        - $ref: "#/parameters/Scope"
+        - $ref: "./api/parameters/Library"
+        - $ref: "./api/parameters/Playable"
+        - $ref: "./api/parameters/PageNumber"
+        - $ref: "./api/parameters/PageSize"
+        - $ref: "./api/parameters/Related"
+        - $ref: "./api/parameters/Scope"
 
       responses:
         200:
@@ -597,18 +595,18 @@ paths:
             application/json:
               schema:
                 allOf:
-                  - $ref: "#/definitions/ResultPage"
+                  - $ref: "./api/definitions.yml#ResultPage"
                   - type: "object"
                     properties:
                       results:
                         type: "array"
                         items:
-                          $ref: "#/definitions/Track"
+                          $ref: "./api/definitions.yml#Track"
   /api/v1/tracks/{id}/:
     get:
       parameters:
-        - $ref: "#/parameters/ObjectId"
-        - $ref: "#/parameters/Refresh"
+        - $ref: "./api/parameters.yml#ObjectId"
+        - $ref: "./api/parameters.yml#Refresh"
       summary: Retrieve a single track
 
       security:
@@ -621,20 +619,20 @@ paths:
           content:
             application/json:
               schema:
-                $ref: "#/definitions/Track"
+                $ref: "./api/definitions.yml#Track"
         404:
           content:
             application/json:
               schema:
-                $ref: "#/definitions/ResourceNotFound"
+                $ref: "./api/definitions.yml#ResourceNotFound"
 
   /api/v1/tracks/{id}/libraries/:
     get:
       summary: List available user libraries containing given track
       parameters:
-        - $ref: "#/parameters/ObjectId"
-        - $ref: "#/parameters/PageNumber"
-        - $ref: "#/parameters/PageSize"
+        - $ref: "./api/parameters.yml#ObjectId"
+        - $ref: "./api/parameters.yml#PageNumber"
+        - $ref: "./api/parameters.yml#PageSize"
       security:
         - oauth2:
           - "read:libraries"
@@ -645,12 +643,12 @@ paths:
           content:
             application/json:
               schema:
-                $ref: "#/definitions/LibraryPage"
+                $ref: "./api/definitions.yml#LibraryPage"
         404:
           content:
             application/json:
               schema:
-                $ref: "#/definitions/ResourceNotFound"
+                $ref: "./api/definitions.yml#ResourceNotFound"
   /api/v1/listen/{uuid}/:
     get:
       summary: Download the audio file matching the given track uuid
@@ -682,7 +680,7 @@ paths:
 
             This endpoint support bytess-range requests.
           schema:
-            $ref: "#/properties/transcode_options"
+            $ref: "./api/properties.yml#transcode_options"
         - name: upload
           in: query
           required: false
@@ -695,6 +693,16 @@ paths:
           schema:
             type: string
             format: uuid
+        - name: token
+          in: query
+          required: false
+          description: |
+            A listen token as returned by /users/me
+
+            This offers an alternative authentication method for situations where HTTP headers
+            can't be modified to include a Bearer token.
+          schema:
+            type: string
 
       tags:
         - "Library and metadata"
@@ -710,7 +718,7 @@ paths:
           content:
             application/json:
               schema:
-                $ref: "#/definitions/ResourceNotFound"
+                $ref: "./api/definitions.yml#ResourceNotFound"
 
   /api/v1/licenses/:
     get:
@@ -721,21 +729,21 @@ paths:
       tags:
         - "Library and metadata"
       parameters:
-        - $ref: "#/parameters/PageNumber"
-        - $ref: "#/parameters/PageSize"
+        - $ref: "./api/parameters.yml#PageNumber"
+        - $ref: "./api/parameters.yml#PageSize"
       responses:
         200:
           content:
             application/json:
               schema:
                 allOf:
-                  - $ref: "#/definitions/ResultPage"
+                  - $ref: "./api/definitions.yml#ResultPage"
                   - type: "object"
                     properties:
                       results:
                         type: "array"
                         items:
-                          $ref: "#/definitions/License"
+                          $ref: "./api/definitions.yml#License"
 
   /api/v1/licenses/{code}/:
     get:
@@ -759,12 +767,12 @@ paths:
           content:
             application/json:
               schema:
-                $ref: "#/definitions/License"
+                $ref: "./api/definitions.yml#License"
         404:
           content:
             application/json:
               schema:
-                $ref: "#/definitions/ResourceNotFound"
+                $ref: "./api/definitions.yml#ResourceNotFound"
 
   /api/v1/libraries/:
     get:
@@ -772,23 +780,23 @@ paths:
       tags:
         - "Uploads and audio content"
       parameters:
-        - $ref: "#/parameters/PageNumber"
-        - $ref: "#/parameters/PageSize"
-        - $ref: "#/parameters/Search"
-        - $ref: "#/parameters/Scope"
+        - $ref: "./api/parameters.yml#PageNumber"
+        - $ref: "./api/parameters.yml#PageSize"
+        - $ref: "./api/parameters.yml#Search"
+        - $ref: "./api/parameters.yml#Scope"
       responses:
         200:
           content:
             application/json:
               schema:
                 allOf:
-                  - $ref: "#/definitions/ResultPage"
+                  - $ref: "./api/definitions.yml#ResultPage"
                   - type: "object"
                     properties:
                       results:
                         type: "array"
                         items:
-                          $ref: "#/definitions/OwnedLibrary"
+                          $ref: "./api/definitions.yml#OwnedLibrary"
     post:
       tags:
         - "Uploads and audio content"
@@ -804,7 +812,7 @@ paths:
         content:
           application/json:
             schema:
-              $ref: "#/definitions/OwnedLibraryCreate"
+              $ref: "./api/definitions.yml#OwnedLibraryCreate"
 
   /api/v1/libraries/{uuid}/:
     parameters:
@@ -823,7 +831,7 @@ paths:
           content:
             application/json:
               schema:
-                $ref: "#/definitions/OwnedLibrary"
+                $ref: "./api/definitions.yml#OwnedLibrary"
     post:
       summary: Update a library
       tags:
@@ -833,13 +841,13 @@ paths:
         content:
           application/json:
             schema:
-              $ref: "#/definitions/OwnedLibraryCreate"
+              $ref: "./api/definitions.yml#OwnedLibraryCreate"
       responses:
         201:
           content:
             application/json:
               schema:
-                $ref: "#/definitions/OwnedLibrary"
+                $ref: "./api/definitions.yml#OwnedLibrary"
     delete:
       summary: Delete a library and all associated uploads
       description: |
@@ -868,14 +876,14 @@ paths:
                   - creation_date
                   - modification_date
                   - random
-        - $ref: "#/parameters/PageNumber"
-        - $ref: "#/parameters/PageSize"
-        - $ref: "#/parameters/Scope"
-        - $ref: "#/parameters/Search"
-        - $ref: "#/parameters/Tags"
-        - $ref: "#/parameters/Subscribed"
-        - $ref: "#/parameters/External"
-        - $ref: "#/parameters/ChannelOrdering"
+        - $ref: "./api/parameters/PageNumber"
+        - $ref: "./api/parameters/PageSize"
+        - $ref: "./api/parameters/Scope"
+        - $ref: "./api/parameters/Search"
+        - $ref: "./api/parameters/Tags"
+        - $ref: "./api/parameters/Subscribed"
+        - $ref: "./api/parameters/External"
+        - $ref: "./api/parameters/ChannelOrdering"
 
       responses:
         200:
@@ -883,13 +891,13 @@ paths:
             application/json:
               schema:
                 allOf:
-                  - $ref: "#/definitions/ResultPage"
+                  - $ref: "./api/definitions.yml#ResultPage"
                   - type: "object"
                     properties:
                       results:
                         type: "array"
                         items:
-                          $ref: "#/definitions/Channel"
+                          $ref: "./api/definitions.yml#Channel"
     post:
       summary: Create a new channel
       tags:
@@ -904,7 +912,7 @@ paths:
         content:
           application/json:
             schema:
-              $ref: "#/definitions/ChannelCreate"
+              $ref: "./api/definitions.yml#ChannelCreate"
 
   /api/v1/channels/metadata-choices:
     summary: List metadata (locales, itunes categories) for creating and editing channels.
@@ -970,7 +978,7 @@ paths:
           content:
             application/json:
               schema:
-                $ref: "#/definitions/Channel"
+                $ref: "./api/definitions.yml#Channel"
     post:
       summary: Update a channel
       tags:
@@ -980,13 +988,13 @@ paths:
         content:
           application/json:
             schema:
-              $ref: "#/definitions/ChannelUpdate"
+              $ref: "./api/definitions.yml#ChannelUpdate"
       responses:
         201:
           content:
             application/json:
               schema:
-                $ref: "#/definitions/Channel"
+                $ref: "./api/definitions.yml#Channel"
     delete:
       summary: Delete a channel and all associated uploads
       description: |
@@ -1020,7 +1028,7 @@ paths:
           content:
             application/json:
               schema:
-                $ref: "#/definitions/Subscription"
+                $ref: "./api/definitions.yml#Subscription"
 
   /api/v1/channels/{uuid}/rss/:
     parameters:
@@ -1056,7 +1064,7 @@ paths:
           content:
             application/json:
               schema:
-                $ref: "#/definitions/Subscription"
+                $ref: "./api/definitions.yml#Subscription"
 
   /api/v1/channels/{uuid}/unsubscribe/:
     parameters:
@@ -1080,23 +1088,23 @@ paths:
         - "Uploads and audio content"
       parameters:
 
-        - $ref: "#/parameters/Search"
-        - $ref: "#/parameters/PageNumber"
-        - $ref: "#/parameters/PageSize"
-        - $ref: "#/parameters/Scope"
+        - $ref: "./api/parameters.yml#Search"
+        - $ref: "./api/parameters.yml#PageNumber"
+        - $ref: "./api/parameters.yml#PageSize"
+        - $ref: "./api/parameters.yml#Scope"
       responses:
         200:
           content:
             application/json:
               schema:
                 allOf:
-                  - $ref: "#/definitions/ResultPage"
+                  - $ref: "./api/definitions.yml#ResultPage"
                   - type: "object"
                     properties:
                       results:
                         type: "array"
                         items:
-                          $ref: "#/definitions/OwnedUpload"
+                          $ref: "./api/definitions.yml#OwnedUpload"
     post:
       tags:
         - "Uploads and audio content"
@@ -1137,7 +1145,7 @@ paths:
                   - "pending"
                 import_metadata:
                   required: false
-                  $ref: "#/definitions/ImportMetadata"
+                  $ref: "./api/definitions.yml#ImportMetadata"
 
 
   /api/v1/subscriptions/{uuid}/:
@@ -1157,7 +1165,7 @@ paths:
           content:
             application/json:
               schema:
-                $ref: "#/definitions/Subscription"
+                $ref: "./api/definitions.yml#Subscription"
 
   /api/v1/subscriptions/:
     get:
@@ -1170,13 +1178,13 @@ paths:
             application/json:
               schema:
                 allOf:
-                  - $ref: "#/definitions/ResultPage"
+                  - $ref: "./api/definitions.yml#ResultPage"
                   - type: "object"
                     properties:
                       results:
                         type: "array"
                         items:
-                          $ref: "#/definitions/Subscription"
+                          $ref: "./api/definitions.yml#Subscription"
 
   /api/v1/subscriptions/all/:
     get:
@@ -1193,7 +1201,7 @@ paths:
                   results:
                     type: "array"
                     items:
-                      $ref: "#/definitions/SubscriptionsAll"
+                      $ref: "./api/definitions.yml#SubscriptionsAll"
 
   /api/v1/uploads/{uuid}/:
     parameters:
@@ -1212,7 +1220,7 @@ paths:
           content:
             application/json:
               schema:
-                $ref: "#/definitions/OwnedUpload"
+                $ref: "./api/definitions.yml#OwnedUpload"
     patch:
       summary: Update a draft upload
       description: |
@@ -1230,7 +1238,7 @@ paths:
           content:
             application/json:
               schema:
-                $ref: "#/definitions/OwnedUpload"
+                $ref: "./api/definitions.yml#OwnedUpload"
     delete:
       summary: Delete an upload
       description: |
@@ -1267,10 +1275,10 @@ paths:
       tags:
         - "Content curation"
       parameters:
-        - $ref: "#/parameters/Search"
-        - $ref: "#/parameters/PageNumber"
-        - $ref: "#/parameters/PageSize"
-        - $ref: "#/parameters/Scope"
+        - $ref: "./api/parameters.yml#Search"
+        - $ref: "./api/parameters.yml#PageNumber"
+        - $ref: "./api/parameters.yml#PageSize"
+        - $ref: "./api/parameters.yml#Scope"
 
       responses:
         200:
@@ -1278,13 +1286,13 @@ paths:
             application/json:
               schema:
                 allOf:
-                  - $ref: "#/definitions/ResultPage"
+                  - $ref: "./api/definitions.yml#ResultPage"
                   - type: "object"
                     properties:
                       results:
                         type: "array"
                         items:
-                          $ref: "#/definitions/TrackFavorite"
+                          $ref: "./api/definitions.yml#TrackFavorite"
     post:
       summary: Mark the given track as favorite
       tags:
@@ -1316,7 +1324,7 @@ paths:
                     format: "int64"
                     example: 98
                   creation_date:
-                    $ref: "#/properties/creation_date"
+                    $ref: "./api/properties.yml#creation_date"
   /api/v1/favorites/tracks/remove/:
     post:
       summary: Remove the given track from favorites
@@ -1376,7 +1384,7 @@ paths:
           content:
             application/json:
               schema:
-                $ref: "#/definitions/Attachment"
+                $ref: "./api/definitions.yml#Attachment"
     delete:
       summary: Delete an attachment
       tags:
@@ -1385,144 +1393,199 @@ paths:
         204:
           $ref: "#/responses/204"
 
-parameters:
-
-  ChannelOrdering:
-    - $ref: "#/parameters/Ordering"
-    - default: "-creation_date"
-      schema:
-        required: false
-        type: "string"
-        example: "-creation_date"
-        enum:
-          - creation_date
-          - artist__modification_date
-
-  External:
-    name: "external"
-    in: "query"
-    default: null
-    description: "Filter/exclude channels created from a third-party, non-Funkwhale RSS feed"
-    schema:
-      required: false
-      type: "boolean"
-
-
-  ObjectId:
-    name: id
-    in: path
-    description: Object ID
-    required: true
-    schema:
-      type: integer
-      format: int64
-
-  Library:
-    name: library
-    in: query
-    description: Restrict to results contained in the given library
-    schema:
-      type: string
-      format: uuid
-
-  Ordering:
-    name: "ordering"
-    in: "query"
-    description: "Ordering for the results, prefix with - for DESC ordering"
-
-  PageNumber:
-    in: query
-    name: page
-    schema:
-      type: "integer"
-      format: "int64"
-      example: 1
-      default: 1
-      minimum: 1
-  PageSize:
-    in: query
-    name: page_size
-    schema:
-      type: "integer"
-      format: "int64"
-      example: 16
-      default: 25
-      minimum: 1
-      maximum: 25
-  Playable:
-    name: "playable"
-    in: "query"
-    default: null
-    description: "Filter/exclude resources with playable tracks"
-    schema:
-      required: false
-      type: "boolean"
-  Refresh:
-    name: "refresh"
-    in: "query"
-    default: false
-    description: "Trigger an ActivityPub fetch to refresh local data"
-    schema:
-      required: false
-      type: "boolean"
-
-  Related:
-    name: related
-    in: query
-    description: Restrict to results similar to the given object (based on tags)
-    schema:
-      type: integer
-      format: int64
-
-  Scope:
-    name: "scope"
-    in: "query"
-    default: "all"
-    description: |
-      Limit the results to a given user or pod:
-        - Use `all` (or do not specify the property to disable scope filtering)
-        - Use `me` to retrieve content relative to the current user
-        - Use `actor:alice@example.com` to retrieve content relative to the account `alice@example.com
-        - Use `domain:example.com` to retrieve content relative to the domain `example.com
-    schema:
-      required: false
-      type: "string"
-      enum:
-      - "me"
-      - "all"
-      - "actor:alice@example.com"
-      - "domain:example.com"
-
-  Search:
-    name: "q"
-    in: "query"
-    default: "all"
-    description: "Limit the results to the corresponding search query"
-    schema:
-      required: false
-      type: "string"
-      example: "Bonobo"
-
-  Subscribed:
-    name: "subscribed"
-    in: "query"
-    description: "Limit or exclude results with a matching subsription from the current user"
-    schema:
-      required: false
-      type: boolean
-
-  Tags:
-    name: "tag"
-    in: "query"
-    description: "Limit the results to the corresponding tags. May be used multiple times, to retrieve objects matching al provided tags"
-    schema:
-      required: false
-      type: array
-      collectionFormat: csv
-      example:
-        - rock
-        - metal
-
+  /api/v1/playlists/:
+    get:
+      summary: List playlists
+      tags:
+        - "Content curation"
+      parameters:
+        - $ref: "./api/parameters.yml#Search"
+        - allOf:
+            - $ref: "./api/parameters.yml#Ordering"
+            - default: "-creation_date"
+              schema:
+                required: false
+                type: "string"
+                example: "creation_date"
+                enum:
+                  - creation_date
+                  - modification_date
+                  - id
+                  - name
+        - in: query
+          name: artist
+          description: Restrict to playlists containing tracks from the given artist
+          schema:
+            type: "integer"
+            format: "int64"
+        - in: query
+          name: album
+          description: Restrict to playlists containing tracks from the given album
+          schema:
+            type: "integer"
+            format: "int64"
+        - in: query
+          name: track
+          description: Restrict to playlists containing the given track
+          schema:
+            type: "integer"
+            format: "int64"
+        - $ref: "./api/parameters.yml#Playable"
+        - $ref: "./api/parameters.yml#PageNumber"
+        - $ref: "./api/parameters.yml#PageSize"
+      responses:
+        200:
+          content:
+            application/json:
+              schema:
+                allOf:
+                  - $ref: "./api/definitions.yml#ResultPage"
+                  - type: "object"
+                    properties:
+                      results:
+                        type: "array"
+                        items:
+                          $ref: "./api/definitions.yml#Playlist"
+    post:
+      tags:
+        - "Content curation"
+      description: Create a new playlist
+      responses:
+        201:
+          $ref: "#/responses/201"
+        400:
+          $ref: "#/responses/400"
+      requestBody:
+        required: true
+        content:
+          application/json:
+            schema:
+              $ref: "./api/definitions.yml#PlaylistCreate"
+  /api/v1/playlists/{id}/:
+    parameters:
+      - name: id
+        in: path
+        required: true
+        schema:
+          type: "integer"
+          format: "int64"
+    get:
+      summary: Retrieve a playlist
+      tags:
+        - "Content curation"
+      responses:
+        200:
+          content:
+            application/json:
+              schema:
+                $ref: "./api/definitions.yml#Playlist"
+    post:
+      summary: Update a playlist
+      tags:
+        - "Content curation"
+      requestBody:
+        required: true
+        content:
+          application/json:
+            schema:
+              $ref: "./api/definitions.yml#PlaylistCreate"
+      responses:
+        201:
+          content:
+            application/json:
+              schema:
+                $ref: "./api/definitions.yml#Playlist"
+    delete:
+      description: Delete the playlist
+      tags:
+        - "Content curation"
+      responses:
+        204:
+          $ref: "#/responses/204"
+  /api/v1/playlists/{id}/tracks:
+    parameters:
+      - name: id
+        in: path
+        required: true
+        schema:
+          type: "integer"
+          format: "int64"
+    get:
+      description: Retrieve all tracks in the playlist
+      tags:
+        - "Content curation"
+      responses:
+        200:
+          content:
+            application/json:
+              schema:
+                allOf:
+                  - $ref: "./api/definitions.yml#ResultPage"
+                  - type: "object"
+                    properties:
+                      results:
+                        type: "array"
+                        items:
+                          $ref: "./api/definitions.yml#PlaylistTrack"
+  /api/v1/playlists/{id}/add:
+    parameters:
+      - name: id
+        in: path
+        required: true
+        schema:
+          type: "integer"
+          format: "int64"
+    post:
+      tags:
+        - "Content curation"
+      summary: Append one or more tracks to a playlist
+      requestBody:
+        required: true
+        content:
+          application/json:
+            schema:
+              type: object
+              properties:
+                tracks:
+                  type: array
+                  description: An array of track IDs
+                  items:
+                    type: "integer"
+                    format: "int64"
+                    example: 13
+                allow_duplicates:
+                  type: boolean
+                  default: false
+                  description: |
+                    Wether to raise an error when the same track is added
+                    multiple time in the playlist
+      responses:
+        201:
+          content:
+            application/json:
+              schema:
+                allOf:
+                  - $ref: "./api/definitions.yml#ResultPage"
+                  - type: "object"
+                    properties:
+                      results:
+                        type: "array"
+                        items:
+                          $ref: "./api/definitions.yml#PlaylistTrack"
+  /api/v1/playlists/{id}/clear:
+    parameters:
+      - name: id
+        in: path
+        required: true
+        schema:
+          type: "integer"
+          format: "int64"
+    delete:
+      description: Remove all tracks in the playlist
+      tags:
+        - "Content curation"
+      responses:
+        204:
 responses:
   200:
     description: Success
@@ -1532,924 +1595,3 @@ responses:
     description: Successfully deleted
   400:
     description: Bad request
-
-properties:
-  description:
-    type: object
-    description: Text content associated with another resource, like and artist or channel.
-    properties:
-      text:
-        type: string
-        example: "This is **me**"
-        description: "The raw user input"
-      content_type:
-        type: string
-        enum:
-          - text/markdown
-          - text/plain
-          - text/html
-        description: "The raw user input"
-      html:
-        type: string
-        description: "HTML output based on user input"
-        readOnly: true
-
-  mbid:
-    type: "string"
-    format: "uuid"
-    description: "A musicbrainz ID"
-  creation_date:
-    type: "string"
-    format: "date-time"
-  privacy_level:
-    type: string
-    example: "me"
-    description: |
-     * `me`: private
-     * `instance`: accessible by local users
-     * `everyone`: public (including over federation)
-    enum:
-      - "me"
-      - "instance"
-      - "everyone"
-  fid:
-    type: "string"
-    format: "uri"
-    description: "Federation ID"
-    example: "https://my.instance/federation/music/libraries/3fa85f64-5717-4562-b3fc-2c963f66afa6"
-  audio_mimetype:
-    type: string
-    example: "audio/ogg"
-    enum:
-      - "audio/ogg"
-      - "audio/mpeg"
-      - "audio/x-flac"
-      - "audio/flac"
-  image_mimetype:
-    type: string
-    example: "image/png"
-    enum:
-      - "image/png"
-      - "image/jpeg"
-  import_status:
-    type: string
-    example: "finished"
-    enum:
-      - "draft"
-      - "pending"
-      - "finished"
-      - "errored"
-      - "skipped"
-    description: |
-     * `draft`: waiting for further modifications from the owner
-     * `pending`: waiting to be processed by the server
-     * `finished`: successfully processed by the server
-     * `errored`: couldn't be processed by the server (e.g because of a tagging issue)
-     * `skipped`: processed by the server but skipped, because considered as a duplicate of an existing upload
-
-  transcode_options:
-    type: string
-    enum:
-      - "ogg"
-      - "mp3"
-
-  tags:
-    type: array
-    description: A list of hashtags associated with a resource
-    items:
-      type: string
-      example: "Rock"
-
-  content_category:
-    type: "string"
-    description: Used to what kind of content is published in a chanel
-    enum:
-     - music
-     - podcast
-     - other
-
-
-
-definitions:
-  OAuthApplication:
-    type: "object"
-    properties:
-      client_id:
-        type: "string"
-        example: "VKIZWv7FwBq56UMfUtbCSIgSxzUTv1b6nMyOkJvP"
-      created:
-        type: "string"
-        format: "date-time"
-      updated:
-        type: "string"
-        format: "date-time"
-      scopes:
-        type: "string"
-        description: "Coma-separated list of scopes requested by the app"
-
-  OAuthApplicationCreation:
-    type: "object"
-    properties:
-      client_secret:
-        type: "string"
-        example: "qnKDX8zjIfC0BG4tUreKlqk3tNtuCfJdGsaEt5MIWrTv0YLLhGI6SGqCjs9kn12gyXtIg4FWfZqWMEckJmolCi7a6qew4LawPWMfnLDii4mQlY1eQG4BJbwPANOrDiTZ"
-      redirect_uris:
-        type: "string"
-        format: "uri"
-        description: "Coma-separated list of redirect uris allowed for the app"
-
-
-  ResultPage:
-    type: "object"
-    properties:
-      count:
-        type: "integer"
-        format: "int64"
-        example: 42
-        description: "The total number of results (all pages included)"
-      next:
-        type: "string"
-        format: "uri"
-        description: "Link to the next page of results"
-      previous:
-        type: "string"
-        format: "uri"
-        description: "Link to the previous page of results"
-
-  Attachment:
-    type: "object"
-    properties:
-      uuid:
-        type: string
-        format: uuid
-      size:
-        type: "integer"
-        format: "int64"
-        example: 2787000
-        description: "Size of the file, in bytes"
-      mimetype:
-        $ref: "#/properties/image_mimetype"
-      creation_date:
-        type: "string"
-        format: "date-time"
-      urls:
-        type: "object"
-        properties:
-          original:
-            type: "string"
-            description: "URL to the original image"
-            example: "https://mydomain/media/attachments/ec2c53aeaac6.jpg"
-          medium_square_crop:
-            type: "string"
-            description: "URL to a medium, squared thumbnail of the image"
-            example: "https://mydomain/media/__sized__/attachments/ec2c53aeaac6-crop-c0-5__0-5-200x200-70.jpg"
-
-  Actor:
-    type: object
-    description: "A federation/ ActivityPub actor"
-    properties:
-      fid:
-        type: string
-        format: uri
-        description: "The actor Federation ID (unique accross federation)"
-      uuid:
-        type: string
-        format: uuid
-        description: "Local ID of the library"
-      creation_date:
-        type: "string"
-        format: "date-time"
-      preferred_username:
-        type: "string"
-        example: "alice"
-      name:
-        type: string
-        example: "Alice Unicorn"
-      last_fetch_date:
-        type: "string"
-        format: "date-time"
-        description: "Last time the actor profile was fetched on its origin server"
-      domain:
-        type: "string"
-        format: "hostname"
-        example: "open.audio"
-      type:
-        type: "string"
-        example: "Person"
-        enum:
-          - Person
-          - Application
-          - Group
-          - Organization
-      manually_approves_followers:
-        type: "boolean"
-      full_username:
-        type: string
-        example: "alice@open.audio"
-
-  BaseArtist:
-    type: "object"
-    properties:
-      mbid:
-        required: false
-        $ref: "#/properties/mbid"
-      id:
-        type: "integer"
-        format: "int64"
-        example: 42
-      fid:
-        type: string
-        format: uri
-        description: "The artist Federation ID (unique accross federation)"
-      name:
-        type: "string"
-        example: "System of a Down"
-      creation_date:
-        type: "string"
-        format: "date-time"
-      is_local:
-        type: "boolean"
-        description: "Indicates if the object was initally created locally or on another server"
-
-  Artist:
-    type: "object"
-    allOf:
-      - $ref: "#/definitions/BaseArtist"
-      - type: "object"
-        properties:
-          tracks_count:
-            type: "integer"
-            format: "int64"
-            example: 42
-          albums:
-            type: "array"
-            items:
-              $ref: "#/definitions/ArtistAlbum"
-
-  BaseAlbum:
-    type: "object"
-    properties:
-      mbid:
-        required: false
-        $ref: "#/properties/mbid"
-      id:
-        type: "integer"
-        format: "int64"
-        example: 16
-      fid:
-        type: string
-        format: uri
-        description: "The album Federation ID (unique accross federation)"
-      artist:
-        type: "integer"
-        format: "int64"
-        example: 42
-      title:
-        type: "string"
-        example: "Toxicity"
-      creation_date:
-        type: "string"
-        format: "date-time"
-      release_date:
-        type: "string"
-        required: false
-        format: "date"
-        example: "2001-01-01"
-      is_playable:
-        type: "boolean"
-      cover:
-        $ref: "#/definitions/Attachment"
-      is_local:
-        type: "boolean"
-        description: "Indicates if the object was initally created locally or on another server"
-
-  Album:
-    type: "object"
-    allOf:
-      - $ref: "#/definitions/BaseAlbum"
-      - type: "object"
-        properties:
-          tracks:
-            type: "array"
-            items:
-              $ref: "#/definitions/AlbumTrack"
-
-  ArtistAlbum:
-    type: "object"
-    allOf:
-      - $ref: "#/definitions/BaseAlbum"
-      - type: "object"
-        properties:
-          tracks_count:
-            type: "integer"
-            format: "int64"
-            example: 16
-
-  ChannelMetadata:
-    type: "object"
-    properties:
-      itunes_category:
-        type: string
-        example: Comedy
-        description: Itunes category (see `/api/v1/channels/metadata-choices`) for allowed values
-      itunes_subcategory:
-        type: string
-        example: Improv
-        description: Itunes subcategory (see `/api/v1/channels/metadata-choices`) for allowed values
-      language:
-        type: string
-        example: en
-        description: Language of the content, in ISO 639 format (see `/api/v1/channels/metadata-choices`) for allowed values
-      owner_name:
-        type: string
-        example: "Alice"
-        description: Used to make the channel compatible with other platforms (iTunes, Spotify, etc.)
-      owner_email:
-        type: string
-        example: "alice@example.com"
-        description: Used to make the channel compatible with other platforms (iTunes, Spotify, etc.)
-
-  ChannelCreate:
-    type: "object"
-    properties:
-      name:
-        type: "string"
-        example: "A short, public name for the channel"
-        maxLength: 255
-      username:
-        type: "string"
-        example: "aliceandbob"
-        description: "The username to associate with the channel, for use over federation. This cannot be changed afterwards."
-      description:
-        $ref: "#/properties/description"
-      tags:
-        $ref: "#/properties/tags"
-      content_category:
-        $ref: "#/properties/content_category"
-      cover:
-        type: string
-        format: uuid
-      metadata:
-        $ref: "#/definitions/ChannelMetadata"
-  ChannelUpdate:
-    type: "object"
-    properties:
-      name:
-        type: "string"
-        example: "A short, public name for the channel"
-        maxLength: 255
-      description:
-        $ref: "#/properties/description"
-      tags:
-        $ref: "#/properties/tags"
-      cover:
-        type: string
-        format: uuid
-      metadata:
-        $ref: "#/definitions/ChannelMetadata"
-
-  Channel:
-    type: "object"
-    properties:
-      uuid:
-        type: "string"
-        format: "uuid"
-      creation_date:
-        $ref: "#/properties/creation_date"
-      artist:
-        $ref: "#/definitions/BaseArtist"
-      attributed_to:
-        $ref: "#/definitions/Actor"
-        description: User account owning the channel
-      actor:
-        $ref: "#/definitions/Actor"
-        description: Actor representing the channel over federation
-
-  Subscription:
-    type: "object"
-    properties:
-      approved:
-        type: "string"
-      fid:
-        $ref: "#/properties/fid"
-      uuid:
-        type: "string"
-        format: "uuid"
-      creation_date:
-        $ref: "#/properties/creation_date"
-      channel:
-        $ref: "#/definitions/Channel"
-
-  SubscriptionsAll:
-    type: "object"
-    properties:
-      uuid:
-        type: "string"
-        format: "uuid"
-      channel:
-        type: "string"
-        format: "uuid"
-
-  Library:
-    type: "object"
-    properties:
-      fid:
-        type: string
-        format: uri
-        description: "The library Federation ID (unique accross federation)"
-      uuid:
-        type: string
-        format: uuid
-        description: "Local ID of the library"
-      name:
-        type: string
-        example: "My awesome library"
-      description:
-        type: string
-        nullable: true
-        example: "This library contains all the stuff I love!"
-      uploads_count:
-        type: "integer"
-        format: "int64"
-        example: 687
-      privacy_level:
-        type: string
-        example: "me"
-        enum:
-          - "me"
-          - "instance"
-          - "everyone"
-      actor:
-        $ref: "#/definitions/Actor"
-  LibraryPage:
-    allOf:
-      - $ref: "#/definitions/ResultPage"
-      - type: "object"
-        properties:
-          results:
-            type: "array"
-            items:
-              $ref: "#/definitions/Library"
-
-  License:
-    type: "object"
-    properties:
-      id:
-        type: string
-        format: uri
-        example: http://creativecommons.org/publicdomain/zero/1.0/
-        description: "The license ID"
-      url:
-        type: string
-        format: uri
-        example: http://creativecommons.org/publicdomain/zero/1.0/
-        description: "The license url (can be different than the ID)"
-      code:
-        type: string
-        description: "A unique code to identify the license"
-        example: cc0-1.0
-      redistribute:
-        type: boolean
-        example: true
-        description: "Does the license allow free redistribution?"
-      derivative:
-        type: boolean
-        example: true
-        description: "Does the license allow the creation of derivative work?"
-      commercial:
-        type: boolean
-        example: true
-        description: "Does the license allow commercial use?"
-      attribution:
-        type: boolean
-        example: false
-        description: "Does the license requires crediting the author?"
-      copyleft:
-        type: boolean
-        example: false
-        description: "Does the license enforce a similar license of derivative work?"
-
-  BaseTrack:
-    type: "object"
-    properties:
-      mbid:
-        required: false
-        $ref: "#/properties/mbid"
-      id:
-        type: "integer"
-        format: "int64"
-        example: 66
-      fid:
-        type: string
-        format: uri
-        description: "The track Federation ID (unique accross federation)"
-      artist:
-        type: "integer"
-        format: "int64"
-        example: 42
-      album:
-        type: "integer"
-        format: "int64"
-        example: 16
-      title:
-        type: "string"
-        example: "Chop Suey!"
-      position:
-        required: false
-        description: "Position of the track in the album"
-        type: "number"
-        minimum: 1
-        example: 1
-      disc_number:
-        required: false
-        type: "number"
-        minimum: 1
-        example: 1
-      listen_url:
-        type: "string"
-        format: "uri"
-        description: "URL to stream the track"
-      copyright:
-        type: "string"
-        example: "Creative Commons Attribution-NonCommercial-NoDerivatives 4.0: http://creativecommons.org/licenses/by-nc-nd/4.0/"
-        description: "Copyright information as extracted from upload tags"
-      license:
-        type: "string"
-        description: "Identifier of the license that is linked to the track"
-        example: "cc-by-nc-nd-4.0"
-      is_local:
-        type: "boolean"
-        description: "Indicates if the object was initally created locally or on another server"
-
-  AlbumTrack:
-    type: "object"
-    allOf:
-      - $ref: "#/definitions/BaseTrack"
-      - type: "object"
-        properties:
-          artist:
-            $ref: "#/definitions/BaseArtist"
-          uploads:
-            type: "array"
-            description: "List of uploads associated with this track"
-            items:
-              $ref: "#/definitions/Upload"
-  Track:
-    type: "object"
-    allOf:
-      - $ref: "#/definitions/BaseTrack"
-      - type: "object"
-        properties:
-          album:
-            $ref: "#/definitions/Album"
-          artist:
-            $ref: "#/definitions/BaseArtist"
-          uploads:
-            type: "array"
-            description: "List of uploads associated with this track"
-            items:
-              $ref: "#/definitions/Upload"
-  Upload:
-    type: "object"
-    properties:
-      uuid:
-        type: string
-        format: uuid
-      size:size:
-        type: "integer"
-        format: "int64"
-        example: 278987000
-        description: "Size of the file, in bytes"
-      duration:
-        type: "integer"
-        format: "int64"
-        example: 184
-        description: "Duration of the audio, in seconds"
-      bitrate:
-        type: "integer"
-        format: "int64"
-        example: 128000
-        description: "Bitrate of the file, in bytes/s"
-      mimetype:
-        $ref: "#/properties/audio_mimetype"
-      extension:
-        type: string
-        example: "ogg"
-        description: "File extension of the upload"
-      filename:
-        type: "string"
-        example: "Myfile.mp3"
-      listen_url:
-        type: "string"
-        format: "uri"
-        description: "URL to stream the upload"
-
-  OwnedLibraryCreate:
-    type: "object"
-    properties:
-      name:
-        type: "string"
-        example: "My new library"
-      description:
-        required: false
-        type: "string"
-        example: "Lots of interesting content"
-      privacy_level:
-        $ref: "#/properties/privacy_level"
-
-  OwnedLibrary:
-    type: "object"
-    properties:
-      uuid:
-        type: string
-        format: uuid
-      fid:
-        $ref: "#/properties/fid"
-      name:
-        type: "string"
-        example: "My Creative Commons library"
-      description:
-        type: "string"
-        example: "All content is under CC-BY"
-      creation_date:
-        $ref: "#/properties/creation_date"
-      privacy_level:
-        $ref: "#/properties/privacy_level"
-      uploads_count:
-        type: "integer"
-        format: "int64"
-        example: 34
-      size:
-        type: "integer"
-        format: "int64"
-        example: 678917000
-        description: "Total size of uploads in the library, in bytes"
-
-  OwnedUpload:
-    type: "object"
-    allOf:
-      - $ref: "#/definitions/Upload"
-      - type: "object"
-        properties:
-          import_status:
-            $ref: "#/properties/import_status"
-          track:
-            $ref: "#/definitions/Track"
-          library:
-            $ref: "#/definitions/OwnedLibrary"
-          source:
-            type: "string"
-            example: "upload://myfile.mp3"
-          import_reference:
-            type: "string"
-            example: "Import launched via web UI on 03/18"
-          import_metadata:
-            $ref: "#/definitions/ImportMetadata"
-
-  ImportMetadata:
-    type: "object"
-    description: "Import metadata to override values from ID3/embedded audio tags"
-    properties:
-      title:
-        type: "string"
-        example: "My Track"
-        required: true
-      mbid:
-        $ref: "#/properties/mbid"
-        required: false
-      copyright:
-        type: "string"
-        example: "Alice, 2018"
-        description: "Copyright information"
-        required: false
-      license:
-        type: "string"
-        example: "cc-by-sa-4.0"
-        required: false
-        description: A license code, as returned by /api/v1/licenses
-      tags:
-        $ref: "#/properties/tags"
-        required: false
-      position:
-        description: "Position of the track in the album or channel"
-        type: "number"
-        minimum: 1
-        example: 1
-
-  TrackFavorite:
-    type: "object"
-    properties:
-      id:
-        type: "integer"
-        format: "int64"
-        example: 876
-      track:
-        $ref: "#/definitions/Track"
-      user:
-        $ref: "#/definitions/User"
-      creation_date:
-        $ref: "#/properties/creation_date"
-  User:
-    type: "object"
-    properties:
-      id:
-        type: "integer"
-        format: "int64"
-        example: 23
-      username:
-        type: "string"
-        example: "alice"
-      name:
-        type: "string"
-        example: "Alice Kingsley"
-      avatar:
-        $ref: "#/definitions/Avatar"
-
-  Me:
-    type: "object"
-    allOf:
-      - $ref: "#/definitions/User"
-      - type: "object"
-        properties:
-          full_username:
-            type: "string"
-            description: Full username, for use on federation
-            example: "alice@yourdomain.com"
-          email:
-            type: "string"
-            format: "email"
-            description: Email address associated with the account
-            example: "alice@email.provider"
-          is_staff:
-            type: "boolean"
-            example: false
-          is_superuser:
-            type: "boolean"
-            example: false
-          date_joined:
-            type: "string"
-            format: "date-time"
-          privacy_level:
-            $ref: "#/properties/privacy_level"
-            description: Default privacy-level associated with the user account
-          quota_status:
-            $ref: "#/definitions/QuotaStatus"
-          permissions:
-            $ref: "#/definitions/Permissions"
-  Avatar:
-    type: "object"
-    properties:
-      original:
-        type: "string"
-        format: "uri"
-        description: "Original image URL"
-        example: "http://yourinstance/media/users/avatars/92/49/60/b3c-4736-43b3-bb5c-ed7a99ac6996.jpg"
-      square_crop:
-        type: "string"
-        format: "uri"
-        description: "400x400 thumbnail URL"
-        example: "http://yourinstance/media/__sized__/users/avatars/92/49/60/b3c-4736-43b3-bb5c-ed7a99ac6996-crop-c0-5__0-5-400x400-70.jpg"
-      small_square_crop:
-        type: "string"
-        format: "uri"
-        description: "50x50 thumbnail URL"
-        example: "http://yourinstance/media/__sized__/users/avatars/92/49/60/b3c-4736-43b3-bb5c-ed7a99ac6996-crop-c0-5__0-5-50x50-70.jpg"
-      medium_square_crop:
-        type: "string"
-        format: "uri"
-        description: "200x200 thumbnail URL"
-        example: "http://yourinstance/media/__sized__/users/avatars/92/49/60/b3c-4736-43b3-bb5c-ed7a99ac6996-crop-c0-5__0-5-200x200-70.jpg"
-  QuotaStatus:
-    type: "object"
-    properties:
-      max:
-        type: "integer"
-        format: "int64"
-        description: Storage space allocated to this user, in MB
-        example: 5000
-      remaining:
-        type: "integer"
-        format: "int64"
-        description: Remaining storage space for this user, in MB
-        example: 4600
-      current:
-        type: "integer"
-        format: "int64"
-        description: Storage space used by this user, in MB
-        example: 400
-      skipped:
-        type: "integer"
-        format: "int64"
-        description: Storage space occupied by uploads with "skipped" import status, in MB
-        example: 30
-      finished:
-        type: "integer"
-        format: "int64"
-        description: Storage space occupied by uploads with "finished" import status, in MB
-        example: 350
-      pending:
-        type: "integer"
-        format: "int64"
-        description: Storage space occupied by uploads with "pending" import status, in MB
-        example: 15
-      draft:
-        type: "integer"
-        format: "int64"
-        description: Storage space occupied by uploads with "draft" import status, in MB
-        example: 8
-      errored:
-        type: "integer"
-        format: "int64"
-        description: Storage space occupied by uploads with "errored" import status, in MB
-        example: 5
-  Permissions:
-    type: "object"
-    properties:
-      library:
-        type: "boolean"
-        example: false
-        description: A boolean indicating if the user can manage the instance library
-      moderation:
-        type: "boolean"
-        example: false
-        description: A boolean indicating if the user has moderation permission
-      settings:
-        type: "boolean"
-        example: false
-        description: A boolean indicating if the user can manage instance settings and users
-  RateLimitStatus:
-    type: "object"
-    properties:
-      enabled:
-        type: "boolean"
-        example: true
-        description: A boolean indicating if rate-limiting is enabled on the server
-      ident:
-        type: "object"
-        description: Client-related data
-        properties:
-          type:
-            type: string
-            example: "anonymous"
-            enum:
-              - "authenticated"
-              - "anonymous"
-          id:
-            type: string
-            example: "92.143.42"
-            description: An address IP or user ID identifying the client
-      scopes:
-        type: "array"
-        items:
-          type: "object"
-          description: Rate-limit scope configuration and usage
-          properties:
-            id:
-              type: string
-              example: "password-reset"
-            description:
-              type: string
-              example: "Password reset request"
-            rate:
-              type: string
-              example: "30/day"
-            limit:
-              type: "integer"
-              format: "int64"
-              example: 30
-            duration:
-              type: "integer"
-              format: "int64"
-              example: 86400
-            remaining:
-              type: "integer"
-              format: "int64"
-              example: 28
-              description: How many requests can be sent with the same scope before the limit applies
-            reset:
-              type: "integer"
-              format: "int64"
-              example: 1568126189
-              description: A timestamp indicating when <code>remaining</code> will return to its higher possible value
-            reset_seconds:
-              type: "integer"
-              format: "int64"
-              example: 86267
-              description: How many seconds to wait before <code>remaining</code> returns to its higher possible value
-            available:
-              type: "integer"
-              format: "int64"
-              example: 1568126089
-              description: A timestamp indicating when the client can retry
-            available_seconds:
-              type: "integer"
-              format: "int64"
-              example: 54
-              description: How many seconds to wait before a retry
-
-  ResourceNotFound:
-    type: "object"
-    properties:
-      detail:
-        type: "string"
-        example: "Not found."