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

Form analysis 0 forms found in the DOM

Text 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