openapi: 3.0.0
info:
  version: '3.0.73'
  title: 'Delphi SMA API'
  description: 'The Delphi Apps API for consumer analytics, including support for SMA.'
servers:
  - description: API v3
    url: /v3
tags:
  - name: Resources
    description: Contains all resource-related endpoints
  - name: Auth
    description: Authentication and authorization-related endpoints
  - name: Utility
    description: General application

paths:
  ############################################################################
  # Resource Routes
  ############################################################################
  /products:
    get:
      tags:
        - Resources
      summary: 'Search for Products'
      operationId: delphi_api.v3.views.products.ProductsView.search
      description: |
        Resource route for getting a list of `Products`
        with filtering based on provided parameters
      security:
        - bearerAuth: []
      parameters:
        - $ref: '#/components/parameters/artist_id'
        - $ref: '#/components/parameters/track_id'
        - $ref: '#/components/parameters/isrc'
        - $ref: '#/components/parameters/limit'
        - $ref: '#/components/parameters/offset'
        - $ref: '#/components/parameters/sort_by'
        - $ref: '#/components/parameters/sort_order'
      responses:
        200:
          $ref: '#/components/responses/ProductsResponse'
        400:
          $ref: '#/components/responses/InvalidInput'
        401:
          $ref: '#/components/responses/Unauthorized'
        500:
          $ref: '#/components/responses/InternalError'
  /products/{product_id}:
    get:
      tags:
        - Resources
      summary: 'Query for a single Product'
      operationId: delphi_api.v3.views.products.ProductsView.get
      description: |
        Resource route for getting a single `Product`
        with filtering based on provided parameters
      security:
        - bearerAuth: []
      parameters:
        - $ref: '#/components/parameters/product_id_path'
      responses:
        200:
          $ref: '#/components/responses/ProductResponse'
        400:
          $ref: '#/components/responses/InvalidInput'
        401:
          $ref: '#/components/responses/Unauthorized'
        404:
          $ref: '#/components/responses/NotFoundError'
        500:
          $ref: '#/components/responses/InternalError'
  /artists:
    get:
      tags:
        - Resources
      summary: 'Search for Artists'
      operationId: delphi_api.v3.views.artists.ArtistsView.search
      description: |
        Resource route for getting a list of `Artists`
        with filtering based on provided parameters
      security:
        - bearerAuth: []
      parameters:
        - $ref: '#/components/parameters/product_id'
        - $ref: '#/components/parameters/track_id'
        - $ref: '#/components/parameters/isrc'
        - $ref: '#/components/parameters/limit'
        - $ref: '#/components/parameters/offset'
        - $ref: '#/components/parameters/sort_by'
        - $ref: '#/components/parameters/sort_order'
      responses:
        200:
          $ref: '#/components/responses/ArtistsResponse'
        400:
          $ref: '#/components/responses/InvalidInput'
        401:
          $ref: '#/components/responses/Unauthorized'
        500:
          $ref: '#/components/responses/InternalError'
  /artists/{artist_id}:
    get:
      tags:
        - Resources
      summary: 'Query for a single Artist'
      operationId: delphi_api.v3.views.artists.ArtistsView.get
      description: |
        Resource route for getting a single `Artist`
        with filtering based on provided parameters
      security:
        - bearerAuth: []
      parameters:
        - $ref: '#/components/parameters/artist_id_path'
      responses:
        200:
          $ref: '#/components/responses/ArtistResponse'
        400:
          $ref: '#/components/responses/InvalidInput'
        401:
          $ref: '#/components/responses/Unauthorized'
        404:
          $ref: '#/components/responses/NotFoundError'
        500:
          $ref: '#/components/responses/InternalError'
  /artists/{artist_id}/followers:
    get:
      tags:
        - Resources
      summary: 'Query for a single Artist with followers grouped by date'
      operationId: delphi_api.v3.views.artists.ArtistsView.get_followers
      description: |
        Resource route for getting `ArtistFollowers` for a single `Artist`
        with filtering based on provided parameters
      security:
        - bearerAuth: []
      parameters:
        - $ref: '#/components/parameters/artist_id_path'
        - $ref: '#/components/parameters/start_date'
        - $ref: '#/components/parameters/end_date'
        - $ref: '#/components/parameters/group_by_period'
        - $ref: '#/components/parameters/limit'
        - $ref: '#/components/parameters/offset'
        - $ref: '#/components/parameters/sort_by'
        - $ref: '#/components/parameters/sort_order'
      responses:
        200:
          $ref: '#/components/responses/ArtistFollowersResponse'
        400:
          $ref: '#/components/responses/InvalidInput'
        401:
          $ref: '#/components/responses/Unauthorized'
        404:
          $ref: '#/components/responses/NotFoundError'
        500:
          $ref: '#/components/responses/InternalError'
  /charts:
    get:
      tags:
        - Resources
      summary: 'Search for Charts'
      operationId: delphi_api.v3.views.charts.ChartsView.search
      description: |
        Resource route for getting a list of `Charts`
        with filtering based on provided parameters
      security:
        - bearerAuth: []
      parameters:
        - $ref: '#/components/parameters/chart_group'
        - $ref: '#/components/parameters/dsp_array'
        - $ref: '#/components/parameters/limit'
        - $ref: '#/components/parameters/offset'
        - $ref: '#/components/parameters/sort_by'
        - $ref: '#/components/parameters/sort_order'
      responses:
        200:
          $ref: '#/components/responses/ChartsResponse'
        400:
          $ref: '#/components/responses/InvalidInput'
        401:
          $ref: '#/components/responses/Unauthorized'
        500:
          $ref: '#/components/responses/InternalError'
  /charts/{chart_id}:
    get:
      tags:
        - Resources
      summary: 'Query for a single Chart'
      operationId: delphi_api.v3.views.charts.ChartsView.get
      description: |
        Resource route for getting a single `Chart`
        with filtering based on provided parameters
      security:
        - bearerAuth: []
      parameters:
        - $ref: '#/components/parameters/chart_id_path'
      responses:
        200:
          $ref: '#/components/responses/ChartResponse'
        400:
          $ref: '#/components/responses/InvalidInput'
        401:
          $ref: '#/components/responses/Unauthorized'
        404:
          $ref: '#/components/responses/NotFoundError'
        500:
          $ref: '#/components/responses/InternalError'
  /dsps:
    get:
      tags:
        - Resources
      summary: 'Search for DSPs'
      operationId: delphi_api.v3.views.dsps.DspsView.search
      description: |
        Resource route for getting a list of `Dsps`
        with filtering based on provided parameters
      security:
        - bearerAuth: []
      parameters:
        - $ref: '#/components/parameters/limit'
        - $ref: '#/components/parameters/offset'
      responses:
        200:
          $ref: '#/components/responses/DspsResponse'
        400:
          $ref: '#/components/responses/InvalidInput'
        401:
          $ref: '#/components/responses/Unauthorized'
        500:
          $ref: '#/components/responses/InternalError'
  /dsps/{dsp_id}:
    get:
      tags:
        - Resources
      summary: 'Query for a single DSP'
      operationId: delphi_api.v3.views.dsps.DspsView.get
      description: |
        Resource route for getting a single `Dsp`
        with filtering based on provided parameters
      security:
        - bearerAuth: []
      parameters:
        - $ref: '#/components/parameters/dsp_id_path'
      responses:
        200:
          $ref: '#/components/responses/DspResponse'
        400:
          $ref: '#/components/responses/InvalidInput'
        401:
          $ref: '#/components/responses/Unauthorized'
        404:
          $ref: '#/components/responses/NotFoundError'
        500:
          $ref: '#/components/responses/InternalError'
  /playlists:
    get:
      tags:
        - Resources
      summary: 'Search for Playlists'
      operationId: delphi_api.v3.views.playlists.PlaylistsView.search
      description: |
        Resource route for getting a list of `Playlists`
        with filtering based on provided parameters
      security:
        - bearerAuth: []
      parameters:
        - $ref: '#/components/parameters/dsp_array'
        - $ref: '#/components/parameters/limit'
        - $ref: '#/components/parameters/offset'
        - $ref: '#/components/parameters/sort_by'
        - $ref: '#/components/parameters/sort_order'
      responses:
        200:
          $ref: '#/components/responses/PlaylistsResponse'
        400:
          $ref: '#/components/responses/InvalidInput'
        401:
          $ref: '#/components/responses/Unauthorized'
        500:
          $ref: '#/components/responses/InternalError'
  /playlists/{playlist_id}:
    get:
      tags:
        - Resources
      summary: 'Query for a single Playlist'
      operationId: delphi_api.v3.views.playlists.PlaylistsView.get
      description: |
        Resource route for getting a single `Playlist`
        with filtering based on provided parameters
      security:
        - bearerAuth: []
      parameters:
        - $ref: '#/components/parameters/playlist_id_path'
      responses:
        200:
          $ref: '#/components/responses/PlaylistResponse'
        400:
          $ref: '#/components/responses/InvalidInput'
        401:
          $ref: '#/components/responses/Unauthorized'
        404:
          $ref: '#/components/responses/NotFoundError'
        500:
          $ref: '#/components/responses/InternalError'
  /popularity:
    get:
      tags:
        - Resources
      summary: 'Query for Spotify popularity'
      operationId: delphi_api.v3.views.popularity.PopularityView.search
      description: |
        Resource route for getting a list of `Popularity`
        with filtering based on provided parameters. At least one of the identifying keys is
        required in the request: `artist_id` / `product_id` / `track_id` or `isrc`.
      security:
        - bearerAuth: []
      parameters:
        - $ref: '#/components/parameters/start_date'
        - $ref: '#/components/parameters/end_date'
        - $ref: '#/components/parameters/artist_id_query_required'
        - $ref: '#/components/parameters/group_by_period'
        - $ref: '#/components/parameters/limit'
        - $ref: '#/components/parameters/offset'
        - $ref: '#/components/parameters/sort_by'
        - $ref: '#/components/parameters/sort_order'
      responses:
        200:
          $ref: '#/components/responses/PopularityResponse'
        400:
          $ref: '#/components/responses/InvalidInput'
        401:
          $ref: '#/components/responses/Unauthorized'
        500:
          $ref: '#/components/responses/InternalError'
  /regions:
    get:
      tags:
        - Resources
      summary: 'Search for Regions'
      operationId: delphi_api.v3.views.regions.RegionsView.search
      description: |
        Resource route for getting a list of `Regions`
        with filtering based on provided parameters
      security:
        - bearerAuth: []
      parameters:
        - $ref: '#/components/parameters/limit'
        - $ref: '#/components/parameters/offset'
        - $ref: '#/components/parameters/sort_by'
        - $ref: '#/components/parameters/sort_order'
      responses:
        200:
          $ref: '#/components/responses/RegionsResponse'
        400:
          $ref: '#/components/responses/InvalidInput'
        401:
          $ref: '#/components/responses/Unauthorized'
        500:
          $ref: '#/components/responses/InternalError'
  /regions/{region_id}:
    get:
      tags:
        - Resources
      summary: 'Query for a single Region'
      operationId: delphi_api.v3.views.regions.RegionsView.get
      description: |
        Resource route for getting a single `Region`
        with filtering based on provided parameters
      security:
        - bearerAuth: []
      parameters:
        - $ref: '#/components/parameters/region_id_path'
      responses:
        200:
          $ref: '#/components/responses/RegionResponse'
        400:
          $ref: '#/components/responses/InvalidInput'
        401:
          $ref: '#/components/responses/Unauthorized'
        404:
          $ref: '#/components/responses/NotFoundError'
        500:
          $ref: '#/components/responses/InternalError'
  /status/data:
    get:
      tags:
        - Resources
      summary: 'Get details about the latest partner data updates'
      operationId: delphi_api.v3.views.status.StatusView.get_data
      description: |
        Resource route for getting the status of partner data updates by DSP.
      security:
        - bearerAuth: []
      responses:
        200:
          $ref: '#/components/responses/DataStatusResponse'
        400:
          $ref: '#/components/responses/InvalidInput'
        401:
          $ref: '#/components/responses/Unauthorized'
        404:
          $ref: '#/components/responses/NotFoundError'
        500:
          $ref: '#/components/responses/InternalError'
  /streams:
    get:
      tags:
        - Resources
      summary: 'Search for Streams'
      operationId: delphi_api.v3.views.streams.StreamsView.search
      description: |
        Resource route for getting a list of `Streams`
        with filtering based on provided parameters
      security:
        - bearerAuth: []
      parameters:
        - $ref: '#/components/parameters/artist_id'
        - $ref: '#/components/parameters/isrc_array'
        - $ref: '#/components/parameters/start_date'
        - $ref: '#/components/parameters/end_date'
        - $ref: '#/components/parameters/country_code_array'
        - $ref: '#/components/parameters/dsp_array'
        - $ref: '#/components/parameters/track_id_array'
        - $ref: '#/components/parameters/playlist_id_array'
        - $ref: '#/components/parameters/chart_id_array'
        - $ref: '#/components/parameters/include_streams'
        - $ref: '#/components/parameters/agg_by'
        - $ref: '#/components/parameters/group_by_period'
        - $ref: '#/components/parameters/subset'
        - $ref: '#/components/parameters/limit'
        - $ref: '#/components/parameters/offset'
        - $ref: '#/components/parameters/sort_by'
        - $ref: '#/components/parameters/sort_order'
      responses:
        200:
          $ref: '#/components/responses/StreamsResponse'
        400:
          $ref: '#/components/responses/InvalidInput'
        401:
          $ref: '#/components/responses/Unauthorized'
        500:
          $ref: '#/components/responses/InternalError'
  /tracks:
    get:
      tags:
        - Resources
      summary: 'Search for Tracks'
      operationId: delphi_api.v3.views.tracks.TracksView.search
      description: |
        Resource route for getting a list of `Tracks`
        with filtering based on provided parameters
      security:
        - bearerAuth: []
      parameters:
        - $ref: '#/components/parameters/isrc_array'
        - $ref: '#/components/parameters/product_id'
        - $ref: '#/components/parameters/artist_id'
        - $ref: '#/components/parameters/limit'
        - $ref: '#/components/parameters/offset'
        - $ref: '#/components/parameters/group_by_field'
        - $ref: '#/components/parameters/sort_by'
        - $ref: '#/components/parameters/sort_order'
      responses:
        200:
          $ref: '#/components/responses/TracksResponse'
        400:
          $ref: '#/components/responses/InvalidInput'
        401:
          $ref: '#/components/responses/Unauthorized'
        500:
          $ref: '#/components/responses/InternalError'
  /tracks/{track_id}:
    get:
      tags:
        - Resources
      summary: 'Query for a single Track'
      operationId: delphi_api.v3.views.tracks.TracksView.get
      description: |
        Resource route for getting a single `Track`
        with filtering based on provided parameters
      security:
        - bearerAuth: []
      parameters:
        - $ref: '#/components/parameters/track_id_path'
      responses:
        200:
          $ref: '#/components/responses/TrackResponse'
        400:
          $ref: '#/components/responses/InvalidInput'
        401:
          $ref: '#/components/responses/Unauthorized'
        404:
          $ref: '#/components/responses/NotFoundError'
        500:
          $ref: '#/components/responses/InternalError'
  /track-positions/charts:
    get:
      tags:
        - Resources
      summary: 'Search for TrackPositions'
      operationId: delphi_api.v3.views.track_positions.TrackPositionsView.search_charts
      description: |
        Resource route for getting a list of `TrackPositions`
        with filtering based on provided parameters. Currently only the latest results within the
        provided date range are included.
      security:
        - bearerAuth: []
      parameters:
        - $ref: '#/components/parameters/start_date'
        - $ref: '#/components/parameters/end_date'
        - $ref: '#/components/parameters/dsp'
        - $ref: '#/components/parameters/chart_id'
        - $ref: '#/components/parameters/artist_id'
        - $ref: '#/components/parameters/isrc_array'
        - $ref: '#/components/parameters/include_tracklist_chart'
        - $ref: '#/components/parameters/limit'
        - $ref: '#/components/parameters/offset'
        - $ref: '#/components/parameters/group_by_period'
        - $ref: '#/components/parameters/sort_by'
        - $ref: '#/components/parameters/sort_order'
      responses:
        200:
          $ref: '#/components/responses/ChartTrackPositionsResponse'
        400:
          $ref: '#/components/responses/InvalidInput'
        401:
          $ref: '#/components/responses/Unauthorized'
        500:
          $ref: '#/components/responses/InternalError'
  /track-positions/playlists:
    get:
      tags:
        - Resources
      summary: 'Search for TrackPositions'
      operationId: delphi_api.v3.views.track_positions.TrackPositionsView.search_playlists
      description: |
        Resource route for getting a list of `TrackPositions`
        with filtering based on provided parameters. Currently only the latest results within the
        provided date range are included.
      security:
        - bearerAuth: []
      parameters:
        - $ref: '#/components/parameters/start_date'
        - $ref: '#/components/parameters/end_date'
        - $ref: '#/components/parameters/dsp'
        - $ref: '#/components/parameters/playlist_id'
        - $ref: '#/components/parameters/artist_id'
        - $ref: '#/components/parameters/isrc_array'
        - $ref: '#/components/parameters/include_tracklist_playlist'
        - $ref: '#/components/parameters/limit'
        - $ref: '#/components/parameters/offset'
        - $ref: '#/components/parameters/group_by_period'
        - $ref: '#/components/parameters/sort_by'
        - $ref: '#/components/parameters/sort_order'
      responses:
        200:
          $ref: '#/components/responses/PlaylistTrackPositionsResponse'
        400:
          $ref: '#/components/responses/InvalidInput'
        401:
          $ref: '#/components/responses/Unauthorized'
        500:
          $ref: '#/components/responses/InternalError'

  ############################################################################
  # Utility Routes
  ############################################################################
  /health:
    get:
      tags:
        - Utility
      summary: 'get basic environment-specific information about the application'
      operationId: delphi_api.v3.views.health.HealthView.get
      responses:
        200:
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/healthCheckResponseBody'

        500:
          $ref: '#/components/responses/InternalError'


  ############################################################################
  # Auth Routes
  ############################################################################
  /oauth/token:
    post:
      tags:
        - Auth
      summary: 'get an access token to make authenticated requests'
      operationId: delphi_api.v2.views.auth.OAuth2.post
      requestBody:
        description: 'access token request body'
        content:
          'application/json':
            schema:
              $ref: '#/components/schemas/authTokenRequestBody'
      responses:
        200:
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/authTokenResponseBody'

        400:
          $ref: '#/components/responses/InvalidInput'
        401:
          $ref: '#/components/responses/Unauthorized'
        500:
          $ref: '#/components/responses/InternalError'


components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      x-bearerInfoFunc: delphi_api.auth.resource_protector.ProxyResourceProtector.decode_token

  responses:
    ##########################################################################
    # Error Responses
    ##########################################################################
    InvalidInput:
      description: 400 Invalid Input Response
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/invalidInputResponseBody'
    Unauthorized:
      description: 401 Unauthorized (AuthError) Response
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/unauthorizedResponseBody'
    InternalError:
      description: 500 Internal Error Response
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/internalErrorResponseBody'
    NotFoundError:
      description: 404 Not Found Error Response
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/notFoundErrorResponseBody'
    ##########################################################################
    # Resource Responses
    ##########################################################################
    PopularityResponse:
      description: '`Popularity` response object'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Popularities'
    ProductResponse:
      description: '`Product` response object'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Product'
    ProductsResponse:
      description: '`Products` response object'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Products'
    ArtistResponse:
      description: '`Artist` response object'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ArtistSimple'
    ArtistsResponse:
      description: '`Artists` response object'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Artists'
    ArtistFollowersResponse:
      description: '`ArtistFollowers` response object'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ArtistFollowers'
    ChartRankResponse:
      description: '`ChartRank` response object'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ChartRank'
    ChartRanksResponse:
      description: '`ChartRanks` response object'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ChartRanks'
    ChartResponse:
      description: '`Chart` response object'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Chart'
    ChartsResponse:
      description: '`Charts` response object'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Charts'
    DataStatusResponse:
      description: '`DataStatus` response object'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/DataStatuses'
    DspResponse:
      description: '`Dsp` response object'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Dsp'
    DspsResponse:
      description: '`Dsps` response object'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Dsps'
    PlaylistRankResponse:
      description: '`PlaylistRank` response object'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/PlaylistRank'
    PlaylistRanksResponse:
      description: '`PlaylistRanks` response object'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/PlaylistRanks'
    PlaylistResponse:
      description: '`Playlist` response object'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Playlist'
    PlaylistsResponse:
      description: '`Playlists` response object'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Playlists'
    RegionResponse:
      description: '`Region` response object'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Region'
    RegionsResponse:
      description: '`Regions` response object'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Regions'
    StreamsResponse:
      description: '`Streams` response object'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Streams'
    TrackResponse:
      description: '`Track` response object'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Track'
    TracksResponse:
      description: '`Tracks` response object'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Tracks'
    ChartTrackPositionsResponse:
      description: '`ChartTrackPositions` response object'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ChartTrackPositions'
    PlaylistTrackPositionsResponse:
      description: '`PlaylistTrackPositions` response object'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/PlaylistTrackPositions'

  parameters:
    agg_by:
      name: agg_by
      description: 'Specific term to aggregate the data (e.g. streams) on'
      in: query
      required: false
      example: 'artist'
      schema:
        $ref: '#/components/schemas/agg_by'
    amazon_playlist_id:
      name: playlist_id
      description: 'Amazon playlist ID'
      in: query
      required: true
      example: 'B07YF2X2F3-B07Z5KBYXK'
      schema:
        $ref: '#/components/schemas/amazon_playlist_id'
    amazon_playlist_id_array:
      name: playlist_id
      description: 'Amazon playlist ID (array)'
      in: query
      required: true
      schema:
        type: array
        items:
          $ref: '#/components/schemas/amazon_playlist_id'
      examples:
        B07YF2X2F3-B07Z5KBYXK:
          value: 'B07YF2X2F3-B07Z5KBYXK'
        B07YF2X2F4-B07Z5KBYXK:
          value: 'B07YF2X2F4-B07Z5KBYXK'
        B07YF2X2F5-B07Z5KBYXK:
          value: 'B07YF2X2F5-B07Z5KBYXK'
        'All Examples':
          value: ['B07YF2X2F3-B07Z5KBYXK', 'B07YF2X2F4-B07Z5KBYXK', 'B07YF2X2F5-B07Z5KBYXK']
    chart_group:
      name: chart_group
      description: 'Identifier for a group of charts'
      in: query
      required: false
      example: 'spotify_top200_daily'
      schema:
        $ref: '#/components/schemas/chart_group'
    country_code:
      name: country_code
      description: 'Typically a lower-case two letter code for the country'
      in: query
      required: false
      example: 'us'
      schema:
        $ref: '#/components/schemas/country_code'
    country_code_array:
      name: country_code
      description: 'Typically a lower-case two letter code for the country'
      in: query
      required: false
      example: 'worldwide'
      schema:
        type: array
        items:
          $ref: '#/components/schemas/country_code'
    dsp:
      name: dsp
      description: 'Slug name of a DSP'
      in: query
      required: false
      example: 'spotify'
      schema:
        $ref: '#/components/schemas/dsp_slug'
    dsp_array:
      name: dsp
      description: 'Slug name of a DSP'
      in: query
      required: false
      examples:
        apple:
          value: 'apple'
        spotify:
          value: 'spotify'
        'Apple & Spotify':
          value: ['apple', 'spotify']
      schema:
        type: array
        items:
          $ref: '#/components/schemas/dsp_slug'
    end_date:
      name: end_date
      description: 'The latest date to include in the query. Data returned is end_date inclusive.'
      in: query
      required: true
      example: '2019-09-01'
      schema:
        $ref: '#/components/schemas/iso_8601_date'
    group_by_field:
      name: group_by
      description: 'Field term to group the data by'
      in: query
      required: false
      example: 'isrc'
      schema:
        $ref: '#/components/schemas/group_by_field'
    group_by_period:
      name: group_by
      description: 'Specific time-based term to group the data by'
      in: query
      required: false
      example: 'date'
      schema:
        $ref: '#/components/schemas/group_by_period'
    include_streams:
      name: include
      description: 'Include optional data like demographics.'
      in: query
      required: false
      example: 'demographics'
      schema:
        $ref: '#/components/schemas/include_streams'
    include_tracklist_chart:
      name: include
      description: |
        Include additional data like the `Chart` object in each response item.
      in: query
      required: false
      example: 'charts'
      schema:
        type: array
        items:
          $ref: '#/components/schemas/include_tracklist_chart'
    include_tracklist_playlist:
      name: include
      description: |
        Include additional data like the `Playlist` object in each response item.
      in: query
      required: false
      example: 'charts'
      schema:
        type: array
        items:
          $ref: '#/components/schemas/include_tracklist_playlist'
    isrc:
      name: isrc
      description: 'International Standard Recording Code (ISRC) number'
      in: query
      required: false
      schema:
        $ref: '#/components/schemas/isrc'
      example: 'USSM11904174'
    isrc_path:
      name: isrc
      description: 'International Standard Recording Code (ISRC) number'
      in: path
      required: true
      schema:
        $ref: '#/components/schemas/isrc'
      example: 'USSM11904174'
    isrc_array:
      name: isrc
      description: 'Array of International Standard Recording Code (ISRC) numbers'
      in: query
      required: false
      schema:
        type: array
        items:
          $ref: '#/components/schemas/isrc'
      examples:
        ESA011891255:
          value: 'ESA011891255'
        USSM11904174:
          value: 'USSM11904174'
        USSD11800343:
          value: 'USSD11800343'
        QMDA61852569:
          value: 'QMDA61852569'
        'All Example ISRCs':
          value: ['ESA011891255', 'USSM11904174', 'USSD11800343', 'QMDA61852569']
    limit:
      in: query
      name: limit
      description: 'The maximum number of `items` to return in a single request.'
      example: 50
      required: false
      schema:
        type: integer
        format: int32
        minimum: 0
        maximum: 5000
    start_date:
      name: start_date
      description: 'The earliest date to include in the query range. Data is start_date inclusive.'
      in: query
      required: true
      example: '2019-08-01'
      schema:
        $ref: '#/components/schemas/iso_8601_date'
    subset:
      name: subset
      description: |
        A subset of data to query without specifying a single item.
        For example, to query for a track in all playlists without providing a `playlist_id`.
        Currently providing `subset=playlists` requires providing parameter `isrc` as well.
        Response items will also be aggregated by `playlist_id` (in addition to ISRC).
      in: query
      required: false
      example: playlists
      schema:
        type: string
        enum:
          - playlists
    offset:
      in: query
      name: offset
      description: 'The number of `items` to offset for pagination.'
      required: false
      example: 0
      schema:
        type: integer
        format: int32
        minimum: 0
    sort_by:
      in: query
      name: sort_by
      description: 'Field name by which to sort the data.'
      required: false
      schema:
        type: string
    sort_order:
      in: query
      name: sort_order
      description: 'Direction to sort the data. Default: `desc` if `sort_by` provided.'
      required: false
      schema:
        type: string
        default: 'desc'
        enum:
          - 'desc'
          - 'asc'
    product_id:
      in: query
      name: product_id
      required: false
      example: 'GRAS_G010003846618R'
      schema:
        $ref: '#/components/schemas/product_id'
    product_id_path:
      in: path
      name: product_id
      required: true
      schema:
        $ref: '#/components/schemas/product_id'
    artist_id:
      in: query
      name: artist_id
      required: false
      schema:
        $ref: '#/components/schemas/artist_id'
    artist_id_query_required:
      in: query
      name: artist_id
      required: true
      description: 'This `artist_id` query parameter is required'
      schema:
        $ref: '#/components/schemas/artist_id'
    artist_id_path:
      in: path
      name: artist_id
      required: true
      schema:
        $ref: '#/components/schemas/artist_id'
    chart_id:
      in: query
      name: chart_id
      required: false
      example: 'spotify_top200_daily_us'
      schema:
        $ref: '#/components/schemas/chart_id'
    chart_id_array:
      in: query
      name: chart_id
      required: false
      schema:
        type: array
        items:
          $ref: '#/components/schemas/chart_id'
    chart_id_path:
      in: path
      name: chart_id
      required: true
      schema:
        $ref: '#/components/schemas/chart_id'
    dsp_id:
      in: query
      name: dsp_id
      required: false
      schema:
        $ref: '#/components/schemas/dsp_id'
    dsp_id_path:
      in: path
      name: dsp_id
      required: true
      schema:
        $ref: '#/components/schemas/dsp_id'
    label_id:
      in: query
      name: label_id
      required: false
      schema:
        $ref: '#/components/schemas/label_id'
    label_id_path:
      in: path
      name: label_id
      required: true
      schema:
        $ref: '#/components/schemas/label_id'
    playlist_id:
      in: query
      name: playlist_id
      required: false
      schema:
        $ref: '#/components/schemas/playlist_id'
    playlist_id_array:
      in: query
      name: playlist_id
      required: false
      schema:
        type: array
        items:
          $ref: '#/components/schemas/playlist_id'
    playlist_id_path:
      in: path
      name: playlist_id
      required: true
      schema:
        $ref: '#/components/schemas/playlist_id'
    region_id:
      in: query
      name: region_id
      required: false
      schema:
        $ref: '#/components/schemas/region_id'
    region_id_path:
      in: path
      name: region_id
      required: true
      schema:
        $ref: '#/components/schemas/region_id'
    track_id:
      in: query
      name: track_id
      required: false
      schema:
        $ref: '#/components/schemas/track_id'
    track_id_array:
      in: query
      name: track_id
      required: false
      schema:
        type: array
        items:
          $ref: '#/components/schemas/track_id'
    track_id_path:
      in: path
      name: track_id
      required: true
      schema:
        $ref: '#/components/schemas/track_id'

  schemas:
    ##########################################################################
    # Request/Response Body Schemas
    ##########################################################################
    authTokenRequestBody:
      type: object
      properties:
        client_id:
          description: 'Required – `client_id` from identity provider credentials'
          type: string
          example: 'REPLACE_WITH_YOUR_CLIENT_ID'
        client_secret:
          description: 'Required – `client_secret` from identity provider credentials'
          type: string
          example: 'REPLACE_WITH_YOUR_CLIENT_SECRET'
        grant_type:
          description: 'Defaults to `client_credentials` as the only currently supported method'
          type: string
          example: 'client_credentials'
    authTokenResponseBody:
      type: object
      properties:
        access_token:
          type: string
          example: 'EXAMPLE7J0JtkhGZzA6MscSiUH8qYwer...'
        scope:
          description: 'After authorizing, the available scopes are returned in a standard space deliminated format.'
          type: string
          example: 'read:files'
        expires_in:
          description: 'Length in seconds until token expiration.'
          type: number
          example: 86400
        expires_at:
          description: 'The timestamp of the token expiration in the (Unix) epoch format.'
          type: number
          format: int32
          example: 1569612083
        token_type:
          description: 'The token type, currently the only implementation is for `Bearer`.'
          type: string
          example: 'Bearer'
    healthCheckResponseBody:
      type: object
      description: 'Health check response body'
      properties:
        api_version:
          type: string
          example: '3.0.0'
        environment:
          type: string
          example: 'stage'
        status:
          type: string
          example: 'OK'
    invalidInputResponseBody:
      type: object
      description: 400 Invalid Input Response Body
      properties:
        code:
          type: string
          example: invalid_input
        description:
          type: object
    unauthorizedResponseBody:
      type: object
      description: 401 Unauthorized (AuthError) Response Body
      properties:
        code:
          type: string
          example: invalid_header
        description:
          type: string
          example: 'Unable to parse authentication token'
    internalErrorResponseBody:
      type: object
      description: 500 Internal Error Response Body
      properties:
        code:
          type: string
          example: internal_error
        description:
          type: string
          example: 'The application encountered an internal error'
        details:
          type: string
          example: 'more specific details about the error for debugging'
    notFoundErrorResponseBody:
      type: object
      description: 404 Not Found Error Response Body
      properties:
        code:
          type: string
          example: item_not_found
        description:
          type: string
          example: 'The item you searched for could not be found'

    ##########################################################################
    # Standardized Property Schemas
    ##########################################################################
    agg_by:
      description: 'Specific term to aggregate the data (e.g. streams) on'
      type: string
      enum:
        - artist
        - isrc
    amazon_chart_id:
      type: string
      example: 'B07YF2X2F3-B07Z5KBYXK'
      nullable: true
    amazon_playlist_id:
      type: string
      example: 'B07YF2X2F3-B07Z5KBYXK'
      nullable: true
    apple_chart_id:
      type: string
      nullable: true
    apple_playlist_id:
      type: string
      nullable: true
    chart_group:
      description: 'Portion of chart primary key describing a general group the chart may belong to'
      type: string
      nullable: false
      example: 'spotify_top200_daily'
    count:
      type: integer
      description: 'The number of ``items`` returned in the response'
      format: int32
      example: 25
    country_code:
      type: string
      description: 'Typically a lower-case two letter code for the country'
      nullable: false
      example: 'us'
    country_code_nullable:
      type: string
      description: 'Typically a lower-case two letter code for the country'
      nullable: true
      example: 'us'
    demographics_value:
      type: integer
      nullable: true
      description: |
        Value for a demographics field. If we are missing data for the field, show it as ``null``
        instead of ``0``, to allow client to interpolate for missing data points.
      example: 10500
    dsp_slug:
      type: string
      description: 'Slug name of a DSP'
      pattern: '^[a-z]*$'
      example: 'apple'
      nullable: false
    dsp_slug_nullable:
      type: string
      description: 'Slug name of a DSP'
      pattern: '^[a-z]*$'
      example: 'apple'
      nullable: true
    include_streams:
      description: 'Names of child objects to include'
      type: string
      enum:
        - demographics
    include_tracklist_chart:
      type: string
      description: 'Available `include` values for tracklists of charts'
      nullable: true
      example: 'charts'
      enum:
        - charts
    include_tracklist_playlist:
      type: string
      description: 'Available `include` values for tracklists of playlists'
      nullable: true
      example: 'playlists'
      enum:
        - playlists
        - streams
    group_by_field:
      description: |
        Field to group data by. Defaults to `track_id` if not provided where relevant.
        This parameter is used akin to a SQL `GROUP BY` clause where fewer results may be returned.
      type: string
      enum:
        - isrc
        - track_id
    group_by_period:
      description: 'Period to group data by. Currently only grouping by `date` (day) is supported'
      type: string
      enum:
        - date
    number_streams:
      type: integer
      nullable: true
      description: 'The number of streams, aggregated by provided filter parameters.'
      example: 200321
    number_followers:
      type: integer
      example: 99321
      nullable: true
    number_views:
      type: integer
      example: 1555000
      nullable: true
    number_likes:
      type: integer
      example: 432000
      nullable: true
    image_uri:
      type: string
      description: 'The direct full URI location of an image.'
      nullable: false
      format: uri
      example: 'https://i.scdn.co/image/ab67706f00000002278197087524cc094f86e82b'
    iso_8601_date:
      type: string
      description: 'ISO 8601 date in format `YYYY-MM-DD`'
      format: date
      pattern: '^\d{4}-\d{2}-\d{2}$'
      example: '2020-01-01'
      nullable: true
    isrc:
      type: string
      description: 'The International Standard Recording Code (ISRC) for a song.'
      pattern: '^[A-Z]{2}\w{3}\d{2}\d{5}$'
      example: 'USSM10202700'
      nullable: false
    isrc_nullable:
      type: string
      description: 'The International Standard Recording Code (ISRC) for a song.'
      example: 'USSM10202700'
      nullable: true
    rank:
      description: 'SME internal ranking'
      type: integer
      nullable: true
      example: 5
    global_rank:
      description: 'SME internal ranking latest for global region'
      type: integer
      nullable: true
      example: 5
    spotify_chart_id:
      description: 'Spotify chart ID'
      example: '16C3dR9mCY3welkjSZqNXR'
      type: string
      nullable: true
    spotify_playlist_id:
      description: 'Spotify playlist ID in `spotify:playlist:{ID_HERE}`'
      example: '03mUE11LSpb7eePR2ck5P4'
      type: string
      nullable: true
    spotify_playlist_uri:
      description: 'Spotify playlist URI'
      example: 'spotify:playlist:03mUE11LSpb7eePR2ck5P4'
      type: string
      nullable: true
    spotify_popularity:
      description: |
        The popularity of a track is a value between 0 and 100, with 100 being the most popular.
        The popularity is calculated by algorithm and is based, in the most part, on the
        total number of plays the track has had and how recent those plays are.
        Generally speaking, songs that are being played a lot now will have a higher popularity
        than songs that were played a lot in the past.
        Duplicate tracks (e.g. the same track from a single and an product) are rated independently.
        Artist and album popularity is derived mathematically from track popularity.
        Note that the popularity value may lag actual popularity by a few days:
        the value is not updated in real time.
      example: 85
      type: integer
      nullable: true
    uuid_identifier:
      type: string
      format: uuid
      example: 'b7f32308-f5fc-49eb-8448-cc147f6a882c'
      description: 'UUID format primary key identifier'
    youtube_chart_id:
      description: 'YouTube chart Identifier'
      type: string
      nullable: true
    youtube_playlist_id:
      description: 'YouTube playlist Identifier'
      type: string
      nullable: true

    ##########################################################################
    # Primary Key Property Schemas
    ##########################################################################
    artist_id:
      type: string
      description: 'Primary key identifier for Artist'
      nullable: false
      example: 'GRAS_740645'
    artist_id_nullable:
      type: string
      description: 'Primary key identifier for Artist'
      nullable: true
      example: 'GRAS_740645'
    chart_id:
      type: string
      description: 'Primary key identifier for Chart'
      nullable: false
      example: 'spotify_top200_daily_us'
    chart_id_nullable:
      type: string
      description: 'Primary key identifier for Chart'
      nullable: true
      example: 'spotify_top200_daily_us'
    dsp_id:
      type: string
      description: 'Primary key identifier for Dsp'
      nullable: false
      example: 'spotify'
    dsp_id_nullable:
      type: string
      description: 'Primary key identifier for Dsp'
      nullable: true
      example: 'spotify'
    dsp_chart_id:
      type: string
      description: 'Object identifier used by the related Dsp. (unknown if this field will exist)'
      nullable: false
    dsp_chart_id_nullable:
      type: string
      description: 'Object identifier used by the related Dsp. (unknown if this field will exist)'
      nullable: true
    label_id:
      type: string
      description: 'Primary key identifier for Label'
      nullable: false
    playlist_id:
      type: string
      description: 'Primary key identifier for Playlist'
      nullable: false
      example: 'spotify_02C8uKtc6CoBpD0IdqOZdT'
    playlist_id_nullable:
      type: string
      description: 'Primary key identifier for Playlist'
      nullable: true
      example: 'spotify_02C8uKtc6CoBpD0IdqOZdT'
    dsp_playlist_id:
      type: string
      description: 'Playlist object identifier used by the related Dsp.'
      nullable: false
      example: '02C8uKtc6CoBpD0IdqOZdT'
    dsp_playlist_id_nullable:
      type: string
      description: 'Playlist object identifier used by the related Dsp.'
      nullable: true
      example: '02C8uKtc6CoBpD0IdqOZdT'
    product_id:
      type: string
      description: 'Primary key identifier for Product'
      nullable: false
      example: 'GRAS_G010003846618R'
    product_id_nullable:
      type: string
      description: 'Primary key identifier for Product'
      nullable: true
      example: 'GRAS_G010003846618R'
    region_id:
      type: string
      description: 'Primary key identifier for Region. Same as the country_code'
      nullable: false
      example: 'us'
    region_id_nullable:
      type: string
      description: 'Primary key identifier for Region. Same as the country_code'
      nullable: true
      example: 'us'
    track_id:
      type: string
      description: 'Primary key identifier for Track'
      nullable: false
      example: 'GRAS_A10328E0008535954C'
    track_id_nullable:
      type: string
      description: 'Primary key identifier for Track'
      nullable: true
      example: 'GRAS_A10328E0008535954C'

    ##########################################################################
    # Resource Schemas
    ##########################################################################
    ProductSimple:
      type: object
      properties:
        name:
          type: string
        product_id:
          $ref: '#/components/schemas/product_id'
        release_date:
          type: string
          format: date
          nullable: true
      required:
        - name
        - product_id

    Product:
      allOf:
        - $ref: '#/components/schemas/ProductSimple'
        - type: object
          properties:
            artists:
              type: array
              items:
                $ref: '#/components/schemas/ArtistSimple'
            tracks:
              type: array
              items:
                $ref: '#/components/schemas/TrackSimple'
            label:
              $ref: '#/components/schemas/Label'

    Products:
      type: object
      description: 'Products response container'
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/ProductSimple'
        count:
          $ref: '#/components/schemas/count'

    ArtistSimple:
      type: object
      properties:
        artist_id:
          $ref: '#/components/schemas/artist_id'
        full_name:
          type: string
        first_name:
          type: string
          nullable: true
        last_name:
          type: string
          nullable: true
        spotify_uri:
          type: string
          format: uri
          nullable: true
        spotify_popularity:
          $ref: '#/components/schemas/spotify_popularity'
        image:
          $ref: '#/components/schemas/ImageSimple'
      required:
        - full_name
        - artist_id

    Artist:
      allOf:
        - $ref: '#/components/schemas/ArtistSimple'
        - type: object
          properties:
            products:
              type: array
              items:
                $ref: '#/components/schemas/ProductSimple'
            tracks:
              type: array
              items:
                $ref: '#/components/schemas/TrackSimple'

    Artists:
      type: object
      description: 'Artists response container'
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/ArtistSimple'
        count:
          $ref: '#/components/schemas/count'

    ArtistFollower:
      type: object
      properties:
        date:
          $ref: '#/components/schemas/iso_8601_date'
        apple_followers:
          $ref: '#/components/schemas/number_followers'
        facebook_likes:
          $ref: '#/components/schemas/number_likes'
        facebook_storytellers:
          $ref: '#/components/schemas/number_followers'
        instagram_followers:
          $ref: '#/components/schemas/number_followers'
        spotify_followers:
          $ref: '#/components/schemas/number_followers'
        spotify_popularity:
          $ref: '#/components/schemas/spotify_popularity'
        twitter_followers:
          $ref: '#/components/schemas/number_followers'
        youtube_channel_subscribers:
          $ref: '#/components/schemas/number_followers'
        youtube_channel_views:
          $ref: '#/components/schemas/number_views'

    ArtistFollowers:
      type: object
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/ArtistFollower'
        count:
          $ref: '#/components/schemas/count'

    Chart:
      type: object
      properties:
        name:
          type: string
          example: 'Spotify Top 100'
        chart_id:
          $ref: '#/components/schemas/chart_id'
        chart_group:
          $ref: '#/components/schemas/chart_group'
        num_tracks:
          type: integer
          description: 'Total number of tracks in the chart'
          default: 0
          example: 100
          nullable: true
        country_code:
          $ref: '#/components/schemas/country_code'
        rank:
          $ref: '#/components/schemas/global_rank'
        dsp:
          $ref: '#/components/schemas/Dsp'
        image:
          $ref: '#/components/schemas/ImageSimple'
      required:
        - name
        - chart_id

    Charts:
      type: object
      description: 'Charts response container'
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/Chart'
        count:
          $ref: '#/components/schemas/count'

    Gender:
      type: object
      nullable: true
      properties:
        female:
          $ref: '#/components/schemas/demographics_value'
        male:
          $ref: '#/components/schemas/demographics_value'
        unknown:
          $ref: '#/components/schemas/demographics_value'
        neutral:
          $ref: '#/components/schemas/demographics_value'

    DataStatus:
      type: object
      description: 'Object containing the data status for a single DSP'
      properties:
        dsp_id:
          $ref: '#/components/schemas/dsp_id'
        updated_date:
          $ref: '#/components/schemas/iso_8601_date'
      required:
        - dsp_id
        - updated_date

    DataStatuses:
      type: object
      description: 'DataStatus response container'
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/DataStatus'
        count:
          $ref: '#/components/schemas/count'

    Dsp:
      type: object
      properties:
        name:
          type: string
          example: 'Amazon'
        dsp_id:
          $ref: '#/components/schemas/dsp_id'
        slug:
          type: string
          description: 'Unique slug identifier for DSP.'
          example: 'amazon'
      required:
        - name
        - dsp_id
        - slug

    Dsps:
      type: object
      description: 'Dsps response container'
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/Dsp'
        count:
          $ref: '#/components/schemas/count'

    AppleAgeBand:
      type: object
      nullable: true
      description: 'Apple-specific age bands'
      properties:
        all_18_24:
          $ref: '#/components/schemas/demographics_value'
        all_25_34:
          $ref: '#/components/schemas/demographics_value'
        all_35_44:
          $ref: '#/components/schemas/demographics_value'
        all_45_54:
          $ref: '#/components/schemas/demographics_value'
        all_55_64:
          $ref: '#/components/schemas/demographics_value'
        all_65_plus:
          $ref: '#/components/schemas/demographics_value'
        all_unknown:
          $ref: '#/components/schemas/demographics_value'
        male_18_24:
          $ref: '#/components/schemas/demographics_value'
        male_25_34:
          $ref: '#/components/schemas/demographics_value'
        male_35_44:
          $ref: '#/components/schemas/demographics_value'
        male_45_54:
          $ref: '#/components/schemas/demographics_value'
        male_55_64:
          $ref: '#/components/schemas/demographics_value'
        male_65_plus:
          $ref: '#/components/schemas/demographics_value'
        male_unknown:
          $ref: '#/components/schemas/demographics_value'
        female_18_24:
          $ref: '#/components/schemas/demographics_value'
        female_25_34:
          $ref: '#/components/schemas/demographics_value'
        female_35_44:
          $ref: '#/components/schemas/demographics_value'
        female_45_54:
          $ref: '#/components/schemas/demographics_value'
        female_55_64:
          $ref: '#/components/schemas/demographics_value'
        female_65_plus:
          $ref: '#/components/schemas/demographics_value'
        female_unknown:
          $ref: '#/components/schemas/demographics_value'
        unknown_18_24:
          $ref: '#/components/schemas/demographics_value'
        unknown_25_34:
          $ref: '#/components/schemas/demographics_value'
        unknown_35_44:
          $ref: '#/components/schemas/demographics_value'
        unknown_45_54:
          $ref: '#/components/schemas/demographics_value'
        unknown_55_64:
          $ref: '#/components/schemas/demographics_value'
        unknown_65_plus:
          $ref: '#/components/schemas/demographics_value'
        unknown_unknown:
          $ref: '#/components/schemas/demographics_value'

    SpotifyAgeBand:
      type: object
      nullable: true
      description: 'Spotify-specific age bands'
      properties:
        all_0_17:
          $ref: '#/components/schemas/demographics_value'
        all_18_22:
          $ref: '#/components/schemas/demographics_value'
        all_23_27:
          $ref: '#/components/schemas/demographics_value'
        all_28_34:
          $ref: '#/components/schemas/demographics_value'
        all_35_44:
          $ref: '#/components/schemas/demographics_value'
        all_45_59:
          $ref: '#/components/schemas/demographics_value'
        all_60_150:
          $ref: '#/components/schemas/demographics_value'
        all_unknown:
          $ref: '#/components/schemas/demographics_value'
        female_0_17:
          $ref: '#/components/schemas/demographics_value'
        female_18_22:
          $ref: '#/components/schemas/demographics_value'
        female_23_27:
          $ref: '#/components/schemas/demographics_value'
        female_28_34:
          $ref: '#/components/schemas/demographics_value'
        female_35_44:
          $ref: '#/components/schemas/demographics_value'
        female_45_59:
          $ref: '#/components/schemas/demographics_value'
        female_60_150:
          $ref: '#/components/schemas/demographics_value'
        female_unknown:
          $ref: '#/components/schemas/demographics_value'
        male_0_17:
          $ref: '#/components/schemas/demographics_value'
        male_18_22:
          $ref: '#/components/schemas/demographics_value'
        male_23_27:
          $ref: '#/components/schemas/demographics_value'
        male_28_34:
          $ref: '#/components/schemas/demographics_value'
        male_35_44:
          $ref: '#/components/schemas/demographics_value'
        male_45_59:
          $ref: '#/components/schemas/demographics_value'
        male_60_150:
          $ref: '#/components/schemas/demographics_value'
        male_unknown:
          $ref: '#/components/schemas/demographics_value'
        neutral_0_17:
          $ref: '#/components/schemas/demographics_value'
        neutral_18_22:
          $ref: '#/components/schemas/demographics_value'
        neutral_23_27:
          $ref: '#/components/schemas/demographics_value'
        neutral_28_34:
          $ref: '#/components/schemas/demographics_value'
        neutral_35_44:
          $ref: '#/components/schemas/demographics_value'
        neutral_45_59:
          $ref: '#/components/schemas/demographics_value'
        neutral_60_150:
          $ref: '#/components/schemas/demographics_value'
        neutral_unknown:
          $ref: '#/components/schemas/demographics_value'
        unknown_0_17:
          $ref: '#/components/schemas/demographics_value'
        unknown_18_22:
          $ref: '#/components/schemas/demographics_value'
        unknown_23_27:
          $ref: '#/components/schemas/demographics_value'
        unknown_28_34:
          $ref: '#/components/schemas/demographics_value'
        unknown_35_44:
          $ref: '#/components/schemas/demographics_value'
        unknown_45_59:
          $ref: '#/components/schemas/demographics_value'
        unknown_60_150:
          $ref: '#/components/schemas/demographics_value'
        unknown_unknown:
          $ref: '#/components/schemas/demographics_value'

    YouTubeAgeBand:
      type: object
      description: 'YouTube-specific age bands'
      nullable: true
      properties:
        all_0_18:
          $ref: '#/components/schemas/demographics_value'
        all_18_24:
          $ref: '#/components/schemas/demographics_value'
        all_25_34:
          $ref: '#/components/schemas/demographics_value'
        all_35_44:
          $ref: '#/components/schemas/demographics_value'
        all_45_54:
          $ref: '#/components/schemas/demographics_value'
        all_55_64:
          $ref: '#/components/schemas/demographics_value'
        all_65_plus:
          $ref: '#/components/schemas/demographics_value'
        all_unknown:
          $ref: '#/components/schemas/demographics_value'
        female_0_18:
          $ref: '#/components/schemas/demographics_value'
        female_18_24:
          $ref: '#/components/schemas/demographics_value'
        female_25_34:
          $ref: '#/components/schemas/demographics_value'
        female_35_44:
          $ref: '#/components/schemas/demographics_value'
        female_45_54:
          $ref: '#/components/schemas/demographics_value'
        female_55_64:
          $ref: '#/components/schemas/demographics_value'
        female_65_plus:
          $ref: '#/components/schemas/demographics_value'
        female_unknown:
          $ref: '#/components/schemas/demographics_value'
        male_0_18:
          $ref: '#/components/schemas/demographics_value'
        male_18_24:
          $ref: '#/components/schemas/demographics_value'
        male_25_34:
          $ref: '#/components/schemas/demographics_value'
        male_35_44:
          $ref: '#/components/schemas/demographics_value'
        male_45_54:
          $ref: '#/components/schemas/demographics_value'
        male_55_64:
          $ref: '#/components/schemas/demographics_value'
        male_65_plus:
          $ref: '#/components/schemas/demographics_value'
        male_unknown:
          $ref: '#/components/schemas/demographics_value'
        unknown_0_18:
          $ref: '#/components/schemas/demographics_value'
        unknown_18_24:
          $ref: '#/components/schemas/demographics_value'
        unknown_25_34:
          $ref: '#/components/schemas/demographics_value'
        unknown_35_44:
          $ref: '#/components/schemas/demographics_value'
        unknown_45_54:
          $ref: '#/components/schemas/demographics_value'
        unknown_55_64:
          $ref: '#/components/schemas/demographics_value'
        unknown_65_plus:
          $ref: '#/components/schemas/demographics_value'
        unknown_unknown:
          $ref: '#/components/schemas/demographics_value'

    ImageSimple:
      type: object
      nullable: true
      description: 'Very basic image container populated with a URI from Atlas (Core)'
      properties:
        uri:
          $ref: '#/components/schemas/image_uri'
        height:
          type: integer
          nullable: true
          description: 'Height of the Image in pixels'
          example: 300
        width:
          type: integer
          nullable: true
          description: 'Width of the Image in pixels'
          example: 300

    Label:
      type: object
      properties:
        name:
          type: string
          example: 'SME'
        label_id:
          $ref: '#/components/schemas/label_id'
      required:
        - name
        - label_id

    Labels:
      type: object
      description: 'Labels response container'
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/Label'
        count:
          $ref: '#/components/schemas/count'

    Playlist:
      type: object
      properties:
        name:
          type: string
          example: 'Downtempo & Lofi Electronic'
        playlist_id:
          $ref: '#/components/schemas/playlist_id'
        uri:
          type: string
          description: 'DSP URI to the playlist'
          format: uri
          example: 'spotify:playlist:03mUE11LSpb7eePR2ck5P4'
          nullable: true
        num_tracks:
          type: integer
          description: 'Total number of tracks in the playlist'
          default: 0
          example: 100
          nullable: true
        country_code:
          $ref: '#/components/schemas/country_code_nullable'
        rank:
          $ref: '#/components/schemas/global_rank'
        dsp:
          $ref: '#/components/schemas/Dsp'
        dsp_playlist_id:
          $ref: '#/components/schemas/dsp_playlist_id'
        image:
          $ref: '#/components/schemas/ImageSimple'
      required:
        - name
        - playlist_id

    Playlists:
      type: object
      description: 'Playlists response container'
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/Playlist'
        count:
          $ref: '#/components/schemas/count'

    Popularity:
      type: object
      description: 'Schema containing the Spotify popularity fields'
      properties:
        artist_id:
          $ref: '#/components/schemas/artist_id_nullable'
        date:
          $ref: '#/components/schemas/iso_8601_date'
        spotify_popularity:
          $ref: '#/components/schemas/spotify_popularity'
      required:
        - spotify_popularity

    Popularities:
      type: object
      description: 'Popularities response container'
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/Popularity'
        count:
          $ref: '#/components/schemas/count'

    Region:
      type: object
      properties:
        region_id:
          $ref: '#/components/schemas/region_id'
        country_code:
          type: string
          description: 'Unique ISO 3166 alpha 2 code.'
          example: 'US'
        country_name:
          type: string
          description: 'ISO 3166 country name.'
          example: 'United States of America'
      required:
        - region_id
        - country_code
        - country_name

    Regions:
      type: object
      description: 'Countries response container'
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/Region'
        count:
          $ref: '#/components/schemas/count'

    Stream:
      type: object
      properties:
        date:
          $ref: '#/components/schemas/iso_8601_date'
        dsp:
          $ref: '#/components/schemas/dsp_slug_nullable'
        region_id:
          $ref: '#/components/schemas/region_id_nullable'
        country_code:
          $ref: '#/components/schemas/country_code'
        streams:
          $ref: '#/components/schemas/number_streams'
        artist_id:
          $ref: '#/components/schemas/artist_id_nullable'
        track_id:
          $ref: '#/components/schemas/track_id_nullable'
        playlist_id:
          $ref: '#/components/schemas/playlist_id_nullable'
        isrc:
          $ref: '#/components/schemas/isrc_nullable'
        apple_age_bands:
          $ref: '#/components/schemas/AppleAgeBand'
        spotify_age_bands:
          $ref: '#/components/schemas/SpotifyAgeBand'
        youtube_age_bands:
          $ref: '#/components/schemas/YouTubeAgeBand'
        genders:
          $ref: '#/components/schemas/Gender'
      required:
        - country_code
        - streams

    Streams:
      type: object
      description: 'Streams response container'
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/Stream'
        count:
          $ref: '#/components/schemas/count'

    TrackSimple:
      type: object
      properties:
        name:
          type: string
          example: 'Iron Man'
        track_name_suppl:
          type: string
          example: 'Album Version'
          nullable: true
        track_id:
          $ref: '#/components/schemas/track_id'
        product:
          $ref: '#/components/schemas/ProductSimple'
        isrc:
          $ref: '#/components/schemas/isrc'
        release_date:
          type: string
          format: date
          nullable: true
      required:
        - name
        - track_id
        - isrc

    Track:
      allOf:
        - $ref: '#/components/schemas/TrackSimple'
        - type: object
          properties:
            artists:
              type: array
              items:
                $ref: '#/components/schemas/ArtistSimple'

    Tracks:
      type: object
      description: 'Tracks response container'
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/TrackSimple'
        count:
          $ref: '#/components/schemas/count'

    BaseTrackPosition:
      type: object
      description: 'Object containing the base details of a Track `Position`.'
      properties:
        isrc:
          $ref: '#/components/schemas/isrc'
        dsp:
          $ref: '#/components/schemas/dsp_slug_nullable'
        current:
          type: integer
          example: 5
          nullable: true
        previous:
          type: integer
          example: 12
          nullable: true
        top:
          type: integer
          example: 3
          nullable: true
        num_weeks_on:
          type: integer
          example: 12
          nullable: true
        date:
          $ref: '#/components/schemas/iso_8601_date'

    ChartTrackPositionSimple:
      allOf:
        - $ref: '#/components/schemas/BaseTrackPosition'
        - type: object
          description: 'Object containing the details of a Track `Position` in a tracklist.'
          properties:
            chart_id:
              $ref: '#/components/schemas/chart_id'

    ChartTrackPosition:
      allOf:
        - $ref: '#/components/schemas/ChartTrackPositionSimple'
        - type: object
          description: 'Object containing the details of a Track `Position` in a tracklist.'
          properties:
            chart_id:
              $ref: '#/components/schemas/chart_id'
            chart:
              $ref: '#/components/schemas/Chart'

    ChartTrackPositions:
      type: object
      description: 'ChartTrackPositions response container'
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/ChartTrackPosition'
        count:
          $ref: '#/components/schemas/count'

    PlaylistRankSimple:
      type: object
      description: 'Object containing the base details of a Playlist market rank'
      properties:
        playlist_rank_id:
          type: integer
          nullable: true
          example: 12345
        playlist_id:
          $ref: '#/components/schemas/playlist_id'
        report_date:
          $ref: '#/components/schemas/iso_8601_date'
        rank:
          $ref: '#/components/schemas/rank'
        dsp_id:
          $ref: '#/components/schemas/dsp_id'
        country_code:
          $ref: '#/components/schemas/country_code'

    PlaylistRank:
      allOf:
        - $ref: '#/components/schemas/PlaylistRankSimple'
        - type: object
          properties:
            playlist:
              $ref: '#/components/schemas/Playlist'

    PlaylistRanks:
      type: object
      description: 'PlaylistRank response container'
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/PlaylistRank'
        count:
          $ref: '#/components/schemas/count'

    ChartRankSimple:
      type: object
      description: 'Object containing the base details of a Chart market rank'
      properties:
        chart_rank_id:
          type: integer
          nullable: true
          example: 12345
        chart_id:
          $ref: '#/components/schemas/chart_id'
        report_date:
          $ref: '#/components/schemas/iso_8601_date'
        rank:
          $ref: '#/components/schemas/rank'
        dsp_id:
          $ref: '#/components/schemas/dsp_id'
        country_code:
          $ref: '#/components/schemas/country_code'

    ChartRank:
      allOf:
        - $ref: '#/components/schemas/ChartRankSimple'
        - type: object
          properties:
            chart:
              $ref: '#/components/schemas/Chart'

    ChartRanks:
      type: object
      description: 'ChartRank response container'
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/ChartRank'
        count:
          $ref: '#/components/schemas/count'

    PlaylistTrackPositionSimple:
      allOf:
        - $ref: '#/components/schemas/BaseTrackPosition'
        - type: object
          description: 'Object containing the details of a Track `Position` in a tracklist.'
          properties:
            playlist_id:
              $ref: '#/components/schemas/playlist_id'

    PlaylistTrackPosition:
      allOf:
        - $ref: '#/components/schemas/PlaylistTrackPositionSimple'
        - type: object
          description: 'Object containing the details of a Track `Position` in a tracklist.'
          properties:
            playlist_id:
              $ref: '#/components/schemas/playlist_id'
            playlist:
              $ref: '#/components/schemas/Playlist'
            streams:
              $ref: '#/components/schemas/number_streams'

    PlaylistTrackPositions:
      type: object
      description: 'PlaylistTrackPositions response container'
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/PlaylistTrackPosition'
        count:
          $ref: '#/components/schemas/count'
