Developer
Catalog-API
37min
the catalog api is the main interface for apps and frontends to communicate with the purple backend this documentation is intended for technical users (integrators and developers) overview the catalog api is based on graphql this allows for a type safe and clearly defined schema while also allowing to query only the data you need this documentation assumes familiarity with graphql please read the official website's introduction to graphql https //graphql org/learn/ to learn about the concepts if you have never worked with graphql before to get started working with our api, you can use the online editor graphiql it allows building and testing your queries without having to setup a local development environment you can view inline documentation of all the available types in both tools and your local development environment as the graphql schema offers direct support for documentation the endpoint that graphql clients have to use is https //catalog purplemanager com/graphql quick examples below are two simplified example queries you can use to understand how the catalog api works when retrieving article data in both cases, we assume you already have valid appinfo, deviceinfo, and authorization values (for more information on that, see below) 1\ article content only use case you want to retrieve a specific article as structured data query query catalogcontents($appinfo appinfo!, $deviceinfo deviceinfo!, $authorization authorization, $filter contentfilter, $sort \[contentcomparator!]) { catalog(appinfo $appinfo, deviceinfo $deviceinfo, authorization $authorization) { contentsconnection(filter $filter, sort $sort) { edges { node { typename id name publicationdate \# this requests custom properties, e g custom fields (acf) defined for that post properties { key value } \# request fields only available for posts on post { \# the list of blocks used for the post in a structured format with this information you can define your own rendering of parts of the content content { id parentid type level children sequence properties { key value } } } } } } } } variables { "appinfo" { "appid" "149923c7 0c63 4194 98dd 4491eac455dd", "appversion" "1 0", "preview" false }, "deviceinfo" { "deviceid" "web", "devicemodel" "chrome", "deviceos" "100", "locale" "de de", "platform" "web" }, "filter" { "name" { "value" "example post" } } } example response { "data" { "catalog" { "contentsconnection" { "edges" \[ { "node" { " typename" "post", "id" "259cd507 212e 47cc 832f c9231359f97a", "name" "example post", "publicationdate" "2025 01 10t08 45 40 000z", "properties" \[ { "key" "slug", "value" "hello world" } ], "content" \[ { "id" "d140212f 4976 41d4 9dc5 0fb16cfa9a17", "parentid" "", "type" "core/paragraph", "level" 0, "children" \[], "sequence" 0, "properties" \[ { "key" "purpleid", "value" "d140212f 4976 41d4 9dc5 0fb16cfa9a17" }, { "key" "content", "value" "welcome to purple this is your first post edit or delete it, then start writing!" } ] } ] } } ] } } } } how it works we specify the catalog field in the query root, passing in mandatory parameters appinfo contains your appid, appversion, and a preview flag deviceinfo captures device/platform details like deviceid, platform, etc authorization provides the token or coupon code needed to access premium or restricted contents within the catalog field, we use contentsconnection to fetch all kinds of content (e g , issues, posts, bundles) and filter them in this example, we filter by the article’s name we then request the id, name, publication date and custom properties if the content is a post (i e , an article), we’ll receive the article’s plain text this query is a great starting point if you only need the text portion of an article without additional formatting or markup, or if you generate article specific markup yourself 2\ article with markup use case you want the same article content, but this time you need its markup as well—perhaps you’re planning to render it with richer html or want to maintain some formatting in your frontend query query catalogcontents($appinfo appinfo!, $deviceinfo deviceinfo!, $authorization authorization, $filter contentfilter, $sort \[contentcomparator!]) { catalog(appinfo $appinfo, deviceinfo $deviceinfo, authorization $authorization) { contentsconnection(filter $filter, sort $sort) { edges { node { typename id name publicationdate \# this requests custom properties, e g custom fields (acf) defined for that post properties { key value } \# request fields only available for posts on post { contenthtml } } } } } } variables { "appinfo" { "appid" "149923c7 0c63 4194 98dd 4491eac455dd", "appversion" "1 0", "preview" false }, "deviceinfo" { "deviceid" "web", "devicemodel" "chrome", "deviceos" "100", "locale" "de de", "platform" "web" }, "filter" { "name" { "value" "example post" } } } example response { "data" { "catalog" { "contentsconnection" { "edges" \[ { "node" { " typename" "post", "id" "259cd507 212e 47cc 832f c9231359f97a", "name" "example post", "publicationdate" "2025 01 10t08 45 40 000z", "properties" \[ { "key" "slug", "value" "hello world" } ], "contenthtml" "\<h1 class='entry title'>example post\</h1>\n\<p>welcome to purple this is your first post edit or delete it, then start writing!\</p>\n" } } ] } } } } how it works this query is almost identical to the first example but we also request the markup field inside article the markup field can contain additional formatting or html that you can render on your frontend for a richer user experience as before, we use contentsconnection to fetch and filter the content, but the requested fields now include text and markup using this approach, you can preserve styling and layout elements from the purple hub, allowing you to display articles in a more visually appealing way without generating markup in your custom frontend queries the catalog api offers both the query and mutation root types the most important part of the catalog api is the ability to query the contents and it's metadata of your app or website the entrypoint for this is the catalog field in the query root type the required arguments define the basic information that all other queries use common request parameters appinfo the appinfo type holds the reference to your appid (the id of your app or website in our system), the appversion (the version of your app) and the preview flag (determines if you want preview or live contents) you can find the appid in the purple manager on the app's api page deviceinfo the deviceinfo type holds information about the requesting system the deviceid is used to uniquely identify the system and allow access to previously anonymously purchased contents, e g in app stores if you are requesting data from a website you should generate a unique id, e g an uuid, and store it in the local storage of the browser the platform defines the platform that is being used to request dats currently we differentiate between android , ios and web it is also used to filter the available contents, e g if you want certain contents to be only available on one platform or deliver different version to different platforms the devicemodel and deviceoss fields are used to determine the device class, e g tables or phone for ios, and for statistical and auditing purposes please provide accurate data about the model, e g the model name of the device or browser name, and the version of the device or browser the smallestscreenwidthdp field is only used for the android platform to determine the device class authorization the authorization type is used to provide access tokens and subscription codes (coupon codes) to determine access and purchase status for contents pagination most queries for data support paging using the graphql cursor connections specification (arguments first and after ) you can identify this by the connection suffix at the fieldnames which support paging all apis limit the maximum number of entries to 200 per query if you need to request more data you will need to request pages using the after argument filtering and sorting all connections support filtering and sorting the results filtering to filter the results you can use the filter parameter the filters provide matchers for many fields of the connections return type you can however only use one field matcher at a time to match based on multiple fields you have to combine multiple filters using the and and or fields example filter for name or description containing the word "sun" expand source example filter for name or description containing the word "sun" { "filter" { "or" \[ { "name" { "operation" "contains", "value" "sun" } }, { "description" { "operation" "contains", "value" "sun" } } ] } } sorting the filtered results can be sorted using the sort parameter each comparator type allows defining the field that is used to compare for the sort and the direction (ascending or descending) multiple comparators can also be chained, e g to sort by publication date and then name example sort by publicationdate and name expand source contents (issues, posts and bundles) the contentsconnection can be used to query issues, posts and bundles of an app the results can be filtered and sorted using the filter and sort arguments the contents have three major types that share the common content interface issue issues are magazine style contents they usually have multiple pages and use our storytelling engine and can display animations, pdfs and other media post posts are (news) article contents produced using our purple hub bundle bundles are collections of posts and are also produced using our purple hub example queries all posts this query returns all the posts of an app query query catalogcontents($appinfo appinfo!, $deviceinfo deviceinfo!, $authorization authorization, $filter contentfilter, $sort \[contentcomparator!]) { catalog(appinfo $appinfo, deviceinfo $deviceinfo, authorization $authorization) { contentsconnection(filter $filter, sort $sort) { edges { node { typename id version name description index alias externalid publicationdate access \# this requests custom properties, e g acfs defined for that post properties { key value } \# request fields only available for posts on post { \# the complete body of the post as html contenthtml \# the list of blocks used for the post in a structured format with this information you can define your own rendering of parts of the content content { id level sequence html } \# same as contenthtml but with reduced content based on the hub preview settings this can be used for paywalls to show a preview of the content previewcontenthtml \# same as content, but with the preview data previewcontents { id level sequence html } } } } } } } variables { "appinfo" { "appid" "149923c7 0c63 4194 98dd 4491eac455dd", "appversion" "1 0", "preview" false }, "deviceinfo" { "deviceid" "web", "devicemodel" "chrome", "deviceos" "100", "locale" "de de", "platform" "web" }, "filter" { "contenttype" { "value" "post" } } } example response { "data" { "catalog" { "contentsconnection" { "edges" \[ { "node" { " typename" "post", "id" "259cd507 212e 47cc 832f c9231359f97a", "version" 10004, "name" "example post", "description" "", "index" 0, "alias" null, "externalid" "1", "publicationdate" "2025 01 10t08 45 40 000z", "access" "free", "properties" \[ { "key" "slug", "value" "hello world" }, { "key" "purple seo meta", "value" "{\\"title\\" \\"example post public documentation hub\\",\\"robots\\" {\\"index\\" \\"index\\",\\"follow\\" \\"follow\\",\\"max snippet\\" \\"max snippet 1\\",\\"max image preview\\" \\"max image preview\ large\\",\\"max video preview\\" \\"max video preview 1\\"},\\"canonical\\" \\"example post\\",\\"og locale\\" \\"en us\\",\\"og type\\" \\"article\\",\\"og title\\" \\"example post public documentation hub\\",\\"og url\\" \\"example post\\",\\"og site name\\" \\"public documentation hub\\",\\"article published time\\" \\"2025 01 10t08 45 40+00 00\\",\\"article modified time\\" \\"2025 01 10t09 31 23+00 00\\",\\"author\\" \\"philip schiffer\@sprylab com\\",\\"twitter card\\" \\"summary large image\\",\\"twitter misc\\" {\\"written by\\" \\"philip schiffer\@sprylab com\\"}}" }, { "key" "purple seo meta html", "value" "\<! this site is optimized with the yoast seo plugin v21 2 https //yoast com/wordpress/plugins/seo/ >\n\<title>example post public documentation hub\</title>\n\n\<meta name=\\"robots\\" content=\\"index, follow, max snippet 1, max image preview\ large, max video preview 1\\" />\n\<link rel=\\"canonical\\" href=\\"example post\\" />\n\<meta property=\\"og\ locale\\" content=\\"en us\\" />\n\<meta property=\\"og\ type\\" content=\\"article\\" />\n\<meta property=\\"og\ title\\" content=\\"example post public documentation hub\\" />\n\<meta property=\\"og\ url\\" content=\\"example post\\" />\n\<meta property=\\"og\ site name\\" content=\\"public documentation hub\\" />\n\<meta property=\\"article\ published time\\" content=\\"2025 01 10t08 45 40+00 00\\" />\n\<meta property=\\"article\ modified time\\" content=\\"2025 01 10t09 31 23+00 00\\" />\n\<meta name=\\"author\\" content=\\"philip schiffer\@sprylab com\\" />\n\<meta name=\\"twitter\ card\\" content=\\"summary large image\\" />\n\<meta name=\\"twitter\ label1\\" content=\\"written by\\" />\n\t\<meta name=\\"twitter\ data1\\" content=\\"philip schiffer\@sprylab com\\" />\n\<! / yoast seo plugin >" } ], "contenthtml" "\<h1 class='entry title'>example post\</h1>\n\<p>welcome to purple this is your first post edit or delete it, then start writing!\</p>\n", "content" \[ { "id" "d140212f 4976 41d4 9dc5 0fb16cfa9a17", "level" 0, "sequence" 0, "html" "\n\<p>welcome to purple this is your first post edit or delete it, then start writing!\</p>\n" } ], "previewcontenthtml" null, "previewcontents" \[] } } ] } } } } all issues query query catalogcontents($appinfo appinfo!, $deviceinfo deviceinfo!, $authorization authorization, $filter contentfilter, $sort \[contentcomparator!]) { catalog(appinfo $appinfo, deviceinfo $deviceinfo, authorization $authorization) { contentsconnection(filter $filter, sort $sort) { edges { node { typename id version name description index alias externalid publicationdate access productid purchasedata { purchased purchasedby } } } } } } variables { "appinfo" { "appid" "149923c7 0c63 4194 98dd 4491eac455dd", "appversion" "1 0", "preview" false }, "deviceinfo" { "deviceid" "web", "devicemodel" "chrome", "deviceos" "100", "locale" "de de", "platform" "web" }, "filter" { "contenttype" { "value" "issue" } } } all bundles query query catalogcontents($appinfo appinfo!, $deviceinfo deviceinfo!, $authorization authorization, $filter contentfilter, $sort \[contentcomparator!]) { catalog(appinfo $appinfo, deviceinfo $deviceinfo, authorization $authorization) { contentsconnection(filter $filter, sort $sort) { edges { node { typename id version name description index alias externalid publicationdate access on bundle { contents { id content { id name contenthtml } } } } } } } } variables { "appinfo" { "appid" "149923c7 0c63 4194 98dd 4491eac455dd", "appversion" "1 0", "preview" false }, "deviceinfo" { "deviceid" "web", "devicemodel" "chrome", "deviceos" "100", "locale" "de de", "platform" "web" }, "filter" { "contenttype" { "value" "bundle" } } } example response { "data" { "catalog" { "contentsconnection" { "edges" \[ { "node" { " typename" "bundle", "id" "3c3172aa a403 4845 9471 00e9cf9616c4", "version" 20004, "name" "example issue", "description" "", "index" 0, "alias" null, "externalid" "23", "publicationdate" "2025 01 10t12 01 33 000z", "access" "free", "contents" \[ { "id" "ff08083f cc39 4728 9861 34532b17907d", "content" { "id" "ff08083f cc39 4728 9861 34532b17907d", "name" "issue article", "contenthtml" "\<h1 class='entry title'>issue article\</h1>\n\<p>this is an article that is part of an issue\</p>\n" } } ] } } ] } } } } all posts which have a category "news" query query catalogcontents($appinfo appinfo!, $deviceinfo deviceinfo!, $authorization authorization, $filter contentfilter, $sort \[contentcomparator!]) { catalog(appinfo $appinfo, deviceinfo $deviceinfo, authorization $authorization) { contentsconnection(filter $filter, sort $sort) { edges { node { typename id version name description index alias externalid publicationdate access categories } } } } } variables { "appinfo" { "appid" "149923c7 0c63 4194 98dd 4491eac455dd", "appversion" "1 0", "preview" false }, "deviceinfo" { "deviceid" "web", "devicemodel" "chrome", "deviceos" "100", "locale" "de de", "platform" "web" }, "filter" { "and" \[ { "contenttype" { "value" "post" } }, { "categories" { "content" { "value" { "value" "news" } } } } ] } } example response { "data" { "catalog" { "contentsconnection" { "edges" \[ { "node" { " typename" "post", "id" "7331d1d9 f824 48ef b06f 746af096caf5", "version" 10004, "name" "example news", "description" "", "index" 0, "alias" null, "externalid" "29", "publicationdate" "2025 01 10t13 08 42 000z", "access" "free", "categories" \[ "news" ] } } ] } } } } all posts which have a tag "news" query query catalogcontents($appinfo appinfo!, $deviceinfo deviceinfo!, $authorization authorization, $filter contentfilter, $sort \[contentcomparator!]) { catalog(appinfo $appinfo, deviceinfo $deviceinfo, authorization $authorization) { contentsconnection(filter $filter, sort $sort) { edges { node { typename id version name description index alias externalid publicationdate access tags } } } } } variables { "appinfo" { "appid" "149923c7 0c63 4194 98dd 4491eac455dd", "appversion" "1 0", "preview" false }, "deviceinfo" { "deviceid" "web", "devicemodel" "chrome", "deviceos" "100", "locale" "de de", "platform" "web" }, "filter" { "and" \[ { "contenttype" { "value" "post" } }, { "tags" { "content" { "value" { "value" "news" } } } } ] } } example response { "data" { "catalog" { "contentsconnection" { "edges" \[ { "node" { " typename" "post", "id" "7331d1d9 f824 48ef b06f 746af096caf5", "version" 30004, "name" "example news", "description" "", "index" 0, "alias" null, "externalid" "29", "publicationdate" "2025 01 10t13 08 42 000z", "access" "free", "categories" \[ "news" ] } } ] } } } } all contents which have a custom property "cover" with value "true" query query catalogcontents($appinfo appinfo!, $deviceinfo deviceinfo!, $authorization authorization, $filter contentfilter, $sort \[contentcomparator!]) { catalog(appinfo $appinfo, deviceinfo $deviceinfo, authorization $authorization) { contentsconnection(filter $filter, sort $sort) { edges { node { typename id version name description index alias externalid publicationdate access tags properties { key value type } } } } } } variables { "appinfo" { "appid" "149923c7 0c63 4194 98dd 4491eac455dd", "appversion" "1 0", "preview" false }, "deviceinfo" { "deviceid" "web", "devicemodel" "chrome", "deviceos" "100", "locale" "de de", "platform" "web" }, "filter" { "properties" { "key" "cover", "value" "true" } } } example response { "data" { "catalog" { "contentsconnection" { "edges" \[ { "node" { " typename" "bundle", "id" "3c3172aa a403 4845 9471 00e9cf9616c4", "version" 30004, "name" "example issue", "description" "", "index" 0, "alias" null, "externalid" "23", "publicationdate" "2025 01 10t12 01 33 000z", "access" "free", "tags" \[], "properties" \[ { "key" "slug", "value" "example issue", "type" "string" }, { "key" "cover", "value" "true", "type" "string" } ] } } ] } } } } future contents (teasers) the futurecontentconnection allows retrieving a limited subset of content metadata for contents with a publication date in the future the futurecontentconnection is disabled by default as it could lead to leaked articles it can be enabled in the api configuration page of an app in the purple manager all future contents this query returns all the future contents of an app query query catalogfuturecontentsquery($appinfo appinfo!, $deviceinfo deviceinfo!) { catalog( appinfo $appinfo deviceinfo $deviceinfo ) { futurecontentconnection { edges{ node { id name description publicationdate properties { key value } } } } } } variables { "appinfo" { "appid" "149923c7 0c63 4194 98dd 4491eac455dd", "appversion" "", "preview" false }, "deviceinfo" { "deviceid" "test replace me", "devicemodel" "test replace me", "locale" "de de", "deviceos" "test replace me", "platform" "web" } } example response { "data" { "catalog" { "futurecontentconnection" { "edges" \[ { "node" { "id" "746ce689 1e7d 43bd a90b cdaf600c0724", "name" "future newsstand issue", "description" "an exciting teaser for the content", "publicationdate" "2034 12 31t23 00 00 000z", "properties" \[ { "key" "customprop", "value" "value" } ] } } ] } } } } publications publications are the main container for contents every content is assigned to one publication the publicationsconnection can be used to query the publications of an app the results can be filtered and sorted using the filter and sort arguments example queries all publications query query catalogpublications($appinfo appinfo!, $deviceinfo deviceinfo!, $authorization authorization, $filter publicationfilter) { catalog( appinfo $appinfo deviceinfo $deviceinfo authorization $authorization ) { publicationsconnection( filter $filter ) { edges { node { id name description type index language currentcontentid thumbnails { kind url } properties { key value } } } } } } variables { "appinfo" { "appid" "149923c7 0c63 4194 98dd 4491eac455dd", "appversion" "1 0", "preview" false }, "deviceinfo" { "deviceid" "web", "devicemodel" "chrome", "deviceos" "100", "locale" "de de", "platform" "web" } } example response { "data" { "catalog" { "publicationsconnection" { "edges" \[ { "node" { "id" "66b940ce f574 4c98 805c c9785d2fc969", "name" "newsstand", "description" "", "type" "kiosk", "index" 1, "language" null, "currentcontentid" "bb3ff14a 13fa 46d4 bd58 2726fd722c55", "thumbnails" \[], "properties" \[] } }, { "node" { "id" "c72424c7 4226 4e71 87a8 35e24599837c", "name" "newsfeed", "description" "", "type" "channel", "index" 2, "language" null, "currentcontentid" "7331d1d9 f824 48ef b06f 746af096caf5", "thumbnails" \[], "properties" \[ { "key" "channel", "value" "true" } ] } } ] } } } } all newsfeeds (internally called channel) query query catalogpublications($appinfo appinfo!, $deviceinfo deviceinfo!, $authorization authorization, $filter publicationfilter) { catalog( appinfo $appinfo deviceinfo $deviceinfo authorization $authorization ) { publicationsconnection( filter $filter ) { edges { node { id name description type index language currentcontentid thumbnails { kind url } properties { key value } } } } } } variables { "appinfo" { "appid" "149923c7 0c63 4194 98dd 4491eac455dd", "appversion" "1 0", "preview" false }, "deviceinfo" { "deviceid" "web", "devicemodel" "chrome", "deviceos" "100", "locale" "de de", "platform" "web" }, "filter" { "type" { "value" "channel" } } }{ "data" { "catalog" { "publicationsconnection" { "edges" \[ { "node" { "id" "c72424c7 4226 4e71 87a8 35e24599837c", "name" "newsfeed", "description" "", "type" "channel", "index" 2, "language" null, "currentcontentid" "7331d1d9 f824 48ef b06f 746af096caf5", "thumbnails" \[], "properties" \[ { "key" "channel", "value" "true" } ] } } ] } } } } all newsstands (internally called kiosk) query query catalogpublications($appinfo appinfo!, $deviceinfo deviceinfo!, $authorization authorization, $filter publicationfilter) { catalog( appinfo $appinfo deviceinfo $deviceinfo authorization $authorization ) { publicationsconnection( filter $filter ) { totalcount edges { node { id name description type index language currentcontentid thumbnails { kind url } properties { key value } } } } } } variables { "appinfo" { "appid" "149923c7 0c63 4194 98dd 4491eac455dd", "appversion" "1 0", "preview" false }, "deviceinfo" { "deviceid" "web", "devicemodel" "chrome", "deviceos" "100", "locale" "de de", "platform" "web" }, "filter" { "type" { "value" "kiosk" } } } example response { "data" { "catalog" { "publicationsconnection" { "edges" \[ { "node" { "id" "66b940ce f574 4c98 805c c9785d2fc969", "name" "newsstand", "description" "", "type" "kiosk", "index" 1, "language" null, "currentcontentid" "bb3ff14a 13fa 46d4 bd58 2726fd722c55", "thumbnails" \[], "properties" \[] } } ] } } } } subscriptions apps can offer subscriptions to their users currently only native app store subscriptions are supported subscriptions will only unlock content for the publications to which they have been assigned the subscriptionsconnection can be used to query the subscriptions of an app the results can be filtered and sorted using the filter and sort arguments example queries all subscriptions (android) note the deviceinfo > platform field value of android subscriptions are assigned to a platform (android/ios) query query catalogsubscriptions($appinfo appinfo!, $deviceinfo deviceinfo!, $authorization authorization, $filter subscriptionfilter, $sort \[subscriptioncomparator!], $first int, $after string) { catalog(appinfo $appinfo, deviceinfo $deviceinfo, authorization $authorization) { subscriptionsconnection(filter $filter, sort $sort, first $first, after $after) { edges { node { id name description type duration hidden productid groupid additionalunlocks { count unit } properties { key value } thumbnails { kind url } eligibilityinfo { trial introductorypricing discountoffers } currentreceiptinfo { istrialperiod isintroofferperiod expirationdate autoresumedate autorenewing } historicreceiptinfo { hadpurchased hadtrial hadintroductorypricing } publications { id name } } } } } } variables { "appinfo" { "appid" "149923c7 0c63 4194 98dd 4491eac455dd", "appversion" "1 0", "preview" false }, "deviceinfo" { "deviceid" "web", "devicemodel" "chrome", "deviceos" "100", "locale" "de de", "platform" "android" }, "filter" {} } example response { "data" { "catalog" { "subscriptionsconnection" { "edges" \[ { "node" { "id" "40382b25 68e0 48dc 8234 511f84cc9088", "name" "premium 1 month", "description" "1 month of premium access", "type" "autorenewable", "duration" "one month", "hidden" false, "productid" "com example monthly", "groupid" null, "additionalunlocks" { "count" 0, "unit" "day" }, "properties" \[], "thumbnails" \[], "eligibilityinfo" { "trial" null, "introductorypricing" true, "discountoffers" false }, "currentreceiptinfo" null, "historicreceiptinfo" { "hadpurchased" false, "hadtrial" false, "hadintroductorypricing" false }, "publications" \[ { "id" "66b940ce f574 4c98 805c c9785d2fc969", "name" "newsstand" }, { "id" "c72424c7 4226 4e71 87a8 35e24599837c", "name" "newsfeed" } ] } } ] } } } } all subscriptions (ios) note the deviceinfo > platform field value of ios subscriptions are assigned to a platform (android/ios) query query catalogsubscriptions($appinfo appinfo!, $deviceinfo deviceinfo!, $authorization authorization, $filter subscriptionfilter, $sort \[subscriptioncomparator!], $first int, $after string) { catalog(appinfo $appinfo, deviceinfo $deviceinfo, authorization $authorization) { subscriptionsconnection(filter $filter, sort $sort, first $first, after $after) { edges { node { id name description type duration hidden productid groupid additionalunlocks { count unit } properties { key value } thumbnails { kind url } eligibilityinfo { trial introductorypricing discountoffers } currentreceiptinfo { istrialperiod isintroofferperiod expirationdate autoresumedate autorenewing } historicreceiptinfo { hadpurchased hadtrial hadintroductorypricing } publications { id name type properties { key value type } } } } } } } variables { "appinfo" { "appid" "149923c7 0c63 4194 98dd 4491eac455dd", "appversion" "1 0", "preview" false }, "deviceinfo" { "deviceid" "web", "devicemodel" "chrome", "deviceos" "100", "locale" "de de", "platform" "ios" }, "filter" {} } example response { "data" { "catalog" { "subscriptionsconnection" { "edges" \[ { "node" { "id" "51d04143 d847 435e a762 cbeff24e4fb2", "name" "premium 1 month", "description" "1 month of premium access", "type" "autorenewable", "duration" "one month", "hidden" false, "productid" "com example monthly", "groupid" null, "additionalunlocks" { "count" 0, "unit" "day" }, "properties" \[], "thumbnails" \[], "eligibilityinfo" { "trial" true, "introductorypricing" true, "discountoffers" false }, "currentreceiptinfo" null, "historicreceiptinfo" { "hadpurchased" false, "hadtrial" false, "hadintroductorypricing" false }, "publications" \[ { "id" "66b940ce f574 4c98 805c c9785d2fc969", "name" "newsstand" }, { "id" "c72424c7 4226 4e71 87a8 35e24599837c", "name" "newsfeed" } ] } } ] } } } } publication products publication products allows publishers, depending of the type of the product, to offer users to purchase all previously published content or use the same (consumable) app store product for multiple purchases of different contents publication products only unlock content for the publications they are assigned to the publicationproductsconnection can be used to query the available product of an app the results can be filtered and sorted using the filter and sort arguments example queries all publication products (android) note the deviceinfo > platform field value of android publication products are assigned to a platform (android/ios) query query catalogpublicationproducts( $appinfo appinfo!, $deviceinfo deviceinfo!, $authorization authorization, $filter publicationproductfilter, $sort \[publicationproductcomparator!], $first int, $after string ) { catalog(appinfo $appinfo, deviceinfo $deviceinfo, authorization $authorization) { publicationproductsconnection( filter $filter, sort $sort, first $first, after $after ) { edges { node { id name description type hidden productid index properties { key value type } thumbnails { kind url } on contentscompletionproduct { purchased includeslatestcontent } publications { id unlockablecontentsconnection { edges { node { id name publicationdate productid publicationid thumbnails { kind url } } } } } } } } } } variables { "appinfo" { "appid" "149923c7 0c63 4194 98dd 4491eac455dd", "appversion" "1 0", "preview" false }, "deviceinfo" { "deviceid" "web", "devicemodel" "chrome", "deviceos" "100", "locale" "de de", "platform" "android" }, "filter" { } } example response { "data" { "catalog" { "publicationproductsconnection" { "edges" \[ { "node" { "id" "dc4ae6d4 c148 4997 8878 e328d519c467", "name" "consumable product", "description" "", "type" "repeatable content purchase", "hidden" false, "productid" "com example consumable", "index" 0, "properties" \[], "thumbnails" \[], "publications" \[ { "id" "c72424c7 4226 4e71 87a8 35e24599837c", "unlockablecontentsconnection" { "edges" \[] } }, { "id" "66b940ce f574 4c98 805c c9785d2fc969", "unlockablecontentsconnection" { "edges" \[] } } ] } } ] } } } } all publication products (ios) query query catalogpublicationproducts( $appinfo appinfo!, $deviceinfo deviceinfo!, $authorization authorization, $filter publicationproductfilter, $sort \[publicationproductcomparator!], $first int, $after string ) { catalog(appinfo $appinfo, deviceinfo $deviceinfo, authorization $authorization) { publicationproductsconnection( filter $filter, sort $sort, first $first, after $after ) { edges { node { id name description type hidden productid index properties { key value type } thumbnails { kind url } on contentscompletionproduct { purchased includeslatestcontent } publications { id unlockablecontentsconnection { edges { node { id name publicationdate productid publicationid thumbnails { kind url } } } } } } } } } } variables { "appinfo" { "appid" "149923c7 0c63 4194 98dd 4491eac455dd", "appversion" "1 0", "preview" false }, "deviceinfo" { "deviceid" "web", "devicemodel" "chrome", "deviceos" "100", "locale" "de de", "platform" "ios" }, "filter" { } } example response { "data" { "catalog" { "publicationproductsconnection" { "edges" \[ { "node" { "id" "a7d74570 f168 43df 9155 aa5833ab6fa2", "name" "consumable product", "description" "", "type" "repeatable content purchase", "hidden" false, "productid" "com example consumable", "index" 0, "properties" \[], "thumbnails" \[], "publications" \[ { "id" "c72424c7 4226 4e71 87a8 35e24599837c", "unlockablecontentsconnection" { "edges" \[] } }, { "id" "66b940ce f574 4c98 805c c9785d2fc969", "unlockablecontentsconnection" { "edges" \[] } } ] } } ] } } } } taxonomies the taxonomiesconnection can be used to query the taxonomies, e g tags and categories, of an app the results can be filtered and sorted using the filter and sort arguments example queries all taxonomies query query catalogtaxonomies($appinfo appinfo!, $deviceinfo deviceinfo!, $authorization authorization, $filter taxonomyfilter) { catalog(appinfo $appinfo, deviceinfo $deviceinfo, authorization $authorization) { taxonomiesconnection(filter $filter) { edges { node { id parentid type name properties { key value type } thumbnails { kind url } } } } } } variables { "appinfo" { "appid" "149923c7 0c63 4194 98dd 4491eac455dd", "appversion" "1 0", "preview" false }, "deviceinfo" { "deviceid" "web", "devicemodel" "chrome", "deviceos" "100", "locale" "de de", "platform" "web" } } example response { "data" { "catalog" { "taxonomiesconnection" { "edges" \[ { "node" { "id" "max mustermann", "parentid" "", "type" "author", "name" "max mustermann", "properties" \[ { "key" "first name", "value" "", "type" "string" }, { "key" "last name", "value" "", "type" "string" }, { "key" "user email", "value" "", "type" "string" }, { "key" "user url", "value" "", "type" "string" }, { "key" "description", "value" "", "type" "string" } ], "thumbnails" \[] } }, { "node" { "id" "news", "parentid" "", "type" "category", "name" "news", "properties" \[], "thumbnails" \[] } }, { "node" { "id" "news", "parentid" "", "type" "tag", "name" "news", "properties" \[], "thumbnails" \[] } } ] } } } } collections collections are curated lists of posts/articles the collectionsconnection can be used to query the collections of an app the results can be filtered and sorted using the filter and sort arguments example queries all collections query query catalogcollections( $appinfo appinfo!, $deviceinfo deviceinfo!, $authorization authorization, $filter collectionfilter, $sort \[collectioncomparator!], $first int, $after string, $elementsfirst int, $elementsafter string ) { catalog(appinfo $appinfo, deviceinfo $deviceinfo, authorization $authorization) { collectionsconnection( filter $filter, sort $sort, first $first, after $after ) { pageinfo { haspreviouspage hasnextpage startcursor endcursor } edges { cursor node { id name properties { key value type } elementsconnection( first $elementsfirst, after $elementsafter ) { pageinfo { haspreviouspage hasnextpage startcursor endcursor } edges { cursor node { on contentelement { id content { id name } } } } } } } } } } variables { "appinfo" { "appid" "149923c7 0c63 4194 98dd 4491eac455dd", "appversion" "1 0", "preview" false }, "deviceinfo" { "deviceid" "web", "devicemodel" "chrome", "deviceos" "100", "locale" "de de", "platform" "web" } } example response { "data" { "catalog" { "collectionsconnection" { "pageinfo" { "haspreviouspage" false, "hasnextpage" false, "startcursor" "1", "endcursor" "1" }, "edges" \[ { "cursor" "1", "node" { "id" "8128fec3 110a 4e6e 8654 461eea8f7321", "name" "daily news", "properties" \[], "elementsconnection" { "pageinfo" { "haspreviouspage" false, "hasnextpage" false, "startcursor" "1", "endcursor" "1" }, "edges" \[ { "cursor" "1", "node" { "id" "7331d1d9 f824 48ef b06f 746af096caf5", "content" { "id" "7331d1d9 f824 48ef b06f 746af096caf5", "name" "example news" } } } ] } } } ] } } } } collection with name query query catalogcollections( $appinfo appinfo!, $deviceinfo deviceinfo!, $authorization authorization, $filter collectionfilter, $sort \[collectioncomparator!], $first int, $after string, $elementsfirst int, $elementsafter string ) { catalog(appinfo $appinfo, deviceinfo $deviceinfo, authorization $authorization) { collectionsconnection( filter $filter, sort $sort, first $first, after $after ) { pageinfo { haspreviouspage hasnextpage startcursor endcursor } edges { cursor node { id name properties { key value type } elementsconnection( first $elementsfirst, after $elementsafter ) { pageinfo { haspreviouspage hasnextpage startcursor endcursor } edges { cursor node { on contentelement { id content { id name } } } } } } } } } } variables { "appinfo" { "appid" "149923c7 0c63 4194 98dd 4491eac455dd", "appversion" "1 0", "preview" false }, "deviceinfo" { "deviceid" "web", "devicemodel" "chrome", "deviceos" "100", "locale" "de de", "platform" "web" }, "filter" { "name" { "value" "daily news" } } } example response { "data" { "catalog" { "collectionsconnection" { "pageinfo" { "haspreviouspage" false, "hasnextpage" false, "startcursor" "1", "endcursor" "1" }, "edges" \[ { "cursor" "1", "node" { "id" "8128fec3 110a 4e6e 8654 461eea8f7321", "name" "daily news", "properties" \[], "elementsconnection" { "pageinfo" { "haspreviouspage" false, "hasnextpage" false, "startcursor" "1", "endcursor" "1" }, "edges" \[ { "cursor" "1", "node" { "id" "7331d1d9 f824 48ef b06f 746af096caf5", "content" { "id" "7331d1d9 f824 48ef b06f 746af096caf5", "name" "example news" } } } ] } } } ] } } } } menus menus are currently only used for websites they allow dynamically configuring the menu of a purple based website the menusconnection can be used to query the menus of an app the results can be filtered using the filter argument example queries all menus query query menu( $appinfo appinfo!, $deviceinfo deviceinfo! ) { catalog(appinfo $appinfo, deviceinfo $deviceinfo) { menusconnection { edges { node { id name properties { key value type } items { id parentid name sortindex url properties { key value type } } } } } } } variables { "appinfo" { "appid" "149923c7 0c63 4194 98dd 4491eac455dd", "appversion" "1 0", "preview" false }, "deviceinfo" { "deviceid" "web", "devicemodel" "chrome", "deviceos" "100", "locale" "de de", "platform" "web" } } example response { "data" { "catalog" { "menusconnection" { "edges" \[ { "node" { "id" "45852f06 50d7 4008 9d5c 89439dbde2fa", "name" "site menu", "properties" \[], "items" \[ { "id" "792a1527 3136 433e 9239 2e19ec53077a", "parentid" "45852f06 50d7 4008 9d5c 89439dbde2fa", "name" "example link", "sortindex" 1, "url" "https //example com", "properties" \[] } ] } } ] } } } } search the api allows to perform full text searches across all contents of an app the contentsearchconnection can be used to perform full text searches the simple query string syntax can be used inside the searchphrase to specify how the search phrase should be processed the following operators are supported \+ signifies and operation | signifies or operation negates a single token " wraps a number of tokens to signify a phrase for searching at the end of a term signifies a prefix query ( and ) signify precedence n after a word signifies edit distance (fuzziness) n after a phrase signifies slop amount the "simple query string syntax" is only available when fuzzymatching is false example queries search for contents that contain the word "news" query query catalogsearch( $appinfo appinfo!, $deviceinfo deviceinfo!, $authorization authorization, $searchphrase string!, $contentfilter contentfilter, $fuzzymatching boolean, $findallwords boolean, $sort \[contentsearchresultcomparator!], $first int, $after string $issuepagesort \[issuepagecomparator!] ) { catalog(appinfo $appinfo, deviceinfo $deviceinfo, authorization $authorization) { contentsearchconnection( searchphrase $searchphrase, contentfilter $contentfilter, fuzzymatching $fuzzymatching, findallwords $findallwords, sort $sort, first $first, after $after ) { edges { node { on issuesearchresult { issue { id name description access purchasedata { purchased purchasedby } } pagesconnection( sort $issuepagesort ) { edges { node { excerpt pageindex pagenumber pagelabel pagetitle elementalias } } } } on postsearchresult { post { id name description access contenthtml } excerpt } on bundlesearchresult { bundle { id name description access purchasedata { purchased purchasedby } } posts { post { id name } excerpt } } } } } } } variables { "appinfo" { "appid" "149923c7 0c63 4194 98dd 4491eac455dd", "appversion" "1 0", "preview" false }, "deviceinfo" { "deviceid" "web", "devicemodel" "chrome", "deviceos" "100", "locale" "de de", "platform" "web" }, "searchphrase" "news" } example response { "data" { "catalog" { "contentsearchconnection" { "edges" \[ { "node" { "post" { "id" "7331d1d9 f824 48ef b06f 746af096caf5", "name" "example news", "description" "", "access" "free", "contenthtml" "\<h1 class='entry title'>example news\</h1>\n\<p>this is a news article in the news category and news tag\</p>\n" }, "excerpt" "example \<strong>news\</strong> this is a \<strong>news\</strong> article in the \<strong>news\</strong> category and \<strong>news\</strong> tag" } } ] } } } } search for contents that contain the words "news" and "article" (using the option findallwords) query query catalogsearch( $appinfo appinfo!, $deviceinfo deviceinfo!, $authorization authorization, $searchphrase string!, $contentfilter contentfilter, $fuzzymatching boolean, $findallwords boolean, $sort \[contentsearchresultcomparator!], $first int, $after string $issuepagesort \[issuepagecomparator!] ) { catalog(appinfo $appinfo, deviceinfo $deviceinfo, authorization $authorization) { contentsearchconnection( searchphrase $searchphrase, contentfilter $contentfilter, fuzzymatching $fuzzymatching, findallwords $findallwords, sort $sort, first $first, after $after ) { edges { node { on issuesearchresult { issue { id name description access purchasedata { purchased purchasedby } } pagesconnection( sort $issuepagesort ) { edges { node { excerpt pageindex pagenumber pagelabel pagetitle elementalias } } } } on postsearchresult { post { id name description access contenthtml } excerpt } on bundlesearchresult { bundle { id name description access purchasedata { purchased purchasedby } } posts { post { id name } excerpt } } } } } } } variables { "appinfo" { "appid" "149923c7 0c63 4194 98dd 4491eac455dd", "appversion" "1 0", "preview" false }, "deviceinfo" { "deviceid" "web", "devicemodel" "chrome", "deviceos" "100", "locale" "de de", "platform" "web" }, "searchphrase" "news article", "findallwords" true } example response { "data" { "catalog" { "contentsearchconnection" { "edges" \[ { "node" { "post" { "id" "7331d1d9 f824 48ef b06f 746af096caf5", "name" "example news", "description" "", "access" "free", "contenthtml" "\<h1 class='entry title'>example news\</h1>\n\<p>this is a news article in the news category and news tag\</p>\n" }, "excerpt" "example \<strong>news\</strong> this is a \<strong>news\</strong> \<strong>article\</strong> in the \<strong>news\</strong> category and \<strong>news\</strong> tag" } } ] } } } } search for contents that contain the words "news" or "article" query query catalogsearch( $appinfo appinfo!, $deviceinfo deviceinfo!, $authorization authorization, $searchphrase string!, $contentfilter contentfilter, $fuzzymatching boolean, $findallwords boolean, $sort \[contentsearchresultcomparator!], $first int, $after string $issuepagesort \[issuepagecomparator!] ) { catalog(appinfo $appinfo, deviceinfo $deviceinfo, authorization $authorization) { contentsearchconnection( searchphrase $searchphrase, contentfilter $contentfilter, fuzzymatching $fuzzymatching, findallwords $findallwords, sort $sort, first $first, after $after ) { edges { node { on issuesearchresult { issue { id name description access purchasedata { purchased purchasedby } } pagesconnection( sort $issuepagesort ) { edges { node { excerpt pageindex pagenumber pagelabel pagetitle elementalias } } } } on postsearchresult { post { id name description access contenthtml } excerpt } on bundlesearchresult { bundle { id name description access purchasedata { purchased purchasedby } } posts { post { id name } excerpt } } } } } } } variables { "appinfo" { "appid" "149923c7 0c63 4194 98dd 4491eac455dd", "appversion" "1 0", "preview" false }, "deviceinfo" { "deviceid" "web", "devicemodel" "chrome", "deviceos" "100", "locale" "de de", "platform" "web" }, "searchphrase" "news article" } example response { "data" { "catalog" { "contentsearchconnection" { "edges" \[ { "node" { "post" { "id" "7331d1d9 f824 48ef b06f 746af096caf5", "name" "example news", "description" "", "access" "free", "contenthtml" "\<h1 class='entry title'>example news\</h1>\n\<p>this is a news article in the news category and news tag\</p>\n" }, "excerpt" "example \<strong>news\</strong> this is a \<strong>news\</strong> \<strong>article\</strong> in the \<strong>news\</strong> category and \<strong>news\</strong> tag" } }, { "node" { "bundle" { "id" "3c3172aa a403 4845 9471 00e9cf9616c4", "name" "example issue", "description" "", "access" "free", "purchasedata" { "purchased" true, "purchasedby" \[] } }, "posts" \[ { "post" { "id" "ff08083f cc39 4728 9861 34532b17907d", "name" "issue article" }, "excerpt" "issue \<strong>article\</strong> this is an \<strong>article\</strong> that is part of an issue" } ] } } ] } } } } suggestions the suggestions api under searchsuggestions takes all contents from a team and provides suggestions based on the provided input string example queries suggestions for "new" query query catalogsearch($appinfo appinfo!, $deviceinfo deviceinfo!, $authorization authorization, $input string!) { catalog(appinfo $appinfo, deviceinfo $deviceinfo, authorization $authorization) { searchsuggestions(input $input) { text } } } variables { "appinfo" { "appid" "149923c7 0c63 4194 98dd 4491eac455dd", "appversion" "1 0", "preview" false }, "deviceinfo" { "deviceid" "web", "devicemodel" "chrome", "deviceos" "100", "locale" "de de", "platform" "web" }, "input" "new" } example response { "data" { "catalog" { "searchsuggestions" \[ { "text" "newsstand issue" }, { "text" "news" }, { "text" "example news" } ] } } } api keys the catalog api can be secured using an api key in order to activate the authorisation for the api, you need to activate the check mark next to "secured mode" in the "basic settings" tab for your app in the purple manager once the secure mode is activated, the api key can be found in the api sub menu of an app in the purple manager