.. _stores: ======================== Brand Stores ======================== Introduction ------------ The *Brand Stores API* provides a means to manipulate brand stores. More information on brand stores and how to setup one can be obtained `here `_. This documentation assumes the brand store already exists, and the reader knows its store ID, e.g. via :ref:`account-api` response. We'll call this store ID ``the-store-id`` in the examples. All endpoints require a macaroon authenticated request, for a user that has admin permission in the store identified by the given store ID. Also, the macaroon used to authenticate the request must contain the ``store_admin`` permission. See :ref:`macaroon-api` for details on how to obtain a suitable macaroon for interacting with this API. You could also use the ``surl`` command line, available as a snap: ``snap install surl`` to exercise this (and other) store APIs. The following example authenticates to the store and saves the macaroon locally for use in subsequent requests: ``surl -a prod -s production -e [[-p ]]`` ``surl -a prod -X https://dashboard.snapcraft.io/ [[-d '']]`` If you call surl with the ``--allowed-store some-store-id`` the saved macaroon will be attenuated and next calls using that macaroon will be able to operate on that store only (or stores, if you pass the option several times). See ``surl help`` for the details about these and other surl options. The *Brand Stores API* is exposed at the following base URLs: * Staging: https://dashboard.staging.snapcraft.io/api/v2/stores * Production: https://dashboard.snapcraft.io/api/v2/stores Response Format _______________ JSON_ will be returned in all responses from the API, including error responses, please refer to the following section for details about the format. .. _JSON: http://www.json.org .. _api-store-info: List the details of a brand store ------------------------------------------------------------------- *Introduced in version 1* .. http:GET:: /api/v2/stores/(?P[\\w_-]+) List the details of a brand store. :reqheader Authorization: macaroon authorization header for a store admin :status 200: success :status 400: error :status 401: authentication required :status 404: store id does not exist or user does not have enough permission to see it Usage _____ As mentioned in the introduction, this endpoint can be exercised using the ``surl`` command as follows: ``surl -p store_admin -s production -e your-email@example.com -X GET https://dashboard.snapcraft.io/api/v2/stores/the-store-id`` where ``your-email@example.com`` has to be an existing account with permission to manage the store with ID ``the-store-id``. If the authenticating macaroon has any ``store_ids`` attenuation, the store ``the-store-id`` has to be among the allowed stores in that constraint (see the ``--allowed-store`` option in surl as a way to get a macaroon with such attenuation). Example _______ .. include:: ../../examples/requests/store_details Errors ______ .. include:: ../../examples/requests/store_details_errors Changelog _________ * Version 31: Added extra field to store info dict: "brand-id". * Version 28: Added extra field to store info dict: parent. * Version 17: Added extra fields to store info dict: private, manual-review-policy * Version 5: Added extra field to store info dict: invites. * Version 3: Added extra field to store info dict: snap-name-prefixes. * Version 2: Added extra fields to store info dict: allowed-inclusion-source-stores and allowed-inclusion-target-stores. Response JSON Schema ____________________ .. code-block:: json { "additionalProperties": false, "properties": { "invites": { "introduced_at": 5, "items": { "additionalProperties": false, "properties": { "email": { "description": "The invited email", "type": "string" }, "expiration-date": { "description": "The date when this invite expires, in ISO 8601 format.", "format": "date-time", "type": "string" }, "roles": { "description": "The roles that this invite's email was invited to join with.", "items": { "type": "string" }, "type": "array" }, "status": { "description": "The status of the invite, can be one of Pending, Accepted, Revoked or Expired.", "enum": [ "Pending", "Revoked", "Expired" ], "type": "string" } }, "required": [ "email", "expiration-date", "roles", "status" ], "type": "object" }, "type": "array" }, "store": { "additionalProperties": false, "properties": { "allowed-inclusion-source-stores": { "description": "The list of store IDs that this store can select snaps from to include in this store.", "introduced_at": 2, "items": { "type": "string" }, "type": "array" }, "allowed-inclusion-target-stores": { "description": "The list of store IDs that can select snaps from this store to include in their stores.", "introduced_at": 2, "items": { "type": "string" }, "type": "array" }, "brand-id": { "description": "The store brand ID or null.", "type": [ "string", "null" ] }, "id": { "description": "The store ID (slug).", "type": "string" }, "manual-review-policy": { "description": "The review policy for the store (one of: \"allow\", \"avoid\", or \"require\").", "enum": [ "allow", "avoid", "require" ], "introduced_at": 17, "type": "string" }, "name": { "description": "Visible name of this store.", "type": "string" }, "parent": { "description": "The store parent's ID (slug).", "type": [ "null", "string" ] }, "private": { "description": "Indicate whether this store will be visible in public lists", "introduced_at": 17, "type": "boolean" }, "roles": { "description": "The list of available roles in this store.", "items": { "type": "string" }, "type": "array" }, "snap-name-prefixes": { "additionalProperties": false, "introduced_at": 3, "properties": { "inheritable": { "description": "Whether this snap name prefix can be used by child stores or not (default is False).", "type": "boolean" }, "parent-id": { "description": "None if this snap name prefix was defined for the requesting store, else the store ID from which this prefix is being inherited.", "type": [ "string", "null" ] }, "prefix": { "description": "The snap name prefix.", "type": "string" } }, "required": [ "prefix", "inheritable", "parent-id" ], "type": "object" }, "store-whitelist": { "description": "The list of store IDs that this store includes.", "items": { "type": "string" }, "type": "array" } }, "required": [ "id", "brand-id", "name", "roles", "store-whitelist", "snap-name-prefixes", "allowed-inclusion-source-stores", "allowed-inclusion-target-stores" ], "type": "object" }, "users": { "introduced_at": 1, "items": { "additionalProperties": false, "properties": { "displayname": { "description": "The full name", "type": "string" }, "email": { "description": "The email", "type": "string" }, "id": { "description": "The account ID", "type": "string" }, "roles": { "description": "The roles that this user has in this store", "items": { "type": "string" }, "type": "array" }, "username": { "description": "The store username", "type": "string" } }, "required": [ "id", "displayname ", "email", "username", "roles" ], "type": "object" }, "type": "array" } }, "required": [ "store", "users", "invites" ], "type": "object" } .. _api-store-snaps: Manage the snaps in a brand store ------------------------------------------------------------------- *Introduced in version 1* .. http:GET:: /api/v2/stores/(?P[\\w_-]+)/snaps .. http:POST:: /api/v2/stores/(?P[\\w_-]+)/snaps Managing the snaps in a brand store. In order to manage the snaps in a brand store, a store admin can GET or POST to the endpoint ``/api/v2/stores/(the-store-id)/snaps``, to get a list of the snaps appearing in their store (GET operation), or to add/remove individual snaps. GET ___ For listing the snaps appearing in the store with ID ``the-store-id``: :reqheader Authorization: macaroon authorization header for a store admin :status 200: success :status 400: error :status 401: authentication required :status 404: store id does not exist or user does not have enough permission to see it Please note that the returned list of snaps include: - The snaps registered and uploaded to this store. - The snaps added into this store by using this API. Snaps included in this store by means of store inclusion (inheritance) are not returned in the result. There are two optional filters that could be passed when doing the GET call as follows: - `allowed-for-inclusion=1` - `publisher=(an-account-id)` POST ____ For adding a snap to the store with ID ``the-store-id``: .. http:post:: /api/v2/stores/(the-store-id)/snaps :reqheader Authorization: macaroon authorization header for a store admin :status 200: success :status 400: error :status 401: authentication required :status 404: store id does not exist or user does not have enough permission to see it ``{"add": [{"name": "snap-name-1"}, {"name": "snap-name-2"}]}`` The snaps that can be selected for addition are the ones that: * are public snaps in the main store, or * are public snaps in other stores that have explicitely allowed this store to add snaps from. For removing a snap from the store with ID ``the-store-id``: .. http:post:: /api/v2/stores/(the-store-id)/snaps :reqheader Authorization: macaroon authorization header for a store admin :status 200: success :status 400: error :status 401: authentication required :status 404: store id does not exist or user does not have enough permission to see it ``{"remove": [{"name": "snap-name-1"}, {"name": "snap-name-2"}]}`` The snaps that can be removed are only those that were previously added by using this API. The operations of ``add`` and ``remove`` can be combined in a single request, to reduce the amount of requests needed for each operation (see the the examples section). Usage _____ As mentioned in the introduction and in the previous endpoints, this endpoint can be exercised using the ``surl`` command. If the authenticating macaroon has any ``store_ids`` attenuation, the store ``the-store-id`` has to be among the allowed stores in that constraint (see the ``--allowed-store`` option in surl as a way to get a macaroon with such attenuation). Example _______ .. include:: ../../examples/requests/store_snaps Errors ______ .. include:: ../../examples/requests/store_snaps_errors Changelog _________ * Version 31: Added extra field to store info dict: "brand-id". * Version 28: Added extra field to store info dict: parent. * Version 25: Add searching of snaps for inclusion in brand store using query params: q and allowed-for-inclusion * Version 24: Remove fields from store snaps endpoint: user id, user email * Version 23: Add searching of snaps to store snaps endpoint using query param: q * Version 22: Added extra field to store snaps GET response: latest-release * Version 21: Added extra field to store snaps response: users (publisher and collaborators). * Version 17: Added extra fields to store info dict: private, manual-review-policy * Version 3: Added extra field to store info dict: snap-name-prefixes. * Version 2: Added extra fields to store info dict: allowed-inclusion-source-stores and allowed-inclusion-target-stores. Request JSON Schema ___________________ .. code-block:: json { "additionalProperties": false, "properties": { "add": { "description": "list of snap names to add to store", "introduced_at": 1, "items": { "type": "string" }, "type": "array" }, "remove": { "description": "list of snap names to remove from store", "introduced_at": 1, "items": { "type": "string" }, "type": "array" } }, "required": [ "add", "remove" ], "type": "object" } Response JSON Schema ____________________ .. code-block:: json { "additionalProperties": false, "properties": { "snaps": { "items": { "additionalProperties": false, "properties": { "essential": { "description": "Whether this snap is essential or not", "type": "boolean" }, "id": { "description": "The snap ID", "type": "string" }, "latest-release": { "description": "Details of the latest release. Only populated in GET requests.", "introduced_at": 22, "properties": { "channel": { "description": "Channel of latest release", "type": [ "string", "null" ] }, "revision": { "description": "Revision of latest release", "type": [ "integer", "null" ] }, "timestamp": { "description": "Timestamp of latest release", "type": [ "string", "null" ] }, "version": { "description": "Version of latest release", "type": [ "string", "null" ] } }, "type": "object" }, "name": { "description": "The snap name", "type": "string" }, "other-stores": { "description": "The list of store IDs that this snap appears in", "items": { "type": "string" }, "type": "array" }, "private": { "description": "Whether this snap is private or not", "type": "boolean" }, "store": { "description": "The store this snap was originally registered to", "type": "string" }, "users": { "description": "Publisher and collaborators for this snap", "introduced_at": 21, "items": { "additionalProperties": false, "properties": { "displayname": { "description": "The full name", "type": "string" }, "roles": { "description": "The roles that this user has for this snap", "items": { "enum": [ "owner", "collaborator" ], "type": "string" }, "type": "array" }, "username": { "description": "The store username", "type": "string" } }, "required": [ "displayname ", "username", "roles" ], "type": "object" }, "type": "array" } }, "required": [ "id", "essential", "name", "private", "store", "users" ], "type": "object" }, "type": "array" }, "store": { "additionalProperties": false, "properties": { "allowed-inclusion-source-stores": { "description": "The list of store IDs that this store can select snaps from to include in this store.", "introduced_at": 2, "items": { "type": "string" }, "type": "array" }, "allowed-inclusion-target-stores": { "description": "The list of store IDs that can select snaps from this store to include in their stores.", "introduced_at": 2, "items": { "type": "string" }, "type": "array" }, "brand-id": { "description": "The store brand ID or null.", "type": [ "string", "null" ] }, "id": { "description": "The store ID (slug).", "type": "string" }, "manual-review-policy": { "description": "The review policy for the store (one of: \"allow\", \"avoid\", or \"require\").", "enum": [ "allow", "avoid", "require" ], "introduced_at": 17, "type": "string" }, "name": { "description": "Visible name of this store.", "type": "string" }, "parent": { "description": "The store parent's ID (slug).", "type": [ "null", "string" ] }, "private": { "description": "Indicate whether this store will be visible in public lists", "introduced_at": 17, "type": "boolean" }, "roles": { "description": "The list of available roles in this store.", "items": { "type": "string" }, "type": "array" }, "snap-name-prefixes": { "additionalProperties": false, "introduced_at": 3, "properties": { "inheritable": { "description": "Whether this snap name prefix can be used by child stores or not (default is False).", "type": "boolean" }, "parent-id": { "description": "None if this snap name prefix was defined for the requesting store, else the store ID from which this prefix is being inherited.", "type": [ "string", "null" ] }, "prefix": { "description": "The snap name prefix.", "type": "string" } }, "required": [ "prefix", "inheritable", "parent-id" ], "type": "object" }, "store-whitelist": { "description": "The list of store IDs that this store includes.", "items": { "type": "string" }, "type": "array" } }, "required": [ "id", "brand-id", "name", "roles", "store-whitelist", "snap-name-prefixes", "allowed-inclusion-source-stores", "allowed-inclusion-target-stores" ], "type": "object" } }, "required": [ "store", "snaps" ], "type": "object" } .. _api-store-users: Add, remove or edit users' roles ------------------------------------------------------------------- *Introduced in version 1* .. http:GET:: /api/v2/stores/(?P[\\w_-]+)/users .. http:POST:: /api/v2/stores/(?P[\\w_-]+)/users Add, remove or edit users' roles. :reqheader Authorization: macaroon authorization header for a store admin :status 200: success :status 400: error :status 401: authentication required :status 404: store id does not exist or user does not have enough permission to see it Usage _____ As mentioned in the introduction, this endpoint can be exercised using the ``surl`` command as follows: GET: ``surl -p store_admin -s production -e your-email@example.com https://dashboard.snapcraft.io/api/v2/stores/the-store-id/users`` POST: ``surl -p store_admin -s production -e your-email@example.com -X POST -d '[{"email": "some-email@example.com", "roles": ["view", "access"]}]' https://dashboard.snapcraft.io/api/v2/stores/the-store-id/users`` where ``your-email@example.com`` has to be an existing account with permission to manage the store with ID ``the-store-id``. If the authenticating macaroon has any ``store_ids`` attenuation, the store ``the-store-id`` has to be among the allowed stores in that constraint (see the ``--allowed-store`` option in surl as a way to get a macaroon with such attenuation). Examples ________ .. include:: ../../examples/requests/store_users Errors ______ .. include:: ../../examples/requests/store_users_errors Changelog _________ * Version 31: Added extra field to store info dict: "brand-id". * Version 28: Added extra field to store info dict: parent. * Version 20: Add GET support to store users endpoint. * Version 17: Added extra fields to store info dict: private, manual-review-policy * Version 3: Added extra field to store info dict: snap-name-prefixes. * Version 2: Added extra fields to store info dict: allowed-inclusion-source-stores and allowed-inclusion-target-stores. Request JSON Schema ___________________ .. code-block:: json { "introduced_at": 1, "items": { "properties": { "email": { "description": "The primary email for the Ubuntu One account.", "format": "email", "title": "Email address", "type": "string" }, "id": { "description": "Used to disambiguate if there are multiple users for the given email.", "title": "Account ID (optional)", "type": "string" }, "roles": { "items": { "type": "string" }, "type": "array" } }, "type": "object" }, "type": "array" } Response JSON Schema ____________________ .. code-block:: json { "additionalProperties": false, "properties": { "invites": { "introduced_at": 5, "items": { "additionalProperties": false, "properties": { "email": { "description": "The invited email", "type": "string" }, "expiration-date": { "description": "The date when this invite expires, in ISO 8601 format.", "format": "date-time", "type": "string" }, "roles": { "description": "The roles that this invite's email was invited to join with.", "items": { "type": "string" }, "type": "array" }, "status": { "description": "The status of the invite, can be one of Pending, Accepted, Revoked or Expired.", "enum": [ "Pending", "Revoked", "Expired" ], "type": "string" } }, "required": [ "email", "expiration-date", "roles", "status" ], "type": "object" }, "type": "array" }, "store": { "additionalProperties": false, "properties": { "allowed-inclusion-source-stores": { "description": "The list of store IDs that this store can select snaps from to include in this store.", "introduced_at": 2, "items": { "type": "string" }, "type": "array" }, "allowed-inclusion-target-stores": { "description": "The list of store IDs that can select snaps from this store to include in their stores.", "introduced_at": 2, "items": { "type": "string" }, "type": "array" }, "brand-id": { "description": "The store brand ID or null.", "type": [ "string", "null" ] }, "id": { "description": "The store ID (slug).", "type": "string" }, "manual-review-policy": { "description": "The review policy for the store (one of: \"allow\", \"avoid\", or \"require\").", "enum": [ "allow", "avoid", "require" ], "introduced_at": 17, "type": "string" }, "name": { "description": "Visible name of this store.", "type": "string" }, "parent": { "description": "The store parent's ID (slug).", "type": [ "null", "string" ] }, "private": { "description": "Indicate whether this store will be visible in public lists", "introduced_at": 17, "type": "boolean" }, "roles": { "description": "The list of available roles in this store.", "items": { "type": "string" }, "type": "array" }, "snap-name-prefixes": { "additionalProperties": false, "introduced_at": 3, "properties": { "inheritable": { "description": "Whether this snap name prefix can be used by child stores or not (default is False).", "type": "boolean" }, "parent-id": { "description": "None if this snap name prefix was defined for the requesting store, else the store ID from which this prefix is being inherited.", "type": [ "string", "null" ] }, "prefix": { "description": "The snap name prefix.", "type": "string" } }, "required": [ "prefix", "inheritable", "parent-id" ], "type": "object" }, "store-whitelist": { "description": "The list of store IDs that this store includes.", "items": { "type": "string" }, "type": "array" } }, "required": [ "id", "brand-id", "name", "roles", "store-whitelist", "snap-name-prefixes", "allowed-inclusion-source-stores", "allowed-inclusion-target-stores" ], "type": "object" }, "users": { "introduced_at": 1, "items": { "additionalProperties": false, "properties": { "displayname": { "description": "The full name", "type": "string" }, "email": { "description": "The email", "type": "string" }, "id": { "description": "The account ID", "type": "string" }, "roles": { "description": "The roles that this user has in this store", "items": { "type": "string" }, "type": "array" }, "username": { "description": "The store username", "type": "string" } }, "required": [ "id", "displayname ", "email", "username", "roles" ], "type": "object" }, "type": "array" } }, "required": [ "store", "users", "invites" ], "type": "object" } .. _api-store-feeds: Fetch store daily releases feeds ------------------------------------------------------------------- *Introduced in version 1* .. http:GET:: /api/v2/stores/(?P[\\w_-]+)/feeds/(?P[\\w\\.-]+) Fetch store daily releases feeds. The daily releases feed provides a chronological view of the changes (releasing or closing channels) in all snaps included in the context store. Events refer to snaps uploaded directly to the context store (local), from allowlisted stores (inherited), specifically selected from related stores (included) and the ones available by default on every store (essential). The release feed format complies with the `JsonFeed`_ specification and store-specific information is provided within the ``_snap_store`` extension. .. _JsonFeed: https://jsonfeed.org/version/1 :reqheader Authorization: macaroon authorization header for a store admin :status 200: success :status 400: malformed or unsupported feed name. :status 401: authentication required :status 404: store id or feed do not exist or user does not have enough permission to see it :status 501: daily-store-feeds feature globaly or locally disabled Usage _____ As mentioned in earlier in this documention, this endpoint can be exercised using the ``surl`` command as follows: ``surl -s production -e your-email@example.com https://dashboard.snapcraft.io/api/v2/stores/the-store-id/feeds/2018-09-01.json`` where ``your-email@example.com`` has to be an existing account with permission to view the store with ID ``the-store-id``. Example _______ .. include:: ../../examples/requests/store_feeds Errors ______ .. include:: ../../examples/requests/store_feeds_errors Response JSON Schema ____________________ .. code-block:: json { "additionalProperties": false, "properties": { "feed_url": { "type": "string" }, "home_page_url": { "type": "string" }, "items": { "items": { "additionalProperties": false, "properties": { "_snap_store": { "additionalProperties": false, "properties": { "architecture": { "type": "string" }, "channel": { "additionalProperties": false, "properties": { "branch": { "type": [ "string", "null" ] }, "risk": { "type": [ "string", "null" ] }, "track": { "type": [ "string", "null" ] } }, "required": [ "track", "risk", "branch" ], "type": "object" }, "event-type": { "enum": [ "release" ], "type": "string" }, "snap-name": { "type": "string" }, "snap-revision": { "additionalProperties": false, "properties": { "build-url": { "type": [ "string", "null" ] }, "revision": { "type": "number" }, "version": { "type": "string" } }, "required": [ "revision", "version", "build_url" ], "type": [ "object", "null" ] } }, "required": [ "snap-name", "snap-revision", "architecture", "channel", "event_type" ], "type": "object" }, "author": { "additionalProperties": false, "properties": { "name": { "type": "string" } }, "required": [ "name" ], "type": "object" }, "date_published": { "format": "date-time", "type": "string" }, "id": { "type": "string" }, "title": { "type": "string" } }, "required": [ "id", "title", "date_published", "author", "_snap_store" ], "type": "object" }, "minItems": 0, "type": "array" }, "next_url": { "type": "string" }, "title": { "type": "string" }, "version": { "type": "string" } }, "required": [ "version", "title", "home_page_url", "feed_url", "next_url", "items" ], "type": "object" } .. _api-store-invites: Manage store invitations ------------------------------------------------------------------- *Introduced in version 7* .. http:POST:: /api/v2/stores/(?P[\\w_-]+)/invites .. http:PUT:: /api/v2/stores/(?P[\\w_-]+)/invites Manage store invitations. :reqheader Authorization: macaroon authorization header for a store admin :status 200: success :status 400: error :status 401: authentication required :status 404: store id does not exist or user does not have enough permission to see it Usage _____ As mentioned in the introduction, this endpoint can be exercised using the ``surl`` command as follows: Create Invites (POST): ``surl -p store_admin -s production -e your-email@example.com -X POST -d '[{"email": "some-email@example.com", "roles": ["view", "access"]}]' https://dashboard.snapcraft.io/api/v2/stores/the-store-id/invites`` Modify Invites (PUT): ``surl -p store_admin -s production -e your-email@example.com -X PUT -d '[{"email": "some-email@example.com", "action": "revoke"}, {"email": "another-email@example.com", "action": "resend"}]' https://dashboard.snapcraft.io/api/v2/stores/the-store-id/invites`` where ``your-email@example.com`` has to be an existing account with permission to manage the store with ID ``the-store-id``. If the authenticating macaroon has any ``store_ids`` attenuation, the store ``the-store-id`` has to be among the allowed stores in that constraint (see the ``--allowed-store`` option in surl as a way to get a macaroon with such attenuation). Changelog _________ * Version 31: Added extra field to store info dict: "brand-id". * Version 28: Added extra field to store info dict: parent. * Version 19: Update store invites endpoint to allow modifications to existing invites. * Version 17: Added extra fields to store info dict: private, manual-review-policy * Version 7: New API endpoint to create store invites. Request JSON Schema ___________________ .. code-block:: json { "description": "For POST, the request should contain a list of emails with their roles to invite to the store. For PUT, the request should contain a list of emails with the actions to take.", "minItems": 1, "oneOf": [ { "description": "List of emails with their roles to invite to the store.", "items": { "additionalProperties": false, "properties": { "email": { "description": "Email to send the invitation to for joining the store.", "type": "string" }, "roles": { "description": "List of roles to assign to the user once the invitation is accepted.", "items": { "type": "string" }, "type": "array" } }, "required": [ "email", "roles" ], "type": "object" }, "type": "array" }, { "description": "List of invited emails with actions to perform.", "introduced_at": 19, "items": { "additionalProperties": false, "properties": { "action": { "description": "Action to apply to the given email.", "enum": [ "open", "resend", "revoke" ], "type": "string" }, "email": { "description": "Email to send the invitation to for joining the store.", "type": "string" } }, "required": [ "email", "action" ], "type": "object" }, "minItems": 1, "type": "array" } ] } Response JSON Schema ____________________ .. code-block:: json { "additionalProperties": false, "properties": { "invites": { "introduced_at": 5, "items": { "additionalProperties": false, "properties": { "email": { "description": "The invited email", "type": "string" }, "expiration-date": { "description": "The date when this invite expires, in ISO 8601 format.", "format": "date-time", "type": "string" }, "roles": { "description": "The roles that this invite's email was invited to join with.", "items": { "type": "string" }, "type": "array" }, "status": { "description": "The status of the invite, can be one of Pending, Accepted, Revoked or Expired.", "enum": [ "Pending", "Revoked", "Expired" ], "type": "string" } }, "required": [ "email", "expiration-date", "roles", "status" ], "type": "object" }, "type": "array" }, "store": { "additionalProperties": false, "properties": { "allowed-inclusion-source-stores": { "description": "The list of store IDs that this store can select snaps from to include in this store.", "introduced_at": 2, "items": { "type": "string" }, "type": "array" }, "allowed-inclusion-target-stores": { "description": "The list of store IDs that can select snaps from this store to include in their stores.", "introduced_at": 2, "items": { "type": "string" }, "type": "array" }, "brand-id": { "description": "The store brand ID or null.", "type": [ "string", "null" ] }, "id": { "description": "The store ID (slug).", "type": "string" }, "manual-review-policy": { "description": "The review policy for the store (one of: \"allow\", \"avoid\", or \"require\").", "enum": [ "allow", "avoid", "require" ], "introduced_at": 17, "type": "string" }, "name": { "description": "Visible name of this store.", "type": "string" }, "parent": { "description": "The store parent's ID (slug).", "type": [ "null", "string" ] }, "private": { "description": "Indicate whether this store will be visible in public lists", "introduced_at": 17, "type": "boolean" }, "roles": { "description": "The list of available roles in this store.", "items": { "type": "string" }, "type": "array" }, "snap-name-prefixes": { "additionalProperties": false, "introduced_at": 3, "properties": { "inheritable": { "description": "Whether this snap name prefix can be used by child stores or not (default is False).", "type": "boolean" }, "parent-id": { "description": "None if this snap name prefix was defined for the requesting store, else the store ID from which this prefix is being inherited.", "type": [ "string", "null" ] }, "prefix": { "description": "The snap name prefix.", "type": "string" } }, "required": [ "prefix", "inheritable", "parent-id" ], "type": "object" }, "store-whitelist": { "description": "The list of store IDs that this store includes.", "items": { "type": "string" }, "type": "array" } }, "required": [ "id", "brand-id", "name", "roles", "store-whitelist", "snap-name-prefixes", "allowed-inclusion-source-stores", "allowed-inclusion-target-stores" ], "type": "object" }, "users": { "introduced_at": 1, "items": { "additionalProperties": false, "properties": { "displayname": { "description": "The full name", "type": "string" }, "email": { "description": "The email", "type": "string" }, "id": { "description": "The account ID", "type": "string" }, "roles": { "description": "The roles that this user has in this store", "items": { "type": "string" }, "type": "array" }, "username": { "description": "The store username", "type": "string" } }, "required": [ "id", "displayname ", "email", "username", "roles" ], "type": "object" }, "type": "array" } }, "required": [ "store", "users", "invites" ], "type": "object" } .. _api-store-metrics-models: Request store metrics ------------------------------------------------------------------- *Introduced in version 15* .. http:POST:: /api/v2/stores/(?P[\\w_-]+)/metrics/models Request store metrics. :reqheader Authorization: macaroon authorization header for a store admin :status 200: success :status 400: error :status 401: authentication required :status 404: store id does not exist or user does not have enough permission to see it Usage _____ As mentioned in the introduction, this endpoint can be exercised using the ``surl`` command as follows: Request store metrics (POST): ``surl -p store_admin -s production -e your-email@example.com -X POST -d '{"filters":{"month":9 ,"year":2021}}' https://dashboard.snapcraft.io/api/v2/stores/the-store-id/metrics/models`` where ``your-email@example.com`` has to be an existing account with permission to manage the store with ID ``the-store-id``. If the authenticating macaroon has any ``store_ids`` attenuation, the store ``the-store-id`` has to be among the allowed stores in that constraint (see the ``--allowed-store`` option in ``surl`` as a way to get a macaroon with such attenuation). Changelog _________ * Version 29: Added extra field to store metrics: "device-ids". * Version 15: New API endpoint to fetch store metrics. Request JSON Schema ___________________ .. code-block:: json { "additionalProperties": false, "properties": { "filters": { "additionalProperties": false, "properties": { "month": { "maximum": 12, "minimum": 1, "type": "integer" }, "year": { "minimum": 2020, "type": "integer" } }, "required": [ "month", "year" ], "type": "object" } }, "type": "object" } Response JSON Schema ____________________ .. code-block:: json { "items": { "additionalProperties": false, "properties": { "brand-id": { "type": "string" }, "brand-username": { "type": "string" }, "count": { "type": "number" }, "device-brand": { "type": "string" }, "device-ids": { "items": { "type": "string" }, "type": "array" }, "device-model": { "type": "string" }, "store": { "type": "string" } }, "required": [ "brand-id", "brand-username", "count", "device-brand", "device-model", "store" ], "type": "object" }, "type": "array" } .. _api-store-settings: Change store settings ------------------------------------------------------------------- *Introduced in version 18* .. http:PUT:: /api/v2/stores/(?P[\\w_-]+)/settings Edit Store settings. :reqheader Authorization: macaroon authorization header for a store admin :status 200: success :status 400: error :status 401: authentication required :status 404: store id does not exist or user does not have enough permission to see it Usage _____ As mentioned in the introduction, this endpoint can be exercised using the ``surl`` command as follows: ``surl -p store_admin -s production -e your-email@example.com -X PUT -d '{"manual-review-policy": "allow", "private": true}' https://dashboard.snapcraft.io/api/v2/stores/the-store-id/settings`` where ``your-email@example.com`` has to be an existing account with permission to manage the store with ID ``the-store-id``. If the authenticating macaroon has any ``store_ids`` attenuation, the store ``the-store-id`` has to be among the allowed stores in that constraint (see the ``--allowed-store`` option in surl as a way to get a macaroon with such attenuation). Changelog _________ * Version 31: Added extra field to store info dict: "brand-id". * Version 28: Added extra field to store info dict: parent. * Version 18: New API endpoint to edit store settings. Request JSON Schema ___________________ .. code-block:: json { "additionalProperties": false, "introduced_at": 18, "properties": { "manual-review-policy": { "description": "The review policy for the store (one of: \"allow\", \"avoid\", or \"require\").", "enum": [ "allow", "avoid", "require" ], "type": "string" }, "private": { "description": "Indicate whether this store will be visible in public lists", "type": "boolean" } }, "required": [ "manual-review-policy", "private" ], "type": "object" } Response JSON Schema ____________________ .. code-block:: json { "additionalProperties": false, "properties": { "invites": { "introduced_at": 5, "items": { "additionalProperties": false, "properties": { "email": { "description": "The invited email", "type": "string" }, "expiration-date": { "description": "The date when this invite expires, in ISO 8601 format.", "format": "date-time", "type": "string" }, "roles": { "description": "The roles that this invite's email was invited to join with.", "items": { "type": "string" }, "type": "array" }, "status": { "description": "The status of the invite, can be one of Pending, Accepted, Revoked or Expired.", "enum": [ "Pending", "Revoked", "Expired" ], "type": "string" } }, "required": [ "email", "expiration-date", "roles", "status" ], "type": "object" }, "type": "array" }, "store": { "additionalProperties": false, "properties": { "allowed-inclusion-source-stores": { "description": "The list of store IDs that this store can select snaps from to include in this store.", "introduced_at": 2, "items": { "type": "string" }, "type": "array" }, "allowed-inclusion-target-stores": { "description": "The list of store IDs that can select snaps from this store to include in their stores.", "introduced_at": 2, "items": { "type": "string" }, "type": "array" }, "brand-id": { "description": "The store brand ID or null.", "type": [ "string", "null" ] }, "id": { "description": "The store ID (slug).", "type": "string" }, "manual-review-policy": { "description": "The review policy for the store (one of: \"allow\", \"avoid\", or \"require\").", "enum": [ "allow", "avoid", "require" ], "introduced_at": 17, "type": "string" }, "name": { "description": "Visible name of this store.", "type": "string" }, "parent": { "description": "The store parent's ID (slug).", "type": [ "null", "string" ] }, "private": { "description": "Indicate whether this store will be visible in public lists", "introduced_at": 17, "type": "boolean" }, "roles": { "description": "The list of available roles in this store.", "items": { "type": "string" }, "type": "array" }, "snap-name-prefixes": { "additionalProperties": false, "introduced_at": 3, "properties": { "inheritable": { "description": "Whether this snap name prefix can be used by child stores or not (default is False).", "type": "boolean" }, "parent-id": { "description": "None if this snap name prefix was defined for the requesting store, else the store ID from which this prefix is being inherited.", "type": [ "string", "null" ] }, "prefix": { "description": "The snap name prefix.", "type": "string" } }, "required": [ "prefix", "inheritable", "parent-id" ], "type": "object" }, "store-whitelist": { "description": "The list of store IDs that this store includes.", "items": { "type": "string" }, "type": "array" } }, "required": [ "id", "brand-id", "name", "roles", "store-whitelist", "snap-name-prefixes", "allowed-inclusion-source-stores", "allowed-inclusion-target-stores" ], "type": "object" }, "users": { "introduced_at": 1, "items": { "additionalProperties": false, "properties": { "displayname": { "description": "The full name", "type": "string" }, "email": { "description": "The email", "type": "string" }, "id": { "description": "The account ID", "type": "string" }, "roles": { "description": "The roles that this user has in this store", "items": { "type": "string" }, "type": "array" }, "username": { "description": "The store username", "type": "string" } }, "required": [ "id", "displayname ", "email", "username", "roles" ], "type": "object" }, "type": "array" } }, "required": [ "store", "users", "invites" ], "type": "object" }