Snap Packages

Introduction

The Snap Packages API provides a series of endpoints supporting common actions during the lifetime of a snap package.

The Snap Packages API is exposed at the following base URLs:

Response Format

JSON will be returned in all responses from the API, including errors.

Reference

Register a package name

POST /dev/api/register-name/
Request Headers:
 
Query Parameters:
 
  • dry_run – (optional) when set, validate the name but don’t register it
Request JSON Object:
 
  • snap_name (string) – name of the snap package
  • is_private (boolean) – (optional, defaults to false) whether the name should be considered private
  • store (string) – (optional, defaults to the global store) the ID of the store to register this snap in
Response JSON Object:
 
  • snap_id (string) – the unique snap_id associated with this package (null when dry_run query parameter is set)
Status Codes:

Important

In order to register a snap name the request’s authentication macaroon needs to include the package_register permission. Refer to the Macaroons for information on how to request a macaroon with the right permissions.

Important

Requesting already registered or reserved names (disputing) is only supported in the Web.

Note

The is_private parameter is used to indicate the privacy setting for the initial push. This setting can be changed at any later time via the web ui.

The dry_run query parameter is used to test if the name is valid and currently available. It does not register the name, so the name may not be available later.

Usage

Before pushing a snap package, the developer needs to register the package name.

Request:

POST /dev/api/register-name/ HTTP/1.1
Host: dashboard.snapcraft.io
Authorization: Macaroon root=..., discharge=...
Content-Type: application/json

{
  "snap_name": "foo"
}

Response:

HTTP/1.1 201 CREATED
Content-Type: application/json

{
  "snap_id": "some-snap-id"
}

The developer can state whether the package is going to be marked as private on first upload by setting the is_private field to true.

Request:

POST /dev/api/register-name/ HTTP/1.1
Host: dashboard.snapcraft.io
Authorization: Macaroon root=..., discharge=...
Content-Type: application/json

{
  "is_private": true,
  "snap_name": "foo"
}

Response:

HTTP/1.1 201 CREATED
Content-Type: application/json

{
  "snap_id": "some-snap-id"
}

It’s possible to just trigger validation for a name without actually registering it by setting dry_run as a query parameter.

Request:

POST /dev/api/register-name/?dry_run=1 HTTP/1.1
Host: dashboard.snapcraft.io
Authorization: Macaroon root=..., discharge=...
Content-Type: application/json

{
  "snap_name": "foo"
}

Response:

HTTP/1.1 200 OK
Content-Type: application/json

{
  "snap_id": null
}

If the macaroon used for authentication does not contain the package_register permission an error response will be returned.

Response:

HTTP/1.1 403 FORBIDDEN
Content-Type: application/json

{
  "type": "devportal:v1:macaroon-permission-required",
  "title": "Macaroon missing required permission.",
  "detail": "Permission is required: package_register",
  "status": 403,
  "permission": "package_register",
  "error_list": [{
    "message": "Permission is required: package_register",
    "code": "macaroon-permission-required"
  }]
}

The developer needs to sign the Developer Programme Agreement before pushing snap packages. Failing to do so will result in an error response

Response:

HTTP/1.1 403 FORBIDDEN
Content-Type: application/json

{
  "error_list": [
    {
      "message": "Developer has not signed agreement.",
      "code": "user-not-ready",
      "extra": {
        "url": "https://dashboard.snapcraft.io/dev/agreements/new/",
        "api": "https://dashboard.snapcraft.io/dev/api/agreement/"
      }
    }
  ],
  "errors": "Developer has not signed agreement.",
  "success": false
}

The developer must have a short namespace before pushing snap packages. Failing to do so will result in an error response

Response:

HTTP/1.1 403 FORBIDDEN
Content-Type: application/json

{
  "error_list": [
    {
      "message": "Developer profile is missing short namespace.",
      "code": "user-not-ready",
      "extra": {
        "url": "https://dashboard.snapcraft.io/dev/account/"
      }
    }
  ],
  "errors": "Developer profile is missing short namespace.",
  "success": false
}

In the event that the request contained invalid data, an error response will be returned detailing the problem(s). Each of them containing at least a code, a human readable reason and the name of the field that’s causing the error. Here’s an example response for errors triggered in the snap_name.

Response:

HTTP/1.1 400 BAD REQUEST
Content-Type: application/json

{
  "type": "devportal:v1:request-invalid",
  "title": "Invalid request.",
  "detail": "Submitted data is not valid.",
  "status": 400,
  "invalid_params": [{
    "code": "invalid",
    "name": "snap_name",
    "reason": "The name 'some name' is not valid: it should only have ASCII lowercase letters, numbers, and hyphens, and must have at least one letter."
  }],
  "error_list": [{
    "message": "The name 'some name' is not valid: it should only have ASCII lowercase letters, numbers, and hyphens, and must have at least one letter.",
    "code": "invalid",
    "extra": {"name": "snap_name"}
  }]
}

In the event that the requested name is already registered by another publisher, the error response will contain extra metadata such as the suggested_snap_name and register_name_url.

Response:

HTTP/1.1 409 CONFLICT
Content-Type: application/json

{
  "type": "devportal:v1:name-already-registered",
  "title": "Name already registered.",
  "detail": "'some-name' is already registered.",
  "status": 409,
  "code": "already_registered",
  "register_name_url": "https://dashboard.snapcraft.io/register-name/",
  "suggested_snap_name": "namespace-some-name",
  "error_list": [{
    "message": "'some-name' is already registered.",
    "code": "already_registered"
  }]
}

Unless it’s an already claimed name which is waiting for review, either because it was a reserved name or already registered by someone else in which case the response would be:

Response:

HTTP/1.1 409 CONFLICT
Content-Type: application/json

{
  "type": "devportal:v1:name-already-claimed",
  "title": "",
  "detail": "You already registered a claim for 'some-name'.",
  "status": 409,
  "code": "already_claimed",
  "error_list": [{
    "message": "You already registered a claim for 'some-name'.",
    "code": "already_claimed"
  }]
}

Or it’s an already owned name, with the following response:

Response:

HTTP/1.1 409 CONFLICT
Content-Type: application/json

{
  "type": "devportal:v1:name-already-owned",
  "title": "",
  "detail": "You already own 'some-name'.",
  "status": 409,
  "code": "already_owned",
  "error_list": [{
    "message": "You already own 'some-name'.",
    "code": "already_owned"
  }]
}

Or the name was previsously owned but then revoked by a Store reviewer, with the following response:

Response:

HTTP/1.1 409 CONFLICT
Content-Type: application/json

{
  "type": "devportal:v1:name-revoked",
  "title": "",
  "detail": "You previously owned 'some-name' but it was revoked.",
  "status": 409,
  "code": "revoked_name",
  "error_list": [{
    "message": "You previously owned 'some-name' but it was revoked.",
    "code": "revoked_name"
  }]
}

In the event that the requested name is a reserved name, the error response will contain extra metadata such as the suggested_snap_name and register_name_url.

Response:

HTTP/1.1 409 CONFLICT
Content-Type: application/json

{
  "type": "devportal:v1:name-reserved",
  "title": "Name is reserved.",
  "detail": "'some-name' is a reserved name.",
  "status": 409,
  "code": "reserved_name",
  "register_name_url": "https://dashboard.snapcraft.io/register-name/",
  "suggested_snap_name": "namespace-some-name",
  "error_list": [{
    "message": "'some-name' is a reserved name.",
    "code": "reserved_name"
  }]
}

If names are tried to be registered too quickly, the following error would be returned with the retry_after field (also reflected in the Retry-After response header) containing the amount of time to wait in seconds before the next attempt:

Response:

HTTP/1.1 429 Too Many Requests
Content-Type: application/json
Retry-After: 59

{
  "status": 429,
  "code": "register_window",
  "title": "You must wait before next name registration.",
  "detail": "You can register up to 10 names every 10\u00a0minutes. You must wait 7\u00a0minutes before the next snap-name registration.",
  "type": "devportal:v1:name-window-wait",
  "retry_after": 399,
  "error_list": [{
    "message": "You can register up to 10 names every 10\u00a0minutes. You must wait 7\u00a0minutes before the next snap-name registration.",
    "code": "register_window"
  }]
}

In some cases the submitted data is valid, but the request might fail to complete. In such cases a response like the following will be returned

Response:

HTTP/1.1 503 SERVICE UNAVAILABLE
Content-Type: application/json

{
  "status": 503,
  "code": "failed-to-register",
  "title": "Invalid request.",
  "detail": "Failed to register",
  "error_list": [
    {
      "message": "Failed to register",
      "code": "failed-to-register"
    }
  ],
  "type": "devportal:v1:request-invalid"
}

Assert a build for a snap

Process and store a snap-build assertion. Currently snap-build is not enforced before publishing an upload.

POST /dev/api/snaps/(snap_id)/builds
Request Headers:
 
Parameters:
  • snap_id – the snap_id of the package
Request JSON Object:
 
  • assertion (string) – UTF-8 signed assertion blob
Response JSON Object:
 
  • success (boolean) – whether the build assertion was saved successfully
Status Codes:

Usage

To submit a build assertion of their package, a developer posts a request like the following:

Request:

POST /dev/api/snaps/some_snap_id/builds HTTP/1.1
Host: dashboard.snapcraft.io
Authorization: Macaroon root=..., discharge=...
Content-Type: application/json

{
  "assertion": "utf-8 signed assertion blob"
}

Note

The assertion blob is simply the snap-build assert data as assembled and signed by developers.

Response:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
   "headers": {
       "authority-id": "",
       "grade": "",
       "sign-key-sha3-384": "",
       "snap-id": "",
       "snap-sha3-384": "",
       "snap-size": "",
       "timestamp": "",
       "revision": "",
       "type": "snap-build"
   }
 }

If the macaroon used for authentication does not contain the package_upload permission or is restricted to a set of snap packages that doesn’t include this package, an error response will be returned

Response:

HTTP/1.1 403 FORBIDDEN
Content-Type: application/problem+json

{
  "type": "devportal:v1:macaroon-permission-required",
  "title": "Macaroon missing required permission.",
  "detail": "Permission is required: package_upload",
  "status": 403,
  "permission": "package_upload"
}

The developer needs to sign the Developer Programme Agreement before they can assert builds. Failing to do so will result in an error response

Response:

HTTP/1.1 403 FORBIDDEN
Content-Type: text/plain

Developer has not signed agreement.

The developer needs to have defined their namespace in their user profile before they can assert builds. Failing to do so will result in an error response

Response:

HTTP/1.1 403 FORBIDDEN
Content-Type: text/plain

Developer profile is missing short namespace.

In the event that the request is missing fields, an error response will be returned detailing the problem

Response:

HTTP/1.1 400 BAD REQUEST
Content-Type: application/json

{
  "success": false,
  "errors": [{"name": ["This field is required."]}]
}

If the content of assertion has any invalid information, an error response will be returned

Response:

HTTP/1.1 400 BAD REQUEST
Content-Type: application/json

{
  "success": false,
  "errors": [{"name": ["Not a valid snap-build assertion."]}]
}

Push a snap build to the Store

POST /dev/api/snap-push/
Request Headers:
 
Request JSON Object:
 
  • name (string) – name of the snap package
  • updown_id (string) – updown_id obtained when uploading the build binary
Response JSON Object:
 
  • success (boolean) – true if the request was acknowledged properly
  • status_url (string) – (deprecated) URL to poll for status changes (for old-style processing)
  • status_details_url (string) – URL to poll for current server side status changes
Status Codes:

Important

In order to push a snap the request’s authentication macaroon needs to include the package_upload permission. Refer to the Macaroons for information on how to request a macaroon with the right permissions.

Usage

To submit a new version of their snap package, a developer pushes it to the Store

Request:

POST /dev/api/snap-push/ HTTP/1.1
Host: dashboard.snapcraft.io
Content-Type: application/json

{
  "name": "foo",
  "updown_id": "some-updown-id"
}

Response:

HTTP/1.1 202 ACCEPTED
Content-Type: application/json; charset=utf-8

{
  "success": true,
  "status_url": "https://dashboard.snapcraft.io/<some upload id>"
}

Note

Receiving a 202 response means the Store has acknowledged the submission and will proceed to analyze the snap package for errors before it’s fully accepted.

If the macaroon used for authentication does not contain the package_upload permission or is restricted to a set of snap packages that doesn’t include this package, an error response will be returned

Response:

HTTP/1.1 403 FORBIDDEN
Content-Type: application/problem+json

{
  "type": "devportal:v1:macaroon-permission-required",
  "title": "Macaroon missing required permission.",
  "detail": "Permission is required: package_upload",
  "status": 403,
  "permission": "package_upload"
}

If a push is attempted for a package that has not had its name registered beforehand, an error like this will be returned

Response:

HTTP/1.1 404 NOT FOUND

The developer needs to sign the Developer Programme Agreement before they can push snap packages. Failing to do so will result in an error response

Response:

HTTP/1.1 403 FORBIDDEN
Content-Type: text/plain

Developer has not signed agreement.

The developer needs to have defined their namespace in their user profile before they can push snap packages. Failing to do so will result in an error response

Response:

HTTP/1.1 403 FORBIDDEN
Content-Type: text/plain

Developer profile is missing short namespace.

In the event that the request contained invalid data, an error response will be returned detailing the problem

Response:

HTTP/1.1 400 BAD REQUEST
Content-Type: application/json

{
  "success": false,
  "errors": [{"name": ["This field is required."]}]
}

Release a snap build to a channel

POST /dev/api/snap-release/
Request Headers:
 
Request JSON Object:
 
  • name (string) – name of the snap package
  • revision (int) – revision to release
  • channels (list) – list of channels to release the build to; these will be added to whatever current channels the build is already released (if any)
Response JSON Object:
 
  • success (boolean) – whether the build was released successfully
  • channel_map (list) – (optional) a list of all the channels and which versions/revisions are released on each (see below for further info)
  • opened_channels (list) – (optional) names of the channels that got their first release on the current call
Status Codes:

Important

In order to release a snap the request’s authentication macaroon needs to include the package_upload permission. Refer to the Macaroons for information on how to request a macaroon with the right permissions.

About channel_map

If present, this field will be a list of channel names with more information for each. The list is ordered according to the channel priority hierarchy (e.g.: stable, candidate, beta, edge).

Every item in the list is a dict, with at least channel and info in it. There are three kind of items.

  • when the channel doesn’t have any release:

    {'channel': 'stable', 'info': 'none'}
    
  • when the channel has a release:

    {'channel': 'candidate', 'info': 'specific', 'version': '2.7', 'revision': 1}
    
  • when the channel doesn’t have any release, but as a superior channel does, it would use that revision if requested:

    {'channel': 'beta', 'info': 'tracking'}
    

Usage

When a developer is ready to make their snap package available to the world, they can release it like

Request:

POST /dev/api/snap-release/ HTTP/1.1
Host: dashboard.snapcraft.io
Content-Type: application/json

{
  "name": "foo",
  "revision": "1",
  "channels": ["stable"]
}

Response:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "success": true
  "channel_map": [
     {"info": "none", "channel": "stable"},
     {"info": "specific", "version": "2.7", "channel": "candidate", "revision": 1},
     {"info": "tracking", "channel": "beta"},
     {"info": "tracking", "channel": "edge"}
  ],
  "opened_channels": ["candidate"],
}

If the macaroon used for authentication does not contain the package_upload permission or is restricted to a set of snap packages that doesn’t include this package, an error response will be returned

Response:

HTTP/1.1 403 FORBIDDEN
Content-Type: application/problem+json

{
  "type": "devportal:v1:macaroon-permission-required",
  "title": "Macaroon missing required permission.",
  "detail": "Permission is required: package_upload",
  "status": 403,
  "permission": "package_upload"
}

If a release is requested for a package that has not had its name registered beforehand, an error like this will be returned

Response:

HTTP/1.1 404 NOT FOUND

The developer needs to sign the Developer Programme Agreement before they can release snap packages. Failing to do so will result in an error response

Response:

HTTP/1.1 403 FORBIDDEN
Content-Type: text/plain

Developer has not signed agreement.

The developer needs to have defined their namespace in their user profile before they can release snap packages. Failing to do so will result in an error response

Response:

HTTP/1.1 403 FORBIDDEN
Content-Type: text/plain

Developer profile is missing short namespace.

In the event that the request contained invalid data, an error response will be returned detailing the problem

Response:

HTTP/1.1 400 BAD REQUEST
Content-Type: application/json

{
  "success": false,
  "errors": [
    {"name": ["This field is required."]}
  ]
}

In some cases the submitted data is valid, but the request might fail to complete. In such cases a response like the following will be returned

Response:

HTTP/1.1 503 SERVICE UNAVAILABLE
Content-Type: application/json

"Failed to publish"

Obtaining information about a snap

This API endpoint allows publishers or collaborators to obtain an overview-set of information about their snaps by simply passing its`name`.

This endpoint is intended to be an quicker alternative to the current process of resolving name to snap_id via the Accounts response, then hit the metadata endpoint for textual fields and the binary-metadata for associated icon and screenshots. This endpoint allows clients to get all they need in a single request.

GET /dev/api/snaps/info/(name)
Request Headers:
 
Response JSON Object:
 
  • snap_id – unique snap identifier
  • snap_name – name of the snap
  • series – series where this snap is available
  • store – store the snap was registered to
  • publisher – snap publisher reference object, see more details in About publisher
  • status – whether the snap is currently available in any channel (‘published’ or ‘unpublished’)
  • channel_maps_list – map of {arch: channel_map} where this snap is currently released, see more details in About channel_map
  • aliases – remote aliases granted to this snap
  • private – whether this is snap is private or not
  • title – single-line text displayed as title in the snap page
  • summary – single-line summary
  • description – multi-line description
  • keywords – list of proposed keywords to facilitate search
  • license – SPDX 1.1 license expression for this snaps
  • media – list of images associated with this snap, see more details in About media
  • price – current price of this snap in USD (as float)
  • contact – upstream project contact URL
  • website – upstream project website URL
  • blacklist_countries – list of country codes (ISO ALPHA-2) in which the snap distribution is forbidden
  • whitelist_countries – list of country codes (ISO ALPHA-2) in which the snap is exclusively allowed to be distributed
  • video_urls – list of third-part video URLs associated for this snap
  • public_metrics_enabled – whether public metrics are enabled for this snap or not
  • public_metrics_blacklist – list of public metric names not available for consumption
  • categories – categories list for the snap, (see Snap categories for more details)
  • originDEPRECATED use publisher["username"]
  • publisher_nameDEPRECATED use publisher["display-name"]
  • company_nameDEPRECATED it is not part of any workflow and will be soon removed.
  • icon_urlDEPRECATED use media
  • screenshot_urlsDEPRECATED use media
Status Codes:

Important

In order to fetch snap metrics the request’s authentication macaroon needs to include the package_access permission. See Macaroons for information on how to request a macaroon with the right permissions.

About publisher

A reference to a snap publisher is a canonical object across the entire API as:

{
  "id": "ap8oZPhPCkgEZAGTyU7lRCR0NtNeMyRh",
  "username": "cprov",
  "display-name": "Celso Providelo",
  "validation": "unproven"
}

The id property is the user identifer, mostly used as a reference in documents exchanged with devices.

The username is the user unique store username, normally inherited from the SSO account, it’s an ascii-only single-word sequence used to visually disambiguate references to the publisher in the UI.

The display-name is the capitalized, multiple-words and free-form (unicode, emoji, etc) users define as a textual label for themselves. It’s normally inherited from the SSO account (First and Last names).

The validation fields represents the identity validation status of the context account in the Store. At the moment, it is either unproven or verified, where verified means the user identity (display-name, username and contact information) is legitimate. For practical purposes, anything other than unproven should be considered, at least, as a verified identity.

About media

The media field is always and array with ZERO or more images associated with a particular snap:

[
  {"type": "icon", "url": "https://..."},
  {"type": "banner", "url": "https://..."},
  {"type": "banner_icon", "url": "https://..."},
  {"type": "screenshot", "url": "https://..."},
  {"type": "screenshot", "url": "https://..."},
]

The images are referred by type (icon, banner, banner_icon or screenshot) and url (store URL serving the corresponding image content).

Snap currently can only have a single icon, a single banner, a single banner_icon and multiple screenshots.

Fetch metrics for snaps

POST /dev/api/snaps/metrics
Request Headers:
 
Request JSON Object:
 
Response JSON Object:
 
Status Codes:

Important

In order to fetch snap metrics the request’s authentication macaroon needs to include the package_upload permission. See Macaroons for information on how to request a macaroon with the right permissions.

About metric filters

The metrics endpoint allows clients to POST as many distinct metric filters needed to retrieve all required metricts at once:

{
  "filters": [
    {"snap_id": "<SNAP-ID>", "metric_name": "installed_base_by_channel",
     "start": "2016-12-18", "end": "2017-12-17"}
    {"snap_id": "<SNAP-ID>", "metric_name": "installed_base_by_country",
     "start": "2016-12-18", "end": "2017-12-17"}
    ...
  ]
}

Clients can retrieve multiple metrics for any snap they have write access to, with distinct intervals for each metric within a single request.

For performance purposes, each individual interval may not be longer than 1 year.

The following metrics are available:

  • daily_device_change: contains the 3 series representing the number of “new”, “continued” and “lost” devices with the given snap installed compared to the previous day.
  • installed_base_by_channel: contains one series per channel representing the number of devices with the given snap installed, channels with no data across the entire interval are omitted.
  • installed_base_by_country: contains one series per country representing the number of devices with the given snap installed.
  • installed_base_by_operating_system: contains one series per operating_system representing the number of devices with the given snap installed.
  • installed_base_by_version: contains one series per version representing the number of devices withe the given snap installed.
  • weekly_device_change: similar to the ‘daily_device_change’ metric but operates on a 7 day window. i.e. “new” contains the number of devices that were seen during the last 7 days but not in the previous 7 day and so on for “continued” and “lost”.
  • weekly_installed_base_by_channel: similar to the ‘installed_base_by_channel’ metric but operates in a 7 day window.
  • weekly_installed_base_by_country: similar to the ‘installed_base_by_country’ metric but operates in a 7 day window.
  • weekly_installed_base_by_operating_system: similar to the ‘installed_base_by_operating_system’ metric but operates in a 7 day window.
  • weekly_installed_base_by_version: similar to the ‘installed_base_by_version’ metric but operates in a 7 day window.

The metrics response

Each given filter will result in a corresponding metrics entry in the following format:

{
  "metrics": [
    {
      "status": "OK|FAIL|NO_DATA",
      "snap_id": "<SNAP-ID>",
      "metric_name": "<METRIC_NAME>",
      "buckets": ["<DAY-1>", ..., "<DAY-N>"],
      "series": [
        {"name":"<SERIES_NAME>",
         "values": [<SAMPLE-1>, ..., <SAMPLE-N>]},
        ...
      ]
    },
    ...
  ]
}

The <SNAP_ID> and <METRIC_NAME> values are taken from the filters passed to the API in the request.

The status field may be FAIL if there are internal problems building this particular metric or NO_DATA if there were no samples in the given interval, in both cases the data should be discarded by clients. Otherwise, it is OK and the data is good to be used.

The buckets array contains the daily steps for the given [start, end] inclusive interval. It does not provide samples more granular than daily.

Finally, the series field contains all available timeseries in the context of the requested metric. The series values vector (Y axis) is built against the metric buckets vector (X axis).

Usage

Any publisher or collaborator can fetch metrics from their snaps.

First step would be to build a macaroon authorization, please follow the instructions in Macaroons and make sure it contains package_upload permission

The snap_ids can be obtained via the publisher WebUI or via the Accounts.

Request:

POST /dev/api/snaps/metrics HTTP/1.1
Host: dashboard.snapcraft.io
Authorization: ...
Content-Type: application/json

{
  "filters": [
    {"snap_id": "wKFeK2U7Y2CB53vRJwg9MeR9bqfPvtZK",
     "metric_name": "installed_base_by_channel",
     "start": "2017-12-16", "end": "2017-12-17"}
  ]
}

Response:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "metrics": [
    {
      "status": "OK",
      "snap_id": "wKFeK2U7Y2CB53vRJwg9MeR9bqfPvtZK",
      "metric_name": "installed_base_by_channel",
      "buckets": ["2017-12-16"],
      "series": [
        {"values": [124], "name":"stable"},
        {"values": [270], "name":"beta"},
        {"values": [74], "name":"candidate"},
        {"values": [147], "name":"edge"}
      ]
    }
  ]
}

If the macaroon used for authentication does not contain the package_upload permission or is restricted to a set of snap packages that doesn’t include this package, an error response will be returned

Response:

HTTP/1.1 403 FORBIDDEN
Content-Type: application/problem+json

{
  "error_list": [
    {
      "message": "Not authorized to access the following snap_ids: <SNAP-ID>",
      "code": "macaroon-permission-required"
    }
  ],
}

In the event that the request contained invalid filters, an error response will be returned detailing the problem

Response:

HTTP/1.1 400 BAD REQUEST
Content-Type: application/json

{
  "error_list": [
    {
      "message": "Filter missing required keys at index 0: end",
      "code": "invalid"
    }
  ],
}

List all revisions of a snap

GET /dev/api/snaps/(snap_id)/history[?arch=<arch>&page=1&size=500]
Request Headers:
 
Query Parameters:
 
  • arch – (optional) when set, retrieve only revisions for this architecture
Response JSON Array of Objects:
 
  • revision (int) – the revision of the build
  • version (string) – the version of the build
  • timestamp (string) – the date and time when the build was uploaded
  • series (list) – list of series the build was pushed to
  • arch (list) – list of architectures supported by the build
  • channels (list) – list of channels the build was released to
  • current_channels (list) – list of channels where this revision is currently available
Status Codes:

The results can be optionally filtered by architecture via the corresponding query-string parameter arch.

The results are also paginated, with a default (and maximum) size of 500 entries. Clients can request smaller page sizes and further pages via query-string parameters size and page (1-indexed).

Important

There are no particular permissions required in the macaroon for retrieving revision history. Refer to the Macaroons for information on how to request a macaroon with the right permissions.

Note

The user must be the owner or a contributor of the requested package; returns 404 Not Found otherwise.

Usage

List all revisions of the snap with id some_snap_id:

Request:

GET /dev/api/snaps/some_snap_id/history HTTP/1.1
Host: dashboard.snapcraft.io
Authorization: Macaroon root=..., discharge=...
Content-Type: application/json

Response:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

[
    {
        "series": [
            "16"
        ],
        "channels": [
            "beta"
        ],
        "version": "1.1-amd64",
        "timestamp": "2016-10-05T00:33:58.209",
        "current_channels": [
            "beta",
            "edge"
        ],
        "arch": "amd64",
        "revision": 4
    },
    {
        "series": [
            "16"
        ],
        "channels": [
            "edge"
        ],
        "version": "1.0-i386",
        "timestamp": "2016-10-03T20:33:58.162",
        "current_channels": [
            "edge"
        ],
        "arch": "i386",
        "revision": 3
    },
    {
        "series": [
            "16"
        ],
        "channels": [
            "stable",
        ],
        "version": "1.0-amd64",
        "timestamp": "2016-10-01T10:33:58.021",
        "current_channels": [
            "stable",
            "candidate"
        ],
        "arch": "amd64",
        "revision": 2
    }
]

Filter revisions by architecture:

Request:

GET /dev/api/snaps/some_snap_id/history?arch=i386 HTTP/1.1
Host: dashboard.snapcraft.io
Authorization: Macaroon root=..., discharge=...
Content-Type: application/json

Response:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

[
    {
        "series": [
            "16"
        ],
        "channels": [
            "edge"
        ],
        "version": "1.0-i386",
        "timestamp": "2016-10-03T20:33:58.162",
        "current_channels": [
            "edge"
        ],
        "arch": "i386",
        "revision": 3
    }
]

Retrieve the publishing status of a snap

Retrieves the channel map of a snap for all related architectures.

GET /dev/api/snaps/(snap_id)/status
Request Headers:
 
Response JSON Object:
 
  • object – map of {arch: channel_map} for each architecture related to the context snap: refer to About channel_map
Query Parameters:
 
  • arch – (optional) when set, retrieve the channel map for this architecture only
Status Codes:

Important

There are no particular permissions required in the macaroon for retrieving the snap status. Refer to the Macaroons for information on how to request a macaroon with the right permissions.

Note

The user must be the owner or a contributor of the requested package.

Usage

Retrieve the channel map for all architectures of the snap with id some_snap_id:

Request:

GET /dev/api/snaps/some_snap_id/status HTTP/1.1
Host: dashboard.snapcraft.io
Authorization: Macaroon root=..., discharge=...
Content-Type: application/json

Response:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
    "i386": [
        {
            "info": "none",
            "channel": "stable"
        },
        {
            "info": "none",
            "channel": "candidate"
        },
        {
            "info": "none",
            "channel": "beta"
        },
        {
            "info": "specific",
            "version": "1.0-i386",
            "channel": "edge",
            "revision": 3
        }
    ],
    "amd64": [
        {
            "info": "specific",
            "version": "1.0-amd64",
            "channel": "stable",
            "revision": 2
        },
        {
            "info": "tracking",
            "channel": "candidate"
        },
        {
            "info": "specific",
            "version": "1.1-amd64",
            "channel": "beta",
            "revision": 4
        },
        {
            "info": "tracking",
            "channel": "edge"
        }
    ]
}

Filter by architecture:

Request:

GET /dev/api/snaps/some_snap_id/status?arch=amd64 HTTP/1.1
Host: dashboard.snapcraft.io
Authorization: Macaroon root=..., discharge=...
Content-Type: application/json

Response:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
    "amd64": [
        {
            "info": "specific",
            "version": "1.0-amd64",
            "channel": "stable",
            "revision": 2
        },
        {
            "info": "tracking",
            "channel": "candidate"
        },
        {
            "info": "specific",
            "version": "1.1-amd64",
            "channel": "beta",
            "revision": 4
        },
        {
            "info": "tracking",
            "channel": "edge"
        }
    ]
}

Managing snap metadata

The metadata endpoint allows clients to fetch and update textual attributes of a snap.

GET /dev/api/snaps/(snap_id)/metadata
Request Headers:
 
Response JSON Object:
 
  • title – single-line text displayed as title in the snap page
  • summary – single-line summary
  • description – multi-line description
  • contact – upstream project contact URL
  • website – upstream project website URL
  • keywords – list of proposed keywords to facilitate search
  • license – SPDX 1.1 license expression for this snaps
  • price – current price of this snap in USD (as float)
  • private – whether this is snap is private or not
  • blacklist_countries – list of country codes (ISO ALPHA-2) in which the snap distribution is forbidden
  • whitelist_countries – list of country codes (ISO ALPHA-2) in which the snap is exclusively allowed to be distributed
  • public_metrics_enabled – whether public metrics are enabled for this snap or not
  • public_metrics_blacklist – list of public metric names not available for consumption
  • categories – categories information for the snap, (see Snap categories for more details)
Status Codes:

POST-ing to metadata allows clients to update attributes after checking for conflicts.

POST /dev/api/snaps/(snap_id)/metadata[?conflict_on_update=false]
Request Headers:
 
Request JSON Object:
 
  • . – any combination of the fields mentioned above that should be updated
Status Codes:

Note

The optional conflict_on_update modifier can be set to true to flag the updated fields to be checked for conflicts on future updates. If omitted, a false value is assumed.

Whereas PUT-ing to metadata forces updates, ignoring any conflicts with fields previously updated via webui.

PUT /dev/api/snaps/(snap_id)/metadata[?conflict_on_update=false]
Request Headers:
 
Request JSON Object:
 
  • . – any combination of the fields mentioned above that should be updated
Status Codes:

The binary-metadata endpoint allows fetching and updating binary attributes of a snap (icon and screenshots).

GET /dev/api/snaps/(snap_id)/binary-metadata
Request Headers:
 
Response JSON Array of Objects:
 
  • type – whether it’s an icon, screenshot, banner or banner_icon
  • filename – the original filename
  • url – the url where the file is served
  • hash – the SHA-256 hex-digest of the file
Status Codes:

POST-ing to binary-metadata involves a specially-crafted multipart payload, where the info part is a JSON-encoded array of objects describing the subsequent parts, as in:

{
  "info": [
    {"key": "the_icon", "type": "icon", "filename": "my_icon.png", "hash": "<SHA-256>"},
    {"key": "ss_1", "type": "screenshot", "filename": "ss_1.png", "hash": "<SHA-256>"},
    {"key": "ss_2", "type": "screenshot", "filename": "ss_2.png", "hash": "<SHA-256>"},
  ]
}

Similarly to the textual endpoint, POST-ing to binary-metadata will submit the proposed files to a conflict check against files uploaded via webui (based on the “hash” attribute in info) before updating the snap information. It is an additive operation, i.e. existing icon or screenshots will not get removed as long as they are still referenced in the info structure.

POST /dev/api/snaps/(snap_id)/binary-metadata[?conflict_on_update=false]
Request Headers:
 
Form Parameters:
 
  • info – JSON-encoded array of objects describing the next parts
  • <key> – binary metadata as described in info (form-encoded)
  • <...> – additional files
Status Codes:

PUT-ing to binary-metadada will first remove all files related to the snap not mentioned in the info structure and then add the proposed ones.

PUT /dev/api/snaps/(snap_id)/binary-metadata[?conflict_on_update=false]
Request Headers:
 
Form Parameters:
 
  • info – JSON-encoded array of objects describing the next parts
  • <key> – binary metadata as decribed in info (form-encoded)
  • <...> – additional files
Status Codes:

Important

In order to fetch or update snap metadata the request’s authentication macaroon needs to include the package_upload permission. See Macaroons for information on how to request a macaroon with the right permissions.

Usage

Any publisher or collaborator can fetch or update metadata from their snaps.

First step would be to build a macaroon authorization, please follow the instructions in Macaroons and make sure it contains the package_upload permission.

The snap_id can be obtained via the publisher WebUI or via the Accounts.

Updating summary (textual metadata):

POST /dev/api/snaps/(snap_id)/metadata HTTP/1.1
Host: dashboard.snapcraft.io
Authorization: ...
Content-Type: application/json

{
  "summary": "Updated summary",
}

Response:

HTTP/1.1 200 OK
Content-Type: application/json

{
  "blacklist_countries": [],
  "description": "Some description",
  "license": "GPL-3.0",
  "title": "the_title",
  "price": null,
  "whitelist_countries": [],
  "summary": "Updated summary",
  "contact": "http://example.com/hello",
  "website": "http://example.com"
  "keywords": []
}

Updating summary (textual metadata) and flag the field for conflict check:

POST /dev/api/snaps/(snap_id)/metadata?conflict_on_update=true HTTP/1.1
Host: dashboard.snapcraft.io
Authorization: ...
Content-Type: application/json

{
  "summary": "Updated summary",
}

Response:

HTTP/1.1 200 OK
Content-Type: application/json

{
  "blacklist_countries": [],
  "description": "Some description",
  "license": "GPL-3.0",
  "title": "the_title",
  "price": null,
  "whitelist_countries": [],
  "summary": "Updated summary",
  "contact": "http://example.com/hello",
  "website": "http://example.com"
  "keywords": []
}

Future updates to the summary field through the API will check the value for possible conflicts.

Updating icon (binary metadata):

POST /dev/api/snaps/(snap_id)/binary-metadata HTTP/1.1
Host: dashboard.snapcraft.io
Authorization: ...
Content-Type: multipart/form-data; boundary=c6472a1ed83b44fbb697beab700ca8b3

--c6472a1ed83b44fbb697beab700ca8b3
Content-Disposition: form-data; name="info"

{"info": [{"key": "icon", "type": "icon", "filename": "icon.png", "hash": "<SHA-256>"}]}
--c6472a1ed83b44fbb697beab700ca8b3
Content-Disposition: form-data; name="icon"; filename="icon.png"

<binary content>
--c6472a1ed83b44fbb697beab700ca8b3--

Response:

HTTP/1.1 200 OK
Content-Type: application/json

[
  {
    "hash": "<SHA-256>",
    "type": "icon",
    "filename": "icon.png",
    "url": "http://dashboard.snapcraft.io/site_media/appmedia/2018/01/icon.png"
  }
]

If the macaroon used for authentication does not contain the package_upload permission or is restricted to a set of snap packages that doesn’t include this package, an error response will be returned.

Response:

HTTP/1.1 403 FORBIDDEN
Content-Type: application/json

{
  "error_list": [
    {
      "message": "Permission is required: package_upload",
      "code": "macaroon-permission-required"
    }
  ]
}

In the event that the request contained invalid fields, an error response will be returned detailing the problem.

Response:

HTTP/1.1 400 BAD REQUEST
Content-Type: application/json

{
  "error_list": [
    {
      "message": "Invalid field: zoing",
      "code": "invalid-request"
    }
  ]
}

Snap categories

The metadata categories field is a dict containing the following:

  • locked: whether categories are locked from modification by snap publishers
  • items: a list of dicts having:
    • name: the name of the category
    • since: an ISO 8601 timestamp of when this category was assigned
    • featured: whether this category is set by store curators

Categories can be added to a snap by POST-ing categories names to the metadata endpoint.

Request:

POST /dev/api/snaps/(snap_id)/metadata HTTP/1.1
Host: dashboard.snapcraft.io
Authorization: ...
Content-Type: application/json

{
  "categories": ["utilities", "developers"]
}

Response:

HTTP/1.1 200 OK
Content-Type: application/json

{
  "title": "the_title",
  "summary": "Updated summary",
  "contact": "http://example.com/hello",
  "website": "http://example.com",
  "categories": {
    "locked": false,
    "items": [
      {"name": "developers", "since": "2016-10-05T00:33:58.209", "featured": false},
      {"name": "utilities", "since": "2016-10-05T00:33:58.209", "featured": false}
    ]
  }
}

Existing categories assignments can be cleared by POST-ing an empty list.

POST /dev/api/snaps/(snap_id)/metadata HTTP/1.1
Host: dashboard.snapcraft.io
Authorization: ...
Content-Type: application/json

{
  "categories": []
}

Response:

HTTP/1.1 200 OK
Content-Type: application/json

{
  "title": "the_title",
  "summary": "Updated summary",
  "contact": "http://example.com/hello",
  "website": "http://example.com",
  "categories": {
    "locked": false,
    "items": []
  }
}

Supervise the status of a build

The response from a successful hit to the Push endpoint includes a status_details_url (see Push a snap build to the Store for more details).

The status_details_url will return proper information about the processing of the build happening server side.

GET /dev/api/snaps/(snap_id)/builds/(updown_id)/status
Response JSON Object:
 
  • processed (boolean) – true if the server side processing already finished (if false, please wait a few seconds and hit the status_details_url again).
  • can_release (boolean) – true if all finished OK server side, so the client can proceed to release (see Release a snap build to a channel for more info).
  • code (string) – a short (but representative) string indicating concisely in which stage the server side processing is (see below for the list)
  • url (string) – (optional) present if the user can continue the procedure, realize some action and/or retrieve some information through the web site.
  • errors (list) – (optional) present only if the build processing ended in an error state, this list of error messages will help the user to fix the build (see below for format).
  • revision (int) – (optional) the revision of the pushed build, present only if the build binary structure was ok and a revision was assigned to it.
Status Codes:

The code informing in which stage the processing is can be any of the following:

  • being_processed: the processing still didn’t finish
  • processing_error: there was an error processing the build
  • need_manual_review: a manual review is needed for the push to be approved
  • ready_to_release: free to go

The errors field (if present) will be a list of dictionaries, each dict containing…

  • a code element, which is a short string to indicate unambiguously the type of error, and can be used by the client to present a special message or take an specific action; note that it also can be null if the error type is generic.
  • a message element, which is a short descriptive message for the error.

Set or update a guard-rail version pattern for a channel’s track

A track guard-rail pattern is a regular expression which a revision’s version must match to allow it to be released in any channel of the given track. When trying to release a revision with a version label not matching the defined pattern, the request will be rejected with a bad request error response.

POST /dev/api/snap-track-update/
Request Headers:
 
Request JSON Object:
 
  • name (string) – name of the snap package
  • track (string) – name of the channel track
  • pattern (string) – regular expression a version must match when releasing a revision in the given track
Response JSON Object:
 
  • track (object) – a dictionary with the track’s current ‘name’ and ‘pattern’
Status Codes:

Important

Note the backslash escaping: regular expression backslash is escaped in its string representation; in the examples below there is also json escaping in the request/response data (and that’s why r'\d' then becomes "\\\\d" in the payload).

Important

No nested repeats (e.g. (\d+\w+)*) are allowed in the given regular expression. A bad request response will be returned if the provided regular expression is not valid.

Important

In order to set a track’s pattern, authentication macaroon needs to include the package_release permission. Refer to the Macaroons for information on how to request a macaroon with the right permissions.

Usage

Without passing a pattern, the developer can get track’s current details:

Request:

POST /dev/api/snap-track-update/ HTTP/1.1
Host: dashboard.snapcraft.io
Content-Type: application/json

{
  "name": "foo",
  "track": "1.1"
}

Response:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "track": {
     "name": "1.1",
     "pattern": "^1\\\\.1"
  },
}

Otherwise, a pattern can be specified to update the track guard-rail. Note that revisions currently released under the given track must match the posted regular expression. An empty pattern means no validation will be required when releasing to the track.

Request:

POST /dev/api/snap-track-update/ HTTP/1.1
Host: dashboard.snapcraft.io
Content-Type: application/json

{
  "name": "foo",
  "track": "1.1",
  "pattern": "^1\\\\.1\\\\.\\\\d+"
}

Response:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "track": {
     "name": "1.1",
     "pattern": "^1\\\\.1\\\\.\\\\d+"
  },
}

If there is a previously released revision with a version label not matching the provided regular expression, the pattern will not be updated:

Request:

POST /dev/api/snap-track-update/ HTTP/1.1
Host: dashboard.snapcraft.io
Content-Type: application/json

{
  "name": "foo",
  "track": "1.1",
  "pattern": "^1\\\\.1\\\\.\\\\d+"
}

Response:

HTTP/1.1 400 BAD REQUEST
Content-Type: application/json; charset=utf-8

{
  "error_list": [
     {
       "message": "Released version=1.8 does not match pattern=^1\\.1\\.\\d+",
       "code": "invalid-field"
     }
   ]
 }

If the macaroon used for authentication does not contain the package_release permission or is restricted to a set of snap packages that doesn’t include this package, an error response will be returned:

Response:

HTTP/1.1 403 FORBIDDEN
Content-Type: application/problem+json

{
  "status": 403,
  "permission": "package_release",
  "title": "Macaroon missing required permission.",
  "detail": "Permission is required: package_release",
  "error_list": [
    {
      "message": "Permission is required: package_release",
      "code": "macaroon-permission-required"
    }
  ],
  "type": "devportal:v1:macaroon-permission-required"
}

If an update is requested for a package or track that has not had its name registered beforehand, an error like this will be returned:

Response:

HTTP/1.1 404 NOT FOUND

The developer needs to sign the Developer Programme Agreement before they can release snap packages. Failing to do so will result in an error response:

Response:

HTTP/1.1 403 FORBIDDEN
Content-Type: text/plain

Developer has not signed agreement.

The developer needs to have defined their namespace in their user profile before they can update a track. Failing to do so will result in an error response:

Response:

HTTP/1.1 403 FORBIDDEN
Content-Type: text/plain

Developer profile is missing short namespace.

In the event that the request contained invalid data, an error response will be returned detailing the problem:

Response:

HTTP/1.1 400 BAD REQUEST
Content-Type: application/json; charset=utf-8

{
  "error_list": [
     {
       "message": "Specific error message",
       "code": "invalid-field"
     }
   ]
 }

Close a channel for a snap package

POST /dev/api/snaps/(snap_id)/close
Request Headers:
 
Request JSON Object:
 
  • channels (list) – list of channels to close
Response JSON Object:
 
  • channel_maps (object) – channel_map for each architecture related to the context snap.
  • closed_channels (list) – list of channels currently closed for the context snap.
Status Codes:

Important

In order to close a channel the request’s authentication macaroon needs to include the package_upload permission. Refer to the Macaroons for information on how to request a macaroon with the right permissions.

Manage collaborators for a snap package

GET /dev/api/snaps/(snap_id)/developers
Request Headers:
 
Parameters:
  • snap_id – the snap_id of the package
Response JSON Object:
 
  • snap_developer (object) – parsed snap-developer assertion (headers, etc).
Status Codes:
PUT /dev/api/snaps/(snap_id)/developers
Request Headers:
 
Parameters:
  • snap_id – the snap_id of the package
Request JSON Object:
 
  • snap_developer (string) – the snap-developer assertion
Response JSON Object:
 
  • snap_developer (object) – parsed snap-developer assertion (headers, etc).
Status Codes:

Important

In order to manage collaborators the request’s authentication macaroon needs to include the package_manage permission. Refer to the Macaroons for information on how to request a macaroon with the right permissions.

Note

The assertion’s publisher-id must be the authorized user’s account ID.

The assertion’s authority-id must be the same as the publisher-id, i.e. the assertion must be signed by one of the authorized user’s private keys.

The snap ID and any developer account ID in the assertion must identify a valid snap and developer respectively.

Errors

The Snap Packages API uses conventional HTTP response codes to indicate success or failure of an API request.

In general, codes in the 2xx range indicate success, codes in the 4xx range indicate an error that resulted from the provided information (e.g. a required parameter was missing) and codes in the 5xx range indicate an error with our servers.

Here is detailed the format for API responses that end in error.

This applies to all the 4xx responses, but also to some 5xx ones (if possible, the client should be prepared to handle 5xx responses with no informational body). Note that this structure format does not apply to 2xx and 3xx responses, as those are note errors.

Important

Not all API endpoints are migrated yet to this new error format

Format

An error response body will contain the following field:

  • error_list: a list of one or several items (never empty), each item described by…
    • message: a text in English describing the error that happened, ready to show to the user.
    • code: a short (but representative) string indicating concisely the error; it’s aimed for clients to take specific actions and react to the problem. See below for the list of existing codes.

Additionally and for backwards compatibility reasons, some other fields may be present as well, but are considered deprecated and will be removed in the near future.

No status or success indication is returned inside the response body, the client should react properly to the received HTTP return code according to its well established semantics.

Codes

These are the codes used in the response and their meanings:

  • already_claimed: the requested snap name is already claimed.
  • already_owned: the user already owns the requested snap name.
  • already_registered: the requested snap name is already registered.
  • assertion-creation-failed: the assertion associated with the requested action could not be created.
  • bad-request: there is a problem in the structure of the request.
  • internal-server-error: some unexpected problem server side; this will be the code in all 5xx cases.
  • failed-to-register: the snap name registration failed because we failed to store the assertion.
  • invalid: the snap name is not valid: it should only have ASCII lowercase letters, numbers, and hyphens, and must have at least one letter; furthermore, it should not start nor end with a hyphen, it should not have two hyphens in a row, and it should have no more than 40 characters in total.
  • invalid_choice: current selected choice is not one of the available choices.
  • invalid-field: the field received in the request has format problems (e.g.: must be a number and it’s not) or value problems (e.g.: it specified a channel “foo” but that is an invalid channel for this Store).
  • macaroon-permission-required: the macaroon authorization is missing in the received request or not enough for it to be fulfilled.
  • missing-field: the request received must include a field which was not present.
  • register_window: the user cannot register more snap names temporarily.
  • required: the field in the request can’t be empty or null.
  • reserved_name: the requested snap name is reserved.
  • resource-forbidden: the resources in question cannot be accessed by the request authorization.
  • resource-not-found: one or more fields are included to specify a resource, but it is not found in the Store.
  • resource-not-ready: the request actions on a resource that is not ready yet for that purpose; normally something else would need to be done first on the resource before this request can be repeated.
  • revoked_name: the requested snap name is revoked.
  • user-not-ready: the user is not ready to issue the received request; normally some actions would need to be done in the user account before repeating the request.

Examples

A simple error:

{
  "error_list": [{
     "message": "The field 'expiration' must be an integer",
     "code": "invalid-field"
  }]
}

A multiple error:

{
  "error_list": [{
     "message": "The 'foo' field is required",
     "code": "missing-field"
  }, {
     "message": "The 'bar' field is required",
     "code": "missing-field"
  }, {
     "message": "The 'baz' field must not be empty",
     "code": "invalid-field"
  }]
}