Every API here is available over the APIs.io API and to AI agents over MCP.
openapi: 3.1.0
info:
title: Pebble API
version: v1
paths:
/v1/changes:
get:
summary: Get changes
tags:
- changes and tasks
description: Fetch information for the specified changes.
parameters:
- name: select
in: query
description: Filter changes by status.
schema:
type: string
enum: [all, in-progress, ready]
default: in-progress
- name: for
in: query
description: Filter changes for a specific service name.
schema:
type: string
responses:
"200":
description: Information about changes.
content:
application/json:
schema:
$ref: "#/components/schemas/GetChangesResponse"
example:
{
"type": "sync",
"status-code": 200,
"status": "OK",
"result": [
{
"id": "4",
"kind": "stop",
"summary": "Stop service \"svc1\" and 1 more",
"status": "Done",
"tasks": [
{
"id": "7",
"kind": "stop",
"summary": "Stop service \"svc1\"",
"status": "Done",
"progress": {
"label": "",
"done": 1,
"total": 1
},
"spawn-time": "2024-12-27T10:08:14.399194229+08:00",
"ready-time": "2024-12-27T10:08:14.429319813+08:00"
},
{
"id": "8",
"kind": "stop",
"summary": "Stop service \"svc2\"",
"status": "Done",
"progress": {
"label": "",
"done": 1,
"total": 1
},
"spawn-time": "2024-12-27T10:08:14.399199354+08:00",
"ready-time": "2024-12-27T10:08:14.432387271+08:00"
}
],
"ready": true,
"spawn-time": "2024-12-27T10:08:14.399202521+08:00",
"ready-time": "2024-12-27T10:08:14.432389313+08:00"
}
]
}
/v1/changes/{id}:
get:
summary: Get a specific change
tags:
- changes and tasks
description: Fetch information about a Change given its ID.
parameters:
- name: id
in: path
required: true
description: ID of the change.
schema:
type: string
responses:
"200":
description: Information about the change.
content:
application/json:
schema:
$ref: "#/components/schemas/GetChangeByIDResponse"
example:
{
"type": "sync",
"status-code": 200,
"status": "OK",
"result": {
"id": "38",
"kind": "autostart",
"summary": "Autostart service \"svc1\" and 1 more",
"status": "Done",
"tasks": [
{
"id": "54",
"kind": "start",
"summary": "Start service \"svc1\"",
"status": "Done",
"progress": {
"label": "",
"done": 1,
"total": 1
},
"spawn-time": "2024-12-27T12:31:26.673287868+08:00",
"ready-time": "2024-12-27T12:31:27.681780702+08:00"
}
],
"ready": true,
"spawn-time": "2024-12-27T12:31:26.673297951+08:00",
"ready-time": "2024-12-27T12:31:27.686371869+08:00"
}
}
post:
summary: Perform an action on a change
tags:
- changes and tasks
description: Perform an action on a change. Currently the only supported action is "abort".
parameters:
- name: id
in: path
required: true
description: ID of the change.
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
action:
type: string
description: The action to perform on the change.
enum: [abort]
responses:
"200":
description: Change aborted.
content:
application/json:
schema:
$ref: "#/components/schemas/GetChangeByIDResponse"
example:
{
"type": "sync",
"status-code": 200,
"status": "OK",
"result": {
"id": "8",
"kind": "perform-check",
"summary": "Perform HTTP check \"check1\"",
"status": "Abort",
"tasks": [
{
"id": "14",
"kind": "perform-check",
"summary": "Perform HTTP check \"check1\"",
"status": "Abort",
"progress": {
"label": "",
"done": 1,
"total": 1
},
"spawn-time": "2024-12-27T10:15:31.390053104+08:00"
}
],
"ready": false,
"spawn-time": "2024-12-27T10:15:31.390062521+08:00"
}
}
/v1/changes/{id}/wait:
get:
summary: Wait for a change to complete
description: |
Wait for the change to be finished.
If the wait operation succeeds, the result will have the "err" field set to an appropriate error message if the change itself had an error.
tags:
- changes and tasks
parameters:
- in: path
name: id
schema:
type: string
required: true
description: The ID of the change to wait for.
- in: query
name: timeout
schema:
type: string
description: |
Optional timeout (a [duration](#duration)).
If specified, wait till the change is ready or a timeout occurs, whichever is first.
If not specified or zero, wait indefinitely until the change is ready.
responses:
"200":
description: Wait for a change.
content:
application/json:
schema:
$ref: "#/components/schemas/GetChangeByIDResponse"
example:
{
"type": "sync",
"status-code": 200,
"status": "OK",
"result": {
"id": "38",
"kind": "autostart",
"summary": "Autostart service \"svc1\" and 1 more",
"status": "Done",
"tasks": [
{
"id": "54",
"kind": "start",
"summary": "Start service \"svc1\"",
"status": "Done",
"progress": {
"label": "",
"done": 1,
"total": 1
},
"spawn-time": "2024-12-27T12:31:26.673287868+08:00",
"ready-time": "2024-12-27T12:31:27.681780702+08:00"
}
],
"ready": true,
"spawn-time": "2024-12-27T12:31:26.673297951+08:00",
"ready-time": "2024-12-27T12:31:27.686371869+08:00"
}
}
/v1/tasks/{task-id}/websocket/{websocket-id}:
get:
summary: Connect to a task's websocket
tags:
- changes and tasks
description: Establish a websocket connection to a specific task.
parameters:
- in: path
name: task-id
schema:
type: string
required: true
description: The ID of the task.
- in: path
name: websocket-id
schema:
type: string
required: true
description: The ID of the websocket.
enum: [control, stderr, stdio]
responses:
"101": # Switching Protocols (Successful Websocket Upgrade)
description: |
The connection is upgraded to the websocket protocol and the websocket connection is established.
The full websocket protocol is not documented. For details, see the [Python client code](https://github.com/canonical/operator/blob/main/ops/pebble.py#L1818).
content:
application/json: # A hack to make the automatically rendered result show "null" instead of "string" which is incorrect.
example:
/v1/checks:
get:
summary: Get checks
tags:
- checks
description: Fetch information about specific health checks (or all of them), ordered by check name.
parameters:
- name: level
in: query
description: Filter checks by level. If omitted, aggregate healthy status of checks with any (or no) level.
schema:
type: string
enum: [alive, ready]
- name: names
in: query
description: The names of the checks to get. To get multiple checks, specify this parameter multiple times. If not set, get all checks.
schema:
type: string
responses:
"200":
description: Information about health checks.
content:
application/json:
schema:
$ref: "#/components/schemas/GetChecksResponse"
example:
{
"type": "sync",
"status-code": 200,
"status": "OK",
"result": [
{
"name": "check1",
"status": "up",
"threshold": 3,
"change-id": "37",
"prev-change-id": "23"
}
]
}
post:
summary: Manage checks
description: Perform a check operation such as start or stop.
tags:
- checks
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
action:
type: string
description: The action to perform.
enum: ["start", "stop"]
checks:
type: array
description: |
A list of service names. Required.
items:
type: string
example:
{"action": "start", "checks": ["svc1"]}
responses:
"200":
description: Check operations completed.
content:
application/json:
schema:
$ref: "#/components/schemas/CheckActionResponse"
example:
{
"type": "sync",
"status-code": 200,
"result": {"changed": ["chk1", "chk2"]}
}
/v1/checks/refresh:
post:
summary: Refresh a check
description: Runs a specified check immediately.
tags:
- checks
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
name:
type: string
description: The name of the check to refresh.
required:
- name
example:
{"name": "chk1"}
responses:
"200":
description: Check refreshed successfully.
content:
application/json:
schema:
$ref: "#/components/schemas/RefreshCheckResponse"
example:
{
"type": "sync",
"status-code": 200,
"status": "OK",
"result": {
"info": {
"name": "check1",
"startup": "enabled",
"status": "up",
"successes": 2,
"failures": 1,
"threshold": 3,
"change-id": "1"
},
"error": "check timed out after 1s"
}
}
/v1/exec:
post:
summary: Execute a command
tags:
- exec
description: |
Start a command with the given options and return a value representing the process.
This API returns a `task-id` (see the response schema and the example below),
then you need to call `/v1/tasks/{task-id}/websocket/control` and `/v1/tasks/{task-id}/websocket/stdio`
(also `/v1/tasks/{task-id}/websocket/stderr` if `split-stderr` is true) with the returned `task-id`.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/PostExecRequest"
example:
command: ["/bin/ls", "-l"]
responses:
"202":
description: Command execution initiated.
content:
application/json:
schema:
$ref: "#/components/schemas/PostExecResponse"
example:
{
"type": "async",
"status-code": 202,
"status": "Accepted",
"change": "4",
"result": {
"environment": {
"HOME": "/home/ubuntu"
},
"task-id": "7",
"working-dir": "/home/ubuntu"
}
}
/v1/files:
get:
summary: Read or list files
tags:
- files
description: Read the contents of files or list files from the remote system.
parameters:
- name: action
in: query
description: Action to perform.
required: true
schema:
type: string
enum: ["list", "read"]
- name: path
in: query
description: |
For "read": Absolute file path to read. To read multiple files, specify this parameter multiple times.
For "list": Absolute path to the directory to list.
required: true
schema:
type: string
style: form # For handling comma-separated values in "read".
explode: true # For handling comma-separated values in "read".
- name: pattern
in: query
description: Glob pattern to filter files/directories for the "list" action.
schema:
type: string
- name: itself
in: query
description: |
For the "list" action, `itself` specifies whether to return information about the directory itself ("true")
or list the contents of the directory ("false").
schema:
type: string
enum: ["false", "true"]
responses:
"200":
description: |
For "list": JSON array of file information.
For "read": Multipart form data response with file contents and metadata. Raw multipart response example:
```
Content-Type: multipart/form-data; boundary=01234567890123456789012345678901\r
--01234567890123456789012345678901\r
Content-Disposition: form-data; name="files"; filename="/etc/hosts"\r
\r
127.0.0.1 localhost # \xf0\x9f\x98\x80\nfoo\r\nbar\r
--01234567890123456789012345678901\r
Content-Disposition: form-data; name="response"\r
\r
{
"result": [{"path": "/etc/hosts"}],
"status": "OK",
"status-code": 200,
"type": "sync"
}\r
--01234567890123456789012345678901--\r
```
content:
application/json: # list
schema:
$ref: "#/components/schemas/ListFilesResponse"
example:
{
"type": "sync",
"status-code": 200,
"status": "OK",
"result": [
{
"path": "/home/ubuntu/PEBBLE_HOME/layers/001-simple-layer.yaml",
"name": "001-simple-layer.yaml",
"type": "file",
"size": 122,
"permissions": "664",
"last-modified": "2024-12-27T11:13:31+08:00",
"user-id": 1000,
"user": "ubuntu",
"group-id": 1000,
"group": "ubuntu"
}
]
}
multipart/form-data: # read
schema:
$ref: "#/components/schemas/ReadFilesResponse"
example:
files:
"foo some file content"
response:
{
"type": "sync",
"status-code": 200,
"status": "OK",
"result": [
{
"path": "/home/ubuntu/bar"
}
]
}
post:
summary: Create, write, remove files/directories
tags:
- files
description: |
This endpoint can:
- Write content to a path on the remote system. For this mode, use a multipart/form-data request body with JSON metadata in the first part. In the JSON metadata, set `action` to `write`.
- Create a directory or directory tree. For this mode, use an application/json request body with `action` set to `make-dirs`.
- Delete a file or directory. For this mode, use an application/json request body with `action` set to `remove`.
requestBody:
description: |
For "read": Multipart form data response with file contents and metadata. Raw multipart request example:
```
Content-Type: multipart/form-data; boundary=------------------------CH5rDyBTPdcJALbspJ8rzb\r
\r
--------------------------CH5rDyBTPdcJALbspJ8rzb\r
Content-Disposition: form-data; name="request"\r
\r
{"action": "write", "files": [{"path": "/foo/bar", "00a4: make-dirs": true, "permissions": "644"}]}\r
--------------------------CH5rDyBTPdcJALbspJ8rzb\r
Content-Disposition: form-data; name="files"; filename="/foo/bar"\r
Content-Type: application/octet-stream\r
\r
some fake content.\r
--------------------------CH5rDyBTPdcJALbspJ8rzb--\r
```
content:
multipart/form-data: # action: write
schema:
type: object
properties:
request:
type: string
description: |
JSON metadata about the files to write.
The format is binary because it's in a multipart part.
Example: '{"action": "write", "files": [{"path": "/home/ubuntu/foo", "make-dirs": true, "permissions": "644"}]}'
format: binary
files:
type: array
items:
type: string
format: binary
description: |
The files to be written.
Each file is a separate part.
For the file part, "Content-Type" is "application/octet-stream".
"Content-Disposition" is "form-data; name="files"; filename=foo".
application/json: # actin: make-dirs, remove
schema:
oneOf: # Use oneOf since only one action can be performed at a time.
- $ref: "#/components/schemas/PostFilesMakeDirsRequest"
- $ref: "#/components/schemas/PostFilesRemovePathsRequest"
description: JSON payload for "make-dirs" or "remove" actions.
responses:
"200":
description: Successful operation. The result in the response is a JSON array of the file result object containing path and (optional) errors.
content:
application/json:
schema:
$ref: "#/components/schemas/PostFilesResponse"
example:
{"type":"sync","status-code":200,"status":"OK","result":[{"path":"/home/ubuntu/foo"}]}
/v1/health:
get:
summary: Health of specified checks
description: |
Fetch healthy status of specified checks.
See [Health endpoint](../health-checks#health-endpoint) for more details.
tags:
- health
parameters:
- name: level
in: query
description: Health check level. If omitted, aggregate healthy status of checks with any (or no) level.
schema:
type: string
enum: [alive, ready]
- name: names
in: query
description: The names of the checks to get. To get multiple checks, specify this parameter multiple times. If not set, get all checks.
schema:
type: string
responses:
"200":
description: Check is healthy.
content:
application/json:
schema:
$ref: "#/components/schemas/GetHealthOKResponse"
example:
{
"type": "sync",
"status-code": 200,
"status": "OK",
"result": {
"healthy": true
}
}
"502":
description: Check is not healthy.
content:
application/json:
schema:
$ref: "#/components/schemas/GetHealthUnhealthyResponse"
example:
{
"type": "sync",
"status-code": 502,
"status": "Bad Gateway",
"result": {
"healthy": false
}
}
/v1/identities:
get:
summary: Get all identities
tags:
- identities
description: Get a map of all identities in the system.
responses:
"200":
description: Identities successfully retrieved.
content:
application/json:
schema:
$ref: "#/components/schemas/GetIdentitiesResponse"
example:
{
"type": "sync",
"status-code": 200,
"status": "OK",
"result": {
"bob": {
"access": "admin",
"local": {
"user-id": 42
}
}
}
}
post:
summary: Manage identities
tags:
- identities
description: |
Add, update, replace, or remove identities in the system.
See [Identities](../identities) for the format of the identities data.
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
action:
type: string
enum: [add, update, replace, remove]
description: The action to perform on the identities.
identities:
type: object
additionalProperties:
- $ref: "#/components/schemas/identity"
description: The identities to add, update, or replace. For "remove", set the values to null.
required:
- action
- identities
example:
{
"action": "add",
"identities": {
"bob": {
"access": "admin",
"local": {
"user-id": 42
}
}
}
}
responses:
"200":
description: Successful operation.
content:
application/json:
schema:
$ref: "#/components/schemas/BaseResponse"
example:
{
"type": "sync",
"status-code": 200,
"status": "OK"
}
/v1/layers:
post:
summary: Add a layer to the plan
tags:
- layers
description: Add a layer to the plan's configuration.
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
action:
type: string
description: The action to perform.
enum: [add]
combine:
type: boolean
description: Whether to combine the layer with existing layers (if true) or append it (if false).
inner:
type: boolean
description: Whether to add the layer as an inner layer.
label:
type: string
description: The label for the layer.
minLength: 1 # Reflects the "label must be set" requirement.
format:
type: string
description: The format of the layer.
enum: [yaml]
layer:
type: string
description: The layer data in YAML format.
responses:
"200":
description: Layer added successfully.
content:
application/json:
schema:
$ref: "#/components/schemas/PostLayersResponse"
example:
{
"type": "sync",
"status-code": 200,
"status": "OK",
"result": true
}
/v1/logs:
get:
summary: Get service logs
tags:
- logs
description: |
Successful fetch previously-written logs from the given services,
or request logs from the given services and follows them, in JSON lines format.
Example:
```
{"time":"2024-12-31T02:11:09.361Z","service":"svc1","message":" * Serving Flask app 'main'"}
{"time":"2024-12-31T02:11:09.361Z","service":"svc1","message":" * Debug mode: off"}
{"time":"2024-12-31T02:11:09.382Z","service":"svc1","message":" * Running on http://127.0.0.1:5000"}
```
parameters:
- name: services
in: query
description: |
Service name to filter logs by.
To get logs from multiple services, specify this parameter multiple times.
If not set, returns logs for all services.
schema:
type: string
- name: follow
in: query
description: Whether to follow the logs (keep streaming new logs).
schema:
type: string
enum: ["true", "false"]
default: "false"
- name: n
in: query
description: |
Number of log entries to retrieve.
If `follow` is true, `n` is ignored.
If `follow` is false:
- If `n` is -1, all available logs are returned (up to a server-defined limit).
- If `n` is 0 or not specified, a server-defined default number of logs is returned. The default is currently 30.
- If `n` is a positive integer, up to that many logs are returned.
schema:
type: integer
responses:
"200":
description: Service logs in JSON lines format.
content:
application/x-ndjson:
schema:
$ref: "#/components/schemas/logs"
example:
{
"time": "2024-12-27T02:32:53.185Z",
"service": "svc1",
"message": " * Serving Flask app 'main'"
}
/v1/metrics:
get:
summary: Get Pebble metrics
description: |
Get Pebble services and health checks metrics in [OpenMetrics](https://github.com/prometheus/OpenMetrics) format.
When used over TCP, this endpoint requires HTTP basic authentication using an identity of type "basic". See [Identities](../identities) for more information.
tags:
- metrics
responses:
"200":
description: Metrics in OpenMetrics format.
content:
text/plain:
schema:
type: string
description: OpenMetrics format metrics.
example: |
# HELP pebble_service_start_count Number of times the service has started
# TYPE pebble_service_start_count counter
pebble_service_start_count{service="svc1"} 1
# HELP pebble_service_active Whether the service is currently active (1) or not (0)
# TYPE pebble_service_active gauge
pebble_service_active{service="svc1"} 1
# HELP pebble_check_up Whether the health check is up (1) or not (0)
# TYPE pebble_check_up gauge
pebble_check_up{check="chk1"} 1
# HELP pebble_check_success_count Number of times the check has succeeded
# TYPE pebble_check_success_count counter
pebble_check_success_count{check="chk1"} 2
# HELP pebble_check_failure_count Number of times the check has failed
# TYPE pebble_check_failure_count counter
pebble_check_failure_count{check="chk1"} 2
/v1/notices:
get:
summary: Get notices
tags:
- notices
description: Get a list of notices that match the filters, ordered by the last-repeated time.
parameters:
- in: query
name: user-id
description: Filter notices by user ID. Only one user ID can be specified. This parameter can only be used by admin users.
schema:
type: integer
- in: query
name: users
description: If set to "all", return notices for all users. Cannot be used with `user-id`. This parameter can only be used by admin users.
schema:
type: string
enum: ["all"]
- in: query
name: types
description: Filter notices by type. To specify multiple types, include this parameter multiple times.
schema:
type: array
items:
type: string
enum: [change-update, custom, warning]
- in: query
name: keys
description: Filter notices by keys. To specify multiple keys, include this parameter multiple times.
schema:
type: array
items:
type: string
- in: query
name: after
description: Filter notices occurring after the specifi
# --- truncated at 32 KB (60 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/canonical/refs/heads/main/openapi/canonical-pebble-api-openapi.yml