From cbbcd70463862c5aac1c2467d70895a77bdb96b3 Mon Sep 17 00:00:00 2001 From: Mike Crute Date: Sun, 29 Oct 2017 04:32:32 +0000 Subject: Stub out REST API docs --- index.rst | 2 +- rest/authentication.rst | 88 +++++++++++++++++++++++ rest/endpoints.rst | 134 +++++++++++++++++++++++++++++++++++ rest/errorcodes.rst | 41 +++++++++++ rest/implementations.rst | 11 +++ rest/index.rst | 84 ++++++++++++++++++++++ rest/stations.rst | 178 +++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 537 insertions(+), 1 deletion(-) create mode 100644 rest/authentication.rst create mode 100644 rest/endpoints.rst create mode 100644 rest/errorcodes.rst create mode 100644 rest/implementations.rst create mode 100644 rest/index.rst create mode 100644 rest/stations.rst diff --git a/index.rst b/index.rst index 5d0bbc2..bd2c377 100644 --- a/index.rst +++ b/index.rst @@ -25,4 +25,4 @@ Suggestions and patches are welcome. :maxdepth: 2 json/index - + rest/index diff --git a/rest/authentication.rst b/rest/authentication.rst new file mode 100644 index 0000000..763ddcc --- /dev/null +++ b/rest/authentication.rst @@ -0,0 +1,88 @@ +.. _rest-authentication: + +============== +Authentication +============== + +.. _rest-v1-auth-login: + +User Login +========== + +:Endpoint: /v1/login + +Request +------- +.. code:: json + + { + "existingAuthToken": null, + "keepLoggedIn": true, + "password": "secretpassword", + "username": "email@example.com" + } + +.. csv-table:: + :header: Name,Type,Description + + username,string,User's username + password,string,User's password + +Response +-------- +.. code:: json + + { + "activeVxRewards": [], + "adkv": {}, + "allowProfileComments": false, + "artistAudioMessagesEnabled": false, + "artistPromoEmailsEnabled": false, + "authToken": "dGhpcyBpcyBqdXN0IGFuIGV4YW1wbGUgY29kZQo=", + "birthYear": 1920, + "config": { + "branding": "PandoraPlus", + "dailySkipLimit": 60, + "experiments": [ + 123, + 456 + ], + "flags": [ + "noAds", + "adFreeSkip", + "adFreeReplay", + "noSmartConversion", + "disableNonAdPageTimeout", + "highQualityStreamingAvailable", + "replaysEnabled" + ], + "inactivityTimeout": 28800, + "monthlyListeningCapHours": 320, + "stationSkipLimit": 6 + }, + "emailOptOut": true, + "explicitContentFilterEnabled": false, + "gender": "FEMALE", + "highQualityStreamingEnabled": true, + "isNew": false, + "listenerId": "12345", + "listenerToken": "GFuIGV4YW1wbGUgY29kZQodGhpcyBpcyBqdXN0I", + "minor": false, + "notifyOnComment": true, + "notifyOnFollow": true, + "profilePrivate": true, + "seenEducation": true, + "smartConversionAdUrl": "https://adserver.pandora.com/...", + "smartConversionDisabled": true, + "smartConversionTimeoutMillis": 5000, + "stationCount": 13, + "username": "email@example.com", + "webClientVersion": "0.48.0", + "webname": "user", + "zipCode": "12345" + } + +.. csv-table:: + :header: Name,Type,Description + + authToken,string,See :ref:`rest-auth-token` diff --git a/rest/endpoints.rst b/rest/endpoints.rst new file mode 100644 index 0000000..d7b893d --- /dev/null +++ b/rest/endpoints.rst @@ -0,0 +1,134 @@ +================= +List of Endpoints +================= + +.. index:: + single: REST Endpoints + +.. _endpoints: + +- :ref:`\/v1/ad/brokenAd ` +- :ref:`\/v1/ad/getAdList ` +- :ref:`\/v1/ad/registerImpression ` +- :ref:`\/v1/ad/registerVideoAdImpression ` +- :ref:`\/v1/ad/startValueExchange ` +- :ref:`\/v1/ad/useReplayReward ` +- :ref:`\/v1/ad/useSkipReward ` +- :ref:`\/v1/amp/flagMessage ` +- :ref:`\/v1/amp/insertArtistMessageMetric ` +- :ref:`\/v1/auth/anonymousLogin ` +- :ref:`\/v1/auth/login ` +- :ref:`\/v1/auth/logout ` +- :ref:`\/v1/billing/acquireProduct ` +- :ref:`\/v1/billing/getAvailableProducts ` +- :ref:`\/v1/billing/getCreditCardV2 ` +- :ref:`\/v1/billing/getSpecialOffer ` +- :ref:`\/v1/billing/infoV2 ` +- :ref:`\/v1/billing/prepareToAcquirePaypalProduct ` +- :ref:`\/v1/billing/updateBillingInformationV2 ` +- :ref:`\/v1/bookmark/add ` +- :ref:`\/v1/bookmark/delete ` +- :ref:`\/v1/bookmark/getBookmarks ` +- :ref:`\/v1/commerce/deleteCreditCard ` +- :ref:`\/v1/commerce/getCreditCard ` +- :ref:`\/v1/commerce/purchaseSubscription ` +- :ref:`\/v1/commerce/redeemCCBackedCode ` +- :ref:`\/v1/commerce/startCCBackedTrial ` +- :ref:`\/v1/commerce/updateBillingInformation ` +- :ref:`\/v1/commerce/updatePaypalBillingInformation ` +- :ref:`\/v1/facebook/connect ` +- :ref:`\/v1/facebook/disconnect ` +- :ref:`\/v1/feedback ` +- :ref:`\/v1/listener/accountMessageDismissed ` +- :ref:`\/v1/listener/addTiredSong ` +- :ref:`\/v1/listener/addTrackingCode ` +- :ref:`\/v1/listener/deleteListener ` +- :ref:`\/v1/listener/emailExplicitPINRescue ` +- :ref:`\/v1/listener/emailPassword ` +- :ref:`\/v1/listener/getProfile ` +- :ref:`\/v1/listener/register ` +- :ref:`\/v1/listener/resetPassword ` +- :ref:`\/v1/listener/setExplicitPIN ` +- :ref:`\/v1/listener/setProfile ` +- :ref:`\/v1/listener/updateAccount ` +- :ref:`\/v1/listener/updateSettings ` +- :ref:`\/v1/listener/validatePasswordResetToken ` +- :ref:`\/v1/mip/insertVoiceTrackMetric ` +- :ref:`\/v1/music/album ` +- :ref:`\/v1/music/artist ` +- :ref:`\/v1/music/composer ` +- :ref:`\/v1/music/fullLyrics ` +- :ref:`\/v1/music/genrecategories ` +- :ref:`\/v1/music/genres ` +- :ref:`\/v1/music/track ` +- :ref:`\/v1/ondemand/getAudioPlaybackInfo ` +- :ref:`\/v1/ondemand/getReplayTrack ` +- :ref:`\/v1/playlist/getFragment ` +- :ref:`\/v1/playlist/narrative ` +- :ref:`\/v1/search/fullSearch ` +- :ref:`\/v1/search/getSeedSuggestions ` +- :ref:`\/v1/search/getStationRecommendations ` +- :ref:`\/v1/share/artist ` +- :ref:`\/v1/station/addFeedback ` +- :ref:`\/v1/station/addSeed ` +- :ref:`\/v1/station/createStation ` +- :ref:`\/v1/station/deleteFeedback ` +- :ref:`\/v1/station/deleteSeed ` +- :ref:`\/v1/station/getFeedback ` +- :ref:`\/v1/station/getSeeds ` +- :ref:`\/v1/station/getStationDetails ` +- :ref:`\/v1/station/getStationFeedback ` +- :ref:`\/v1/station/getStations ` +- :ref:`\/v1/station/playbackPaused ` +- :ref:`\/v1/station/playbackResumed ` +- :ref:`\/v1/station/removeStation ` +- :ref:`\/v1/station/shuffle ` +- :ref:`\/v1/station/trackStarted ` +- :ref:`\/v1/station/transformShared ` +- :ref:`\/v1/station/updateShuffleStation ` +- :ref:`\/v1/station/updateStation ` +- :ref:`\/v1/station/verifyHybridStationChecksum ` +- :ref:`\/v1/subscription/checkPremiumEligibility ` +- :ref:`\/v1/subscription/completePaypalBackedTrial ` +- :ref:`\/v1/subscription/completePaypalPayment ` +- :ref:`\/v1/subscription/completeRedeemPaypalBackedCode ` +- :ref:`\/v1/subscription/info ` +- :ref:`\/v1/subscription/redeemCode ` +- :ref:`\/v1/subscription/startPaypalBackedTrial ` +- :ref:`\/v1/subscription/startPaypalPayment ` +- :ref:`\/v1/subscription/startRedeemPaypalBackedCode ` +- :ref:`\/v1/twitter/setUserTokens ` +- :ref:`\/v3/catalog/annotateObjects ` +- :ref:`\/v3/catalog/annotateObjectsSimple ` +- :ref:`\/v3/catalog/sortObjects ` +- :ref:`\/v3/playlists/deleteTracks ` +- :ref:`\/v3/sod/search ` +- :ref:`\/v4/catalog/getAllArtistTracks ` +- :ref:`\/v4/catalog/getArtistDiscography ` +- :ref:`\/v4/catalog/getDetails ` +- :ref:`\/v4/collections/addItem ` +- :ref:`\/v4/collections/countItems ` +- :ref:`\/v4/collections/getItemsByArtist ` +- :ref:`\/v4/collections/getItems ` +- :ref:`\/v4/collections/getSortedItems ` +- :ref:`\/v4/collections/getVersion ` +- :ref:`\/v4/collections/hasItems ` +- :ref:`\/v4/collections/removeItem ` +- :ref:`\/v4/playlists/annotatePlaylists ` +- :ref:`\/v4/playlists/appendItems ` +- :ref:`\/v4/playlists/create ` +- :ref:`\/v4/playlists/delete ` +- :ref:`\/v4/playlists/editTracks ` +- :ref:`\/v4/playlists/getTracks ` +- :ref:`\/v4/pods/addAutoplayFeedback ` +- :ref:`\/v4/pods/getAutoplaySongs ` +- :ref:`\/v4/pods/getPlaylistAutoplaySongs ` +- :ref:`\/v5beta/collections/getSortedAlbums ` +- :ref:`\/v5beta/collections/getSortedAll ` +- :ref:`\/v5beta/collections/getSortedArtists ` +- :ref:`\/v5beta/collections/getSortedPlaylists ` +- :ref:`\/v5beta/collections/getSortedTracks ` +- :ref:`\/v5beta/playlists/setDetails ` +- :ref:`\/v5/playlists/shuffleTracks ` +- :ref:`\/v5/pods/getPlaylistAutofillSongs ` +- :ref:`\/v5/pods/getPlaylistSearchRecommendations ` diff --git a/rest/errorcodes.rst b/rest/errorcodes.rst new file mode 100644 index 0000000..13d8a59 --- /dev/null +++ b/rest/errorcodes.rst @@ -0,0 +1,41 @@ +=================== +List of Error Codes +=================== + +.. index:: + single: REST Error codes + +.. note:: + + This page is incomplete. The error enumeration should be complete but codes + and descriptions are guesses. + +These error codes can be returned by all endpoints: + +.. code:: json + + { + "errorCode": 0, + "errorString": "INVALID_REQUEST", + "message": "The request could not be validated" + } + +========== ============================= =========== +Error Code Error String Description +========== ============================= =========== +0 INVALID_REQUEST General bad request error. Often means authentication was invalid +? STREAM_VIOLATION Unable to stream to this region? +? STATION_LIMIT_REACHED Stream minutes limit or skip count reached? +? THUMBPRINT_RADIO_NOT_ELIGIBLE Not enough feedback to construct a Thumbprint station? +? LISTENER_NOT_AUTHORIZED Current user is not able to access shared content? +? PLAYLIST_END End of playlist? +? READONLY_MODE Pandora back-end maintenance? +? STATION_CODE_INVALID Invalid station +? STATION_DOES_NOT_EXIST Station does not exist +? LISTENER_SUSPENDED Account has been suspended +? CREDIT_CARD_NO_RECORD_FOUND No credit card on file? +? CONTENT_HAS_EXPIRED Audio link for song has expired? +? SERVER_ERROR Generic server error +? NOT_FOUND Content not found +? UNPLAYABLE_SHUFFLE_STATION Unable to play shuffle station? +========== ============================= =========== diff --git a/rest/implementations.rst b/rest/implementations.rst new file mode 100644 index 0000000..06cbcf7 --- /dev/null +++ b/rest/implementations.rst @@ -0,0 +1,11 @@ +=============== +Implementations +=============== + +.. index:: + single: Implementations + +A list of open source Pandora REST API implementations. + +.. csv-table:: + :header: Name, Used in client, Language, Remarks diff --git a/rest/index.rst b/rest/index.rst new file mode 100644 index 0000000..a0cd991 --- /dev/null +++ b/rest/index.rst @@ -0,0 +1,84 @@ +======== +REST API +======== + +.. toctree:: + :maxdepth: 2 + + authentication + stations + bookmarks + account + ads + endpoints + errorcodes + implementations + +The Pandora REST API is used by modern Pandora apps including the website and +the various mobile apps provided by Pandora. The current REST API has multiple +versions and not all functionality seems to be supported for each version. +Released API versions are stable but new APIs are added often as the Pandora +feature set evolves. The main endpoint is: + +- https://www.pandora.com/api/ + +All requests are JSON-encoded and sent via HTTP POST body to the endpoints over +HTTPS. Response bodies are JSON-encoded values. Unlike the JSON v5 API there is +no requirement for time syncronization, Blowfish cryptography, or partner +logins. + +The API requires a cookie aware client as several cookies will be issued during +authentication that **must** be present in every request. Failure to provide +the cookies will result in HTTP 400 errors. + +.. _rest-csrf-token: + +CSRF Token / Cookie +=================== +All requests require an ``X-CsrfToken`` header as well as a matching +``csrftoken`` cookie. The current version of the API merely validates that the +token and cookie match so the client can make up whatever they want. However, +the token can also be obtained by making a ``HEAD`` request to +``https://www.pandora.com/`` and saving the cookies. The API endpoints will not +serve cookies until after authentication. Clients *SHOULD* make a ``HEAD`` +request to the root domain and include the current value of the ``csrftoken`` +cookie in each request. + +.. code:: http + + POST /api/v1/auth/login HTTP/1.1 + Host: www.pandora.com + X-CsrfToken: 123456a7889b1c23 + X-AuthToken: + + { "username": "foo", "password": "bar" } + +.. _rest-auth-token: + +Auth Token +========== +All requests except for login require an ``X-AuthToken`` header which contains +the auth token obtained during login. It is acceptable to include the +``X-AuthToken`` header with an empty value during login. + +.. code:: http + + POST /api/v1/station/getStations HTTP/1.1 + Host: www.pandora.com + X-CsrfToken: 123456a7889b1c23 + X-AuthToken: dGhpcyBpcyBqdXN0IGFuIGV4YW1wbGUgY29kZQo= + + { "pageSize": 250 } + +Errors +====== +Error conditions are indicated by a combination of HTTP status code and a JSON +response body. Any responses with a 200 status code are successful. + +.. code:: json + + { + "errorCode": 0, + "errorString": "INVALID_REQUEST", + "message": "The request could not be validated" + } diff --git a/rest/stations.rst b/rest/stations.rst new file mode 100644 index 0000000..8d2324b --- /dev/null +++ b/rest/stations.rst @@ -0,0 +1,178 @@ +.. _rest-stations: + +======== +Stations +======== + +.. _rest-v1-station-getStations: + +Get Stations +============ + +:Endpoint: /v1/station/getStations + +Request +------- +.. code:: json + + { + "pageSize": 250 + } + +Response +-------- +.. code:: json + + { + "totalStations": 2, + "sortedBy": "lastPlayedTime", + "index": 0, + "stations": [ + { + "stationId": "12345", + "stationFactoryPandoraId": "SF:12345:123", + "pandoraId": "ST:12345", + "name": "Chill Out Radio", + "art": [ + { + "url": "https://mediaserver-cont-sv5-2-v4v6.pandora.com/images/public/int/9/2/0/5/634904045029_90W_90H.jpg", + "size": 90 + }, + { + "url": "https://mediaserver-cont-dc6-2-v4v6.pandora.com/images/public/int/9/2/0/5/634904045029_130W_130H.jpg", + "size": 130 + }, + { + "url": "https://mediaserver-cont-sv5-3-v4v6.pandora.com/images/public/int/9/2/0/5/634904045029_500W_500H.jpg", + "size": 500 + }, + { + "url": "https://mediaserver-cont-sv5-3-v4v6.pandora.com/images/public/int/9/2/0/5/634904045029_640W_640H.jpg", + "size": 640 + }, + { + "url": "https://cont-2.p-cdn.com/images/public/int/9/2/0/5/634904045029_1080W_1080H.jpg", + "size": 1080 + } + ], + "dateCreated": "2017-10-27T20:10:33.202-07:00", + "lastPlayed": "2017-10-27T21:36:04.426-07:00", + "totalPlayTime": 987, + "isNew": false, + "allowDelete": true, + "allowRename": false, + "allowEditDescription": false, + "allowAddSeed": false, + "isShared": false, + "isTransformAllowed": false, + "isOnDemandEditorialStation": false, + "isAdvertiserStation": false, + "canShuffleStation": true, + "canAutoshare": true, + "advertisingKey": "", + "isArtistMessagesEnabled": true, + "isThumbprint": false, + "isShuffle": false, + "genre": [ + "Rock", + "Dance / Electronica" + ], + "genreSponsorship": "G464", + "adGenre": "electronica", + "antiTarget": false, + "initialSeed": { + "musicId": "G464", + "pandoraId": "GE:464", + "genre": { + "stationName": "Chill Out", + "isRedirect": false, + "isComedy": false + }, + "listenerCount": 4165328, + "art": [ + { + "url": "https://mediaserver-cont-dc6-1-v4v6.pandora.com/images/public/int/9/2/0/5/634904045029_90W_90H.jpg", + "size": 90 + }, + { + "url": "https://mediaserver-cont-dc6-1-v4v6.pandora.com/images/public/int/9/2/0/5/634904045029_130W_130H.jpg", + "size": 130 + }, + { + "url": "https://mediaserver-cont-dc6-2-v4v6.pandora.com/images/public/int/9/2/0/5/634904045029_500W_500H.jpg", + "size": 500 + }, + { + "url": "https://mediaserver-cont-ch1-2-v4v6.pandora.com/images/public/int/9/2/0/5/634904045029_640W_640H.jpg", + "size": 640 + }, + { + "url": "https://cont-1.p-cdn.com/images/public/int/9/2/0/5/634904045029_1080W_1080H.jpg", + "size": 1080 + } + ] + }, + "adkv": { + "artist": "G464", + "genre": "electronica", + "clean": "0", + "gcat": "G464" + }, + "creatorWebname": "example", + "artId": "images/public/int/9/2/0/5/634904045029" + }, + { + "stationId": "12345", + "stationFactoryPandoraId": "SF:12345:0", + "pandoraId": "TT:0", + "name": "Thumbprint Radio", + "description": "Music inspired by your 999 thumbs from across all your stations.", + "art": [ + { + "url": "https://mediaserver-cont-sv5-3-v4v6.pandora.com/images/public/devicead/t/r/a/m/daartpralbumart_90W_90H.jpg", + "size": 90 + }, + { + "url": "https://cont-2.p-cdn.com/images/public/devicead/t/r/a/m/daartpralbumart_130W_130H.jpg", + "size": 130 + }, + { + "url": "https://mediaserver-cont-dc6-1-v4v6.pandora.com/images/public/devicead/t/r/a/m/daartpralbumart_500W_500H.jpg", + "size": 500 + } + ], + "dateCreated": "2017-10-27T20:10:33.202-07:00", + "lastPlayed": "2017-10-27T21:36:04.426-07:00", + "totalPlayTime": 99999, + "isNew": false, + "allowDelete": true, + "allowRename": false, + "allowEditDescription": false, + "allowAddSeed": false, + "isShared": false, + "isTransformAllowed": false, + "isOnDemandEditorialStation": false, + "isAdvertiserStation": false, + "canShuffleStation": false, + "canAutoshare": true, + "advertisingKey": "", + "isArtistMessagesEnabled": false, + "isThumbprint": true, + "thumbprintThumbCount": 999, + "thumbprintProcessSkips": true, + "thumbprintShareArt": "https://mediaserver-cont-sv5-1-v4v6.pandora.com/images/public/devicead/t/r/a/m/daartprfbalbumart_1200W_630H.jpg", + "shareName": "example's Thumbprint Radio", + "isShuffle": false, + "genre": [], + "adkv": { + "artist": "", + "genre": "thumbprintradio", + "clean": "0", + "gcat": "thumbprintradio" + }, + "creatorWebname": "example", + "artId": "images/public/devicead/t/r/a/m/daartpralbumart", + "dominantColor": "0c81c6" + } + ] + } -- cgit v1.2.3