Only available in 2.3 or later.

Portus REST API

Introduction

We have been working on a REST API that can be used to operate Portus without needing to access the web UI, and we are already building some tooling like openSUSE/portusctl which already takes advantage of this new API.

Note though that we are doing organically. This means that we make no guarantees over the stability of this version of the API (once we’ve learned what we need from v1, we will make these guarantees on a v2 version of the API).

The specification listed below corresponds to the current state of the master branch, so the specification may vary from the v2.3 release. That being said, we are writing down the changes from the v2.3, so early users are not caught off guard. Besides this, take into account the following:

  • You have to set the Content-Type and the Accept headers to application/json for every request.
  • Error messages are a bit chaotic (i.e. with different formats). We are tracking this on this issue.

Authentication

Authentication is done through application tokens. This way, you don’t compromise your password, and you can revoke it whenever you think it’s necessary.

Once you have created this application token, you will have to pass the PORTUS-AUTH header for every HTTP request that you perform. This header follows this format: <username>:<application token>. So, if your user name is user, and the application token you have created has the value T7Dfuz4fsy1UVxNUKyac, then you have to set this header with the value: user:T7Dfuz4fsy1UVxNUKyac. You can try that this is working by performing the following HTTP request (where https://172.17.0.1 points to a Portus instance):

$ curl -X GET --header 'Accept: application/json' --header 'Portus-Auth: user:T7Dfuz4fsy1UVxNUKyac' 'https://172.17.0.1/api/v1/users'

If everything went correctly, then you will get a JSON response with all the users from your Portus instance.

Finally, portusctl does this automatically for you if you provide the environment variables: PORTUSCTL_API_SERVER, PORTUSCTL_API_TOKEN and PORTUSCTL_API_USER. With this in mind, the following is equivalent to the previously used curl command:

$ export PORTUSCTL_API_USER="user"
$ export PORTUSCTL_API_TOKEN="T7Dfuz4fsy1UVxNUKyac"
$ export PORTUSCTL_API_SERVER="https://172.17.0.1"
$ portusctl get users

Endpoints

Health

GET /api/v1/health

Returns general metrics on the health of the system.

Response Class (status: 200)

Returns hash of metrics. Format of the response:

{
  "database": {
    "msg": "string",
    "success": true
  },
  "registry": {
    "msg": "string",
    "success": true
  },
  "clair": {
    "msg": "string",
    "success": true
  }
}

Response Messages

503 Some of the required services are unhealthy.

GET /api/v1/_ping

Returns 200 as a status code.

Response Messages

200 Ping this API.

Namespaces

GET /api/v1/namespaces

This will expose all accessible namespaces.

Response Class (status: 200)

Returns a list of namespaces. Format of the response:

[
  {
    "id": 0,
    "name": "string",
    "created_at": "<date-time>",
    "updated_at": "<date-time>",
    "description": "string",
    "team_name": "string",
    "team_id": 0,
    "repositories_count": 0,
    "webhooks_count": 0,
    "visibility": "string",
    "global": true,
    "permissions": "string"
  }
]

Response Messages

401 Authentication fails.
403 Authorization fails.

POST /api/v1/namespaces

Create a namespace.

Parameters

  • name (string, required): Namespace name. This parameter is part of the data to be sent as a form.
  • team (string, required): Team name. This parameter is part of the data to be sent as a form.
  • description (string): Team description. This parameter is part of the data to be sent as a form.

Response Class (status: 201)

Format of the response:

{
  "id": 0,
  "name": "string",
  "created_at": "<date-time>",
  "updated_at": true,
  "hidden": true,
  "role": "string",
  "users_count": 0,
  "namespaces_count": 0
}

Response Messages

401 Authentication fails.
403 Authorization fails.

GET /api/v1/namespaces/validate

Validates the given namespace.

Parameters

  • name (string, required): Name to be checked. This parameter has to be set in the URL query.

Response Class (status: 200)

Format of the response:

{
  "messages": "<object>: Detailed hash with the fields",
  "valid": true
}

Response Messages

401 Authentication fails.
403 Authorization fails.

GET /api/v1/namespaces/{id}/repositories

Returns the list of the repositories for the given namespace.

Parameters

  • id (integer, required): Namespace ID. This parameter has to be included as part of the path.

Response Class (status: 200)

Format of the response:

[
  {
    "id": 0,
    "name": "string",
    "full_name": "string",
    "created_at": "<date-time>",
    "updated_at": "<date-time>",
    "namespace": "string",
    "registry_hostname": 0,
    "stars": 0,
    "tags_count": 0,
    "tags": [
      "strings"
    ]
  }
]

Response Messages

401 Authentication fails.
403 Authorization fails.
404 Not found.

GET /api/v1/namespaces/{id}

Show namespaces by id.

Parameters

  • id (integer, required): Namespace ID. This parameter has to be included as part of the path.

Response Class (status: 200)

Format of the response:

{
  "id": 0,
  "name": "string",
  "created_at": "<date-time>",
  "updated_at": "<date-time>",
  "description": "string",
  "team_name": "string",
  "team_id": 0,
  "repositories_count": 0,
  "webhooks_count": 0,
  "visibility": "string",
  "global": true,
  "permissions": "string"
}

Response Messages

401 Authentication fails.
403 Authorization fails.
404 Not found.

Registries

GET /api/v1/registries

This will expose all accessible registries.

Response Class (status: 200)

Returns a list of registries. Format of the response:

[
  {
    "id": 0,
    "name": "string",
    "hostname": "string",
    "external_hostname": "string",
    "use_ssl": true,
    "created_at": "<date-time>",
    "updated_at": "<date-time>"
  }
]

Response Messages

401 Authentication fails.
403 Authorization fails.

GET /api/v1/registries/validate

Besides containing the usual Status object, it adds the reachable validation to the `hostname` field in the `messages` hash. This validation returns a string containing the error as given by the registry. If empty then everything went well.

Parameters

  • name (string): The name of the registry. This parameter has to be set in the URL query.
  • hostname (string): The hostname of the registry. This parameter has to be set in the URL query.
  • external_hostname (string): An external hostname of the registry, useful if behind a proxy with a different FQDN. This parameter has to be set in the URL query.
  • use_ssl (boolean): Whether the registry uses SSL or not. This parameter has to be set in the URL query.
  • only (array): Restrict which parameters are to be validated. This parameter is part of the data to be sent as a form.

Response Class (status: 200)

Validates the given registry. Format of the response:

{
  "messages": "<object>: Detailed hash with the fields",
  "valid": true
}

Response Messages

401 Authentication fails.
403 Authorization fails.

Repositories

GET /api/v1/repositories

This will expose all repositories.

Response Class (status: 200)

Returns list of repositories. Format of the response:

[
  {
    "id": 0,
    "name": "string",
    "full_name": "string",
    "created_at": "<date-time>",
    "updated_at": "<date-time>",
    "namespace": "string",
    "registry_hostname": 0,
    "stars": 0,
    "tags_count": 0,
    "tags": [
      "strings"
    ]
  }
]

Response Messages

401 Authentication fails.
403 Authorization fails.

GET /api/v1/repositories/{id}/tags

Returns the list of the tags for the given repository.

Parameters

  • id (integer, required): Repository ID. This parameter has to be included as part of the path.

Response Class (status: 200)

Format of the response:

[
  {
    "id": 0,
    "name": "string",
    "author": 0,
    "digest": "string",
    "image_id": "string",
    "created_at": "<date-time>",
    "updated_at": "<date-time>",
    "scanned": 0,
    "vulnerabilities": [
      "strings"
    ]
  }
]

Response Messages

401 Authentication fails.
403 Authorization fails.
404 Not found.

GET /api/v1/repositories/{id}/tags/grouped

Returns the list of the tags for the given repository groupped by digest.

Parameters

  • id (integer, required): Repository ID. This parameter has to be included as part of the path.

Response Class (status: 200)

Format of the response:

[
  {
    "id": 0,
    "name": "string",
    "author": 0,
    "digest": "string",
    "image_id": "string",
    "created_at": "<date-time>",
    "updated_at": "<date-time>",
    "scanned": 0,
    "vulnerabilities": [
      "strings"
    ]
  }
]

Response Messages

401 Authentication fails.
403 Authorization fails.
404 Not found.

GET /api/v1/repositories/{id}/tags/{tag_id}

Show tag by id.

Parameters

  • id (integer, required): Repository ID. This parameter has to be included as part of the path.
  • tag_id (string, required): Tag ID. This parameter has to be included as part of the path.

Response Class (status: 200)

Format of the response:

{
  "id": 0,
  "name": "string",
  "author": 0,
  "digest": "string",
  "image_id": "string",
  "created_at": "<date-time>",
  "updated_at": "<date-time>",
  "scanned": 0,
  "vulnerabilities": [
    "strings"
  ]
}

Response Messages

401 Authentication fails.
403 Authorization fails.
404 Not found.

GET /api/v1/repositories/{id}

Show repositories by id.

Parameters

  • id (integer, required): Repository ID. This parameter has to be included as part of the path.

Response Class (status: 200)

Format of the response:

{
  "id": 0,
  "name": "string",
  "full_name": "string",
  "created_at": "<date-time>",
  "updated_at": "<date-time>",
  "namespace": "string",
  "registry_hostname": 0,
  "stars": 0,
  "tags_count": 0,
  "tags": [
    "strings"
  ]
}

Response Messages

401 Authentication fails.
403 Authorization fails.
404 Not found.

Tags

GET /api/v1/tags

This will expose all tags.

Response Class (status: 200)

Returns list of tags. Format of the response:

[
  {
    "id": 0,
    "name": "string",
    "author": 0,
    "digest": "string",
    "image_id": "string",
    "created_at": "<date-time>",
    "updated_at": "<date-time>",
    "scanned": 0,
    "vulnerabilities": [
      "strings"
    ]
  }
]

Response Messages

401 Authentication fails.
403 Authorization fails.

GET /api/v1/tags/{id}

Show tag by id.

Parameters

  • id (integer, required): Tag ID. This parameter has to be included as part of the path.

Response Class (status: 200)

Format of the response:

{
  "id": 0,
  "name": "string",
  "author": 0,
  "digest": "string",
  "image_id": "string",
  "created_at": "<date-time>",
  "updated_at": "<date-time>",
  "scanned": 0,
  "vulnerabilities": [
    "strings"
  ]
}

Response Messages

401 Authentication fails.
403 Authorization fails.
404 Not found.

Teams

GET /api/v1/teams

This will expose all teams.

Response Class (status: 200)

Returns list of teams. Format of the response:

[
  {
    "id": 0,
    "name": "string",
    "created_at": "<date-time>",
    "updated_at": true,
    "hidden": true,
    "role": "string",
    "users_count": 0,
    "namespaces_count": 0
  }
]

Response Messages

401 Authentication fails.
403 Authorization fails.

POST /api/v1/teams

Create a team.

Parameters

  • name (string, required): Team name. This parameter is part of the data to be sent as a form.
  • description (string): Team description. This parameter is part of the data to be sent as a form.

Response Class (status: 201)

Format of the response:

{
  "id": 0,
  "name": "string",
  "created_at": "<date-time>",
  "updated_at": true,
  "hidden": true,
  "role": "string",
  "users_count": 0,
  "namespaces_count": 0
}

Response Messages

401 Authentication fails.
403 Authorization fails.

GET /api/v1/teams/{id}/namespaces

Returns the list of namespaces for the given team.

Parameters

  • id (integer, required): Repository ID. This parameter has to be included as part of the path.

Response Class (status: 200)

Format of the response:

[
  {
    "id": 0,
    "name": "string",
    "created_at": "<date-time>",
    "updated_at": "<date-time>",
    "description": "string",
    "team_name": "string",
    "team_id": 0,
    "repositories_count": 0,
    "webhooks_count": 0,
    "visibility": "string",
    "global": true,
    "permissions": "string"
  }
]

Response Messages

401 Authentication fails.
403 Authorization fails.
404 Not found.

GET /api/v1/teams/{id}/members

Returns the list of team members.

Parameters

  • id (integer, required): Repository ID. This parameter has to be included as part of the path.

Response Class (status: 200)

Format of the response:

[
  {
    "id": 0,
    "username": "string",
    "email": "string",
    "current_sign_in_at": "<date-time>",
    "last_sign_in_at": "<date-time>",
    "created_at": "<date-time>",
    "updated_at": "<date-time>",
    "admin": true,
    "enabled": true,
    "locked_at": "<date-time>",
    "namespace_id": 0,
    "display_name": "string"
  }
]

Response Messages

401 Authentication fails.
403 Authorization fails.
404 Not found.

GET /api/v1/teams/{id}

Show teams by id.

Parameters

  • id (string, required): Team ID. This parameter has to be included as part of the path.

Response Class (status: 200)

Format of the response:

{
  "id": 0,
  "name": "string",
  "created_at": "<date-time>",
  "updated_at": true,
  "hidden": true,
  "role": "string",
  "users_count": 0,
  "namespaces_count": 0
}

Response Messages

401 Authentication fails.
403 Authorization fails.
404 Not found.

Users

GET /api/v1/users/{id}/application_tokens

Returns list of user's tokens.

Parameters

  • id (integer, required): User ID. This parameter has to be included as part of the path.

Response Class (status: 200)

Format of the response:

[
  {
    "id": 0,
    "application": "string",
    "plain_token": "string"
  }
]

Response Messages

401 Authentication fails.
403 Authorization fails.
404 Not found.

POST /api/v1/users/{id}/application_tokens

Create user's token.

Parameters

  • application (string, required): Application name. This parameter is part of the data to be sent as a form.
  • id (integer, required): User ID. This parameter has to be included as part of the path.

Response Class (status: 201)

Format of the response:

{
  "id": 0,
  "application": "string",
  "plain_token": "string"
}

Response Messages

400 Bad request.
401 Authentication fails.
403 Authorization fails.

DELETE /api/v1/users/application_tokens/{id}

Delete application token.

Parameters

  • id (string, required): Token id. This parameter has to be included as part of the path.

Response Messages

204 Delete application token.
401 Authentication fails.
403 Authorization fails.
404 Not found.

POST /api/v1/users

Create new user.

Parameters

  • user[username] (string, required): User name. This parameter is part of the data to be sent as a form.
  • user[email] (string, required): E-mail. This parameter is part of the data to be sent as a form.
  • user[password] (string, required): Password. This parameter is part of the data to be sent as a form.
  • user[display_name] (string): Display name. This parameter is part of the data to be sent as a form.

Response Class (status: 201)

Format of the response:

{
  "id": 0,
  "username": "string",
  "email": "string",
  "current_sign_in_at": "<date-time>",
  "last_sign_in_at": "<date-time>",
  "created_at": "<date-time>",
  "updated_at": "<date-time>",
  "admin": true,
  "enabled": true,
  "locked_at": "<date-time>",
  "namespace_id": 0,
  "display_name": "string"
}

Response Messages

400 Bad request.
401 Authentication fails.
403 Authorization fails.

GET /api/v1/users

This will expose all users.

Response Class (status: 200)

Returns list of users. Format of the response:

[
  {
    "id": 0,
    "username": "string",
    "email": "string",
    "current_sign_in_at": "<date-time>",
    "last_sign_in_at": "<date-time>",
    "created_at": "<date-time>",
    "updated_at": "<date-time>",
    "admin": true,
    "enabled": true,
    "locked_at": "<date-time>",
    "namespace_id": 0,
    "display_name": "string"
  }
]

Response Messages

401 Authentication fails.
403 Authorization fails.

PUT /api/v1/users/{id}

Update user.

Parameters

  • user[username] (string): User name. This parameter is part of the data to be sent as a form.
  • user[email] (string): E-mail. This parameter is part of the data to be sent as a form.
  • user[password] (string): Password. This parameter is part of the data to be sent as a form.
  • user[display_name] (string): Display name. This parameter is part of the data to be sent as a form.
  • id (integer, required): User ID. This parameter has to be included as part of the path.

Response Class (status: 200)

Format of the response:

{
  "id": 0,
  "username": "string",
  "email": "string",
  "current_sign_in_at": "<date-time>",
  "last_sign_in_at": "<date-time>",
  "created_at": "<date-time>",
  "updated_at": "<date-time>",
  "admin": true,
  "enabled": true,
  "locked_at": "<date-time>",
  "namespace_id": 0,
  "display_name": "string"
}

Response Messages

400 Bad request.
401 Authentication fails.
403 Authorization fails.
404 Not found.

DELETE /api/v1/users/{id}

Delete user.

Parameters

  • id (integer, required): User ID. This parameter has to be included as part of the path.

Response Messages

204 Delete user.
401 Authentication fails.
403 Authorization fails.
404 Not found.

GET /api/v1/users/{id}

Show user by id or email.

Parameters

  • id (string, required): User ID or email. This parameter has to be included as part of the path.

Response Class (status: 200)

Format of the response:

{
  "id": 0,
  "username": "string",
  "email": "string",
  "current_sign_in_at": "<date-time>",
  "last_sign_in_at": "<date-time>",
  "created_at": "<date-time>",
  "updated_at": "<date-time>",
  "admin": true,
  "enabled": true,
  "locked_at": "<date-time>",
  "namespace_id": 0,
  "display_name": "string"
}

Response Messages

401 Authentication fails.
403 Authorization fails.
404 Not found.

Version

GET /api/version

Returns the version of Portus and the supported API versions.

Response Class (status: 200)

Fetch the version of Portus. Format of the response:

{
  "api-versions": [
    "strings"
  ],
  "git": "string",
  "version": "string"
}

Response Messages