.. _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"
}