studio.apollographql.com
Open in
urlscan Pro
2606:4700:10::6816:36e
Public Scan
Submitted URL: http://api.soundtrackyourbrand.com/
Effective URL: https://studio.apollographql.com/public/soundtrack/home?variant=current
Submission Tags: falconsandbox
Submission: On May 05 via api from US — Scanned from DE
Effective URL: https://studio.apollographql.com/public/soundtrack/home?variant=current
Submission Tags: falconsandbox
Submission: On May 05 via api from US — Scanned from DE
Form analysis
0 forms found in the DOMText Content
Scheduled maintenance between May 8, 2023 at 12:00 PM GMT LOCAL:Mon, May 8, 2023 12:00 PM GMT UTC:2023-05-08T12:00:00.000Z and May 8, 2023 at 2:00 PM GMT LOCAL:Mon, May 8, 2023 2:00 PM GMT UTC:2023-05-08T14:00:00.000Z . Learn more soundtrack / current Public Log in soundtrack@current https://api.soundtrackyourbrand.com/v2 Nov 14, 2022 at 8:40 AM GMT LOCAL:Mon, November 14, 2022 8:40 AM GMT UTC:2022-11-14T08:40:10.659Z •13368d 256types 785fields README Updated 8 months ago LOCAL:Wed, August 24, 2022 11:54 AM GMT UTC:2022-08-24T11:54:48.893Z SOUNDTRACK API This is the documentation for Soundtrack API. There's just too much shitty documentation out there, and we aim to be better than that. Feel free to do pull requests straight into the repo if you have any suggestions - or drop us a line in our public Slack channel. Soundtrack is a complete music streaming service for businesses. Soundtrack API lets you build display-, control- and monitoring apps on top of Soundtrack. You can learn more about Soundtrack here and get inspired on how to use the API here. REQUIREMENTS You'll need at least one paying Soundtrack account and an API token to get started (unless you use this way to authorize). Soundtrack API is free for all Soundtrack users. GETTING A GRASP We've built Soundtrack API using GraphQL. One big upside is that you only get what you ask for (we list more upsides here). To get a quick grasp of the API, lets take an example: you want to add some info in your app of what's currently playing in your store. In this query, you ask for the track name and name(s) of the artist(s). What do you get in response? A classic blob of all-data-existing-on-this-endpoint á la REST that you then need to parse? No, the response is... track name and artist(s) name(s). There's obviously a bunch of more stuff you can fetch and control. Keep scrolling to explore some of it (for the full API reference click here). json='{"query": "query { nowPlaying(soundZone: \"U291bmRabwsMWNhedTc1Nm8v\") { track { name artists { name } } } }"}' echo $json | curl -XPOST https://api.soundtrackyourbrand.com/v2 \ -H 'Authorization: Basic your_token' \ -H 'Content-Type: application/json' \ -d @- > Response { "data": { "nowPlaying": { "track": { "name": "Branches", "artists": [ { "name": "Fluida" } ] } } } } THE BASICS It's not a pre-requisite to know the ins and outs of GraphQL, but we do recommend you to at least read our brief GraphQL intro further down this page. YOUR REQUEST ENDPOINT There's only one endpoint, unless you're using subscriptions (we'll come to that in a bit). https://api.soundtrackyourbrand.com/v2 TOKEN For the token you've received from Soundtrack, we use Basic-auth. Make sure to keep your token safe, we'll block any tokens that are compromised. You can login without asking us for a token, given you have login credentials to Soundtrack. Just follow these instructions. -H 'Authorization: Basic your_token' CONTENT-TYPE We do support this content-type however it is not recommended to use it since it will soon be deprecated. -H 'Content-Type: application/graphql' > In production, use the below content-type and adjust your queries -H 'Content-Type: application/json' In production, we recommend that you use parameterised queries (application/json). It decreases the risk for injections and you'll be able to re-use more code. BODY -d ' { nowPlaying(soundZone: "soundzone_id") { track { name album { name image { url } } } } } ' Soundtrack API supports queries (get stuff), mutations (do stuff) and subscriptions (know when stuff changes). We'll describe all of these three in a bit, but what you need to know now is: regardless what you are doing, you need to send a POST body specifying what you want to get/do. OUR RESPONSE { "data": { "nowPlaying": { "track": { "name": "Sweet Addiction - Live Edit", "album": { "name": "Nous Horizon, Vol. 2 (Re-Works & Edits)", "image": { "url": "https://l.cdnurl.com/image/31bbda8605500ba6345bd61941fd3cc536ad779" } } } } } } We will respond with a JSON. Notice that the shape of the JSON in the response follows the shape of the query. SOUNDTRACK HIERARCHY We highly recommend that you play around with your Soundtrack account so you get an overview of the product prior to using the API. All guides and frequently asked questions regarding Soundtrack can be found on our help pages. As you've seen in the examples, there's something called a "sound zone". In the table below, we've explained the different concepts you need to know about. ConceptDescriptionAccounte.g. "Sven's burgers". Can have multiple locations.Locatione.g. "Flagship Store, Stockholm". Can have multiple sound zones.Sound zonee.g. "Bar" or "Lobby". Can only have one device.DeviceOne of the supported player types. Needed to play music.UserCan control one or many accounts. Each sound zone can only output one music stream. So if you want different music in different parts of the same location, you need multiple sound zones (and thus: multiple devices). If you want the same music everywhere in the same location you’ll only need one sound zone (and one device) and then distribute the music using your audio system. Each sound zone equals one subscription (which is what costs money). ASKING WHAT YOU DON'T KNOW json='{"query": "query { me { ...on PublicAPIClient { accounts(first: 1) { edges { node { businessName locations(first: 1) { edges { node { name soundZones(first: 2) { edges { node { id name } } } } } } } } } } } }"}' echo $json | curl -XPOST https://api.soundtrackyourbrand.com/v2 \ -H 'Authorization: Basic your_token' \ -H 'Content-Type: application/json' \ -d @- As you saw in the first example query, with a short query you'll get the info you need - given you know the id (e.g. the id of the sound zone). But how do you get to know what the id is? You ask Soundtrack API. In this example, we want to know: * The businessName of the first account we have access to (e.g. Sven's Burger Corp.) * The name of the first location belonging to that account (e.g. Flagship restaurant NYC) * The id and name of the first two sound zones belonging to that location (e.g. {lLCwxazBn.., The Bar},{wwNHd3ZTg.., Restaurant area}) As you might notice, there are a two new concepts in this query: * Introspection (the me-part) which allows you to explore what you have access to. * Connections (the edges, nodes & first: 1) which enables pagination as well as some other things. For the sake of structure, we'll let you drill down on introspection here and connections here. TYPE OF ACTIONS Soundtrack API supports queries, subscriptions and mutations. Entry pointsUse caseQueriesFetch information that usually doesn't change (e.g. sound zone name)SubscriptionsFetch information that usually changes (e.g. what's currently playing)MutationsMake changes (e.g. skip to next track) QUERIES Use queries for getting information that you don't expect to change very often. For example: a sound zone id, the name of the account and a list of all your locations. In the beginning of your query, there's the root query. If you have the id to your account or sound zone, you can input this id and instantly get the information you need. If you don't have the ids, just start off with me to get it, as explained here. All root queries can be found in the reference. In this example, we ask for the name and the id of a specific sound zone. We also ask whether it is paired to a player or not. For queries, you actually don't need to start the body with query since GraphQL assumes it's a query if that initial string is missing. However, we recommend including it to make the code self-explanatory. json='{"query": "query { soundZone(id:"soundzone_id") { name id isPaired } }"}' echo $json |curl -XPOST https://api.soundtrackyourbrand.com/v2 \ -H 'Authorization: Basic your_token' \ -H 'Content-Type: application/json' \ -d @- > Response { "data": { "soundZone": { "name": "Staff room", "isPaired": true, "id": "U291bmRab25lLCwxanAzcjVsZTlkcy9m8v" } } } SUBSCRIPTIONS Use subscriptions for getting information you expect to change often. For example: what is currently playing, current playback state (played/paused) and current sound zone errors. All subscriptions can be found in the reference. ENDPOINT wss://api.soundtrackyourbrand.com/v2/graphql-transport-ws For subscriptions there are two things you need to adjust: the endpoint and the way you supply your token. The endpoint is wss instead of https. That's because we use web sockets for subscriptions (WSS = Web Sockets Secure). The web socket API adheres to the GraphQL transport WS protocol. The easiest way to connect to it is using their provided packages. Our example app shows how they might be used in a Javascript client. You won't be using any headers, so the token needs to be passed in when setting up the connection as its payload (e.g. plaintext{"type":"connection_init`,"payload":{"Authorization":"Bearer YOUR_TOKEN],"content-type":"application/json"}}). EXAMPLE subscription nowPlaying { nowPlayingUpdate(input: {soundZone: "soundzone_id"}) { nowPlaying { track { name album { name image { url width height } } artists { name } } } } } > Initial response "Your subscription data will appear here after server publication!" > Response once there's data (this response will update) { "data": { "nowPlayingUpdate": { "nowPlaying": { "track": { "name": "Needs", "artists": [ { "name": "Loure" } ], "album": { "name": "Smooth Talk EP", "image": { "width": 640, "url": "https://theurltothealbumartwork.com/07dc5282", "height": 640 } } } } } } } Since cURL doesn't support web sockets out-of-the box, we don't provide you with a cURL example. Instead: if you want to try subscriptions straight away, check out our playground In this example we want to get enough information in order to build a neat display screen showing what's playing. For that we need the name of the artist, album & track as well as some album art info. Once you fire away the request, you'll most likely get an initial response stating that there's not yet any data to display. Once there's anything that is changing, the response will update. "But I want to show what's playing when a user opens my app - they shouldn't have to wait!" Good thinking! In those cases you should have an initial query where you ask for what's playing. Then you'll let the subscription take over from there. "What if the web socket connection is lost in one way or another?" It's up to you to handle this in your code. Maybe by sending a query (to fetch what's playing) and then re-try the subscription. "Why can't I just use queries instead of subscriptions?" With subscriptions you limit the amount of requests as well as avoid getting rate limited. Also, you get the info you need in a more timely manner which makes it easier for you to provide a great user experience! MUTATIONS json='{"query":"mutation { setVolume(input: {soundZone:"soundzone_id", volume: 11}) { volume } }"}' echo $json | curl -XPOST https://api.soundtrackyourbrand.com/v2 \ -H 'Authorization: Basic your_token' \ -H 'Content-Type: application/json' \ -d @- > Response { "data": { "setVolume": { "volume": 11 } } } Use mutations to make changes. For example: change the volume, skip track and play/pause. All mutations can be found in the reference. In this example you set the volume to 11 on a specific sound zone. You always need to ask for a response, so in this case we just ask for the volume. ERRORS With GraphQL, a HTTP code stating 200 OK doesn't always mean that you get the data you wanted. If the query executes but bumps into an error along the way, you'll get a 200 with an errors-object appended to the response body. ErrorDescriptionExampleHTTP 5xx or WebSocket 1xxxServer problemse.g. server not availableHTTP 4xxClient problemse.g. rate limitedHTTP 200 with errors-bodyGraphQL problemse.g. incorrect input > Incorrect input (an account id that doesn't exist) json='{"query": "query { account(id:"QWNjb3VudCwsWNheXg3dTc1Nm8v") { businessName } }"}' echo $json | curl -XPOST https://api.soundtrackyourbrand.com/v2 \ -H 'Authorization: Basic your_token' \ -H 'Content-Type: application/json' \ -d @- > Response (HTTP 200 OK) { "errors": [ { "path": [ "account" ], "message": "Forbidden", "locations": [ { "line": 2, "column": 0 } ] } ], "data": { "account": null } } > Did you get an error message that you think could be improved? Please reach > out on Slack and let us know. RATE LIMIT > Please note that the rate limit is subject to change since we continuously > monitor how the API is used and make relevant updates. The Soundtrack API enforces rate limiting. You start off with the maximum amount of tokens (3600) and for every call (query, mutation or subscription) you make, tokens will be deducted. The number of tokens deducted depends on the complexity of the call you are making. But we don’t just take tokens from you - every second you get 50 tokens back. Let’s say you make a query with a complexity of 1000. Now you’re down to 2600. After 20 seconds you’re back to 3600 tokens (50 tokens per second). Simple, right? QUERIES & MUTATIONS json='{"query: "query { account(id:"account_id") { businessName locations(first: 10) { edges { location: node { soundZones(first: 10) { edges { node { device { id } } } } } } } } }"}' curl -XPOST https://api.soundtrackyourbrand.com/v2 \ -H 'Authorization: Basic your_token' \ -H 'Content-Type: application/json' \ -d @- Queries and mutations calculates the rate limit in the same way. Keep scrolling to understand how we rate limit subscriptions. In this section's example you’re fetching the device information from the first ten sound zones for each of the first ten locations on a single account. In the same call, you’re also fetching the now playing information form one sound zone. Here’s how we calculate: FieldCostaccounts1locations2soundzones3device4+1 (since the id field was selected)total11 A request’s cost is deducted from your tokens. The cost is calculated based on the query, and not the data it would return if it were to execute. In the example above, even if each location only had one single sound zone, the cost for the sound zones would still be 3 (instead of 2). This means you should try to be conservative with how much data you ask for in deeply nested connections in order to preserve your tokens. "BUT I DON'T WANT TO CALCULATE!" All calculations are done for every operation you do and will be returned in the headers x-ratelimiting-cost and x-ratelimiting-tokens-available. So for the example above the returned headers would've been: shell x-ratelimiting-cost: 11 x-ratelimiting-tokens-available: 3589 SUBSCRIPTIONS The maximum complexity of a subscription is 100. EXPLORE The best way to explore (and, in our opinion, the best documentation too!) is our playground. If you'd like to dig into the schema without authorizing, check out our reference. Once you’ve added your Authorization header in the bottom left corner you can use it to create and run queries towards the Soundtrack API. There are documentation and auto-completion features. Please keep in mind that all queries use live data and count towards your rate limit. EXAMPLE APP > Find the example app in this repo. Feel free to contribute. To get you started we’ve implemented a simple react-relay app. We’ve decided to create a frontend app since it is easy for you to get up and running locally. However, we strongly encourage you to not build a frontend application where the API client secret can be found in the source code. Secrets found in public applications will be blocked. What you probably want to do is to build a backend service that implements whatever authentication layer that your app needs. TERMS OF USE > Read and comply to our API Terms of Use By using the Soundtrack API, you accept to our API Terms of Use. Please note that it should be clear to the end user that you are the one that has built and is maintaining the application. Using Soundtrack marketing material (except artwork provided via the API) needs Soundtrack Your Brand’s written consent. For example, you are not allowed to use our graphics (e.g. buttons) used in our products to create a similar experience. Due to licensing restrictions, visitors are currently not allowed to control playback. For example, you are allowed to build an application where your authorized staff changes the playlist but the same functionality can’t be exposed to your visitors, e.g a "jukebox" is not possible to build via our API. Sharing track name, sharing url, etc. is however fine as this is regarded as non-interactive. NEXT LEVEL Want to shape up your queries or just read more about a specific topic? We've gathered some good-to-knows here. GRAPHQL The API is built using GraphQL, abiding by the Relay Connection Specification in order to make it as easy as possible to use third party libraries, such as Relay or Apollo. WHAT IS GRAPHQL? GraphQL is a query language for APIs. It describes the API as a graph of connected objects which can be queried with a single request. A single query can load data from multiple, deeply nested entities that would normally require multiple chained requests in a REST API. This makes it easier for you as an application developer to get the data you need, but also improves performance since it minimises the number of requests you need to make. GraphQL is an API query layer. This means that all queries you run is defined by the API in beforehand. You cannot select data based on any criteria you want, in contrast with other query languages such as SQL. GraphQL is also an open standard with multiple server and client libraries, which makes it easy to get an application scaffold up and running. Subscriptions in the Soundtrack API is powered by the GraphQL Transport WS protocol. An implementation of this protocol can be found here. Here are two noteworthy articles on subscriptions in GraphQL: Subscriptions in GraphQL and Relay & Javascript docs. WHY GRAPHQL? Here are some of the reasons why we chose GraphQL: * Being able to query for the exact data that you need makes it easier to quickly get up and running. And greatly improves the performance. * GraphQL is strongly typed and has very good introspection features, which enables very good tooling for both exploring and using the API. * There are good client libraries as well as IDE support. * The ability to join multiple queries together is a big performance improvement. LIBRARIES If you’re building a backend implementation, all you need is an HTTP client and a JSON parser. If you’re building something for the frontend, Relay and Apollo are popular choices. Just make sure you don’t expose your API Credentials by accident (if we find any exposed credentials, we will revoke them). ADDITIONAL READING * GraphQL’s official site * GraphQL Specification * How to GraphQL * Relay Connection Specification * There are many good talks on GraphQL on YouTube INTROSPECTION Here's a good read on introspection in GraphQL. CONNECTIONS json='{"query":"query { node(id: "track_id") { ...on Track { name previewUrl } } }"}' echo $json | curl -XPOST https://api.soundtrackyourbrand.com/v2 \ -H 'Authorization: Basic your_token' \ -H 'Content-Type: application/json' \ -d @- Every one to many relationship is modelled using a concept of connections, edges and nodes. This is according to Relay’s Connection Specification and allows every such relationship to be paginated in a consistent manner. NODE QUERIES Most of the central entities (account, sound zones, now playing) have specific top-level queries to find them by id. For many other entities, you can use the more general node query to get a specific entity, should you need it. Use the playground to see what entities implement the node interface (or see the reference). > Pagination: first query json='{"query":"query { account(id: "account_id") { access { users(first: 5) { pageInfo { hasNextPage endCursor } edges { role node { name id } } } } } }"}' echo $json | curl -XPOST https://api.soundtrackyourbrand.com/v2 \ -H 'Authorization: Basic your_token' \ -H 'Content-Type: application/json' \ -d @- > Pagination: second query json='{"query": "query { account(id: "account_id") { access { users(first: 5 after: "endCursor") { pageInfo { hasNextPage endCursor } edges { role node { name id } } } } } }"}' echo $json | curl -XPOST https://api.soundtrackyourbrand.com/v2 \ -H 'Authorization: Basic your_token' \ -H 'Content-Type: application/json' \ -d @- PAGINATION You call the connection describing for example how many results you want and from what page, and then you go through the connection’s edges and get each node. The edge contains metadata about the relationship from the parent to the node, such as a user's role. The first query would get the first five users who has access to the account. To get the next page, use the endCursor on the pageInfo as a cursor to the next query. PARAMETERISED QUERIES > The JSON payload is as follows: { "query": "query", "parameters": {"parameter1": "value1"}, "operationName": "only needed if the query has multiple operations" } > For example: curl -XPOST https://api.soundtrackyourbrand.com/v2 \ -H 'Authorization: Basic your_token' \ -H 'Content-Type: application/json' \ -d ' { "query": "query($id: ID!) { soundZone(id: $id) { name } }", "variables": { "id": "soundzone_id" } } ' > A more complex example: curl -XPOST https://api.soundtrackyourbrand.com/v2 \ -H 'Authorization: Basic your_token' \ -H 'Content-Type: application/json' \ -d ' { "query": "query soundZone($id: ID!) { soundZone(id: $id) { name } } query account($id: ID!) { account(id: $id) { businessName } }", "variables": { "id": "soundzone_id" }, "operationName": "soundZone" } ' In production, we recommend that you use parameterised queries. It decreases the risk for injections and you'll be able to re-use more code. In order to use parameterised queries, the API expects the Content-Type to be application/json. FRAGMENTS & MULTIPLE QUERIES json='{"query":"fragment nowPlayingFields on NowPlaying { startedAt track { name artists { name } album { image { url width height } } } } query { nowPlaying1: nowPlaying(soundZone: "soundzone_id_1") { ...nowPlayingFields } nowPlaying2: nowPlaying(soundZone: "soundzone_id_2") { ...nowPlayingFields } }"}' echo $json | curl -XPOST https://api.soundtrackyourbrand.com/v2 \ -H 'Authorization: Basic your_token' \ -H 'Content-Type: application/json' \ -d @- This example combines multiple queries into a single query. This can be done for all GraphQL you want to run (as long as they are independent from each other) in order to save round trips. It also shows how you can use GraphQL fragments to reduce the amount of boilerplate in your queries. AUTHORIZING AS A USER If you want to, you can skip asking for API client credentials and just get a token using your existing Soundtrack-credentials, using the loginUser-mutation. For the loginUser-mutation you (obviously...) don't need an authorization-header. json='{"query": "mutation { loginUser(input: {email: "your_email", password: "your_password"}) { token refreshToken } }"}' echo $json | curl -XPOST https://api.soundtrackyourbrand.com/v2 \ -H 'Content-Type: application/json' \ -d @- The response will contain two tokens: * token is your access token which you will use in your other API calls (e.g. when making queries). * refreshToken is used for obtaining a new token. We'll get back to this in a bit. Note that since you're not logging in as an API client, you can't use ...on PublicAPIClient in your me-query (this example). Instead, use ...on User. > If you use this way of authorizing, use Bearer and not Basic -H 'Authorization: Bearer your_token' USING TOKEN You use the access token in the same way as already described in these docs, except that you should use Bearer instead of Basic in your authorization header (for subscriptions: as a query parameter) The token won't be valid forever. That's why you need to use your refreshToken as soon as you get HTTP 401 on your requests. USING REFRESHTOKEN json='{"query": "mutation{ refreshLogin(input:{refreshToken: "your_refresh_token"}){ token refreshToken } }"}' curl -XPOST https://api.soundtrackyourbrand.com/v2 \ -H 'Content-Type: application/json' \ -d @- The refreshToken will enable you to fetch a new access token. Once you get the response, replace your old token with the new one. Always make it a habit to request the refreshToken as well, since it also can change. If your refreshToken is outdated (your app might have been offline), remember that you always can use the loginUser-mutation to get a new one. Run in Explorer Links No links added yet. Know of an external site related to this graph? Ask a graph admin to add it here... Changelog View full changelog November 14,8:40 AM GMT LOCAL:Mon, November 14, 2022 8:40 AM GMT UTC:2022-11-14T08:40:10.685Z 203 74 6 126 * ACCOUNT * COUNTRY * PLAN * ISINCOHORTS * ACCESS: Access! * CURATOR * SOUNDZONES: AccountSoundZoneConnection * ACCOUNTACCESSPENDINGUSERCONNECTION * PAGEINFO * EDGES * TOTAL * ACCOUNTACCESSPENDINGUSEREDGE * CURSOR * NODE * CONTACT * ROLE * ACCOUNTACCESSUSERCONNECTION * PAGEINFO * EDGES * TOTAL * ACCOUNTACCESSUSEREDGE * CURSOR * NODE * CONTACT * ROLE * ACCOUNTLOCATIONCONNECTION * TOTALCOUNT * TOTAL * ACCOUNTSOUNDZONECONNECTION * PAGEINFO * EDGES * TOTALCOUNT * TOTAL * ACCOUNTSOUNDZONEEDGE * CURSOR * NODE * ARTISTPAGE * ID * SECTIONS * ARTIST * TITLE * EDITORIALPAGE * ARTISTPAGEEDITORIALSECTION * ID * TITLE * COMPONENT * ITEMS * EDITORIALSECTION * AUDIO * DURATIONMS * SAMPLERATE * LOUDNESS * BLOCKTRACKPAYLOAD * PARENT * BLOCKEDTRACK: BlockedTrack! * BROWSEEDITORIALSECTION * ID * TITLE * COMPONENT * ITEMS * DESCRIPTION * BROWSEPAGE * ID * SECTIONS * TABS * TITLE * HEADERIMAGE * BROWSECATEGORY * CURATORCOMPOSER * _ * HOMEEDITORIALSECTION * ID * TITLE * COMPONENT * ITEMS * DESCRIPTION * HOMEPAGE * ID * SECTIONS * TABS * TITLE * LOCATION * ISOCOUNTRY * COUNTRY * SOUNDZONES LocationSoundZoneConnection * orderBy OPTIONAL ARG ADDED * LOCATIONSOUNDZONECONNECTION * PAGEINFO * EDGES * TOTALCOUNT * TOTAL * LOCATIONSOUNDZONEEDGE * CURSOR * NODE * LOUDNESS * INTEGRATED * TRUEPEAK * RANGE * UNDEFINED * MANUAL * _ * MUTATION * PLAYBACKREPORTING * PLAY * PAUSE * SKIPTRACK * SOUNDZONEUNPAIR * SOUNDZONEASSIGNSOURCE * CREATEONBOARDINGTASTEPROFILE * CREATEPLAYLIST * CREATESPOTIFYSYNCEDPLAYLIST * CREATESTATIONFROMPLAYLIST * UPDATEPLAYLISTINFO * UPDATESTATIONINFO * SYNCSPOTIFYSYNCEDPLAYLIST * SPLICEPLAYLIST * CREATESCHEDULE * UPDATESCHEDULE * CREATEHOMETASTEPROFILEFROMONBOARDING * LIKE * UNLIKE * ONBOARDINGPAGE * ID * SECTIONS * TABS * ONBOARDINGSECTION * ID * TITLE * COMPONENT * ITEMS * ONBOARDINGTASTEPROFILE * ARTISTS * PAUSEPAYLOAD * CLIENTMUTATIONID * SOUNDZONE: ID! * PLAYPAYLOAD * CLIENTMUTATIONID * SOUNDZONE: ID! * PLAYLIST * COMPOSERTYPE * SHORTDESCRIPTION: String! * DESCRIPTION: String! * PLAYLISTUPDATEPAYLOAD * PLAYLIST * PUBLICAPICLIENT * ACCOUNTS: PublicAPIClientAccountConnection * orderBy OPTIONAL ARG ADDED * PUBLICAPICLIENTACCOUNTCONNECTION * PAGEINFO * EDGES * TOTAL * PUBLICAPICLIENTACCOUNTEDGE * CURSOR * NODE * QUERY * PLAYLISTEDITORTRACKSUGGESTIONS * EDITORIALSEARCH * HELLOPLAYBACKREPORTING * NODE * id ARG DESCRIPTION CHANGE * QUERYINFO * EDITORIALONBOARDING * ONBOARDINGTASTEPROFILE * EDITORIALHOME * DUMMYACCOUNTCOHORTAPIQUERY * EDITORIALARTIST * EDITORIALBROWSE * BROWSE * SEARCHARTIST * EDITORIALSEARCHSECTION * RECOMMENDEDTRACKEDGE * CURSOR * NODE * RECOMMENDEDTRACKSCONNECTION * TOTAL * PAGEINFO * EDGES * SCHEDULE * UPDATEDAT * SUMMARY String! * SHORTDESCRIPTION * DESCRIPTION: String! * CURATOR: Curator! * SEEDCOMPOSER * _ * SETVOLUMEPAYLOAD * CLIENTMUTATIONID * SOUNDZONE: ID! * VOLUME: Volume! * SKIPTRACKPAYLOAD * CLIENTMUTATIONID * SOUNDZONE: ID! * SLOT * RRULE String! * START String! * DURATION Int! * UPDATEDAT * COLLECTIONS * PLAYLISTIDS * SOUNDZONEERRORCONNECTION * PAGEINFO * EDGES * SOUNDZONEERROREDGE * CURSOR * NODE * SOUNDZONEUNPAIRPAYLOAD * CLIENTMUTATIONID * SOUNDZONE: SoundZone * SOUNDTRACK * CURATOR * PRESENTATION * DESCRIPTION * SHORTDESCRIPTION: String! * SUMMARY * TRACKS * COLLECTIONTYPE * SUBSCRIPTIONS * PLAYLISTUPDATE * TRACK * AUDIO * AVAILABLEMARKETS: [IsoCountry!] * TRACKSTATISTICS * EXPLICITDURATION * EXPLICITPLAYABLE * EXPLICITPLAYABLEDURATION * NODE * ID * PLAYBACKSOURCE * PLAYLISTARTISTTRACKALBUMBROWSECATEGORY * PLAYLISTCOMPOSER * AUDIOFORMAT * AUDIOQUALITY * DEVICEREPORTINGSTATE * PLAN * PLAYORDER * PLAYBACKREPORTINGTRANSITION * PUBLICAPICLIENTACCOUNTFIELD * SOUNDZONEFIELD * TRACKREPORTINGAUDIOFORMAT * TRACKREPORTINGAUDIOQUALITY * TRACKREPORTINGSOURCE * CREATEPLAYLISTINPUT * CREATESCHEDULEINPUT * DESCRIPTION * SHORTDESCRIPTION * COLOR * SLOTS * CREATESPOTIFYSYNCEDPLAYLISTINPUT * CREATESTATIONFROMPLAYLISTINPUT * DEVICEREPORTINGINPUT * LOCATIONSOUNDZONEORDERINPUT * PAUSEINPUT * CLIENTMUTATIONID * PLAYINPUT * CLIENTMUTATIONID * PLAYBACKREPORTINGCONTEXTINPUT * PLAYLIST * SCHEDULE * PLAYBACKREPORTINGINPUT * PLAYLISTREPORTINGINPUT * PLAYLISTUPDATEINPUTINPUT * PUBLICAPICLIENTACCOUNTORDERINPUT * SCHEDULEREPORTINGINPUT * PLAYLISTCONTEXT * SETVOLUMEINPUT * CLIENTMUTATIONID * SKIPTRACKINPUT * CLIENTMUTATIONID * SLOTINPUT * SOUNDZONEFILTER * DEVICEPLATFORM * SOUNDZONEUNPAIRINPUT * CLIENTMUTATIONID * SPLICEPLAYLISTINPUT * SNAPSHOT * SYNCSPOTIFYSYNCEDPLAYLISTINPUT * TRACKREPORTINGINPUT * UPDATEPLAYLISTINFOINPUT * NAME * DESCRIPTION * SHORTDESCRIPTION * PLAYORDER * UPDATESCHEDULEINPUT * NAME * DESCRIPTION * SHORTDESCRIPTION * COLOR * SLOTS * UPDATESTATIONINFOINPUT * NAME * DESCRIPTION * SHORTDESCRIPTION * ACCESS * USERS: AccountAccessUserConnection * PENDINGUSERS: AccountAccessPendingUserConnection * ACCOUNTUSERSCONNECTION * PAGEINFO * EDGES * ACCOUNTUSERSEDGE * CURSOR * CONTACT * ROLE * NODE * ALBUM * COPYRIGHTS: [Copyright!] * AVAILABLEMARKETS: [IsoCountry!] * ARTIST * SOUNDTRACKID: ID! * ARTISTCOMPOSER * ARTIST: Artist! * ARTISTCONNECTION * PAGEINFO * EDGES * TOTAL * ARTISTEDGE * NODE * CURSOR * BLOCKEDTRACK * TRACKID: ID! * BLOCKEDTRACKCONNECTION * EDGES: [BlockedTrackEdge!]! * BLOCKEDTRACKEDGE * NODE: BlockedTrack! * CURSOR: String! * BROWSE * FEATURED * CATEGORIES * COLLECTIONTRACKSCONNECTION * PAGEINFO * EDGES * COLLECTIONTRACKSEDGE * CURSOR * WEIGHT * NODE * CURATOR * NAME: String! * ERRORCONNECTION * PAGEINFO * EDGES * ERROREDGE * NODE * CURSOR * FEATURE * ID * NAME * ENABLED * HISTORYTRACK * STARTEDAT: Date! * FINISHEDAT: Date! * HISTORYTRACKCONNECTION * EDGES: [HistoryTrackEdge!]! * HISTORYTRACKEDGE * NODE: HistoryTrack! * CURSOR: String! * MUSICTAGGROUP * ID: ID! * TAGS: [[MusicTag!]!]! * NOWPLAYING * SOUNDZONE: ID! * PENDINGACCOUNTUSERSCONNECTION * PAGEINFO * EDGES * PENDINGACCOUNTUSERSEDGE * CURSOR * CONTACT * ROLE * NODE * PLATFORM * PUBLICAPICLIENTACCOUNTSCONNECTION * PAGEINFO * EDGES * PUBLICAPICLIENTACCOUNTSEDGE * CURSOR * NODE * QUERYINFO * COMPLEXITY: Int! * RECIPECOMPOSER * TAGGROUPS: [MusicTagGroup!]! * SIMPLERECIPECOMPOSER * ENERGIES: [String!]! * GENRES: [String!]! * ORIGINYEARS: [String!]! * SOUNDS: [String!]! * VOCALS: [String!]! * ALLOWEXPLICIT: Boolean! * SOUNDZONE * ERRORS: SoundZoneErrorConnection * SOUNDZONECONNECTION * PAGEINFO * EDGES * TOTALCOUNT * SOUNDZONEEDGE * NODE * CURSOR * SOUNDTRACKSUMMARY * FEATUREDSONGS * SPOTIFYCOMPOSER * NAME: String! * SYNCEDAT: Date! * TRACKCONNECTION * PAGEINFO * EDGES * TOTAL * TRACKEDGE * NODE * CURSOR Show More New to GraphOS Studio? Check out a few quick tips and links from the Apollo team, designed to get you up and running. View tips Get to know your supergraph Automate tasks with the Rover CLI Build custom tools with the GraphOS Platform API By clicking “Accept All Cookies”, you agree to the storing of cookies on your device to enhance site navigation, analyze site usage, and assist in our marketing efforts. Cookies Settings Accept All Cookies PRIVACY PREFERENCE CENTER When you visit any website, it may store or retrieve information on your browser, mostly in the form of cookies. This information might be about you, your preferences or your device and is mostly used to make the site work as you expect it to. The information does not usually directly identify you, but it can give you a more personalized web experience. Because we respect your right to privacy, you can choose not to allow some types of cookies. Click on the different category headings to find out more and change our default settings. However, blocking some types of cookies may impact your experience of the site and the services we are able to offer. More information Allow All MANAGE CONSENT PREFERENCES TARGETING COOKIES Targeting Cookies These cookies may be set through our site by our advertising partners. They may be used by those companies to build a profile of your interests and show you relevant adverts on other sites. They do not store directly personal information, but are based on uniquely identifying your browser and internet device. If you do not allow these cookies, you will experience less targeted advertising. STRICTLY NECESSARY COOKIES Always Active These cookies are necessary for the website to function and cannot be switched off in our systems. They are usually only set in response to actions made by you which amount to a request for services, such as setting your privacy preferences, logging in or filling in forms. You can set your browser to block or alert you about these cookies, but some parts of the site will not then work. These cookies do not store any personally identifiable information. PERFORMANCE COOKIES Performance Cookies These cookies allow us to count visits and traffic sources so we can measure and improve the performance of our site. They help us to know which pages are the most and least popular and see how visitors move around the site. All information these cookies collect is aggregated and therefore anonymous. If you do not allow these cookies we will not know when you have visited our site, and will not be able to monitor its performance. FUNCTIONAL COOKIES Functional Cookies These cookies enable the website to provide enhanced functionality and personalisation. They may be set by us or by third party providers whose services we have added to our pages. If you do not allow these cookies then some or all of these services may not function properly. Back Button BACK Search Icon Filter Icon Clear checkbox label label Apply Cancel Consent Leg.Interest checkbox label label checkbox label label checkbox label label Reject All Confirm My Choices