moonraker/docs/web_api.md

220 KiB

Most API methods are supported over the Websocket, HTTP, and MQTT (if configured) transports. File Transfer requests (upload and download) exclusive to HTTP. The Websocket is required to receive server generated events such as gcode responses. For information on how to set up the Websocket, please see the Appendix at the end of this document.

HTTP API Overview

Moonraker's HTTP API could best be described as "RESTish". Attempts are made to conform to REST standards, however the dynamic nature of Moonraker's API registration along with the desire to keep consistency between multiple API protocols results in an HTTP API that does not completely adhere to the standard.

Moonraker is capable of parsing request arguments from the both the body (either JSON or form-data depending on the Content-Type header) and from the query string. All arguments are grouped together in one data structure, with body arguments taking precedence over query arguments. Thus if the same argument is supplied both in the body and in the query string the body argument would be used. It is left up to the client developer to decide exactly how they want to provide arguments, however future API documentation will make recommendations. As of March 1st 2021 this document exclusively illustrates arguments via the query string.

All successful HTTP requests will return a json encoded object in the form of:

{result: <response data>}

Response data is generally an object itself, however for some requests this may simply be an "ok" string.

Should a request result in an error, a standard error code along with an error specific message is returned.

Query string type hints

By default all arguments passed via the query string are represented as strings. Most endpoint handlers know the data type for each of their arguments, thus they can perform conversion from a string type if necessary. However some endpoints accept arguments of a "generic" type, thus the client is responsible for specifying the type if "string" is not desirable. This is not a problem for websocket requests as the JSON parser can extract the appropriate type. HTTP requests must provide "type hints" in these scenarios. Moonraker supplies support for the following query string type hints:

  • int
  • bool
  • float
  • json The json type hint can be specified to pass an array or an object via the query string. Remember to percent encode the json string so that the query string is correctly parsed.

Type hints may be specified by post-fixing them to a key, with a ":" separating the key and the hint. For example, lets assume that we have a request that takes seconds (integer) and enabled (boolean) arguments. The query string with type hints might look like:

?seconds:int=120&enabled:bool=true

A query string that takes a value argument with which we want to pass an object, {foo: 21.5, bar: "hello"} might look like:

?value:json=%7B%22foo%22%3A21.5%2C%22bar%22%3A%22hello%22%7D

As you can see, a percent encoded json string is not human readable, thus using this functionality should be seen as a "last resort." If at all possible clients should attempt to put these arguments in the body of a request.

JSON-RPC API Overview

The Websocket and MQTT transports use the JSON-RPC 2.0 protocol. The Websocket transmits JSON-RPC objects in a text frame, whereas MQTT transmits them in the payload of a topic. When MQTT is configured Moonraker subscribes to an api request topic. After an api request is processed Moonraker publishes the return value to a response topic. By default these topics are {instance_name}/moonraker/api/request and {instance_name}/moonraker/api/response. The {instance_name} should be a unique identifier for each instance of Moonraker and defaults to the machine's host name.

In addition, most JSON-RPC methods are available via the JSONRPC HTTP request.

An encoded request should look something like:

{
    "jsonrpc": "2.0",
    "method": "API method",
    "params": {"arg_one": 1, "arg_two": true},
    "id": 354
}

The params field may be left out if the API request takes no arguments. The id should be a unique value that has no chance of colliding with other JSON-RPC requests. The method is the API method, as defined for each API in this document.

!!! tip MQTT requests may provide an optional mqtt_timestamp keyword argument in the params field of the JSON-RPC request. To avoid potential collisions from time drift it is recommended to specify the timestamp in microseconds since the Unix Epoch. If provided Moonraker will use the timestamp to discard duplicate requests. It is recommended to either provide a timestamp or publish API requests at a QoS level of 0 or 2.

A successful request will return a response like the following:

{
    "jsonrpc": "2.0",
    "result": {"res_data": "success"},
    "id": 354
}

The result will generally contain an object, but as with the HTTP API in some cases it may simply return a string. The id field will return an id that matches the one provided by the request.

Requests that result in an error will receive a properly formatted JSON-RPC response:

{
    "jsonrpc": "2.0",
    "error": {"code": 36000, "message": "Error Message"},
    "id": 354
}

Some errors may not return a request ID, such as an improperly formatted request.

The moontest repo includes a basic test interface with example usage for most of the requests below. It also includes a basic JSON-RPC implementation that uses promises to return responses and errors (see json-rpc.js).

Websocket Connections

Primary websocket

The primary websocket supports Moonraker's JSON-RPC API. Most applications that desire a websocket connection will make use of the primary websocket.

The primary websocket is available at:

 ws://host_or_ip:port/websocket`

The primary websocket will remain connected until the application disconnects or Moonraker is shutdown.

Bridge websocket

The "bridge" websocket provides a near direct passthrough to Klipper's API Server. Klipper uses its own RPC protocol, which is effectively a simplified version of the JSON-RPC specification. Developers should refer to Klipper's API documentation for details on the protocol and available APIs.

!!! Note The bridge websocket is described as "near direct passthrough" because Moonraker handles the ETX (0x03) terminator internally. Applications can expect to receive complete JSON encoded messages in a text frame without the ETX terminator. Likewise applications should send JSON encoded messages without the ETX terminator. Messages may be sent using either text frames or binary frames.

The bridge websocket provides access to diagnostic APIs that are not generally suitable for Moonraker's primary connection. These requests stream a substantial amount of data; bridge connections allow Moonraker to avoid decoding and re-encoding this data, reducing CPU load on the host. The "dump" requests, such as motion_report/dump_stepper and adxl345/dump_adxl345, are examples of APIs that should make use of the bridge websocket.

The bridge websocket is available at:

ws://host_or_ip:port/klippysocket

The availability of bridge connections depends on Klippy's availablility. If Klippy is not running or its API server is not enabled then a bridge websocket connection cannot be established. Established bridge connections will close when Klippy is shutdown or restarted. Such connections will also be closed if Moonraker is restarted or shutdown.

!!! Note If JWT or API Key authentication is required the application must use a oneshot token when connecting to a bridge socket. Since Moonraker does not decode bridge requests it is not possible to authenticate post connection.

Unix Socket Connection

All JSON-RPC APIs available over the Websocket transport are also available over the Unix Domain Socket connection. Moonraker creates the socket file at <datapath>/comms/moonraker.sock (ie: ~/printer_data/comms/moonraker.sock). The Unix Socket expects UTF-8 encoded JSON-RPC byte strings. Each JSON-RPC request must be terminated with an ETX character (0x03).

The Unix Socket is desirable for front ends and extensions running on the local machine as authentication is not necessary. There should be a small performance improvement due to the simplified transport protocol, however the impact of this is likely negligible.

The moontest repo contains a python script to test comms over the unix socket.

Jinja2 Template API Calls

Some template options in Moonraker's configuration, such as those in the button component, may call Moonraker APIs through the call_method(method_name, kwargs) context function. The call_method function takes the API's JSON-RPC method name as its first parameter, followed by a set of keyword arguments as per the method's requirements.

# moonraker.conf

# Query Printer Objects example
[button check_status]
pin: gpio26
on_press:
  {% set query_objs = {"toolhead": ["position"], "print_stats": None} %}
  # JSON-RPC method is "printer.objects.query", which takes a single "objects"
  # argument
  {% set status = call_method("printer.objects.query", objects=query_objs) %}
  # do something with the value returned from the object query, perhaps
  # send a websocket notification or publish a mqtt topic

# Publish button event to MQTT Topic
[button check_status]
pin: gpio26
on_release:
  # JSON-RPC method is "server.mqtt.publish"
  {% do call_method("server.mqtt.publish",
                    topic="moonraker/mybutton",
                    payload="Button Released") %}

Server Administration

Query Server Info

HTTP request:

GET /server/info

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "server.info",
    "id": 9546
}

Returns:

An object containing various fields that report server state.

  {
    "klippy_connected": true,
    "klippy_state": "ready",
    "components": [
        "database",
        "file_manager",
        "klippy_apis",
        "machine",
        "data_store",
        "shell_command",
        "proc_stats",
        "history",
        "octoprint_compat",
        "update_manager",
        "power"
    ],
    "failed_components": [],
    "registered_directories": ["config", "gcodes", "config_examples", "docs"],
    "warnings": [
        "Invalid config option 'api_key_path' detected in section [authorization]. Remove the option to resolve this issue. In the future this will result in a startup error.",
        "Unparsed config section [fake_section] detected.  This may be the result of a component that failed to load.  In the future this will result in a startup error."
    ],
    "websocket_count": 2,
    "moonraker_version": "v0.7.1-105-ge4f103c",
    "api_version": [1, 0, 0],
    "api_version_string": "1.0.0"
  }

!!! warning This object also includes plugins and failed_plugins fields that are now deprecated. They duplicate the information in components and failed_components, and will be removed in the future.

Note that klippy_state will match the state value received from /printer/info. The klippy_connected item tracks the state of the unix domain socket connect to Klippy. The components key will return a list of enabled components. This can be used by clients to check if an optional component is available. Optional components that do not load correctly will not prevent the server from starting, thus any components that failed to load will be reported in the failed_components field.

The websocket_count field reports the total number of connected websockets.

Get Server Configuration

HTTP request:

GET /server/config

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "server.config",
    "id": 5616
}

Returns:

An object containing the server's full configuration. Note that this includes auxiliary configuration sections not part of moonraker.conf, for example the update_manager static debian moonraker section. Options not specified in moonraker.conf with default values are also included.

{
    {
        "config": {
            "server": {
                "host": "0.0.0.0",
                "port": 7125,
                "ssl_port": 7130,
                "enable_debug_logging": true,
                "enable_asyncio_debug": false,
                "klippy_uds_address": "/tmp/klippy_uds",
                "max_upload_size": 210,
                "ssl_certificate_path": null,
                "ssl_key_path": null
            },
            "dbus_manager": {},
            "database": {
                "database_path": "~/.moonraker_database",
                "enable_database_debug": false
            },
            "file_manager": {
                "enable_object_processing": true,
                "queue_gcode_uploads": true,
                "config_path": "~/printer_config",
                "log_path": "~/logs"
            },
            "klippy_apis": {},
            "machine": {
                "provider": "systemd_dbus"
            },
            "shell_command": {},
            "data_store": {
                "temperature_store_size": 1200,
                "gcode_store_size": 1000
            },
            "proc_stats": {},
            "job_state": {},
            "job_queue": {
                "load_on_startup": true,
                "automatic_transition": false,
                "job_transition_delay": 2,
                "job_transition_gcode": "\nM118 Transitioning to next job..."
            },
            "http_client": {},
            "announcements": {
                "dev_mode": false,
                "subscriptions": []
            },
            "authorization": {
                "login_timeout": 90,
                "force_logins": false,
                "cors_domains": [
                    "*.home",
                    "http://my.mainsail.xyz",
                    "http://app.fluidd.xyz",
                    "*://localhost:*"
                ],
                "trusted_clients": [
                    "192.168.1.0/24"
                ]
            },
            "zeroconf": {},
            "octoprint_compat": {
                "enable_ufp": true,
                "flip_h": false,
                "flip_v": false,
                "rotate_90": false,
                "stream_url": "/webcam/?action=stream",
                "webcam_enabled": true
            },
            "history": {},
            "secrets": {
                "secrets_path": "~/moonraker_secrets.ini"
            },
            "mqtt": {
                "address": "eric-work.home",
                "port": 1883,
                "username": "{secrets.mqtt_credentials.username}",
                "password_file": null,
                "password": "{secrets.mqtt_credentials.password}",
                "mqtt_protocol": "v3.1.1",
                "instance_name": "pi-debugger",
                "default_qos": 0,
                "status_objects": {
                    "webhooks": null,
                    "toolhead": "position,print_time",
                    "idle_timeout": "state",
                    "gcode_macro M118": null
                },
                "api_qos": 0,
                "enable_moonraker_api": true
            },
            "template": {}
        },
        "orig": {
            "DEFAULT": {},
            "server": {
                "enable_debug_logging": "True",
                "max_upload_size": "210"
            },
            "file_manager": {
                "config_path": "~/printer_config",
                "log_path": "~/logs",
                "queue_gcode_uploads": "True",
                "enable_object_processing": "True"
            },
            "machine": {
                "provider": "systemd_dbus"
            },
            "announcements": {},
            "job_queue": {
                "job_transition_delay": "2.",
                "job_transition_gcode": "\nM118 Transitioning to next job...",
                "load_on_startup": "True"
            },
            "authorization": {
                "trusted_clients": "\n192.168.1.0/24",
                "cors_domains": "\n*.home\nhttp://my.mainsail.xyz\nhttp://app.fluidd.xyz\n*://localhost:*"
            },
            "zeroconf": {},
            "octoprint_compat": {},
            "history": {},
            "secrets": {
                "secrets_path": "~/moonraker_secrets.ini"
            },
            "mqtt": {
                "address": "eric-work.home",
                "port": "1883",
                "username": "{secrets.mqtt_credentials.username}",
                "password": "{secrets.mqtt_credentials.password}",
                "enable_moonraker_api": "True",
                "status_objects": "\nwebhooks\ntoolhead=position,print_time\nidle_timeout=state\ngcode_macro M118"
            }
        },
        "files": [
            {
                "filename": "moonraker.conf",
                "sections": [
                    "server",
                    "file_manager",
                    "machine",
                    "announcements",
                    "job_queue",
                    "authorization",
                    "zeroconf",
                    "octoprint_compat",
                    "history",
                    "secrets"
                ]
            },
            {
                "filename": "include/extras.conf",
                "sections": [
                    "mqtt"
                ]
            }
        ]
    }
}

Request Cached Temperature Data

HTTP request:

GET /server/temperature_store?include_monitors=false

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "server.temperature_store",
    "params": {
        "include_monitors": false
    },
    "id": 2313
}

Parameters:

  • include_monitors: Optional, defaults to false. When set to true the response will include sensors reported as temperature monitors by Klipper. A temperature monitor may report null values in the temperatures field, applications should be sure that they are modified to handle this condition before setting inlcude_monitors to true.

Returns:

An object where the keys are the available temperature sensor names, and with the value being an array of stored temperatures. The array is updated every 1 second by default, containing a total of 1200 values (20 minutes). The array is organized from oldest temperature to most recent (left to right). Note that when the host starts each array is initialized to 0s.

{
    "extruder": {
        "temperatures": [21.05, 21.12, 21.1, 21.1, 21.1],
        "targets": [0, 0, 0, 0, 0],
        "powers": [0, 0, 0, 0, 0]
    },
    "temperature_fan my_fan": {
        "temperatures": [21.05, 21.12, 21.1, 21.1, 21.1],
        "targets": [0, 0, 0, 0, 0],
        "speeds": [0, 0, 0, 0, 0],
    },
    "temperature_sensor my_sensor": {
        "temperatures": [21.05, 21.12, 21.1, 21.1, 21.1]
    }
}

Request Cached GCode Responses

HTTP request:

GET /server/gcode_store?count=100

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "server.gcode_store",
    "params": {
        "count": 100
    },
    "id": 7643}

The count argument is optional, limiting number of returned items in the response to the value specified. If omitted, the entire gcode store will be returned (up to 1000 responses).

Returns:

An object with the field gcode_store that contains an array of objects. Each object will contain message, time, and type fields. The time field is reported in Unix Time. The type field will either be command or response.

{
    "gcode_store": [
        {
            "message": "FIRMWARE_RESTART",
            "time": 1615832299.1167388,
            "type": "command"
        },
        {
            "message": "// Klipper state: Ready",
            "time": 1615832309.9977088,
            "type": "response"
        },
        {
            "message": "M117 This is a test",
            "time": 1615834094.8662775,
            "type": "command"
        },
        {
            "message": "G4 P1000",
            "time": 1615834098.761729,
            "type": "command"
        },
        {
            "message": "STATUS",
            "time": 1615834104.2860553,
            "type": "command"
        },
        {
            "message": "// Klipper state: Ready",
            "time": 1615834104.3299904,
            "type": "response"
        }
    ]
}

Rollover Logs

Requests a manual rollover for log files registered with Moonraker's log management facility. Currently these are limited to moonraker.log and klippy.log.

HTTP request:

POST /server/logs/rollover
Content-Type: application/json

{
    "application": "moonraker"
}

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "server.logs.rollover",
    "params": {
        "application": "moonraker"
    },
    "id": 4656
}

Parameters:

  • application - (Optional) The name of the application to rollover. Currently can be moonraker or klipper. The default is to rollover all logs.

!!! Note Moonraker must be able to manage Klipper's systemd service to perform a manual rollover. The rollover will fail under the following conditions:

- Moonraker cannot detect Klipper's systemd unit
- Moonraker cannot detect the location of Klipper's files
- A print is in progress

Returns: An object in the following format:

{
    "rolled_over": [
        "moonraker",
        "klipper"
    ],
    "failed": {}
}
  • rolled_over - An array of application names successfully rolled over.
  • failed - An object containing information about failed applications. The key will match an application name and its value will be an error message.

Restart Server

HTTP request:

POST /server/restart

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "server.restart",
    "id": 4656
}

Returns:

ok upon receipt of the restart request. After the request is returns, the server will restart. Any existing connection will be disconnected. A restart will result in the creation of a new server instance where the configuration is reloaded.

Identify Connection

This method provides a way for persistent clients to identify themselves to Moonraker. This information may be used by Moonraker perform an action or present information based on if a specific client is connected. Currently this method is only available to websocket and unix socket connections. Once this endpoint returns success it cannot be called again, repeated calls will result in an error.

HTTP request: Not Available

JSON-RPC request (Websocket/Unix Socket Only):

{
    "jsonrpc": "2.0",
    "method": "server.connection.identify",
    "params": {
        "client_name": "moontest",
        "version": "0.0.1",
        "type": "web",
        "url": "http://github.com/arksine/moontest",
        "access_token": "<base64 encoded token>",
        "api_key": "<system API key>"
    },
    "id": 4656
}

Parameters:

  • client_name: (required) The name of your client, such as Mainsail, Fluidd, KlipperScreen, MoonCord, etc.
  • version: (required) The current version of the connected client
  • type: (required) Application type. May be one of web, mobile, desktop, display, bot, agent or other. These should be self explanatory, use other if your client does not fit any of the prescribed options.
  • url: (required) The url for your client's homepage
  • access_token: (optional) A JSON Web Token that may be used to assign a logged in user to the connection. See the authorization section for APIs used to create and refresh the access token.
  • api_key:. (optional) The system API Key. This key may be used to grant access to clients that do not wish to implement user authentication. Note that if the access_token is also supplied then this parameter will be ignored.

!!! Note When identifying as an agent, only one instance should be connected to Moonraker at a time. If multiple agents of the same client_name attempt to identify themselves this endpoint will return an error. See the extension APIs for more information about agents.

Returns:

The connection's unique identifier.

{
    "connection_id": 1730367696
}

Get Websocket ID

!!! Warning This method is deprecated. Please use the identify endpoint to retrieve the Websocket's UID

HTTP request: Not Available

JSON-RPC request (Websocket/Unix Socket Only):

{
    "jsonrpc": "2.0",
    "method": "server.websocket.id",
    "id": 4656
}

Returns:

The connected websocket's unique identifier.

{
    "websocket_id": 1730367696
}

JSON-RPC over HTTP

Exposes the JSON-RPC interface over HTTP. All JSON-RPC methods with corresponding HTTP APIs are available. Methods exclusive to other transports, such as Identify Connection, are not available.

HTTP request:

POST /server/jsonrpc
Content-Type: application/json
{
    "jsonrpc": "2.0",
    "method": "printer.info",
    "id": 5153
}

!!! Note If authentication is required it must be part of the HTTP request, either using the API Key Header (X-Api-Key) or JWT Bearer Token.

Returns:

The full JSON-RPC response.

{
    "jsonrpc": "2.0",
    "id": 5153,
    "result": {
        "state": "ready",
        "state_message": "Printer is ready",
        "hostname": "my-pi-hostname",
        "software_version": "v0.9.1-302-g900c7396",
        "cpu_info": "4 core ARMv7 Processor rev 4 (v7l)",
        "klipper_path": "/home/pi/klipper",
        "python_path": "/home/pi/klippy-env/bin/python",
        "log_file": "/tmp/klippy.log",
        "config_file": "/home/pi/printer.cfg",
    }
}

!!! Note This request will never return an HTTP error. When an error is encountered a JSON-RPC error response will be returned.

Printer Administration

Get Klippy host information

HTTP Request:

GET /printer/info

JSON-RPC Request:

{
    "jsonrpc": "2.0",
    "method": "printer.info",
    "id": 5445
}

Returns:

An object containing the build version, cpu info, Klippy's current state.

{
    "state": "ready",
    "state_message": "Printer is ready",
    "hostname": "my-pi-hostname",
    "software_version": "v0.9.1-302-g900c7396",
    "cpu_info": "4 core ARMv7 Processor rev 4 (v7l)",
    "klipper_path": "/home/pi/klipper",
    "python_path": "/home/pi/klippy-env/bin/python",
    "log_file": "/tmp/klippy.log",
    "config_file": "/home/pi/printer.cfg",
}

Emergency Stop

HTTP request:

POST /printer/emergency_stop

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "printer.emergency_stop",
    "id": 4564
}

!!! note This endpoint will immediately halt the printer and put it in a "shutdown" state. It should be used to implement an "emergency stop" button and also used if a user enters M112(emergency stop) via a console.

Returns:

ok

Host Restart

HTTP request:

POST /printer/restart

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "printer.restart",
    "id": 4894
}

Returns:

ok

Firmware Restart

HTTP request:

POST /printer/firmware_restart

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "printer.firmware_restart",
    "id": 8463
}

Returns:

ok

Printer Status

List available printer objects

HTTP request:

GET /printer/objects/list

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "printer.objects.list",
    "id": 1454
}

Returns:

An array of "printer objects" that are currently available for query or subscription. This list will be passed in an objects parameter.

{
    "objects": ["gcode", "toolhead", "bed_mesh", "configfile",...]
}

Query printer object status

HTTP request:

GET /printer/objects/query?gcode_move&toolhead&extruder=target,temperature

The above will request a status update for all gcode_move and toolhead attributes. Only the temperature and target attributes are requested for the extruder.

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "printer.objects.query",
    "params": {
        "objects": {
            "gcode_move": null,
            "toolhead": ["position", "status"]
        }
    },
    "id": 4654
}

!!! note A null value will fetch all available attributes for its key.

Returns:

An object where the top level items are "eventtime" and "status". The "status" item contains data about the requested update.

{
    "eventtime": 578243.57824499,
    "status": {
        "gcode_move": {
            "absolute_coordinates": true,
            "absolute_extrude": true,
            "extrude_factor": 1,
            "gcode_position": [0, 0, 0, 0],
            "homing_origin": [0, 0, 0, 0],
            "position": [0, 0, 0, 0],
            "speed": 1500,
            "speed_factor": 1,
        },
        "toolhead": {
            "position": [0, 0, 0, 0],
            "status": "Ready"
        }
    }
}

See Klipper's status reference for details on the printer objects available for query.

Subscribe to printer object status

HTTP request:

POST /printer/objects/subscribe?connection_id=123456789&gcode_move&extruder`

!!! note The HTTP API requires that a connection_id is passed via the query string or as part of the form. This should be the ID reported from a currently connected websocket. A request that includes only the connection_id argument will cancel the subscription on the specified websocket.

This request is not available over MQTT as it can not be set per client.
Instead MQTT can publish printer status by setting the `status_objects`
option in the `[mqtt]` section.

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "printer.objects.subscribe",
    "params": {
        "objects": {
            "gcode_move": null,
            "toolhead": ["position", "status"]
        }
    },
    "id": 5434
}

!!! note If objects is set to an empty object then the subscription will be cancelled.

Returns:

Status data for objects in the request, with the format matching that of the /printer/objects/query:

{
    "eventtime": 578243.57824499,
    "status": {
        "gcode_move": {
            "absolute_coordinates": true,
            "absolute_extrude": true,
            "extrude_factor": 1,
            "gcode_position": [0, 0, 0, 0],
            "homing_origin": [0, 0, 0, 0],
            "position": [0, 0, 0, 0],
            "speed": 1500,
            "speed_factor": 1,
        },
        "toolhead": {
            "position": [0, 0, 0, 0],
            "status": "Ready"
        }
    }
}

See Klipper's status reference for details on the printer objects available for subscription.

Status updates for subscribed objects are sent asynchronously over the websocket. See the notify_status_update notification for details.

Query Endstops

HTTP request:

GET /printer/query_endstops/status

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "printer.query_endstops.status",
    "id": 3456
}

Returns:

An object containing the current endstop state, where each field is an endstop identifier, with a string value of "open" or "TRIGGERED".

{
    "x": "TRIGGERED",
    "y": "open",
    "z": "open"
}

GCode APIs

Run a gcode:

HTTP request:

POST /printer/gcode/script?script=G28

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "printer.gcode.script",
    "params": {
        "script": "G28"
    },
    "id": 7466}

!!! warning When M112(emergency stop) is requested via this endpoint it will not immediately stop the printer. M112 will be placed on the gcode queue and executed after all previous gcodes are complete. If a client detects M112 via user input (such as a console) it should request the /printer/emergency_stop endpoint to immediately halt the printer. This may be done in addition to sending the M112 gcode if desired.

Returns:

ok when the gcode has completed execution.

Get GCode Help

HTTP request:

GET /printer/gcode/help

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "printer.gcode.help",
    "id": 4645
}

Returns:

An object where they keys are gcode handlers and values are the associated help strings. Note that help strings are not available for default gcode handlers such as G1, G28, etc, nor are they available for extended handlers that failed to register a description in Klippy.

{
    "RESTORE_GCODE_STATE": "Restore a previously saved G-Code state",
    "PID_CALIBRATE": "Run PID calibration test",
    "QUERY_ADC": "Report the last value of an analog pin",
    "TUNING_TOWER": "Tool to adjust a parameter at each Z height",
    "SAVE_CONFIG": "Overwrite config file and restart",
    "SET_DISPLAY_GROUP": "Set the active display group",
    "SAVE_GCODE_STATE": "Save G-Code coordinate state",
    "SET_PRESSURE_ADVANCE": "Set pressure advance parameters",
    "SET_GCODE_OFFSET": "Set a virtual offset to g-code positions",
    "BED_TILT_CALIBRATE": "Bed tilt calibration script",
    ...
}

Print Management

Print a file

HTTP request:

POST /printer/print/start?filename=test_print.gcode

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "printer.print.start",
    "params": {
        "filename": "test_pring.gcode"
    },
    "id": 4654
}

Returns:

ok

Pause a print

HTTP request:

POST /printer/print/pause

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "printer.print.pause",
    "id": 4564
}

Returns:

ok

Resume a print

HTTP request:

POST /printer/print/resume

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "printer.print.resume",
    "id": 1465
}

Returns:

ok

Cancel a print

HTTP request:

POST /printer/print/cancel

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "printer.print.cancel",
    "id": 2578
}

Returns:

ok

Machine Requests

Get System Info

HTTP request:

GET /machine/system_info

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "machine.system_info",
    "id": 4665
}

Returns: Information about the host system in the following format:

{
    "system_info": {
        "cpu_info": {
            "cpu_count": 4,
            "bits": "32bit",
            "processor": "armv7l",
            "cpu_desc": "ARMv7 Processor rev 4 (v7l)",
            "serial_number": "b898bdb4",
            "hardware_desc": "BCM2835",
            "model": "Raspberry Pi 3 Model B Rev 1.2",
            "total_memory": 945364,
            "memory_units": "kB"
        },
        "sd_info": {
            "manufacturer_id": "03",
            "manufacturer": "Sandisk",
            "oem_id": "5344",
            "product_name": "SU32G",
            "product_revision": "8.0",
            "serial_number": "46ba46",
            "manufacturer_date": "4/2018",
            "capacity": "29.7 GiB",
            "total_bytes": 31914983424
        },
        "distribution": {
            "name": "Raspbian GNU/Linux 10 (buster)",
            "id": "raspbian",
            "version": "10",
            "version_parts": {
                "major": "10",
                "minor": "",
                "build_number": ""
            },
            "like": "debian",
            "codename": "buster"
        },
        "available_services": [
            "klipper",
            "klipper_mcu",
            "moonraker"
        ],
        "instance_ids": {
            "moonraker": "moonraker",
            "klipper": "klipper"
        },
        "service_state": {
            "klipper": {
                "active_state": "active",
                "sub_state": "running"
            },
            "klipper_mcu": {
                "active_state": "active",
                "sub_state": "running"
            },
            "moonraker": {
                "active_state": "active",
                "sub_state": "running"
            }
        },
        "virtualization": {
            "virt_type": "none",
            "virt_identifier": "none"
        },
        "python": {
            "version": [
                3,
                7,
                3,
                "final",
                0
            ],
            "version_string": "3.7.3 (default, Jan 22 2021, 20:04:44)  [GCC 8.3.0]"
        },
        "network": {
            "wlan0": {
                "mac_address": "<redacted_mac>",
                "ip_addresses": [
                    {
                        "family": "ipv4",
                        "address": "192.168.1.127",
                        "is_link_local": false
                    },
                    {
                        "family": "ipv6",
                        "address": "<redacted_ipv6>",
                        "is_link_local": false
                    },
                    {
                        "family": "ipv6",
                        "address": "fe80::<redacted>",
                        "is_link_local": true
                    }
                ]
            }
        },
        "canbus": {
            "can0": {
                "tx_queue_len": 128,
                "bitrate": 500000,
                "driver": "mcp251x"
            },
            "can1": {
                "tx_queue_len": 128,
                "bitrate": 500000,
                "driver": "gs_usb"
            }
        }
    }
}

!!! note If no SD Card is detected the sd_info field will contain an empty object.

Shutdown the Operating System

HTTP request:

POST /machine/shutdown

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "machine.shutdown",
    "id": 4665
}

Returns:

This request will not return. The machine will shutdown and the socket connection will drop.

Reboot the Operating System

HTTP request:

POST /machine/reboot

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "machine.reboot",
    "id": 4665
}

Returns:

This request will not return. The machine will reboot and the socket connection will drop.

Restart a system service

Uses: sudo systemctl restart {name}

Services allowed:

  • crowsnest
  • MoonCord
  • moonraker
  • moonraker-telegram-bot
  • klipper
  • KlipperScreen
  • sonar
  • webcamd

HTTP request:

POST /machine/services/restart?service={name}

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "machine.services.restart",
    "params": {
        "service": "{name}"
    },
    "id": 4656}

Returns:

ok when complete. !!! note If moonraker is chosen, the return value will be sent prior to the service restart.

Stop a system service

Stops a system service via sudo systemctl stop <name>. Currently only webcamd and klipper are supported.

HTTP request:

POST /machine/services/stop?service={name}

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "machine.services.stop",
    "params": {
        "service": "{name}"
    },
    "id": 4645
}

Returns:

ok

Start a system service

Starts a system service via sudo systemctl start <name>. Currently only webcamd and klipper are supported.

HTTP request:

POST /machine/services/start?service={name}

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "machine.services.start",
    "params": {
        "service": "{name}"
    },
    "id": 4645
}

Returns:

ok

Get Moonraker Process Stats

Returns system usage information about the moonraker process.

HTTP request:

GET /machine/proc_stats

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "machine.proc_stats",
    "id": 7896
}

Returns:

An object in the following format:

{
    "moonraker_stats": [
        {
            "time": 1626612666.850755,
            "cpu_usage": 2.66,
            "memory": 24732,
            "mem_units": "kB"
        },
        {
            "time": 1626612667.8521338,
            "cpu_usage": 2.62,
            "memory": 24732,
            "mem_units": "kB"
        }
    ],
    "throttled_state": {
        "bits": 0,
        "flags": []
    },
    "cpu_temp": 45.622,
    "network": {
        "lo": {
            "rx_bytes": 113516429,
            "tx_bytes": 113516429,
            "bandwidth": 3342.68
        },
        "wlan0": {
            "rx_bytes": 48471767,
            "tx_bytes": 113430843,
            "bandwidth": 4455.91
        }
    },
    "system_cpu_usage": {
        "cpu": 2.53,
        "cpu0": 3.03,
        "cpu1": 5.1,
        "cpu2": 1.02,
        "cpu3": 1
    },
    "system_uptime": 2876970.38089603,
    "websocket_connections": 4
}

Process information is sampled every second. The moonraker_stats field will return up to 30 samples, each sample with the following fields:

  • time: Time of the sample (in seconds since the Epoch)
  • cpu_usage: A floating point value between 0-100, representing the CPU usage of the Moonraker process.
  • memory: Integer value representing the current amount of memory allocated in RAM (resident set size).
  • mem_units: A string identifying the units of the value in the memory field. This is typically "kB", but not guaranteed.

If the system running Moonraker supports vcgencmd then Moonraker will check the current throttled flags via vcgencmd get_throttled and report them in the throttled_state field:

  • bits: An integer value that represents the bits reported by vcgencmd get_throttled
  • flags: Descriptive flags parsed out of the bits. One or more of the following flags may be reported:
  • "Under-Voltage Detected"
  • "Frequency Capped"
  • "Currently Throttled"
  • "Temperature Limit Active"
  • "Previously Under-Volted"
  • "Previously Frequency Capped"
  • "Previously Throttled"
  • "Previously Temperature Limited"

The first four flags indicate an active throttling condition, whereas the last four indicate a previous condition (may or may not still be active). If vcgencmd is not available throttled_state will report null.

If the system reports CPU temp at /sys/class/thermal/thermal_zone0 then temperature will be supplied in the cpu_temp field. Otherwise the field will be set to null.

If the system reports network statistics at /proc/net/dev then the network field will contain network statistics. All available interfaces will be tracked. Each interface reports the following fields:

  • rx_bytes: total number of bytes received over the interface
  • tx_bytes: total number of bytes transferred over the interface
  • bandwidth: estimated current bandwidth used (both rx and tx) in bytes/second

If network information is not available then the network field will contain an empty object.

If the system reports cpu usage at /proc/stat then the system_cpu_usage field will contain an object with cpu usage data. The cpu field of this object reports total cpu usage, while each cpuX field is usage per core.

The websocket_connections field reports the number of active websockets currently connected to moonraker.

Get Sudo Info

Retrieve sudo information status. Optionally checks if Moonraker has permission to run commands as root.

HTTP request:

GET /machine/sudo/info?check_access=false

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "machine.sudo.info",
    "params": {
        "check_access": false
    },
    "id": 7896
}

Parameters:

  • check_access: A boolean value, when set to true Moonraker will attempt to run a command with elevated permissions. The result will be returned in the sudo_access field of the response. Defaults to false.

Returns:

An object in the following format:

{
    "sudo_access": null,
    "linux_user": "pi",
    "sudo_requested": false,
    "request_messages": []
}
  • sudo_access: The result of a request to check access. Returns true if Moonraker has sudo permission, false if it does not, and null if check_access is false.
  • linux_user: The current linux user running Moonraker.
  • sudo_requested: Returns true if Moonraker is currently requesting sudo access.
  • request_messages: An array of strings, each string describing a pending sudo request. The array will be empty if no sudo requests are pending.

Set sudo password

Sets/updates the sudo password currently used by Moonraker. When the password is set using this endpoint the change is not persistent across restarts. If Moonraker has one or more pending sudo requests they will be processed.

HTTP request:

POST /machine/sudo/password
Content-Type: application/json

{
    "password": "linux_user_password"
}

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "machine.sudo.password",
    "params": {
        "password": "linux_user_password"
    },
    "id": 7896
}

Parameters:

  • password: The linux user password used to grant elevated permission. This parameter must be provided.

Returns:

An object in the following format:

{
    "sudo_responses": [
        "Sudo password successfully set."
    ],
    "is_restarting": false
}
  • sudo_responses: An array of one or more sudo responses. If there are pending sudo requests each request will provide a response.
  • is_restarting: A boolean value indicating that a sudo request prompted Moonraker to restart its service.

This request will return an error if the supplied password is incorrect or if any pending sudo requests fail.

List USB Devices

Returns a list of all USB devices currently detected on the system.

GET /machine/peripherals/usb
{
    "jsonrpc": "2.0",
    "method": "machine.peripherals.usb",
    "id": 7896
}

/// api-example-response

{
    "usb_devices": [
        {
            "device_num": 1,
            "bus_num": 1,
            "vendor_id": "1d6b",
            "product_id": "0002",
            "usb_location": "1:1",
            "manufacturer": "Linux 6.1.0-rpi7-rpi-v8 dwc_otg_hcd",
            "product": "DWC OTG Controller",
            "serial": "3f980000.usb",
            "class": "Hub",
            "subclass": null,
            "protocol": "Single TT",
            "description": "Linux Foundation 2.0 root hub"
        },
        {
            "device_num": 3,
            "bus_num": 1,
            "vendor_id": "046d",
            "product_id": "0825",
            "usb_location": "1:3",
            "manufacturer": "Logitech, Inc.",
            "product": "Webcam C270",
            "serial": "<unique serial number>",
            "class": "Miscellaneous Device",
            "subclass": null,
            "protocol": "Interface Association",
            "description": "Logitech, Inc. Webcam C270"
        },
        {
            "device_num": 2,
            "bus_num": 1,
            "vendor_id": "1a40",
            "product_id": "0101",
            "usb_location": "1:2",
            "manufacturer": "Terminus Technology Inc.",
            "product": "USB 2.0 Hub",
            "serial": null,
            "class": "Hub",
            "subclass": null,
            "protocol": "Single TT",
            "description": "Terminus Technology Inc. Hub"
        },
        {
            "device_num": 5,
            "bus_num": 1,
            "vendor_id": "0403",
            "product_id": "6001",
            "usb_location": "1:5",
            "manufacturer": "FTDI",
            "product": "FT232R USB UART",
            "serial": "<unique serial number>",
            "class": null,
            "subclass": null,
            "protocol": null,
            "description": "Future Technology Devices International, Ltd FT232 Serial (UART) IC"
        },
        {
            "device_num": 4,
            "bus_num": 1,
            "vendor_id": "1d50",
            "product_id": "614e",
            "usb_location": "1:4",
            "manufacturer": "Klipper",
            "product": "stm32f407xx",
            "serial": "<unique serial number>",
            "class": "Communications",
            "subclass": null,
            "protocol": null,
            "description": "OpenMoko, Inc. Klipper 3d-Printer Firmware"
        }
    ]
}

///

/// api-response-schema open: True Response

Field Type Description
usb_devices array An array of objects containing USB device information.

USB Device

Field Type Description
bus_num int The USB bus number as reported by the host.
device_num int The USB device number as reported by the host.
usb_location string A combination of the bus number and device number,
yielding a unique location ID on the host system.
vendor_id string The vendor ID as reported by the driver.
product_id string The product ID as reported by the driver.
manufacturer string? The manufacturer name as reported by the driver.
This will be null if no manufacturer is found.
product string? The product description as reported by the driver.
This will be null if no description is found.
class string? The class description as reported by the driver.
This will be null if no description is found.
subclass string? The subclass description as reported by the driver.
This will be null if no description is found.
protocol string? The protocol description as reported by the driver.
This will be null if no description is found.
description string? The full device description string as reported by
the usb.ids file. This will be null if no
description is found.
///

List Serial Devices

Returns a list of all serial devices detected on the system. These may be USB CDC-ACM devices or hardware UARTs.

GET /machine/peripherals/serial
{
    "jsonrpc": "2.0",
    "method": "machine.peripherals.serial",
    "id": 7896
}

/// api-example-response

{
    "serial_devices": [
        {
            "device_type": "hardware_uart",
            "device_path": "/dev/ttyS0",
            "device_name": "ttyS0",
            "driver_name": "serial8250",
            "path_by_hardware": null,
            "path_by_id": null,
            "usb_location": null
        },
        {
            "device_type": "usb",
            "device_path": "/dev/ttyACM0",
            "device_name": "ttyACM0",
            "driver_name": "cdc_acm",
            "path_by_hardware": "/dev/serial/by-path/platform-3f980000.usb-usb-0:1.2:1.0",
            "path_by_id": "/dev/serial/by-id/usb-Klipper_stm32f407xx_unique_serial-if00",
            "usb_location": "1:4"
        },
        {
            "device_type": "usb",
            "device_path": "/dev/ttyUSB0",
            "device_name": "ttyUSB0",
            "driver_name": "ftdi_sio",
            "path_by_hardware": "/dev/serial/by-path/platform-3f980000.usb-usb-0:1.4:1.0-port0",
            "path_by_id": "/dev/serial/by-id/usb-FTDI_FT232R_USB_UART_unique_serial-if00-port0",
            "usb_location": "1:5"
        },
        {
            "device_type": "hardware_uart",
            "device_path": "/dev/ttyAMA0",
            "device_name": "ttyAMA0",
            "driver_name": "uart-pl011",
            "path_by_hardware": null,
            "path_by_id": null,
            "usb_location": null
        }
    ]
}

///

/// api-response-schema open: True Response

Field Type Description
serial_devices array An array of objects containing serial device information.

Serial Device

Field Type Description
device_type string The type of serial device. Can be hardware_uart or usb.
device_path string The absolute file path to the device.
device_name string The device file name as reported by sysfs.
driver_name string The name of the device driver.
path_by_hardware string? A symbolic link to the device based on its physical
connection, ie: usb port. Will be null if no
matching link exists.
path_by_id string? A symbolic link the the device based on its reported IDs.
Will be null if no matching link exists.
usb_location string? An identifier derived from the reported usb bus and .
device numbers Can be used to match results from
/machine/peripherals/usb. Will be null for non-usb
devices.
///

List Video Capture Devices

Retrieves a list of V4L2 video capture devices on the system. If the python3-libcamera system package is installed this request will also return libcamera devices.

GET /machine/peripherals/video
{
    "jsonrpc": "2.0",
    "method": "machine.peripherals.video",
    "id": 7896
}

/// api-example-response

{
    "v4l2_devices": [
        {
            "device_name": "video0",
            "device_path": "/dev/video0",
            "camera_name": "unicam",
            "driver_name": "unicam",
            "hardware_bus": "platform:3f801000.csi",
            "capabilities": [
                "VIDEO_CAPTURE",
                "EXT_PIX_FORMAT",
                "READWRITE",
                "STREAMING",
                "IO_MC"
            ],
            "version": "6.1.63",
            "path_by_hardware": "/dev/v4l/by-path/platform-3f801000.csi-video-index0",
            "path_by_id": null,
            "alt_name": "unicam-image",
            "usb_location": null
        },
        {
            "device_name": "video1",
            "device_path": "/dev/video1",
            "camera_name": "UVC Camera (046d:0825)",
            "driver_name": "uvcvideo",
            "hardware_bus": "usb-3f980000.usb-1.1",
            "capabilities": [
                "VIDEO_CAPTURE",
                "EXT_PIX_FORMAT",
                "STREAMING"
            ],
            "version": "6.1.63",
            "path_by_hardware": "/dev/v4l/by-path/platform-3f980000.usb-usb-0:1.1:1.0-video-index0",
            "path_by_id": "/dev/v4l/by-id/usb-046d_0825_66EF0390-video-index0",
            "alt_name": "UVC Camera (046d:0825)",
            "usb_location": "1:3"
        },
        {
            "device_name": "video14",
            "device_path": "/dev/video14",
            "camera_name": "bcm2835-isp",
            "driver_name": "bcm2835-isp",
            "hardware_bus": "platform:bcm2835-isp",
            "capabilities": [
                "VIDEO_CAPTURE",
                "EXT_PIX_FORMAT",
                "STREAMING"
            ],
            "version": "6.1.63",
            "path_by_hardware": null,
            "path_by_id": null,
            "alt_name": "bcm2835-isp-capture0",
            "usb_location": null
        },
        {
            "device_name": "video15",
            "device_path": "/dev/video15",
            "camera_name": "bcm2835-isp",
            "driver_name": "bcm2835-isp",
            "hardware_bus": "platform:bcm2835-isp",
            "capabilities": [
                "VIDEO_CAPTURE",
                "EXT_PIX_FORMAT",
                "STREAMING"
            ],
            "version": "6.1.63",
            "path_by_hardware": null,
            "path_by_id": null,
            "alt_name": "bcm2835-isp-capture1",
            "usb_location": null
        },
        {
            "device_name": "video21",
            "device_path": "/dev/video21",
            "camera_name": "bcm2835-isp",
            "driver_name": "bcm2835-isp",
            "hardware_bus": "platform:bcm2835-isp",
            "capabilities": [
                "VIDEO_CAPTURE",
                "EXT_PIX_FORMAT",
                "STREAMING"
            ],
            "version": "6.1.63",
            "path_by_hardware": "/dev/v4l/by-path/platform-bcm2835-isp-video-index1",
            "path_by_id": null,
            "alt_name": "bcm2835-isp-capture0",
            "usb_location": null
        },
        {
            "device_name": "video22",
            "device_path": "/dev/video22",
            "camera_name": "bcm2835-isp",
            "driver_name": "bcm2835-isp",
            "hardware_bus": "platform:bcm2835-isp",
            "capabilities": [
                "VIDEO_CAPTURE",
                "EXT_PIX_FORMAT",
                "STREAMING"
            ],
            "version": "6.1.63",
            "path_by_hardware": "/dev/v4l/by-path/platform-bcm2835-isp-video-index2",
            "path_by_id": null,
            "alt_name": "bcm2835-isp-capture1",
            "usb_location": null
        }
    ],
    "libcamera_devices": [
        {
            "libcamera_id": "/base/soc/i2c0mux/i2c@1/ov5647@36",
            "model": "ov5647",
            "modes": [
                {
                    "format": "SGBRG10_CSI2P",
                    "resolutions": [
                        "640x480",
                        "1296x972",
                        "1920x1080",
                        "2592x1944"
                    ]
                }
            ]
        },
        {
            "libcamera_id": "/base/soc/usb@7e980000/usb-port@1/usb-port@1-1.1:1.0-046d:0825",
            "model": "UVC Camera (046d:0825)",
            "modes": [
                {
                    "format": "MJPEG",
                    "resolutions": [
                        "160x120",
                        "176x144",
                        "320x176",
                        "320x240",
                        "352x288",
                        "432x240",
                        "544x288",
                        "640x360",
                        "640x480",
                        "752x416",
                        "800x448",
                        "864x480",
                        "800x600",
                        "960x544",
                        "1024x576",
                        "960x720",
                        "1184x656",
                        "1280x720",
                        "1280x960"
                    ]
                },
                {
                    "format": "YUYV",
                    "resolutions": [
                        "160x120",
                        "176x144",
                        "320x176",
                        "320x240",
                        "352x288",
                        "432x240",
                        "544x288",
                        "640x360",
                        "640x480",
                        "752x416",
                        "800x448",
                        "864x480",
                        "800x600",
                        "960x544",
                        "1024x576",
                        "960x720",
                        "1184x656",
                        "1280x720",
                        "1280x960"
                    ]
                }
            ]
        }
    ]
}

///

/// api-response-schema open: True Response

Field Type Description
v4l2_devices array An array of V4L2 Device objects.
libcamera_devices array An array of Libcamera Device objects.

V4L2 Device

Field Type Description
device_name string The V4L2 name assigned to the device. This is typically
the name of the file associated with the device.
device_path string The absolute system path to the device file.
camera_name string The camera name reported by the device driver.
driver_name string The name of the driver loaded for the device.
alt_name string? An alternative device name optionally reported by
sysfs. Will be null if the name file does not exist.
hardware_bus string A description of the hardware location of the device
capabilities array An array of strings indicating the capabilities the
device supports as reported by V4L2.
version string The device version as reported by V4L2.
path_by_hardware string? A symbolic link to the device based on its physical
connection, ie: usb port.. Will be null if no
matching link exists.
path_by_id string? A symbolic link the the device based on its reported
ID. Will be null if no matching link exists.
usb_location string? An identifier derived from the reported usb bus and
device numbers. Will be null for non-usb devices.

Libcamera Device

Field Type Description
libcamera_id string The ID of the device as reported by libcamera.
model string The model name of the device.
modes array An array of Libcamera Mode objects, each describing a
mode supported by the device.

Libcamera Mode

Field Type Description
format string The pixel format of the mode.
resolutions array An array of strings describing the resolutions supported by
the mode. Each entry is reported as <WIDTH>x<HEIGHT>
///

Query Unassigned Canbus UUIDs

Queries the provided canbus interface for unassigned Klipper or Katapult node IDs.

!!! Warning It is recommended that frontends provide users with an explanation of how UUID queries work and the potential pitfalls when querying a bus with multiple unassigned nodes. An "unassigned" node is a CAN node that has not been activated by Katapult or Klipper. If either Klipper or Katapult has connected to the node, it will be assigned a Node ID and therefore will no longer respond to queries. A device reset is required to remove the assignment.

When multiple unassigned nodes are on the network, each responds to
the query at roughly the same time.  This results in arbitration
errors.  Nodes will retry the send until the response reports success.
However, nodes track the count of arbitration errors, and once a
specific threshold is reached they will go into a "bus off" state. A
device reset is required to reset the counter and recover from "bus off".

For this reason, it is recommended that users only issue a query when
a single unassigned node is on the network.  If a user does wish to
query multiple unassigned nodes it is vital that they reset all nodes
on the network before running Klipper.
GET /machine/peripherals/canbus?interface=can0
{
    "jsonrpc": "2.0",
    "method": "machine.peripherals.canbus",
    "params": {
        "interface": "can0"
    },
    "id": 7896
}

/// api-parameters open: True

Name Type Description
interface string The cansocket interface to query. Default is can0.
///

/// api-example-response

{
    "can_uuids": ["11AABBCCDD"]
}

///

/// api-response-schema open: True Response

Field Type Description
can_uuids array An array of discovered CAN UUID objects, or an empty array if no
unassigned CAN nodes are found.

Can UUID

Field Type Description
uuid string The UUID of the unassigned node.
application string The name of the application running on the unassigned Node.
Should be "Klipper" or "Katapult".
///

File Operations

Most file operations are available over both APIs, however file upload and file download are currently only available via HTTP APIs.

Moonraker organizes local directories into "roots". For example, gcodes are located at http:\\host\server\files\gcodes\*, otherwise known as the "gcodes" root. The following roots are available:

  • gcodes
  • config
  • config_examples (read-only)
  • docs (read-only)

Write operations (upload, delete, make directory, remove directory) are only available on the gcodes and config roots. Note that the config root is only available if the config_path option has been set in Moonraker's configuration.

List available files

Walks through a directory and fetches all files. All file names include a path relative to the specified root.

HTTP request:

GET /server/files/list?root={root_folder}

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "server.files.list",
    "params": {
        "root": "{root_folder}"
    },
    "id": 4644
}

!!! tip If the root argument is omitted the request will default to the gcodes root.

!!! note The gcodes root will only return files with valid gcode extensions.

Returns: A list of objects, where each object contains file data.

[
    {
        "path": "3DBenchy_0.15mm_PLA_MK3S_2h6m.gcode",
        "modified": 1615077020.2025201,
        "size": 4926481,
        "permissions": "rw"
    },
    {
        "path": "Shape-Box_0.2mm_PLA_Ender2_20m.gcode",
        "modified": 1614910966.946807,
        "size": 324236,
        "permissions": "rw"
    },
    {
        "path": "test_dir/A-Wing.gcode",
        "modified": 1605202259,
        "size": 1687387,
        "permissions": "rw"
    },
    {
        "path": "test_dir/CE2_CubeTest.gcode",
        "modified": 1614644445.4025,
        "size": 1467339,
        "permissions": "rw"
    },
    {
        "path": "test_dir/V350_Engine_Block_-_2_-_Scaled.gcode",
        "modified": 1615768477.5133543,
        "size": 189713016,
        "permissions": "rw"
    },
]

List registered roots

Reports all "root" directories registered with Moonraker. Information such as location on disk and permissions are included.

HTTP request:

GET /server/files/roots

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "server.files.roots",
    "id": 4644
}

Returns: A list of objects, where each object contains file data:

[
    {
        "name": "config",
        "path": "/home/pi/printer_data/config",
        "permissions": "rw"
    },
    {
        "name": "logs",
        "path": "/home/pi/printer_data/logs",
        "permissions": "r"
    },
    {
        "name": "gcodes",
        "path": "/home/pi/printer_data/gcodes",
        "permissions": "rw"
    },
    {
        "name": "config_examples",
        "path": "/home/pi/klipper/config",
        "permissions": "r"
    },
    {
        "name": "docs",
        "path": "/home/pi/klipper/docs",
        "permissions": "r"
    }
]

Get GCode Metadata

Get metadata for a specified gcode file.

HTTP request:

GET /server/files/metadata?filename={filename}

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "server.files.metadata",
    "params": {
        "filename": "{filename}"
    },
    "id": 3545
}

Parameters:

  • filename: Path to the gcode file, relative to the gcodes root. For example, if the file is located at http://host/server/files/gcodes/tools/drill_head.gcode, the filename should be specified as tools/drill_head.gcode

Returns:

Metadata for the requested file if it exists. If any fields failed parsing they will be omitted. The metadata will always include the file name, modified time, and size.

{
    "print_start_time": null,
    "job_id": null,
    "size": 4926481,
    "modified": 1615077020.2025201,
    "slicer": "SuperSlicer",
    "slicer_version": "2.2.52",
    "layer_height": 0.15,
    "first_layer_height": 0.2,
    "object_height": 48.05,
    "filament_total": 4056.4,
    "estimated_time": 7569,
    "thumbnails": [
        {
            "width": 32,
            "height": 32,
            "size": 2596,
            "relative_path": ".thumbs/3DBenchy_0.15mm_PLA_MK3S_2h6m-32x32.png"
        },
        {
            "width": 400,
            "height": 300,
            "size": 73308,
            "relative_path": ".thumbs/3DBenchy_0.15mm_PLA_MK3S_2h6m-400x300.png"
        }
    ],
    "first_layer_bed_temp": 60,
    "first_layer_extr_temp": 215,
    "gcode_start_byte": 79451,
    "gcode_end_byte": 4915668,
    "filename": "3DBenchy_0.15mm_PLA_MK3S_2h6m.gcode"
}

!!! Note The print_start_time and job_id fields are initialized to null. They will be updated for each print job if the user has the [history] component configured

Scan GCode Metadata

Initiate a metadata scan for a selected file. If the file has already been scanned the endpoint will force a rescan

HTTP request:

GET /server/files/metascan?filename={filename}

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "server.files.metascan",
    "params": {
        "filename": "{filename}"
    },
    "id": 3545
}

Parameters:

  • filename: Path to the gcode file, relative to the gcodes root. For example, if the file is located at http://host/server/files/gcodes/tools/drill_head.gcode, the filename should be specified as tools/drill_head.gcode

Returns:

  • An object containing the metadata resulting from the scan, matching the return value of the Get Metdata Endpoint.

Get GCode Thumbnails

Returns thumbnail information for a supplied gcode file. If no thumbnail information is available

HTTP request:

GET /server/files/thumbnails?filename={filename}

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "server.files.thumbnails",
    "params": {
        "filename": "{filename}"
    },
    "id": 3545
}

Parameters:

  • filename: Path to the gcode file, relative to the gcodes root. For example, if the file is located at http://host/server/files/gcodes/tools/drill_head.gcode, the filename should be specified as tools/drill_head.gcode

Returns:

An array of objects containing thumbnail information. If no thumbnail information exists for the specified file then the returned array wil be empty.

[
    {
        "width": 32,
        "height": 32,
        "size": 1551,
        "thumbnail_path": "test/.thumbs/CE2_FanCover-120mm-Mesh-32x32.png"
    },
    {
        "width": 300,
        "height": 300,
        "size": 31819,
        "thumbnail_path": "test/.thumbs/CE2_FanCover-120mm-Mesh.png"
    }
]

!!! Note This information is the same as reported in the thumbnails field of a metadata object, with one exception. The thumbnail_path field in the result above contains a path relative to the gcodes root, whereas the relative_path field reported in the metadata is relative to the gcode file's parent folder.

Get directory information

Returns a list of files and subdirectories given a supplied path. Unlike /server/files/list, this command does not walk through subdirectories. This request will return all files in a directory, including files in the gcodes root that do not have a valid gcode extension.

HTTP request:

GET /server/files/directory?path=gcodes/my_subdir&extended=true

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "server.files.get_directory",
    "params": {
        "path": "gcodes/my_subdir",
        "extended": true
    },
    "id": 5644
}

!!! tip If the path argument is omitted then the command will return directory information from the gcodes root.

The extended argument is optional and defaults to false. If supplied and set to true then data returned for gcode files will also include metadata (if available).

Returns:

An object containing file and subdirectory information in the following format:

{
    "dirs": [
        {
            "modified": 1615768162.0412788,
            "size": 4096,
            "permissions": "rw",
            "dirname": "test"
        },
        {
            "modified": 1613569827.489749,
            "size": 4096,
            "permissions": "rw",
            "dirname": "Cura"
        },
        {
            "modified": 1615767459.6265886,
            "size": 4096,
            "permissions": "rw",
            "dirname": "thumbs"
        }
    ],
    "files": [
        {
            "modified": 1615578004.9639666,
            "size": 7300692,
            "permissions": "rw",
            "filename": "Funnel_0.2mm_PLA_Ender2_2h4m.gcode"
        },
        {
            "modified": 1589156863.9726968,
            "size": 4214831,
            "permissions": "rw",
            "filename": "CE2_Pi3_A+_CaseLID.gcode"
        },
        {
            "modified": 1615030592.7722695,
            "size": 2388774,
            "permissions": "rw",
            "filename": "CE2_calicat.gcode"
        },
    ],
    "disk_usage": {
        "total": 7522213888,
        "used": 4280369152,
        "free": 2903625728
    },
    "root_info": {
        "name": "gcodes",
        "permissions": "rw"
    }
}

Create directory

Creates a directory at the specified path.

HTTP request:

POST /server/files/directory?path=gcodes/my_new_dir

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "server.files.post_directory",
    "params": {
        "path": "gcodes/my_new_dir"
    },
    "id": 6548
}

Returns: Information about the created directory

{
    "item": {
        "path": "my_new_dir",
        "root": "gcodes",
        "modified": 1676983427.3732708,
        "size": 4096,
        "permissions": "rw"

    },
    "action": "create_dir"
}

Delete directory

Deletes a directory at the specified path.

HTTP request:

DELETE /server/files/directory?path=gcodes/my_subdir&force=false

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "server.files.delete_directory",
    "params": {
        "path": "gcodes/my_subdir",
        "force": false
    },
    "id": 6545
}

!!! warning If the specified directory contains files then the delete request will fail unless the force argument is set to true.

Returns: Information about the deleted directory

{
    "item": {
        "path": "my_subdir",
        "root": "gcodes",
        "modified": 0,
        "size": 0,
        "permissions": ""

    },
    "action": "delete_dir"
}

Move a file or directory

Moves a file or directory from one location to another. The following conditions must be met for a move successful move:

  • The source must exist
  • The user (typically "pi") must have the appropriate file permissions
  • Neither the source nor destination can be loaded by the virtual_sdcard. If the source is a directory, it must not contain a file loaded by the virtual_sdcard.

When specifying the source and dest, the root directory should be prefixed. Currently the only supported roots for dest are gcodes" and config".

This API may also be used to rename a file or directory. Be aware that an attempt to rename a directory to a directory that already exists will result in moving the source directory into the destination directory. Also be aware that renaming a file to a file that already exists will result in overwriting the existing file.

HTTP request:

POST /server/files/move?source=gcodes/testdir/my_file.gcode&dest=gcodes/subdir/my_file.gcode

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "server.files.move",
    "params": {
        "source": "gcodes/testdir/my_file.gcode",
        "dest": "gcodes/subdir/my_file.gcode"
    },
    "id": 5664
}

Returns: Information about the moved file or directory

{
    "result": {
        "item": {
            "root": "gcodes",
            "path": "subdir/my_file.gcode",
            "modified": 1676940082.8595376,
            "size": 384096,
            "permissions": "rw"
        },
        "source_item": {
            "path": "testdir/my_file.gcode",
            "root": "gcodes"
        },
        "action": "move_file"
    }
}

!!! Note The item field contains file info for the destination. The source_item contains the path and root the item was moved from. The action field will be move_file if the source is a file or move_dir if the source is a directory.

Copy a file or directory

Copies a file or directory from one location to another. A successful copy has the prerequisites as a move with one exception, a copy may complete if the source file or directory is loaded by the virtual_sdcard. As with the move API, the source and dest should have the root prefixed to the path.

HTTP request:

POST /server/files/copy?source=gcodes/my_file.gcode&dest=gcodes/subdir/my_file.gcode

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "server.files.copy",
    "params": {
        "source": "gcodes/my_file.gcode",
        "dest": "gcodes/subdir/my_file.gcode"
    },
    "id": 5623
}

Returns: Information about the copied file or directory

{
    "item": {
        "root": "gcodes",
        "path": "subdir/my_file.gcode",
        "modified": 1676940082.8595376,
        "size": 384096,
        "permissions": "rw"
    },
    "action": "create_file"
}

!!! Note The item field contains file info for the destination. The action field will be create_file if a new file was created, modify_file if an exiting file was overwitten, or create_dir if an entire directory was copied.

Create a ZIP archive

Creates a zip file consisting of one or more files.

HTTP request:

POST /server/files/zip
Content-Type: application/json

{
    "dest": "config/errorlogs.zip",
    "items": [
        "config/printer.cfg",
        "logs",
        "gcodes/subfolder"
    ],
    "store_only": false
}

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "server.files.zip",
    "params": {
        "dest": "config/errorlogs.zip",
        "items": [
            "config/printer.cfg",
            "logs",
            "gcodes/subfolder"
        ],
        "store_only": false
    },
    "id": 5623
}

Parameters:

  • dest - (Optional) - Relative path to the destination zip. The first element of the path must be valid root with write access. If the path contains subfolders the parent folder must exist. The default is config/collection-{timestamp}.zip, where {timestamp} is generated based on the localtime.
  • items - (Required) - An array of relative paths containing files and or folders to include in the archive. Each item must meet the following requirements:
    • The first element of the item must be a registered root with read access.
    • Each item must point to a valid file or folder.
    • Moonraker must have permission to read the specified files and/or directories.
    • If the path is to a directory then all files with read permissions are included. Subfolders are not included recursively.
  • store_only - (Optional) - If set to true then the archive will not compress its contents. Otherwise the traditional deflation algorithm is used to compress the archives contents. The default is false.

Returns: An object in the following format:

{
    "destination": {
        "root": "config",
        "path": "errorlogs.zip",
        "modified": 1676984423.8892415,
        "size": 420,
        "permissions": "rw"
    },
    "action": "zip_files"
}
  • destination - an object containing the destination root and a path to the file relative to the root.
  • action - The file action, will be zip_files

File download

Retrieves file filename at root root. The filename must include the relative path if it is not in the root folder.

HTTP request:

GET /server/files/{root}/{filename}

JSON-RPC request: Not Available

Returns:

The requested file

File upload

Upload a file. Currently files may be uploaded to the gcodes or config roots, with gcodes being the default. If one wishes to upload to a subdirectory, the path may be added to the upload's file name (relative to the root). If the directory does not exist an error will be returned. Alternatively, the path form argument may be set, as explained below.

HTTP request:

POST /server/files/upload`
Content-Type: multipart/form-data

------FormBoundaryemap3PkuvKX0B3HH
Content-Disposition: form-data; name="file"; filename="myfile.gcode"
Content-Type: application/octet-stream

<binary data>
------FormBoundaryemap3PkuvKX0B3HH--

The file must be uploaded in the request's body multipart/form-data (ie: <input type="file">). The following arguments may also be added to the form-data:

  • root: The root location in which to upload the file. Currently this may be gcodes or config. If not specified the default is gcodes.
  • path: This argument may contain a path (relative to the root) indicating a subdirectory to which the file is written. If a path is present the server will attempt to create any subdirectories that do not exist.
  • checksum: A SHA256 hex digest calculated by the client for the uploaded file. If this argument is supplied the server will compare it to its own checksum calculation after the upload has completed. A checksum mismatch will result in a 422 error.

Arguments available only for the gcodes root:

  • print: If set to "true", Klippy will attempt to start the print after uploading. Note that this value should be a string type, not boolean. This provides compatibility with OctoPrint's upload API.

JSON-RPC request: Not Available

Returns: Information about the uploaded file. Note that print_started is only included when the supplied root is set to gcodes.

{
    "item": {
        "path": "Lock Body Shim 1mm_0.2mm_FLEX_MK3S_2h30m.gcode",
        "root": "gcodes",
        "modified": 1676984527.636818,
        "size": 71973,
        "permissions": "rw"
    },
    "print_started": false,
    "print_queued": false,
    "action": "create_file"
}

File delete

Delete a file in the requested root. If the file exists in a subdirectory, its relative path must be part of the {filename} argument.

HTTP request:

DELETE /server/files/{root}/{filename}

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "server.files.delete_file",
    "params": {
        "path": "{root}/{filename}"
    },
    "id": 1323
}

Returns: Information about the deleted file

{
    "item": {
        "path": "Lock Body Shim 1mm_0.2mm_FLEX_MK3S_2h30m.gcode",
        "root": "gcodes",
        "size": 0,
        "modified": 0,
        "permissions": ""
    },
    "action": "delete_file"
}

Download klippy.log

!!! Note Logs are now available in the logs root. Front ends should consider presenting all available logs using "file manager" type of UI. That said, If Klipper has not been configured to write logs in the logs root then this endpoint is available as a fallback.

HTTP request:

GET /server/files/klippy.log

JSON-RPC request: Not Available

Returns:

The requested file

Download moonraker.log

!!! Note Logs are now available in the logs root. Front ends should consider presenting all available logs using "file manager" type of UI. That said, If Moonraker has not been configured to write logs in the logs root then this endpoint is available as a fallback.

HTTP request:

GET /server/files/moonraker.log

JSON-RPC request: Not Available

Returns:

The requested file

Authorization

The Authorization endpoints are enabled when the user has the [authorization] component configured in moonraker.conf.

Untrusted clients must use either a JSON Web Token or an API key to access Moonraker's HTTP APIs. JWTs should be included in the Authorization header as a Bearer type for each HTTP request. If using an API Key it should be included in the X-Api-Key header for each HTTP Request.

Websocket authentication can be achieved via the request itself or post connection. Unlike HTTP requests it is not necessasry to pass a token and/or API Key to each request. The identify connection endpoint takes optional access_token and api_key parameters that may be used to authentiate a user already logged in, otherwise the login API may be used for authentication. Websocket connections will stay authenticated until the connection is closed or the user logs out.

!!! note ECMAScript imposes limitations on certain requests that prohibit the developer from modifying the HTTP headers (ie: The request to open a websocket, "download" requests that open a dialog). In these cases it is recommended for the developer to request a oneshot_token, then send the result via the token query string argument in the desired request.

!!! warning It is strongly recommended that arguments for the below APIs are passed in the request's body.

Login User

HTTP Request:

POST /access/login
Content-Type: application/json

{
    "username": "my_user",
    "password": "my_password",
    "source": "moonraker"
}

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "access.login",
    "params": {
        "username": "my_user",
        "password": "my_password",
        "source": "moonraker"
    },
    "id": 1323
}

Arguments:

  • username: The user login name. This argument is required.
  • password: The user password. This arugment is required.
  • source: The authentication source. Can be moonraker or ldap. The default is moonraker.

Returns: An object the logged in username, auth token, refresh token, and action summary:

{
    "username": "my_user",
    "token": "eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJpc3MiOiAiTW9vbnJha2VyIiwgImlhdCI6IDE2MTg4NzY4MDAuNDgxNjU1LCAiZXhwIjogMTYxODg4MDQwMC40ODE2NTUsICJ1c2VybmFtZSI6ICJteV91c2VyIiwgInRva2VuX3R5cGUiOiAiYXV0aCJ9.QdieeEskrU0FrH7rXKuPDSZxscM54kV_vH60uJqdU9g",
    "refresh_token": "eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJpc3MiOiAiTW9vbnJha2VyIiwgImlhdCI6IDE2MTg4NzY4MDAuNDgxNzUxNCwgImV4cCI6IDE2MjY2NTI4MDAuNDgxNzUxNCwgInVzZXJuYW1lIjogIm15X3VzZXIiLCAidG9rZW5fdHlwZSI6ICJyZWZyZXNoIn0.btJF0LJfymInhGJQ2xvPwkp2dFUqwgcw4OA_wE-EcCM",
    "action": "user_logged_in",
    "source": "moonraker"
}
  • The token field is a JSON Web Token used to authorize the user. It should be included in the Authorization header as a Bearer type for all HTTP requests. The token expires after 1 hour.
  • The refresh_token field contains a JWT that can be used to generate new tokens after they are expire. See the refresh token section for details.

!!! Note This endpoint may be accessed by unauthorized clients. A 401 would only be returned if the authentication failed.

Logout Current User

HTTP Request:

POST /access/logout

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "access.logout",
    "id": 1323
}

Returns: An object containing the logged out username and action summary.

{
    "username": "my_user",
    "action": "user_logged_out"
}

Get Current User

HTTP Request:

GET /access/user

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "access.get_user",
    "id": 1323
}

Returns: An object containing the currently logged in user name, the source and the date on which the user was created (in unix time).

{
    "username": "my_user",
    "source": "moonraker",
    "created_on": 1618876783.8896716
}

Create User

HTTP Request:

POST /access/user
Content-Type: application/json

{
    "username": "my_user",
    "password": "my_password"
}

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "access.post_user",
    "params": {
        "username": "my_user",
        "password": "my_password"
    },
    "id": 1323
}

Returns: An object containing the created user name, an auth token, a refresh token, the source, and an action summary. Creating a user also effectively logs the user in.

{
    "username": "my_user",
    "token": "eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJpc3MiOiAiTW9vbnJha2VyIiwgImlhdCI6IDE2MTg4NzY3ODMuODkxNjE5LCAiZXhwIjogMTYxODg4MDM4My44OTE2MTksICJ1c2VybmFtZSI6ICJteV91c2VyIiwgInRva2VuX3R5cGUiOiAiYXV0aCJ9.oH0IShTL7mdlVs4kcx3BIs_-1j0Oe-qXezJKjo-9Xgo",
    "refresh_token": "eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJpc3MiOiAiTW9vbnJha2VyIiwgImlhdCI6IDE2MTg4NzY3ODMuODkxNzAyNCwgImV4cCI6IDE2MjY2NTI3ODMuODkxNzAyNCwgInVzZXJuYW1lIjogIm15X3VzZXIiLCAidG9rZW5fdHlwZSI6ICJyZWZyZXNoIn0.a6ZeRjk8RQQJDDH0JV-qGY_d_HIgfI3XpsqUlUaFT7c",
    "source": "moonraker",
    "action": "user_created"
}

!!! note Unlike /access/login, /access/user is a protected endpoint. To create a new user a client must either be trusted, use the API Key, or be logged in as another user.

Delete User

Deletes a registered user.

!!! note A request to delete a user MUST come from an authorized source other than the account to be deleted. This can be a "trusted user", the "api key user", or any other user account.

HTTP Request:

DELETE /access/user
Content-Type: application/json

{
    "username": "my_username"
}

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "access.delete_user",
    "params": {
        "username": "my_username"
    },
    "id": 1323
}

Returns: The username of the deleted user and an action summary. This effectively logs the user out, as all outstanding tokens will be invalid.

{
    "username": "my_user",
    "action": "user_deleted"
}

List Available Users

HTTP Request:

GET /access/users/list

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "access.users.list",
    "id": 1323
}

Returns: A list of created users on the system

{
    "users": [
        {
            "username": "testuser",
            "source": "moonraker",
            "created_on": 1618771331.1685035
        },
        {
            "username": "testuser2",
            "source": "ldap",
            "created_on": 1620943153.0191233
        }
    ]
}

Reset User Password

HTTP Request:

POST /access/user/password
Content-Type: application/json

{
    "password": "my_current_password",
    "new_password": "my_new_pass"
}

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "access.user.password",
    "params": {
        "password": "my_current_password",
        "new_password": "my_new_pass"
    },
    "id": 1323
}

Returns: The username and action summary.

{
    "username": "my_user",
    "action": "user_password_reset"
}

Refresh JSON Web Token

This endpoint can be used to refresh an expired auth token. If this request returns an error then the refresh token is no longer valid and the user must login with their credentials.

HTTP Request:

POST /access/refresh_jwt
Content-Type: application/json

{
    "refresh_token": "eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJpc3MiOiAiTW9vbnJha2VyIiwgImlhdCI6IDE2MTg4Nzc0ODUuNzcyMjg5OCwgImV4cCI6IDE2MjY2NTM0ODUuNzcyMjg5OCwgInVzZXJuYW1lIjogInRlc3R1c2VyIiwgInRva2VuX3R5cGUiOiAicmVmcmVzaCJ9.Y5YxGuYSzwJN2WlunxlR7XNa2Y3GWK-2kt-MzHvLbP8"
}

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "access.refresh_jwt",
    "params": {
        "refresh_token": "eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJpc3MiOiAiTW9vbnJha2VyIiwgImlhdCI6IDE2MTg4Nzc0ODUuNzcyMjg5OCwgImV4cCI6IDE2MjY2NTM0ODUuNzcyMjg5OCwgInVzZXJuYW1lIjogInRlc3R1c2VyIiwgInRva2VuX3R5cGUiOiAicmVmcmVzaCJ9.Y5YxGuYSzwJN2WlunxlR7XNa2Y3GWK-2kt-MzHvLbP8"
    },
    "id": 1323
}

Returns: The username, new auth token, the source and action summary.

{
    "username": "my_user",
    "token": "eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJpc3MiOiAiTW9vbnJha2VyIiwgImlhdCI6IDE2MTg4NzgyNDMuNTE2Nzc5MiwgImV4cCI6IDE2MTg4ODE4NDMuNTE2Nzc5MiwgInVzZXJuYW1lIjogInRlc3R1c2VyIiwgInRva2VuX3R5cGUiOiAiYXV0aCJ9.Ia_X_pf20RR4RAEXcxalZIOzOBOs2OwearWHfRnTSGU",
    "source": "moonraker",
    "action": "user_jwt_refresh"
}

!!! Note This endpoint may be accessed by unauthorized clients. A 401 would only be returned if the refresh token is invalid.

Generate a Oneshot Token

Javascript is not capable of modifying the headers for some HTTP requests (for example, the websocket), which is a requirement to apply JWT or API Key authorization. To work around this clients may request a Oneshot Token and pass it via the query string for these requests. Tokens expire in 5 seconds and may only be used once, making them relatively safe for inclusion in the query string.

HTTP request:

GET /access/oneshot_token

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "access.oneshot_token",
    "id": 1323
}

Returns:

A temporary token that may be added to a request's query string for access to any API endpoint. The query string should be added in the form of:

?token={base32_random_token}

Retrieve information about authorization endpoints

HTTP Request:

GET /access/info

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "access.info",
    "id": 1323
}

Returns: An object containing information about authorization endpoints, such as default_source and available_sources.

{
    "default_source": "moonraker",
    "available_sources": [
        "moonraker",
        "ldap"
    ]
}

Get the Current API Key

HTTP request:

GET /access/api_key

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "access.get_api_key",
    "id": 1323
}

Returns:

The current API key

Generate a New API Key

HTTP request:

POST /access/api_key

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "access.post_api_key",
    "id": 1323
}

Returns:

The newly generated API key. This overwrites the previous key. Note that the API key change is applied immediately, all subsequent HTTP requests from untrusted clients must use the new key. Changing the API Key will not affect open websockets authenticated using the previous API Key.

Database APIs

The following endpoints provide access to Moonraker's lmdb database. The database is divided into namespaces. Each client may define its own namespace to store information. From the client's point of view, a namespace is an object. Items in the database are accessed by providing a namespace and a key. A key may be specified as string, where a "." is a delimiter, to access nested fields. Alternatively the key may be specified as an array of strings, where each string references a nested field. This is useful for scenarios where your namespace contains keys that include a "." character.

!!! note Moonraker reserves the moonraker, gcode_metadata, and history namespaces. Clients may read from these namespaces but they may not modify them.

For example, assume the following object is stored in the "superclient" namespace:

{
    "settings": {
        "console": {
            "enable_autocomplete": true
        }
    },
    "theme": {
        "background_color": "black"
    }
}

One may access the enable_autocomplete field by supplying superclient as the namespace argument and settings.console.enable_autocomplete or ["settings", "console", "enable_autocomplete"] as the key argument for the request. The entire settings object could be accessed by providing settings or ["settings"] as the key argument. The entire namespace may be read by omitting the key argument, however as explained below it is not possible to modify a namespace without specifying a key.

List namespaces

Lists all available namespaces.

HTTP request:

GET /server/database/list

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "server.database.list",
    "id": 8694
}

Returns:

An object containing an array of namespaces in the following format:

{
    "namespaces": [
        "gcode_metadata",
        "history",
        "moonraker",
        "test_namespace"
    ]
}

Get Database Item

Retrieves an item from a specified namespace. The key argument may be omitted, in which case an object representing the entire namespace will be returned in the value field. If the key is provided and does not exist in the database an error will be returned.

HTTP request:

GET /server/database/item?namespace={namespace}&key={key}

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "server.database.get_item",
    "params": {
        "namespace": "{namespace}",
        "key": "{key}"
    },
    "id": 5644
}

Returns:

An object containing the requested namespace, key, and value.

{
    "namespace": "moonraker",
    "key": "file_manager.metadata_version",
    "value": 2
}

Add Database Item

Inserts an item into the database. If the namespace does not exist it will be created. If the key specifies a nested field, all parents will be created if they do not exist. If the key exists it will be overwritten with the provided value. The key parameter must be provided, as it is not possible to assign a value directly to a namespace.

HTTP request:

POST /server/database/item?namespace={namespace}&key={key}value={value}`

!!! note If the value is not a string type, the value argument must provide a type hint. Alternatively, arguments may be passed via the request body in JSON format. For example:

POST /server/database/item
Content-Type: application/json

{
    "namespace": "my_client",
    "key": "settings.some_count",
    "value": 100
}

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "server.database.post_item",
    "params": {
        "namespace": "{namespace}",
        "key": "{key}",
        "value": 100
    },
    "id": 4654
}

Returns:

An object containing the inserted namespace, key, and value.

{
    "namespace": "test",
    "key": "settings.some_count",
    "value": 9001
}

Delete Database Item

Deletes an item from a namespace at the specified key. If the key does not exist in the namespace an error will be returned. If the deleted item results in an empty namespace, the namespace will be removed from the database.

HTTP request:

DELETE /server/database/item?namespace={namespace}&key={key}

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "server.database.delete_item",
    "params": {
        "namespace": "{namespace}",
        "key": "{key}"
    },
    "id": 4654
}

Returns: An object containing the namespace, key, and value of the deleted item.

{
    "namespace": "test",
    "key": "settings.some_count",
    "value": 9001
}

Job Queue APIs

The following endpoints may be used to manage Moonraker's job queue. Note that Moonraker's Job Queue is implemented as a FIFO queue and it may contain multiple references to the same job.

!!! Note All filenames provided to and returned by these endpoints are relative to the gcodes root.

Retrieve the job queue status

Retrieves the current state of the job queue

HTTP request:

GET /server/job_queue/status

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "server.job_queue.status",
    "id": 4654
}

Returns:

The current state of the job queue:

{
    "queued_jobs": [
        {
            "filename": "job1.gcode",
            "job_id": "0000000066D99C90",
            "time_added": 1636151050.7666452,
            "time_in_queue": 21.89680004119873
        },
        {
            "filename": "job2.gcode",
            "job_id": "0000000066D991F0",
            "time_added": 1636151050.7766452,
            "time_in_queue": 21.88680004119873
        },
        {
            "filename": "subdir/job3.gcode",
            "job_id": "0000000066D99D80",
            "time_added": 1636151050.7866452,
            "time_in_queue": 21.90680004119873
        }
    ],
    "queue_state": "ready"
}

Below is a description of the returned fields:

  • queued_jobs: an array of objects representing each queued job. Each object contains the filename of the enqueued job and a unique job_id generated for each job. The job_id is a 64-bit Hexadecimal string value. On 32-bit systems the most significant bits will always contain zeros. Items are ordered by the time they were queued, the first item will be the next job loaded.
  • queue_state: The current state of the queue. Can be one of the following:
    • ready: The queue is active and will load the next job upon completion of the current job
    • loading: The queue is currently loading the next job. If the user specified a job_transition_delay and/or job_transition_gcode, the queue will remain in the loading state until both are completed or an error is encountered.
    • starting: The queue enters this state after the loading phase is complete before attempting to start the job.
    • paused: The queue is currently paused and will not load the next job upon completion of the current job. The queue will enter the paused state if an error is encountered during the loading or starting phases, or if the user pauses the queue through the provided endpoint.
  • time_added: The time (in Unix Time) the job was added to the queue
  • time_in_queue: The cumulative amount of time (in seconds) the job has been pending in the queue

Enqueue a job

Adds a job, or an array of jobs, to the end of the job queue. The same filename may be specified multiple times to queue a job that repeats. When multiple jobs are specified they will be enqueued in the order they are received.

!!! Note The request will be aborted and return an error if any of the supplied files do not exist.

HTTP request:

POST /server/job_queue/job?filenames=job1.gcode,job2.gcode,subdir/job3.gcode

!!! Note Multiple jobs should be comma separated as shown above. Alternatively filenames maybe be specified as a json object in the body of the request.

POST /server/job_queue/job
Content-Type: application/json

{
    "filenames": [
        "job1.gcode",
        "job2.gcode",
        "subdir/job3.gcode"
    ],
    "reset": false
}

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "server.job_queue.post_job",
    "params": {
        "filenames": [
            "job1.gcode",
            "job2.gcode",
            "subdir/job3.gcode"
        ],
        "reset": false
    },
    "id": 4654
}

Parameters:

  • reset: A boolean value indicating whether Moonraker should clear the existing queued jobs before adding the new jobs. Defaults to false.

Returns:

The current state of the job queue:

{
    "queued_jobs": [
        {
            "filename": "job1.gcode",
            "job_id": "0000000066D99C90",
            "time_added": 1636151050.7666452,
            "time_in_queue": 21.89680004119873
        },
        {
            "filename": "job2.gcode",
            "job_id": "0000000066D991F0",
            "time_added": 1636151050.7766452,
            "time_in_queue": 21.88680004119873
        },
        {
            "filename": "subdir/job3.gcode",
            "job_id": "0000000066D99D80",
            "time_added": 1636151050.7866452,
            "time_in_queue": 21.90680004119873
        }
    ],
    "queue_state": "ready"
}

Remove a Job

Removes one or more jobs from the queue.

!!! Note Unlike the POST version of this method, it is not necessary that all job ids exist. If any supplied job id does not exist in the queue it will be silently ignored. Clients can verify the contents of the queue via the return value.

HTTP request:

DELETE /server/job_queue/job?job_ids=0000000066D991F0,0000000066D99D80

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "server.job_queue.delete_job",
    "params": {
        "job_ids": [
            "0000000066D991F0".
            "0000000066D99D80"
        ]
    },
    "id": 4654
}

!!! Tip Alternatively all=true ("all": true for JSON-RPC) may specified to clear the job queue.

Returns:

The current state of the job queue:

{
    "queued_jobs": [
        {
            "filename": "job1.gcode",
            "job_id": "0000000066D99C90",
            "time_added": 1636151050.7666452,
            "time_in_queue": 21.89680004119873
        }
    ],
    "queue_state": "ready"
}

Pause the job queue

Sets the job queue state to "pause", which prevents the next job in the queue from loading after an job in progress is complete.

!!! Note If the queue is paused while the queue is in the loading state the load will be aborted.

HTTP request:

POST /server/job_queue/pause

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "server.job_queue.pause",
    "id": 4654
}

Returns:

The current state of the job queue:

{
    "queued_jobs": [
        {
            "filename": "job1.gcode",
            "job_id": "0000000066D99C90",
            "time_added": 1636151050.7666452,
            "time_in_queue": 21.89680004119873
        },
        {
            "filename": "job2.gcode",
            "job_id": "0000000066D991F0",
            "time_added": 1636151050.7766452,
            "time_in_queue": 21.88680004119873
        },
        {
            "filename": "subdir/job3.gcode",
            "job_id": "0000000066D99D80",
            "time_added": 1636151050.7866452,
            "time_in_queue": 21.90680004119873
        }
    ],
    "queue_state": "paused"
}

Start the job queue

Starts the job queue. If Klipper is ready to start a print the next job in the queue will be loaded. Otherwise the queue will be put into the "ready" state, enabling automatic transition after the next completed print.

HTTP request:

POST /server/job_queue/start

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "server.job_queue.start",
    "id": 4654
}

Returns:

The current state of the job queue:

{
    "queued_jobs": [
        {
            "filename": "job1.gcode",
            "job_id": "0000000066D99C90",
            "time_added": 1636151050.7666452,
            "time_in_queue": 21.89680004119873
        },
        {
            "filename": "job2.gcode",
            "job_id": "0000000066D991F0",
            "time_added": 1636151050.7766452,
            "time_in_queue": 21.88680004119873
        },
        {
            "filename": "subdir/job3.gcode",
            "job_id": "0000000066D99D80",
            "time_added": 1636151050.7866452,
            "time_in_queue": 21.90680004119873
        }
    ],
    "queue_state": "loading"
}

Perform a Queue Jump

Jumps a job to the front of the queue.

HTTP request:

POST /server/job_queue/jump?job_id=0000000066D991F0

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "server.job_queue.jump",
    "params" {
        "job_id": "0000000066D991F0"
    },
    "id": 4654
}

Returns:

The current state of the job queue:

{
    "queued_jobs": [
        {
            "filename": "job2.gcode",
            "job_id": "0000000066D991F0",
            "time_added": 1636151050.7766452,
            "time_in_queue": 21.88680004119873
        },
        {
            "filename": "job1.gcode",
            "job_id": "0000000066D99C90",
            "time_added": 1636151050.7666452,
            "time_in_queue": 21.89680004119873
        },
        {
            "filename": "subdir/job3.gcode",
            "job_id": "0000000066D99D80",
            "time_added": 1636151050.7866452,
            "time_in_queue": 21.90680004119873
        }
    ],
    "queue_state": "loading"
}

Announcement APIs

The following endpoints are available to manage announcements. See the appendix for details on how announcements work and recommendations for your implementation.

List announcements

Retrieves a list of current announcements. The include_dismissed argument is optional and defaults to true. If set to false dismissed entries will be omitted from the return value.

HTTP request:

GET /server/announcements/list?include_dismissed=false

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "server.announcements.list",
    "params": {
        "include_dismissed": false
    },
    "id": 4654
}

Returns:

The current list of announcements, in descending order (newest to oldest) sorted by date and a list of feeds Moonraker is currently subscribed to:

{
    {
    "entries": [
        {
            "entry_id": "arksine/moonlight/issue/3",
            "url": "https://github.com/Arksine/moonlight/issues/3",
            "title": "Test announcement 3",
            "description": "Test Description [with a link](https://moonraker.readthedocs.io).",
            "priority": "normal",
            "date": 1647459219,
            "dismissed": false,
            "date_dismissed": null,
            "dismiss_wake": null,
            "source": "moonlight",
            "feed": "moonlight"
        },
        {
            "entry_id": "arksine/moonlight/issue/2",
            "url": "https://github.com/Arksine/moonlight/issues/2",
            "title": "Announcement Test Two",
            "description": "This is a high priority announcement. This line is included in the description.",
            "priority": "high",
            "date": 1646855579,
            "dismissed": false,
            "date_dismissed": null,
            "dismiss_wake": null,
            "source": "moonlight",
            "feed": "moonlight"
        },
        {
            "entry_id": "arksine/moonlight/issue/1",
            "url": "https://github.com/Arksine/moonlight/issues/1",
            "title": "Announcement Test One",
            "description": "This is the description.  Anything here should appear in the announcement, up to 512 characters.",
            "priority": "normal",
            "date": 1646854678,
            "dismissed": false,
            "date_dismissed": null,
            "dismiss_wake": null,
            "source": "moonlight",
            "feed": "moonlight"
        },
        {
            "entry_id": "arksine/moonraker/issue/349",
            "url": "https://github.com/Arksine/moonraker/issues/349",
            "title": "PolicyKit warnings; unable to manage services, restart system, or update packages",
            "description": "This announcement is an effort to get ahead of a coming change that will certainly result in issues.  PR #346  has been merged, and with it are some changes to Moonraker's default behavior.",
            "priority": "normal",
            "date": 1643392406,
            "dismissed": false,
            "source": "moonlight",
            "feed": "Moonraker"
        }
    ],
    "feeds": [
        "moonraker",
        "klipper",
        "moonlight"
    ]
}
}

Update announcements

Requests that Moonraker check for announcement updates. This is generally not required in production, as Moonraker will automatically check for updates every 30 minutes. However, during development this endpoint is useful to force an update when it is necessary to perform integration tests.

HTTP request:

POST /server/announcements/update

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "server.announcements.update",
    "id": 4654
}

Returns:

The current list of announcements, in descending order (newest to oldest) sorted by date, and a modified field that contains a boolean value indicating if the update resulted in a change:

{
    "entries": [
        {
            "entry_id": "arksine/moonraker/issue/349",
            "url": "https://github.com/Arksine/moonraker/issues/349",
            "title": "PolicyKit warnings; unable to manage services, restart system, or update packages",
            "description": "This announcement is an effort to get ahead of a coming change that will certainly result in issues.  PR #346  has been merged, and with it are some changes to Moonraker's default behavior.",
            "priority": "normal",
            "date": 1643392406,
            "dismissed": false,
            "source": "moonlight",
            "feed": "Moonraker"
        },
        {
            "entry_id": "arksine/moonlight/issue/1",
            "url": "https://github.com/Arksine/moonlight/issues/1",
            "title": "Announcement Test One",
            "description": "This is the description.  Anything here should appear in the announcement, up to 512 characters.",
            "priority": "normal",
            "date": 1646854678,
            "dismissed": true,
            "source": "moonlight",
            "feed": "Moonlight"
        },
        {
            "entry_id": "arksine/moonlight/issue/2",
            "url": "https://github.com/Arksine/moonlight/issues/2",
            "title": "Announcement Test Two",
            "description": "This is a high priority announcement. This line is included in the description.",
            "priority": "high",
            "date": 1646855579,
            "dismissed": false,
            "source": "moonlight",
            "feed": "Moonlight"
        },
        {
            "entry_id": "arksine/moonlight/issue/3",
            "url": "https://github.com/Arksine/moonlight/issues/3",
            "title": "Test announcement 3",
            "description": "Test Description [with a link](https://moonraker.readthedocs.io).",
            "priority": "normal",
            "date": 1647459219,
            "dismissed": false,
            "source": "moonlight",
            "feed": "Moonlight"
        }
    ],
    "modified": false
}

Dismiss an announcement

Sets the dismiss flag of an announcement to true. The entry_id field is required. The entry_id contains forward slashes so remember to escape the ID if including it in the query string of an HTTP request.

HTTP request:

POST /server/announcements/dismiss?entry_id=arksine%2Fmoonlight%2Fissue%2F1&wake_time=600

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "server.announcements.dismiss",
    "params": {
        "entry_id": "arksine/moonlight/issue/1",
        "wake_time": 600
    },
    "id": 4654
}

Parameters:

  • entry_id: The entry identifier. This field may contain forward slashes so it should be url escaped when placed in the query string of an http request. This parameter is required.
  • wake_time: The time, in seconds, in which the entry's dismissed state will revert to false. This parameter is optional, if omitted the entry will be dismissed indefinitely.

Returns:

The entry_id of the dismissed entry:

{
    "entry_id": "arksine/moonlight/issue/1"
}

List announcement feeds

HTTP request:

GET /server/announcements/feeds

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "server.announcements.feeds",
    "id": 4654
}

Returns:

A list of feeds the instance of Moonraker is subscribed to.

{
    "feeds": [
        "moonraker",
        "klipper"
    ]
}

Add an announcement feed

Specifies a new feed for Moonraker's announcements component to query in addition to moonraker, klipper, and feeds configured in moonraker.conf.

HTTP request:

POST /server/announcements/feed?name=my_feed

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "server.announcements.post_feed",
    "params": {
        "name": "my_feed"
    },
    "id": 4654
}

Parameters:

  • name: The name of the new feed. This parameter is required.

Returns:

The name of the new feed and the action taken. The action will be added if a new feed added, or skipped if the feed already exists.

{
    "feed": "my_feed",
    "action": "added"
}

Remove an announcement feed

Removes a subscribed feed. Only feeds previously subscribed to using the add feed API may be removed. Feeds configured in moonraker.conf may not be removed.

HTTP request:

DELETE /server/announcements/feed?name=my_feed

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "server.announcements.delete_feed",
    "params": {
        "name": "my_feed"
    },
    "id": 4654
}

Parameters:

  • name: The name of the new feed to remove. This parameter is required.

Returns:

The name of the new feed and the action taken. The action will be removed if the operation was successful.

{
    "feed": "my_feed",
    "action": "removed"
}

Webcam APIs

The following APIs are available to manage webcam configuration:

List Webcams

HTTP request:

GET /server/webcams/list

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "server.webcams.list",
    "id": 4654
}

Returns:

A list of configured webcams:

{
    "webcams": [
        {
            "name": "testcam3",
            "location": "door",
            "service": "mjpegstreamer",
            "enabled": true,
            "icon": "mdiWebcam",
            "target_fps": 20,
            "target_fps_idle": 5,
            "stream_url": "http://camera.lan/webcam?action=stream",
            "snapshot_url": "http://camera.lan/webcam?action=snapshot",
            "flip_horizontal": false,
            "flip_vertical": true,
            "rotation": 90,
            "aspect_ratio": "4:3",
            "extra_data": {},
            "source": "config",
            "uid": "55d3801e-fdc1-438d-8728-2fff8b83b909"
        },
        {
            "name": "tc2",
            "location": "printer",
            "service": "mjpegstreamer",
            "enabled": true,
            "icon": "mdiWebcam",
            "target_fps": 15,
            "target_fps_idle": 5,
            "stream_url": "http://printer.lan/webcam?action=stream",
            "snapshot_url": "http://printer.lan/webcam?action=snapshot",
            "flip_horizontal": false,
            "flip_vertical": false,
            "rotation": 0,
            "aspect_ratio": "4:3",
            "extra_data": {},
            "source": "database",
            "uid": "65e51c8a-6763-41d4-8e76-345bb6e8e7c3"
        },
        {
            "name": "TestCam",
            "location": "printer",
            "service": "mjpegstreamer",
            "enabled": true,
            "icon": "mdiWebcam",
            "target_fps": 15,
            "target_fps_idle": 5,
            "stream_url": "/webcam/?action=stream",
            "snapshot_url": "/webcam/?action=snapshot",
            "flip_horizontal": false,
            "flip_vertical": false,
            "rotation": 0,
            "aspect_ratio": "4:3",
            "extra_data": {},
            "source": "database",
            "uid": "341778f9-387f-455b-8b69-ff68442d41d9"
        }
    ]
}

Get Webcam Information

HTTP request:

GET /server/webcams/item?uid=341778f9-387f-455b-8b69-ff68442d41d9

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "server.webcams.get_item",
    "params": {
        "uid": "341778f9-387f-455b-8b69-ff68442d41d9"
    },
    "id": 4654
}

Parameters:

  • uid: The webcam's assigned unique ID. This parameter is optional, when not specified the request will fallback to the name parameter.
  • name: The name of the webcam to request information for. If the named webcam is not available the request will return with an error. This parameter must be provided when the uid is omitted.

Returns:

The full configuration for the requested webcam:

{
    "webcam": {
        "name": "TestCam",
        "location": "printer",
        "service": "mjpegstreamer",
        "enabled": true,
        "icon": "mdiWebcam",
        "target_fps": 15,
        "target_fps_idle": 5,
        "stream_url": "/webcam/?action=stream",
        "snapshot_url": "/webcam/?action=snapshot",
        "flip_horizontal": false,
        "flip_vertical": false,
        "rotation": 0,
        "aspect_ratio": "4:3",
        "extra_data": {},
        "source": "database",
        "uid": "341778f9-387f-455b-8b69-ff68442d41d9"
    }
}

Add or update a webcam

Adds a new webcam entry or updates an existing entry. When updating an entry only the fields provided will be modified.

!!! Note A webcam configured via moonraker.conf cannot be updated or overwritten using this API.

HTTP request:

POST /server/webcams/item
Content-Type: application/json

{
    "name": "cam_name",
    "snapshot_url": "http://printer.lan:8080/webcam?action=snapshot",
    "stream_url": "http://printer.lan:8080/webcam?action=stream"
}

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "server.webcams.post_item",
    "params": {
        "name": "cam_name",
        "snapshot_url": "/webcam?action=snapshot",
        "stream_url": "/webcam?action=stream"
    },
    "id": 4654
}

Parameters:

  • uid: The unique ID of the webcam. This parameter may be specified to modify an existing webcam. New entries must omit the uid.
  • name: The name of the camera to add or update. This parameter must be provided for new entries.
  • location: A description of the webcam location, ie: what the webcam is observing. The default is printer for new entries.
  • icon: The name of the icon to use for the camera. The default is mdiWebcam for new entries.
  • enabled: A boolean value to indicate if this webcam should be enabled. Default is True for new entries.
  • service: The name of the webcam application streaming service. The default is "mjpegstreamer" for new entries.
  • target_fps: The target framerate. The default is 15 for new entries.
  • target_fps_idle: The target framerate when the printer is idle. The default is 5 for new entries.
  • stream_url: The url for the camera stream request. This may be a full url or a url relative to Moonraker's host machine. If the url is relative it is assumed that the stream is available over http on port 80. This parameter must be provided for new entries.
  • snapshot_url: The url for the camera snapshot request. This may be a full url or a url relative to Moonraker's host machine. If the url is relative it is assumed that the snapshot is available over http on port 80. The default is an empty string for new entries.
  • flip_horizontal: A boolean value indicating whether the stream should be flipped horizontally. The default is false for new entries.
  • flip_vertical: A boolean value indicating whether the stream should be flipped vertically. The default is false for new entries.
  • rotation: An integer value indicating the amount of clockwise rotation to apply to the stream. May be 0, 90, 180, or 270. The default is 0 for new entries.
  • aspect_ratio: The aspect ratio to display for the camera. Note that this option is specific to certain services, otherwise it is ignored. The default is 4:3 for new entries.
  • extra_data: Additional webcam data set by the front end in the form of a json object. This may be used to store any additional webcam options and/or data. The default is an empty object for new entries.

!!! Tip When modifying existing entries it is possible to rename an existing item by specifying its current uid and a new value for name. Keep in mind that names must be unique, an attempt to rename an existing webcam to another name that is reserved will result in an error.

Returns:

The full configuration for the added/updated webcam:

{
    "webcam": {
        "name": "TestCam",
        "location": "printer",
        "service": "mjpegstreamer",
        "enabled": true,
        "icon": "mdiWebcam",
        "target_fps": 15,
        "target_fps_idle": 5,
        "stream_url": "/webcam/?action=stream",
        "snapshot_url": "/webcam/?action=snapshot",
        "flip_horizontal": false,
        "flip_vertical": false,
        "rotation": 0,
        "aspect_ratio": "4:3",
        "extra_data": {},
        "source": "database",
        "uid": "341778f9-387f-455b-8b69-ff68442d41d9"
    }
}

Delete a webcam

!!! Note A webcam configured via moonraker.conf cannot be deleted using this API.

HTTP request:

DELETE /server/webcams/uid?name=341778f9-387f-455b-8b69-ff68442d41d9

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "server.webcams.delete_item",
    "params": {
        "uid": "341778f9-387f-455b-8b69-ff68442d41d9"
    },
    "id": 4654
}

Parameters:

  • uid: The webcam's assigned unique ID. This parameter is optional, when not specified the request will fallback to the name parameter.
  • name: The name of the webcam to delete. If the named webcam is not available the request will return with an error. This parameter must be provided when the uid is omitted.

Returns:

The full configuration of the deleted webcam:

{
    "webcam": {
        "name": "TestCam",
        "location": "printer",
        "service": "mjpegstreamer",
        "target_fps": 15,
        "stream_url": "/webcam/?action=stream",
        "snapshot_url": "/webcam/?action=snapshot",
        "flip_horizontal": false,
        "flip_vertical": false,
        "rotation": 0,
        "source": "database",
        "uid": "341778f9-387f-455b-8b69-ff68442d41d9"
    }
}

Test a webcam

Resolves a webcam's stream and snapshot urls. If the snapshot is served over http, a test is performed to see if the url is reachable.

HTTP request:

POST /server/webcams/test?uid=341778f9-387f-455b-8b69-ff68442d41d9

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "server.webcams.test",
    "params": {
        "uid": "341778f9-387f-455b-8b69-ff68442d41d9"
    },
    "id": 4654
}

Parameters:

  • uid: The webcam's assigned unique ID. This parameter is optional, when not specified the request will fallback to the name parameter.
  • name: The name of the webcam to test. If the named webcam is not available the request will return with an error. This parameter must be provided when the uid is omitted.

Returns: Test results in the following format

{
    "name": "TestCam",
    "snapshot_reachable": true,
    "snapshot_url": "http://127.0.0.1:80/webcam/?action=snapshot",
    "stream_url": "http://127.0.0.1:80/webcam/?action=stream"
}

Notifier APIs

The following APIs are available to view and tests notifiers.

List Notifiers

HTTP request:

GET /server/notifiers/list

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "server.notifiers.list",
    "id": 4654
}

Returns:

A list of configured notifiers:

{
    "notifiers": [
        {
            "name": "print_start",
            "url": "tgram://{bottoken}/{ChatID}",
            "events": [
                "started"
            ],
            "body": "Your printer started printing '{event_args[1].filename}'",
            "title": null,
            "attach": null
        },
        {
            "name": "print_complete",
            "url": "tgram://{bottoken}/{ChatID}",
            "events": [
                "complete"
            ],
            "body": "Your printer completed printing '{event_args[1].filename}",
            "title": null,
            "attach": "http://192.168.1.100/webcam/?action=snapshot"
        },
        {
            "name": "print_error",
            "url": "tgram://{bottoken}/{ChatID}",
            "events": [
                "error"
            ],
            "body": "{event_args[1].message}",
            "title": null,
            "attach": "http://192.168.1.100/webcam/?action=snapshot"
        }
    ]
}

Update Manager APIs

The following endpoints are available when the [update_manager] component has been configured:

Get update status

Retrieves the current state of each item available for update. Items may include the linux package manager (system), applications such as moonraker and klipper, web clients such as mainsail and fluidd, and other configured applications/extensions.

HTTP request:

GET /machine/update/status?refresh=false

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "machine.update.status",
    "params": {
        "refresh": false
    },
    "id": 4644
}

Parameters:

  • refresh: (Optional) When set to true state for all updaters will be refreshed. The default is false. A request to refresh is aborted under the following conditions:
    • An update is in progress
    • A print is in progress
    • The update manager hasn't completed initialization
    • A previous refresh has occured within the last 60 seconds

!!! Note The refresh parameter is deprecated. Client developers should use the refresh endpoint to request a refresh.

Returns:

Status information for each update package. Note that mainsail and fluidd are present as clients configured in moonraker.conf

{
    "busy": false,
    "github_rate_limit": 60,
    "github_requests_remaining": 57,
    "github_limit_reset_time": 1615836932,
    "version_info": {
        "system": {
            "package_count": 4,
            "package_list": [
                "libtiff5",
                "raspberrypi-sys-mods",
                "rpi-eeprom-images",
                "rpi-eeprom"
            ]
        },
        "moonraker": {
            "channel": "dev",
            "debug_enabled": true,
            "is_valid": true,
            "configured_type": "git_repo",
            "corrupt": false,
            "info_tags": [],
            "detected_type": "git_repo",
            "remote_alias": "arksine",
            "branch": "master",
            "owner": "?",
            "repo_name": "moonraker",
            "version": "v0.7.1-364",
            "remote_version": "v0.7.1-364",
            "rollback_version": "v0.7.1-360",
            "current_hash": "ecfad5cff15fff1d82cb9bdc64d6b548ed53dfaf",
            "remote_hash": "ecfad5cff15fff1d82cb9bdc64d6b548ed53dfaf",
            "is_dirty": false,
            "detached": true,
            "commits_behind": [],
            "git_messages": [],
            "full_version_string": "v0.7.1-364-gecfad5c",
            "pristine": true,
            "recovery_url": "https://github.com/Arksine/moonraker.git",
            "remote_url": "https://github.com/Arksine/moonraker.git",
            "warnings": [],
            "anomalies": [
                "Unofficial remote url: https://github.com/Arksine/moonraker-fork.git",
                "Repo not on offical remote/branch, expected: origin/master, detected: altremote/altbranch",
                "Detached HEAD detected"
            ]
        },
        "mainsail": {
            "name": "mainsail",
            "owner": "mainsail-crew",
            "version": "v2.1.1",
            "remote_version": "v2.1.1",
            "rollback_version": "v2.0.0",
            "configured_type": "web",
            "channel": "stable",
            "info_tags": [
                "desc=Mainsail Web Client",
                "action=some_action"
            ],
            "warnings": [],
            "anomalies": [],
            "is_valid": true
        },
        "fluidd": {
            "name": "fluidd",
            "owner": "fluidd-core",
            "version": "v1.16.2",
            "remote_version": "v1.16.2",
            "rollback_version": "v1.15.0",
            "configured_type": "web",
            "channel": "beta",
            "info_tags": [],
            "warnings": [],
            "anomalies": [],
            "is_valid": true
        },
        "klipper": {
            "channel": "dev",
            "debug_enabled": true,
            "is_valid": true,
            "configured_type": "git_repo",
            "corrupt": false,
            "info_tags": [],
            "detected_type": "git_repo",
            "remote_alias": "origin",
            "branch": "master",
            "owner": "Klipper3d",
            "repo_name": "klipper",
            "version": "v0.10.0-1",
            "remote_version": "v0.10.0-41",
            "rollback_version": "v0.9.1-340",
            "current_hash": "4c8d24ae03eadf3fc5a28efb1209ce810251d02d",
            "remote_hash": "e3cbe7ea3663a8cd10207a9aecc4e5458aeb1f1f",
            "is_dirty": false,
            "detached": false,
            "commits_behind": [
                {
                    "sha": "e3cbe7ea3663a8cd10207a9aecc4e5458aeb1f1f",
                    "author": "Kevin O'Connor",
                    "date": "1644534721",
                    "subject": "stm32: Clear SPE flag on a change to SPI CR1 register",
                    "message": "The stm32 specs indicate that the SPE bit must be cleared before\nchanging the CPHA or CPOL bits.\n\nReported by @cbc02009 and @bigtreetech.\n\nSigned-off-by: Kevin O'Connor <kevin@koconnor.net>",
                    "tag": null
                },
                {
                    "sha": "99d55185a21703611b862f6ce4b80bba70a9c4b5",
                    "author": "Kevin O'Connor",
                    "date": "1644532075",
                    "subject": "stm32: Wait for transmission to complete before returning from spi_transfer()",
                    "message": "It's possible for the SCLK pin to still be updating even after the\nlast byte of data has been read from the receive pin.  (In particular\nin spi mode 0 and 1.)  Exiting early from spi_transfer() in this case\ncould result in the CS pin being raised before the final updates to\nSCLK pin.\n\nAdd an additional wait at the end of spi_transfer() to avoid this\nissue.\n\nSigned-off-by: Kevin O'Connor <kevin@koconnor.net>",
                    "tag": null
                },
            ],
            "git_messages": [],
            "full_version_string": "v0.10.0-1-g4c8d24ae-shallow",
            "pristine": true,
            "recovery_url": "https://github.com/Klipper3d/klipper.git",
            "remote_url": "https://github.com/Klipper3d/klipper.git",
            "warnings": [],
            "anomalies": [],
        }
    }
}

Below is an explanation for each field:

  • busy: set to true if an update is in progress. Moonraker will not allow concurrent updates.
  • github_rate_limit: the maximum number of github API requests the user currently is allowed. An unauthenticated user typically has 60 requests per hour.
  • github_requests_remaining: the number of API request the user currently has remaining.
  • github_limit_reset_time: the time when the rate limit will reset, reported as seconds since the epoch (aka Unix Time).

Extensions configured with the git_repo type will contain the following fields:

  • configured_type: the application type configured by the user
  • detected_type: the application type as detected by Moonraker.
  • channel: the currently configured update channel. For Moonraker and Klipper this is set in the [update_manager] configuration. For clients the channel is determined by the configured type
  • pristine: Indicates that there are no modified files or untracked source files in a git_repo. A repo with untracked files can still be updated, however a repo with modified files (ie: dirty) cannot be updated.
  • owner: the owner of the repo / application
  • branch: the name of the current git branch. This should typically be "master".
  • remote_alias: the alias for the remote. This should typically be "origin".
  • version: abbreviated version of the current repo on disk
  • remote_version: abbreviated version of the latest available update
  • rollback_version: version the repo will revert to when a rollback is requested
  • full_version_string: The complete version string of the current repo.
  • current_hash: hash of the most recent commit on disk
  • remote_hash: hash of the most recent commit pushed to the remote
  • is_valid: true if the git_repo is valid and can be updated.
  • corrupt: Indicates that the git repo has been corrupted. When a repo is in this state it a hard recovery (ie: re-cloning the repo) is necessary. Note that the most common cause of repo corruption is removing power from the host machine without safely shutting down. Damaged storage can also lead to repo corruption.
  • is_dirty: true if a git_repo has modified files. A dirty repo cannot be updated.
  • detached: true if the git_repo is currently in a detached state.
  • debug_enabled: True when debug flag has been set via the command line. When debug is enabled Moonraker will allow detached updates.
  • commits_behind: A list of commits behind. Up to 30 "untagged" commits will be reported. Moonraker checks the last 100 commits for tags, any commits beyond the last 30 with a tag will also be reported.
  • git_messages: If a repo is in the "invalid" state this field will hold a list of string messages containing the output of the last failed git command. Note that it is possible for a git command to fail without providing output (for example, it may become non-responsive and time out), so it is possible for this field to be an empty list when the repo is invalid.
  • info_tags: These are tags defined in the [update_manager client_name] configuration for each client. Client developers my define what tags, if any, users will configure. They can choose to use those tags to display information or perform an additional action after an update if necessary.
  • recovery_url: The url Moonraker will use to re-clone the repo when a hard recovery is requested. If this reports a "?" then a hard recovery is not possible.
  • remote_url: The url for the currently configured remote.
  • warnings: An array of strings that describe warnings detected during repo init. These warnings provide additional context when the is_valid field reports true.
  • anomalies: An array of strings that describe anomalies found during initialization. An anomaly can be defined as an unexpected condition, they will not result in an invalid state, nor will they prevent an update. For example, when the detected remote url does not match the configured/expected url Moonraker will fall back to the detected url and report this condition as an anomaly.

Extensions configured with the web type will contain the following fields:

  • channel: channel to fetch updates from
  • configured_type: will be web
  • name: name of the configured client
  • owner: the owner of the client
  • version: version of the installed client.
  • remote_version: version of the latest release published to GitHub
  • rollback_version: version the client will revert to when a rollback is requested
  • info_tags: These are tags defined in the [update_manager client_name] configuration for each client. Client developers my define what tags, if any, users will configure. They can choose to use those tags to display information or perform an additional action after an update if necessary.
  • is_valid: A boolean that reports true if an update is possible, false if an update cannot be performed.
  • warnings: An array of strings that describe warnings detected during updater init. These warnings add context when the is_valid field reports true.
  • anomalies: An array of strings that describe anomalies found during initialization. An anomaly can be defined as an unexpected condition, they will not result in an invalid state, nor will they prevent an update. For example, when the configured repo to check for updates does not match the detected repo Moonraker will fall back to the detected repo and report this condition as an anomaly.

The system object contains the following fields:

  • package_count: the number of system packages available for update
  • package_list: an array containing the names of packages available for update

Refresh update status

Refreshes the internal update state for the requested item(s).

HTTP request:

POST /machine/update/refresh?name=klipper

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "machine.update.refresh",
    "params": {
        "name": "klipper"
    },
    "id": 4644
}

Parameters:

  • name: (Optional) The name of the specified application. If omitted all registered applications will be refreshed.

Returns:

An object containing full update status matching the response in the status endpoint.

!!! Note This endpoint will raise 503 error under the following conditions:

  - An update is in progress
  - A print is in progress
  - The update manager hasn't completed initialization

!!! Warning Applications should use care when calling this method as a refresh is CPU intensive and may be time consuming. Moonraker can be configured to refresh state periodically, thus it is recommended that applications avoid their own procedural implementations. Instead it is best to call this API only when a user requests a refresh.

Perform a full update

Attempts to update all configured items in Moonraker. Updates are performed in the following order:

  • system if enabled
  • All configured clients
  • Klipper
  • Moonraker

HTTP request:

POST /machine/update/full

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "machine.update.full",
    "id": 4645
}

Returns:

ok when complete

Update Moonraker

Pulls the most recent version of Moonraker from GitHub and restarts the service. If an update is requested while a print is in progress then this request will return an error.

HTTP request:

POST /machine/update/moonraker

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "machine.update.moonraker",
    "id": 4645
}

Returns:

ok when complete

Update Klipper

Pulls the most recent version of Klipper from GitHub and restarts the service. If an update is requested while a print is in progress then this request will return an error.

HTTP request:

POST /machine/update/klipper

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "machine.update.klipper",
    "id": 5745
}

Returns:

ok when complete

Update Client

If one more more [update_manager client client_name] sections have been configured this endpoint can be used to install the most recently published release of the client. If an update is requested while a print is in progress then this request will return an error. The name argument is required, it's value should match the client_name of the configured section.

HTTP request:

POST /machine/update/client?name={client_name}

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method":  "machine.update.client",
    "params": {
        "name": "client_name"
    },
    "id": 8546
}

Returns:

ok when complete

Update System Packages

Upgrades system packages. Currently only apt-get is supported. If an update is requested while a print is in progress then this request will return an error.

HTTP request:

POST /machine/update/system

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "machine.update.system",
    "id": 4564
}

Returns:

ok when complete

Recover a corrupt repo

On occasion a git command may fail resulting in a repo in a dirty or invalid state. When this happens it is possible to recover. The name argument must specify the name of the repo to recover, it must be of a git repo type. There are two methods of recovery, the hard argument determines which method is used:

  • hard == true: Moonraker will remove the old directory entirely. It will then attempt to recover with rsync by restoring a backup of a recent valid repo.
  • hard == false: Will run git clean -f -d followed by git reset --hard {remote}/{branch}. This is useful for recovering dirty repos that are valid. It is possible that this will work on an invalid repo, however it will not work on a corrupt repo.

The hard argument defaults to false.

HTTP request:

POST /machine/update/recover?name=moonraker&hard=false

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "machine.update.recover",
    "params": {
        "name": "moonraker",
        "hard": false
    },
    "id": 4564
}

Returns:

ok when complete

Rollback to the previous version

HTTP request:

POST /machine/update/rollback?name=moonraker

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "machine.update.rollback",
    "params": {
        "name": "moonraker"
    },
    "id": 4564
}

Returns:

ok when complete

Power APIs

The APIs below are available when the [power] component has been configured.

Get Device List

HTTP request:

GET /machine/device_power/devices

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method":"machine.device_power.devices",
    "id": 5646
}

Returns:

An array of objects containing info for each configured device.

{
    "devices": [
        {
            "device": "green_led",
            "status": "off",
            "locked_while_printing": true,
            "type": "gpio"
        },
        {
            "device": "printer",
            "status": "off",
            "locked_while_printing": false,
            "type": "tplink_smartplug"
        }
    ]
}

Get Device Status

Returns the status for a single configured device.

HTTP request:

GET /machine/device_power/device?device=green_led

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "machine.device_power.get_device",
    "params": {
        "device": "green_led"
    },
    "id": 4564
}

Returns:

An object containing power state for the requested device:

{
    "green_led": "off"
}

Set Device State

Toggle, turn on, or turn off a specified device.

HTTP request:

POST /machine/device_power/device?device=green_led&action=on

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "machine.device_power.post_device",
    "params": {
        "device": "green_led",
        "action": "on"
    },
    "id": 4564
}

!!! note The action argument may be on, off, or toggle. Any other value will result in an error.

Returns:

An object containing new power state for the requested device:

{
    "green_led": "off"
}

Get Batch Device Status

Get power status for the requested devices. At least one device must be specified.

HTTP request:

GET /machine/device_power/status?dev_one&dev_two

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "machine.device_power.status",
    "params": {
        "dev_one":null,
        "dev_two": null
    },
    "id": 4564
}

Returns:

An object containing power state for each requested device:

{
    "green_led": "off",
    "printer": "off"
}

Batch Power On Devices

Power on the requested devices. At least one device must be specified.

HTTP request:

POST /machine/device_power/on?dev_one&dev_two

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "machine.device_power.on",
    "params": {
        "dev_one":null,
        "dev_two": null
    },
    "id": 4564
}

An object containing power state for each requested device:

{
    "green_led": "on",
    "printer": "on"
}

Batch Power Off Devices

Power off the requested devices. At least one device must be specified.

HTTP request:

POST /machine/device_power/off?dev_one&dev_two

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "machine.device_power.off",
    "params": {
        "dev_one": null,
        "dev_two": null
    },
    "id": 4564
}

An object containing power state for each requested device:

{
    "green_led": "off",
    "printer": "off"
}

WLED APIs

The APIs for WLED are available when the [wled] component has been configured. For lower-level control of wled consider using the WLED JOSN API directly.

Get strips

HTTP request:

GET /machine/wled/strips

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method":"machine.wled.strips",
    "id": 7123
}

Returns:

Strip information for all wled strips.

{
    "result": {
        "strips": {
            "lights": {
                "strip": "lights",
                "status": "on",
                "chain_count": 79,
                "preset": -1,
                "brightness": 255,
                "intensity": -1,
                "speed": -1,
                "error": null
            },
            "desk": {
                "strip": "desk",
                "status": "on",
                "chain_count": 60,
                "preset": 8,
                "brightness": -1,
                "intensity": -1,
                "speed": -1,
                "error": null
            }
        }
    }
}

Get strip status

HTTP request:

GET /machine/wled/status?strip1&strip2

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method":"machine.wled.status",
    "params": {
        "lights": null,
        "desk": null
    },
    "id": 7124
}

Returns:

Strip information for requested strips.

{
    "result": {
        "lights": {
            "strip": "lights",
            "status": "on",
            "chain_count": 79,
            "preset": -1,
            "brightness": 255,
            "intensity": -1,
            "speed": -1,
            "error": null
        },
        "desk": {
            "strip": "desk",
            "status": "on",
            "chain_count": 60,
            "preset": 8,
            "brightness": -1,
            "intensity": -1,
            "speed": -1,
            "error": null
        }
    }
}

Turn strip on

Turns the specified strips on to the initial colors or intial preset.

HTTP request:

POST /machine/wled/on?strip1&strip2

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method":"machine.wled.on",
    "params": {
        "lights": null,
        "desk": null
    },
    "id": 7125
}

Returns:

Strip information for requested strips.

{
    "result": {
        "lights": {
            "strip": "lights",
            "status": "on",
            "chain_count": 79,
            "preset": -1,
            "brightness": 255,
            "intensity": -1,
            "speed": -1,
            "error": null
        },
        "desk": {
            "strip": "desk",
            "status": "on",
            "chain_count": 60,
            "preset": 8,
            "brightness": -1,
            "intensity": -1,
            "speed": -1,
            "error": null
        }
    }
}

Turn strip off

Turns off all specified strips.

HTTP request:

POST /machine/wled/off?strip1&strip2

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method":"machine.wled.off",
    "params": {
        "lights": null,
        "desk": null
    },
    "id": 7126
}

Returns:

The new state of the specified strips.

{
    "result": {
        "lights": {
            "strip": "lights",
            "status": "off",
            "chain_count": 79,
            "preset": -1,
            "brightness": 255,
            "intensity": -1,
            "speed": -1,
            "error": null
        },
        "desk": {
            "strip": "desk",
            "status": "off",
            "chain_count": 60,
            "preset": 8,
            "brightness": -1,
            "intensity": -1,
            "speed": -1,
            "error": null
        }
    }
}

Toggle strip on/off state

Turns each strip off if it is on and on if it is off.

HTTP request:

POST /machine/wled/off?strip1&strip2

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method":"machine.wled.toggle",
    "params": {
        "lights": null,
        "desk": null
    },
    "id": 7127
}

Returns:

The new state of the specified strips.

{
    "result": {
        "lights": {
            "strip": "lights",
            "status": "on",
            "chain_count": 79,
            "preset": -1,
            "brightness": 255,
            "intensity": -1,
            "speed": -1,
            "error": null
        },
        "desk": {
            "strip": "desk",
            "status": "off",
            "chain_count": 60,
            "preset": 8,
            "brightness": -1,
            "intensity": -1,
            "speed": -1,
            "error": null
        }
    }
}

Control individual strip state

Toggle, turn on, turn off, turn on with preset, turn on with brightness, or turn on preset will some of brightness, intensity, and speed. Or simply set some of brightness, intensity, and speed.

HTTP requests:

Turn strip lights off

POST /machine/wled/strip?strip=lights&action=off

Turn strip lights on to the initial colors or intial preset.

POST /machine/wled/strip?strip=lights&action=on

Turn strip lights on activating preset 3.

POST /machine/wled/strip?strip=lights&action=on&preset=3

Turn strip lights on activating preset 3 while specifying speed and intensity.

POST /machine/wled/strip?strip=lights&action=on&preset=3&intensity=50&speed=255

Change strip lights brightness (if on) and speed (if a preset is active).

POST /machine/wled/strip?strip=lights&action=control&brightness=99&speed=50

JSON-RPC request:

Returns information for the specified strip.

{
    "jsonrpc": "2.0",
    "method":"machine.wled.get_strip",
    "params": {
        "strip": "lights",
    },
    "id": 7128
}

Calls the action with the arguments for the specified strip.

{
    "jsonrpc": "2.0",
    "method":"machine.wled.post_strip",
    "params": {
        "strip": "lights",
        "action": "on",
        "preset": 1,
        "brightness": 255,
        "intensity": 255,
        "speed": 255
    },
    "id": 7129
}

!!! note The action argument may be on, off, toggle or control. Any other value will result in an error.

The intensity and speed arguments are only used if a preset is active. Permitted ranges are 1-255 for brightness and 0-255 for intensity and speed. When action is on a preset with some or all of brightness, intensity and speed may also be specified. If the action control is used one or all of brightness, intensity, and speed must be specified.

Returns:

State of the strip.

{
    "result": {
        "lights": {
            "strip": "lights",
            "status": "on",
            "chain_count": 79,
            "preset": 1,
            "brightness": 50,
            "intensity": 255,
            "speed": 255,
            "error": null
        }
    }
}

Sensor APIs

The APIs below are available when the [sensor] component has been configured.

Get Sensor List

HTTP request:

GET /server/sensors/list

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method":"server.sensors.list",
    "id": 5646
}

Returns:

An array of objects containing info for each configured sensor.

{
    "sensors": {
        "sensor1": {
            "id": "sensor1",
            "friendly_name": "Sensor 1",
            "type": "mqtt",
            "values": {
                "value1": 0,
                "value2": 119.8
            }
        }
    }
}

Get Sensor Information

Returns the status for a single configured sensor.

HTTP request:

GET /server/sensors/info?sensor=sensor1

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "server.sensors.info",
    "params": {
        "sensor": "sensor1"
    },
    "id": 4564
}

Returns:

An object containing sensor information for the requested sensor:

{
    "id": "sensor1",
    "friendly_name": "Sensor 1",
    "type": "mqtt",
    "values": {
        "value1": 0.0,
        "value2": 120.0
    }
}

Get Sensor Measurements

Returns all recorded measurements for a configured sensor.

HTTP request:

GET /server/sensors/measurements?sensor=sensor1

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "server.sensors.measurements",
    "params": {
        "sensor": "sensor1"
    },
    "id": 4564
}

Returns:

An object containing all recorded measurements for the requested sensor:

{
    "sensor1": {
        "value1": [
            3.1,
            3.2,
            3.0
        ],
        "value2": [
            120.0,
            120.0,
            119.9
        ]
    }
}

Get Batch Sensor Measurements

Returns recorded measurements for all sensors.

HTTP request:

GET /server/sensors/measurements

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "server.sensors.measurements",
    "id": 4564
}

Returns:

An object containing all measurements for every configured sensor:

{
    "sensor1": {
        "value1": [
            3.1,
            3.2,
            3.0
        ],
        "value2": [
            120.0,
            120.0,
            119.9
        ]
    },
    "sensor2": {
        "value_a": [
            1,
            1,
            0
        ]
    }
}

Spoolman APIs

The following APIs are available to interact with the Spoolman integration:

Get Spoolman Status

Returns the current status of the spoolman module.

HTTP request:

GET /server/spoolman/status

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "server.spoolman.status",
    "id": 4654
}

Returns:

An object containing details about the current status:

{
    "spoolman_connected": false,
    "pending_reports": [
        {
            "spool_id": 1,
            "filament_used": 10
        }
    ],
    "spool_id": 2
}
  • spoolman_connected: A boolean indicating if Moonraker is connected to Spoolman. When false Spoolman is unavailable.
  • pending_reports: A list of objects containing spool data that has yet to be reported to Spoolman.
  • spool_id: The current Spool ID. Can be an integer value or null.

Set active spool

Set the ID of the spool that Moonraker should report usage to Spoolman of.

HTTP request:

POST /server/spoolman/spool_id
Content-Type: application/json

{
    "spool_id": 1
}

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "server.spoolman.post_spool_id",
    "params": {
        "spool_id": 1
    },
    "id": 4654
}

Returns:

The id of the now active spool:

{
    "spool_id": 1
}

!!! note Send an empty object, {}, to un-set the spool ID and stop any reporting. The response spool_id will then be set to null

Get active spool

Retrieve the ID of the spool to which Moonraker reports usage for Spoolman.

HTTP request:

GET /server/spoolman/spool_id

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "server.spoolman.get_spool_id",
    "id": 4654
}

Returns:

The id of the active spool:

{
    "spool_id": 1
}

!!! note The spool_id can be null if there is no active spool.

Proxy

Moonraker supplies a proxy endpoint where you have full access to the Spoolman API without having to configure the endpoint yourself.

See Spoolman's OpenAPI Description for detailed information about it's API.

HTTP request:

POST /server/spoolman/proxy
Content-Type: application/json

{
    "request_method": "POST",
    "path": "/v1/spool",
    "query": "a=1&b=4",
    "body": {
        "filament_id": 1
    }
}

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "server.spoolman.proxy",
    "params": {
        "use_v2_response": true,
        "request_method": "POST",
        "path": "/v1/spool",
        "query": "a=1&b=4",
        "body": {
            "filament_id": 1
        }
    },
    "id": 4654
}

The following parameters are available. request_method and path are required, the rest are optional.

  • request_method: The HTTP request method, e.g. GET, POST, DELETE, etc..
  • path: The endpoint, including API version, e.g. /v1/filament.
  • query: The query part of the URL, e.g. filament_material=PLA&vendor_name=Prima.
  • body: The request body for the request.
  • use_v2_response: Returns the spoolman response in version 2 format. Default is false.

!!! Note The version 2 response has been added to eliminate ambiguity between Spoolman errors and Moonraker errors. With version 1 a frontend is not able to reliably to determine if the error is sourced from Spoolman or Moonraker. Version 2 responses will return success unless Moonraker is the source of the error.

The version 2 response is currently opt-in to avoid breaking
existing implementations, however in the future it will be
required, at which point the version 1 response will be removed.
The version 1 response is now deprecated.

Returns:

  • Version 1

The json response from the Spoolman server. Errors are proxied directly. For example, if a request returns 404, Moonraker will return a 404 error or the JSON-RPC equivalent of -32601, Method Not Found.

  • Version 2

Returns the spoolman response wrapped in an object. The object contains two fields, error and response. A successful request will place the returned value in the response field and error will be null. When Spoolman returns an error the response field will be null and the error field will contain details about the error.

{
    "response": {
        "id": 2,
        "registered": "2023-11-23T12:18:31Z",
        "first_used": "2023-11-22T12:17:56.123000Z",
        "last_used": "2023-11-23T10:17:59.900000Z",
        "filament": {
            "id": 2,
            "registered": "2023-11-23T12:17:44Z",
            "name": "Reactor Red",
            "vendor": {
                "id": 2,
                "registered": "2023-06-26T21:00:42Z",
                "name": "Fusion"
            },
            "material": "PLA",
            "price": 25,
            "density": 1.24,
            "diameter": 1.75,
            "weight": 1000,
            "color_hex": "BD0B0B"
        },
        "remaining_weight": 950,
        "used_weight": 50,
        "remaining_length": 318519.4384459262,
        "used_length": 16764.18097083822,
        "archived": false
    },
    "error": null
}

On Spoolman error:

{
    "response": null,
    "error": {
        "status_code": 404,
        "message": "No spool with ID 3 found."
    }
}

OctoPrint API emulation

Partial support of OctoPrint API is implemented with the purpose of allowing uploading of sliced prints to a moonraker instance. Currently we support Slic3r derivatives and Cura with Cura-OctoPrint.

Version information

HTTP request:

GET /api/version

JSON-RPC request: Not Available

Returns:

An object containing simulated OctoPrint version information

{
    "server": "1.5.0",
    "api": "0.1",
    "text": "OctoPrint (Moonraker v0.3.1-12)"
}

Server status

HTTP request:

GET /api/server

JSON-RPC request: Not Available

Returns:

An object containing simulated OctoPrint server status

{
    "server": "1.5.0",
    "safemode": "settings"
}

Login verification & User information

HTTP request:

GET /api/login

JSON-RPC request: Not Available

Returns:

An object containing stubbed OctoPrint login/user verification

{
    "_is_external_client": false,
    "_login_mechanism": "apikey",
    "name": "_api",
    "active": true,
    "user": true,
    "admin": true,
    "apikey": null,
    "permissions": [],
    "groups": ["admins", "users"],
}

Get settings

HTTP request:

GET /api/settings

JSON-RPC request: Not Available

Returns:

An object containing stubbed OctoPrint settings. The webcam route is hardcoded to Fluidd/Mainsail default path. We say we have the UFP plugin installed so that Cura-OctoPrint will upload in the preferred UFP format.

{
    "plugins": {
        "UltimakerFormatPackage": {
            "align_inline_thumbnail": false,
            "inline_thumbnail": false,
            "inline_thumbnail_align_value": "left",
            "inline_thumbnail_scale_value": "50",
            "installed": true,
            "installed_version": "0.2.2",
            "scale_inline_thumbnail": false,
            "state_panel_thumbnail": true
        }
    },
    "feature": {
        "sdSupport": false,
        "temperatureGraph": false
    },
    "webcam": {
        "flipH": false,
        "flipV": false,
        "rotate90": false,
        "streamUrl": "/webcam/?action=stream",
        "webcamEnabled": true
    }
}

OctoPrint File Upload

HTTP request:

POST /api/files/local

JSON-RPC request: Not Available

Alias for Moonraker's file upload API.

Get Job status

HTTP request:

GET /api/job

JSON-RPC request: Not Available

Returns:

An object containing stubbed OctoPrint Job status

{
    "job": {
        "file": {"name": null},
        "estimatedPrintTime": null,
        "filament": {"length": null},
        "user": null
    },
    "progress": {
        "completion": null,
        "filepos": null,
        "printTime": null,
        "printTimeLeft": null,
        "printTimeOrigin": null
    },
    "state": "Offline"
}

Get Printer status

HTTP request:

GET /api/printer

JSON-RPC request: Not Available

Returns:

An object containing OctoPrint Printer status

{
    "temperature": {
        "tool0": {
            "actual": 22.25,
            "offset": 0,
            "target": 0
        },
        "bed": {
            "actual": 22.25,
            "offset": 0,
            "target": 0
        }, ...<additional heaters>
    },
    "state": {
        "text": "state",
        "flags": {
            "operational": true,
            "paused": false,
            "printing": false,
            "cancelling": false,
            "pausing": false,
            "error": false,
            "ready": false,
            "closedOrError": false
        }
    }
}

Send GCode command

HTTP request:

POST /api/printer/command
Content-Type: application/json

{
    "commands": ["G28"]
}

JSON-RPC request: Not Available

Returns:

An empty JSON object

{}

List Printer profiles

HTTP request:

GET /api/printerprofiles

JSON-RPC request: Not Available

Returns:

An object containing simulates OctoPrint Printer profile

{
    "profiles": {
        "_default": {
            "id": "_default",
            "name": "Default",
            "color": "default",
            "model": "Default",
            "default": true,
            "current": true,
            "heatedBed": true,
            "heatedChamber": false
        }
    }
}

History APIs

The APIs below are available when the [history] component has been configured.

Get job list

HTTP request:

GET /server/history/list?limit=50&start=50&since=1&before=5&order=asc

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method":"server.history.list",
    "params":{
        "limit": 50,
        "start": 10,
        "since": 464.54,
        "before": 1322.54,
        "order": "asc"
    },
    "id": 5656
}

All arguments are optional. Arguments are as follows:

  • start Record number to start from (i.e. 10 would start at the 10th print)
  • limit Maximum Number of prints to return (default: 50)
  • before All jobs before this UNIX timestamp
  • since All jobs after this UNIX timestamp
  • order Define return order asc or desc (default)

Returns:

An array of requested historical jobs:

{
    "count": 1,
    "jobs": [
        {
            "job_id": "000001",
            "exists": true,
            "end_time": 1615764265.6493807,
            "filament_used": 7.83,
            "filename": "test/history_test.gcode",
            "metadata": {
                // Object containing metadata at time of job
            },
            "print_duration": 18.37201827496756,
            "status": "completed",
            "start_time": 1615764496.622146,
            "total_duration": 18.37201827496756
        },
    ]
}

Get job totals

HTTP request:

GET /server/history/totals

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method":"server.history.totals",
    "id": 5656
}

Returns:

An object containing the following total job statistics:

{
    "job_totals": {
        "total_jobs": 3,
        "total_time": 11748.077333278954,
        "total_print_time": 11348.794790096988,
        "total_filament_used": 11615.718840001999,
        "longest_job": 11665.191012736992,
        "longest_print": 11348.794790096988
    }
}

Reset totals

Resets the persistent "job totals" to zero.

HTTP request:

POST /server/history/reset_totals

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "server.history.reset_totals",
    "id": 5534
}

Returns:

The totals prior to the reset:

```json
{
    "last_totals": {
        "total_jobs": 3,
        "total_time": 11748.077333278954,
        "total_print_time": 11348.794790096988,
        "total_filament_used": 11615.718840001999,
        "longest_job": 11665.191012736992,
        "longest_print": 11348.794790096988
    }
}

Get a single job

HTTP request:

GET /server/history/job?uid=<id>

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method":"server.history.get_job",
    "params":{"uid": "{uid}"},
    "id": 4564
}

Returns:

Data associated with the job ID in the following format:

{
    "job": {
        "job_id": "000001",
        "exists": true,
        "end_time": 1615764265.6493807,
        "filament_used": 7.83,
        "filename": "test/history_test.gcode",
        "metadata": {
            // Object containing metadata at time of job
        },
        "print_duration": 18.37201827496756,
        "status": "completed",
        "start_time": 1615764496.622146,
        "total_duration": 18.37201827496756
    }
}

Delete job

HTTP request:

DELETE /server/history/job?uid=<id>

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "server.history.delete_job",
    "params":{
        "uid": "{uid}"
    },
    "id": 5534
}

!!! tip It is possible to replace the uid argument with all=true to delete all jobs in the history database.

Returns:

An array of deleted job ids

[
    "000000",
    "000001",
]

MQTT APIs

The following API is available when [mqtt] has been configured.

!!! Note These requests are not available over the mqtt transport as they are redundant. MQTT clients can publish and subscribe to topics directly.

Publish a topic

HTTP request:

POST /server/mqtt/publish
Content-Type: application/json

{
    "topic": "home/test/pub",
    "payload": "hello",
    "qos": 0,
    "retain": false,
    "timeout": 5
}

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method":"server.mqtt.publish",
    "params":{
        "topic": "home/test/pub",
        "payload": "hello",
        "qos": 0,
        "retain": false,
        "timeout": 5
    },
    "id": 4564
}

Only the topic parameter is required. Below is an explanation for each parameter:

  • topic: The topic to publish.
  • payload: Payload to send with the topic. May be a boolean, float, integer, string, object, or array. All values are converted to strings prior to publishing. Objects and Arrays are JSON encoded. If omitted an empty payload is sent.
  • qos: QOS level to use when publishing the topic. Must be an integer value from 0 to 2. If omitted the system configured default is used.
  • retain: If set to true the MQTT broker will retain the payload of this request. Note that only the mostly recently tagged payload is retained. When other clients first subscribe to the topic they immediately receive the retained message. The default is false.
  • timeout: A float value in seconds. By default requests with QoS levels of 1 or 2 will block until the Broker acknowledges confirmation. This option applies a timeout to the request, returning a 504 error if the timeout is exceeded. Note that the topic will still be published if the QoS level is 1 or 2.

!!! tip To clear a retained value of a topic, publish the topic with an empty payload and retain set to true.

Returns:

The published topic:

{
    "topic": "home/test/pub"
}

Subscribe to a topic

HTTP request:

POST /server/mqtt/subscribe
Content-Type: application/json

{
    "topic": "home/test/sub",
    "qos": 0,
    "timeout": 5
}

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method":"server.mqtt.subscribe",
    "params":{
        "topic": "home/test/sub",
        "qos": 0,
        "timeout": 5
    },
    "id": 4564
}

Only the topic parameter is required. Below is an explanation for each paramater:

  • topic: The topic to subscribe. Note that wildcards may not be used.
  • qos: QOS level to use when subscribing to the topic. Must be an integer value from 0 to 2. If omitted the system configured default is used.
  • timeout: A float value in seconds. By default requests will block indefinitely until a response is received. This option applies a timeout to the request, returning a 504 error if the timeout is exceeded. The subscription will be removed after a timeout.

!!! note If the topic was previously published with a retained payload this request will return with the retained value.

Returns:

The subscribed topic and its payload:

{
    "topic": "home/test/pub",
    "payload": "test"
}

If the payload is json encodable it will be returned as an object or array. Otherwise it will be a string.

Extension APIs

Moonraker currently has limited support for 3rd party extensions. These extensions must create a websocket connect and identify themselves as an agent. Agents may host their own JSON-RPC methods that other clients may call. Agents may also emit events that are broadcast to all other websocket connections.

List Extensions

Returns a list of all available extensions. Currently Moonraker can only be officially extended through connected agents.

HTTP request:

GET /server/extensions/list

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method":"server.extensions.list",
    "id": 4564
}

Returns:

A list of connected agents, where each item is an object containing the agent's identity:

{
    "agents": [
        {
            "name": "moonagent",
            "version": "0.0.1",
            "type": "agent",
            "url": "https://github.com/arksine/moontest"
        }
    ]
}

Call an extension method

This API may be used to call a method on a connected agent. The request effectively relays a JSON-RPC request from a client to the agent.

HTTP request:

POST /server/extensions/request
Content-Type: application/json

{
    "agent": "moonagent",
    "method": "moontest.hello_world",
    "arguments": {"argone": true, "argtwo": 9000}
}

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method":"server.extensions.request",
    "params":{
        "agent": "moonagent",
        "method": "moontest.hello_world",
        "arguments": {"argone": true, "argtwo": 9000}
    },
    "id": 4564
}

Parameters:

  • agent: The name of the agent. This parameter is required.
  • method: The name of the method to call on the agent. Agents determine the method names they expose. This parameter is required.
  • arguments: This parameter is optional, depending on if the method being called takes parameters. This should be either an array of positional arguments or an object of keyword arguments.

Returns:

The result returned by the JSON-RPC call to the agent. This can be any JSON value as determined by the agent.

Send an agent event

!!! Note This API is only available to websocket connections that have identified themselves as an agent type.

HTTP Request: Not Available

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method":"connection.send_event",
    "params":{
        "event": "my_event",
        "data": {"my_arg": "optional data"}
    }
}

Parameters:

  • event: The name of the event. This may be any name as determined by the agent, with the exception of the reserved names noted below.
  • data: Optional supplemental data sent with the event. This can be any JSON value.

!!! Note The connected and disconnected events are reserved for use by Moonraker.

Returns:

ok if an id was present in the request, otherwise no response is returned. Once received, Moonraker will broadcast this event via the agent event notification to all other connections.

Register a method with Klipper

Allows agents to register remote methods with Klipper. These methods may be called in gcode_macros.

!!! Note This API is only available to websocket connections that have identified themselves as an agent type.

HTTP Request: Not Available

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method":"connection.register_remote_method",
    "params": {
        "method_name": "firemon_alert_heated"
    }
}

Parameters:

  • method_name: The name of the desired method. Agents should make sure that the name is unique. One recommendation is to prefix the agent's name to each method it registers.

Returns:

ok if registration is successful. An error is returned if the method name is already registered.

!!! Note Methods registered by agents will persist until the agent disconnects. Upon connection, it is only necessary that they register their desired methods once.

Example:

Presume an application named firemon has connected to Moonraker's websocket and identified itself as an agent. After identification it registers a remote method named firemon_alert_heated.

In addition, the user the following gcode_macro configured in printer.cfg:

# printer.cfg

[gcode_macro ALERT_HEATED]
gcode:
  {% if not params %}
    {action_call_remote_method("firemon_alert_heated")}
  {% else %}
    {% set htr = params.HEATER|default("unknown") %}
    {% set tmp = params.TEMP|default(0)|float %}
    {action_call_remote_method(
        "firemon_alert_heated", heater=htr, temp=tmp)}
  {% endif %}


When the ALERT_HEATED HEATER=extruder TEMP=200 gcode is executed by Klipper, the agent will receive the following:

{
    "jsonrpc": "2.0",
    "method":"firemon_alert_heated",
    "params": {
        "heater": "extruder",
        "temp": 200
    }
}

When the ALERT_HEATED gcode is executed with no parameters, the agent will receive the following:

{
    "jsonrpc": "2.0",
    "method":"monitor_alert_heated"
}

!!! Note Methods called from Klipper never contain the "id" field, as Klipper does not accept return values to remote methods.

Debug APIs

The APIs in this section are available when Moonraker the debug argument (-g) has been supplied via the command line. Some API may also depend on Moonraker's configuration, ie: an optional component may choose to register a debug API.

!!! Warning Debug APIs may expose security vulnerabilities. They should only be enabled by developers on secured machines.

List Database Namespaces (debug)

Debug version of List Namespaces. Return value includes namespaces exlusively reserved for Moonraker. Only availble when Moonraker's debug features are enabled.

HTTP request:

GET /debug/database/list

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "debug.database.list",
    "id": 8694
}

Get Database Item (debug)

Debug version of Get Database Item. Keys within protected and forbidden namespaces are accessible. Only availble when Moonraker's debug features are enabled.

!!! Warning Moonraker's forbidden namespaces include items such as user credentials. This endpoint should NOT be implemented in front ends directly.

HTTP request:

GET /debug/database/item?namespace={namespace}&key={key}

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "debug.database.get_item",
    "params": {
        "namespace": "{namespace}",
        "key": "{key}"
    },
    "id": 5644
}

Add Database Item (debug)

Debug version of Add Database Item. Keys within protected and forbidden namespaces may be added. Only availble when Moonraker's debug features are enabled.

!!! Warning This endpoint should be used for testing/debugging purposes only. Modifying protected namespaces outside of Moonraker can result in broken functionality and is not supported for production environments. Issues opened with reports/queries related to this endpoint will be redirected to this documentation and closed.

POST /debug/database/item
Content-Type: application/json

{
    "namespace": "my_client",
    "key": "settings.some_count",
    "value": 100
}

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "debug.database.post_item",
    "params": {
        "namespace": "{namespace}",
        "key": "{key}",
        "value": 100
    },
    "id": 4654
}

Delete Database Item (debug)

Debug version of Delete Database Item. Keys within protected and forbidden namespaces may be removed. Only availble when Moonraker's debug features are enabled.

!!! Warning This endpoint should be used for testing/debugging purposes only. Modifying protected namespaces outside of Moonraker can result in broken functionality and is not supported for production environments. Issues opened with reports/queries related to this endpoint will be redirected to this documentation and closed.

HTTP request:

DELETE /debug/database/item?namespace={namespace}&key={key}

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "debug.database.delete_item",
    "params": {
        "namespace": "{namespace}",
        "key": "{key}"
    },
    "id": 4654
}

Test a notifier (debug)

You can trigger a notifier manually using this endpoint.

HTTP request:

POST /debug/notifiers/test?name=notifier_name

JSON-RPC request:

{
    "jsonrpc": "2.0",
    "method": "debug.notifiers.test",
    "params": {
        "name": "notifier_name"
    },
    "id": 4654
}

Parameters:

  • name: The name of the notifier to test.

Returns: Test results in the following format

{
    "status": "success",
    "stats": {
        "print_duration": 0.0,
        "total_duration": 0.0,
        "filament_used": 0.0,
        "filename": "notifier_test.gcode",
        "state": "standby",
        "message": ""
    }
}

Websocket notifications

Printer generated events are sent over the websocket as JSON-RPC 2.0 notifications. These notifications are sent to all connected clients in the following format:

{
    "jsonrpc": "2.0",
    "method": "{event method name}"
}

OR

{
    "jsonrpc": "2.0",
    "method": "{event method name}",
    "params": [<event parameter>]
}

If a notification has parameters, the params value will always be wrapped in an array as directed by the JSON-RPC standard. Currently all notifications available are broadcast with either no parameters or a single parameter.

Gcode Response

All of Klippy's gcode responses are forwarded over the websocket. They arrive as a "gcode_response" notification:

{
    "jsonrpc": "2.0",
    "method": "notify_gcode_response",
    "params": ["response message"]
}

Subscriptions

Status Subscriptions arrive as a "notify_status_update" notification:

{
    "jsonrpc": "2.0",
    "method": "notify_status_update",
    "params": [{<status object>}, <eventtime>]
}

The structure of the status object is identical to the structure that is returned from an object query's status field.

The eventtime is a timestamp generated by Klipper when the update was originally pushed. This timestamp is a float value, relative to Klipper's monotonic clock.

Klippy Ready

Notify clients when Klippy has reported a ready state

{
    "jsonrpc": "2.0",
    "method": "notify_klippy_ready"
}

Klippy Shutdown

Notify clients when Klippy has reported a shutdown state

{
    "jsonrpc": "2.0",
    "method": "notify_klippy_shutdown"
}

Klippy Disconnected

Notify clients when Moonraker's connection to Klippy has terminated

{
    "jsonrpc": "2.0",
    "method": "notify_klippy_disconnected"
}

File List Changed

When a client makes a change to a file or directory in a registered root (via upload, delete, move, etc) a notification is broadcast to alert all connected clients of the change:

{
    "jsonrpc": "2.0",
    "method": "notify_filelist_changed",
    "params": [
        {
            "action": "{action}",
            "item": {
                "path": "{file or directory path relative to root}",
                "root": "{root}",
                "size": 46458,
                "modified": 545465,
                "permissions": "rw"
            },
            "source_item": {
                "path": "{file or directory path relative to root}",
                "root": "{root_name}"
            }
        }
    ]
}

!!! Note The source_item field is only present for move_file and move_dir actions.

The action field will be set to one of the following values:

  • create_file
  • create_dir
  • delete_file
  • delete_dir
  • move_file
  • move_dir
  • modify_file
  • root_update

Most of the above actions are self explanatory. The root_update notification is sent when a root folder has changed its location. This should be a rare event as folders are now managed in using the data folder structure.

Notifications are bundled where applicable. For example, when a directory containing children is deleted a single delete_dir notification is pushed. Likewise, when a directory is moved or copied, a single move_dir or create_dir notification is pushed. Children that are moved, copied, or deleted as a result of a parent's action will not receive individual notifications.

Update Manager Response

The update manager will send asynchronous messages to the client during an update:

{
    "jsonrpc": "2.0",
    "method": "notify_update_response",
    "params": [
        {
            "application": "{app_name}",
            "proc_id": 446461,
            "message": "Update Response Message",
            "complete": false
        }
    ]
}

The fields reported in the response are as follows:

  • The application field contains the name of application currently being updated. Generally this will be either "moonraker", "klipper", "system", or "client".
  • The proc_id field contains a unique id associated with the current update process. This id is generated for each update request.
  • The message field contains an asynchronous message sent during the update process.
  • The complete field is set to true on the final message sent during an update, indicating that the update completed successfully. Otherwise it will be false.

Update Manager Refreshed

The update manager periodically auto refreshes the state of each application it is tracking. After an auto refresh has completed the following notification is broadcast:

{
    "jsonrpc": "2.0",
    "method": "notify_update_refreshed",
    "params": [{update_info}]}

Where update_info is an object that matches the response from an update status request.

CPU Throttled

If the system supports throttled CPU monitoring Moonraker will send the following notification when it detects a change to the current throttled state:

{
    "jsonrpc": "2.0",
    "method": "notify_cpu_throttled",
    "params": [{throttled_state}]
}

Where throttled_state is an object that matches the throttled_state field in the response from a Moonraker process stats request. It is possible for clients to receive this notification multiple times if the system repeatedly transitions between an active and inactive throttled condition.

Moonraker Process Statistic Update

Moonraker will emit the following notification each time it samples its process statistics:

{
    "jsonrpc": "2.0",
    "method": "notify_proc_stat_update",
    "params": [{
        "moonraker_stats": {
            "time": 1615837812.0894408,
            "cpu_usage": 1.99,
            "memory": 23636,
            "mem_units": "kB"
        },
        "cpu_temp": 44.008,
        "network": {
            "lo": {
                "rx_bytes": 114555457,
                "tx_bytes": 114555457,
                "bandwidth": 2911.49
            },
            "wlan0": {
                "rx_bytes": 48773134,
                "tx_bytes": 115035939,
                "bandwidth": 3458.77
            }
        },
        "system_cpu_usage": {
            "cpu": 2.53,
            "cpu0": 3.03,
            "cpu1": 5.1,
            "cpu2": 1.02,
            "cpu3": 1
        },
        "websocket_connections": 2
    }]
}

As with the proc_stats request the cpu_temp field will be set to null if the host machine does not support retrieving CPU temperatures at /sys/class/thermal/thermal_zone0.

History Changed

If the [history] module is enabled the following notification is sent when a job is added or finished:

{
    "jsonrpc": "2.0",
    "method": "notify_history_changed",
    "params": [
        {
            "action": "added",
            "job": <job object>
        }
    ]
}

The action field may be added or finished. The job field contains an object matches the one returned when requesting job data.

Authorized User Created

If the [authorization] module is enabled the following notification is sent when a new user is created:

{
    "jsonrpc": "2.0",
    "method": "notify_user_created",
    "params": [
        {
            "username": "<username>"
        }
    ]
}

Authorized User Deleted

If the [authorization] module is enabled the following notification is sent when an existing user is deleted.

{
    "jsonrpc": "2.0",
    "method": "notify_user_deleted",
    "params": [
        {
            "username": "<username>"
        }
    ]
}

Authorized User Logged Out

If the [authorization] module is enabled the following notification is sent when an existing user is logged out.

{
    "jsonrpc": "2.0",
    "method": "notify_user_logged_out",
    "params": [
        {
            "username": "<username>"
        }
    ]
}

Service State Changed

Moonraker monitors the state of systemd services it is authorized to track. When the state of a service changes the following notification is sent:

{
    "jsonrpc": "2.0",
    "method": "notify_service_state_changed",
    "params": [
        {
            "klipper": {
                "active_state": "inactive",
                "sub_state": "dead"
            }
        }
    ]
}

The example above shows that the klipper service has changed to inactive.

Job Queue Changed

Moonraker will send a job_queue_changed notification when a change is detected to the queue state or the queue itself:

{
    "jsonrpc": "2.0",
    "method": "notify_job_queue_changed",
    "params": [
        {
            "action": "state_changed",
            "updated_queue": null,
            "queue_state": "paused"
        }
    ]
}

The object sent with the notification contains the following fields:

  • action: The action taken to the queue which led to the notification. Will be a string set to one of the following values:
    • state_changed: The queue state has changed
    • jobs_added: One or more jobs were added to the queue
    • jobs_removed: One or more jobs were removed from the queue
    • job_loaded: A job was popped off the queue and successfully started
  • updated_queue: If the queue itself is changed this will be a list containing each item in the queue. If the queue has not changed this will be null.
  • queue_state: The current queue state

Button Event

Moonraker [button] components may be configured to emit websocket notifications.

{
    "jsonrpc": "2.0",
    "method": "notify_button_event",
    "params": [
        {
            "name": "my_button",
            "type": "gpio",
            "event": {
                "elapsed_time": 0.09323832602240145,
                "received_time": 698614.214597004,
                "render_time": 698614.214728513,
                "pressed": false
            },
            "aux": null
        }
    ]
}

The params array will always contain a single object with the following fields:

  • name: The name of the configured button
  • type: The button type, currently this will always be gpio
  • event: An object with details about the button event, containing the following fields:
    • elapsed_time: The time elapsed (in seconds) since the last detected button event
    • received_time: The time the event was detected according to asyncio's monotonic clock. Note that this is not in "unix time".
    • render_time: The time the template was rendered (began execution) according to asyncio's monotonic clock. It is possible execution of an event may be delayed well beyond the received_time.
    • pressed: A boolean value to indicate if the button is currently pressed.
  • aux: This is an optional field where the button may specify any json encodable value. Clients may suggest a specific button configuration that includes details about the event. If no aux parameter is specified in the configuration this will be a null value.

Announcement update event

Moonraker will emit the notify_announcement_update notification when a announcement entries are added or removed:

{
    "jsonrpc": "2.0",
    "method": "notify_announcement_update",
    "params": [
        {
            "entries": [
                {
                    "entry_id": "arksine/moonlight/issue/3",
                    "url": "https://github.com/Arksine/moonlight/issues/3",
                    "title": "Test announcement 3",
                    "description": "Test Description [with a link](https://moonraker.readthedocs.io).",
                    "priority": "normal",
                    "date": 1647459219,
                    "dismissed": false,
                    "date_dismissed": null,
                    "dismiss_wake": null,
                    "source": "moonlight",
                    "feed": "moonlight"
                },
                {
                    "entry_id": "arksine/moonlight/issue/2",
                    "url": "https://github.com/Arksine/moonlight/issues/2",
                    "title": "Announcement Test Two",
                    "description": "This is a high priority announcement. This line is included in the description.",
                    "priority": "high",
                    "date": 1646855579,
                    "dismissed": false,
                    "date_dismissed": null,
                    "dismiss_wake": null,
                    "source": "moonlight",
                    "feed": "moonlight"
                }
                {
                    "entry_id": "arksine/moonraker/issue/349",
                    "url": "https://github.com/Arksine/moonraker/issues/349",
                    "title": "PolicyKit warnings; unable to manage services, restart system, or update packages",
                    "description": "This announcement is an effort to get ahead of a coming change that will certainly result in issues.  PR #346  has been merged, and with it are some changes to Moonraker's default behavior.",
                    "priority": "normal",
                    "date": 1643392406,
                    "dismissed": false,
                    "source": "moonlight",
                    "feed": "Moonraker"
                }
            ]
        }
    ]
}

The params array will contain an object with all current announcement entries. This object is identical to that returned by the list announcements endpoint.

Announcement dismissed event

Moonraker will emit the notify_announcement_dismissed notification when a dismissed announcement is detected:

{
    "jsonrpc": "2.0",
    "method": "notify_announcement_dismissed",
    "params": [
        {
            "entry_id": "arksine/moonlight/issue/3"
        }
    ]
}

The params array will contain an object with the entry_id of the dismissed announcement.

Announcement wake event

Moonraker will emit the notify_announcement_wake notification when a specified wake_time for a dismissed announcement has expired.

{
    "jsonrpc": "2.0",
    "method": "notify_announcement_wake",
    "params": [
        {
            "entry_id": "arksine/moonlight/issue/1"
        }
    ]
}

The params array will contain an object with the entry_id of the announcement that is no longer dismissed.

Sudo alert event

Moonraker will emit the notify_sudo_alert notification when a component has requested sudo access. The event is also emitted when a sudo request has been granted.

{
    "jsonrpc": "2.0",
    "method": "notify_sudo_alert",
    "params": [
        {
            "sudo_requested": true,
            "sudo_messages": [
                "Sudo password required to update Moonraker's systemd service."
            ]
        }
    ]
}

The params array contains an object with the following fields:

  • sudo_requested: Returns true if Moonraker is currently requesting sudo access.
  • request_messages: An array of strings, each string describing a pending sudo request. The array will be empty if no sudo requests are pending.

Webcams changed event

Moonraker will emit the notify_webcams_changed event when a configured webcam is added, removed, or updated.

{
    "jsonrpc": "2.0",
    "method": "notify_webcams_changed",
    "params": [
        {
            "webcams": [
                {
                    "name": "tc2",
                    "location": "printer",
                    "service": "mjpegstreamer",
                    "enabled": true,
                    "icon": "mdiWebcam",
                    "target_fps": 15,
                    "target_fps_idle": 5,
                    "stream_url": "http://printer.lan/webcam?action=stream",
                    "snapshot_url": "http://printer.lan/webcam?action=snapshot",
                    "flip_horizontal": false,
                    "flip_vertical": false,
                    "rotation": 0,
                    "aspect_ratio": "4:3",
                    "extra_data": {},
                    "source": "database"
                },
                {
                    "name": "TestCam",
                    "location": "printer",
                    "service": "mjpegstreamer",
                    "enabled": true,
                    "icon": "mdiWebcam",
                    "target_fps": 15,
                    "target_fps_idle": 5,
                    "stream_url": "/webcam/?action=stream",
                    "snapshot_url": "/webcam/?action=snapshot",
                    "flip_horizontal": false,
                    "flip_vertical": false,
                    "rotation": 0,
                    "aspect_ratio": "4:3",
                    "extra_data": {},
                    "source": "database"
                }
            ]
        }
    ]
}

The webcams field contans an array of objects like those returned by the list webcams API.

Spoolman active spool ID changed

Moonraker will emit the notify_active_spool_set event when the active spool ID for the Spoolman integration has been changed.

See the Spoolman API for more information.

{
    "jsonrpc": "2.0",
    "method": "notify_active_spool_set",
    "params": [
        {
            "spool_id": 1
        }
    ]
}

Spoolman Status Changed

Moonraker will emit the notify_spoolman_status_changed event when the connection state to the Spoolman service has changed:

{
    "jsonrpc": "2.0",
    "method": "notify_spoolman_status_changed",
    "params": [
        {
            "spoolman_connected": false
        }
    ]
}

Agent Events

Moonraker will emit the notify_agent_event notification when it an agent event is received.

{
    "jsonrpc": "2.0",
    "method": "notify_agent_event",
    "params": [
        {
            "agent": "moonagent",
            "event": "connected",
            "data": {
                "name": "moonagent",
                "version": "0.0.1",
                "type": "agent",
                "url": "https://github.com/arksine/moontest"
            }
        }
    ]
}

When an agent connects, all connections will receive a connected event for that agent, with its identity info in the data field. When an agent disconnects clients will receive a disconnected event with the data field omitted. All other events are determined by the agent, where each event may or may not include optional data.

Sensor Events

Moonraker will emit a sensors:sensor_update notification when a measurement from at least one monitored sensor changes.

{
    "jsonrpc": "2.0",
    "method": "sensors:sensor_update",
    "params": [
        {
            "sensor1": {
                "humidity": 28.9,
                "temperature": 22.4
            }
        }
    ]
}

When a sensor reading changes, all connections will receive a sensors:sensor_update event where the params contains a data struct with the sensor id as the key and the sensors letest measurements as value struct.

Appendix

Websocket setup

The websocket is located at ws://host:port/websocket, for example:

var s = new WebSocket("ws://" + location.host + "/websocket");

!!! tip A client using API Key authorization may request a oneshot token, applying the result to the websocket request's query string:

ws://host:port/websocket?token={32 character base32 string}

The following startup sequence is recommended for clients which make use of the websocket:

  1. Attempt to connect to /websocket until successful using a timer-like mechanism
  2. Once connected, query /server/info (or server.info) for the ready status.
    • If the response returns an error (such as 404) then either the client is not authorized or Moonraker is not running. Direct the user to SSH into the machine and check /tmp/moonraker.log.
    • If the response returns success, check the result's klippy_state field:
      • klippy_state == "ready": you may proceed to request status of printer objects make subscriptions, get the file list, etc.
      • klippy_state == "error": Klippy has experienced an error starting up
      • klippy_state == "shutdown": Klippy is in a shutdown state.
      • klippy_state == "startup": re-request /server/info in 2 seconds.
        • If error or shutdown is detected it might be wise to prompt the user. You can get a description from the state_message field of a /printer/info request.
  3. Repeat step 2 until Klipper reports ready.
  4. Clients should watch for the notify_klippy_disconnected event. If received then Klippy has either been stopped or restarted. In this state the client should repeat the steps above to determine when klippy is ready.

Basic Print Status

An advanced client will likely use subscriptions and notifications to interact with Moonraker, however simple clients such as home automation software and embedded devices (ie: ESP32) may only wish to monitor the status of a print. Below is a high level walkthrough for receiving print state via polling.

  • Set up a timer to poll at the desired interval. Depending on your use case, 1 to 2 seconds is recommended.

  • On each cycle, issue the following request:

      GET http://host/printer/objects/query?webhooks&virtual_sdcard&print_stats
    

    Or via JSON-RPC 2.0:

      {
          "jsonrpc": "2.0",
          "method": "printer.objects.query",
          "params": {
              "objects": {
                  "webhooks": null,
                  "virtual_sdcard": null,
                  "print_stats": null
              }
          },
          "id": 5664
      }
    
  • If the request returns an error or the returned result.status is an empty object, then this is an indication that Klippy either experienced an error or it is not properly configured. Each queried object should be available in result.status. The client should check to make sure that all objects are received before proceeding.

  • Inspect webhooks.ready. If the value is not ready the printer is not available. webhooks.message contains a message pertaining to the current state.

  • If the printer is ready, inspect print_stats.state. It may be one of the following values: - standby: No print in progress - printing: The printer is currently printing - paused: A print in progress has been paused - error: The print exited with an error. print_stats.message contains a related error message - complete: The last print has completed

  • If print_stats.state is not standby then print_stats.filename will report the name of the currently loaded file.

  • print_stats.filename can be used to fetch file metadata. It is only necessary to fetch metadata once per print.

      GET http://host/server/files/metadata?filename=<filename>
    

    Or via JSON-RPC 2.0:

      {
          "jsonrpc": "2.0",
          "method": "server.files.metadata",
          "params": {
              "filename": "{filename}"
          },
          "id": 5643
      }
    

    If metadata extraction failed then this request will return an error. Some metadata fields are only populated for specific slicers, and unsupported slicers will only return the size and modified date.

  • There are multiple ways to calculate the ETA, this example will use file progress, as it is possible calculate the ETA with or without metadata.

    • If metadata.estimated_time is available, the eta calculation can be done as:

        // assume "result" is the response from the status query
        let vsd = result.status.virtual_sdcard;
        let prog_time = vsd.progress * metadata.estimated_time;
        let eta = metadata.estimated_time - prog_time
      

      Alternatively, one can simply subtract the print duration from the estimated time:

        // assume "result" is the response from the status query
        let pstats = result.status.print_status;
        let eta = metadata.estimated_time - pstats.print_duration;
        if (eta < 0)
        eta = 0;
      
    • If no metadata is available, print duration and progress can be used to calculate the ETA:

        // assume "result" is the response from the status query
        let vsd = result.status.virtual_sdcard;
        let pstats = result.status.print_stats;
        let total_time = pstats.print_duration / vsd.progress;
        let eta = total_time - pstats.print_duration;
      
  • It is possible to query additional objects if a client wishes to display more information (ie: temperatures). See the Printer Objects documentation for details.

Bed Mesh Coordinates

The Bed Mesh printer object may be used to generate three dimensional coordinates of a probed area (or mesh). Below is an example (in javascript) of how to transform the data received from a bed_mesh object query into an array of 3D coordinates.

// assume that we have executed an object query for bed_mesh and have the
// result.  This example generates 3D coordinates for the probed matrix,
// however it would work with the mesh matrix as well
function process_mesh(result) {
  let bed_mesh = result.status.bed_mesh
  let matrix = bed_mesh.probed_matrix;
  if (!(matrix instanceof Array) ||  matrix.length < 3 ||
      !(matrix[0] instanceof Array) || matrix[0].length < 3)
      // make sure that the matrix is valid
      return;
  let coordinates = [];
  let x_distance = (bed_mesh.mesh_max[0] - bed_mesh.mesh_min[0]) /
    (matrix[0].length - 1);
  let y_distance = (bed_mesh.mesh_max[1] - bed_mesh.mesh_min[1]) /
    (matrix.length - 1);
  let x_idx = 0;
  let y_idx = 0;
  for (const x_axis of matrix) {
    x_idx = 0;
    let y_coord = bed_mesh.mesh_min[1] + (y_idx * y_distance);
    for (const z_coord of x_axis) {
      let x_coord = bed_mesh.mesh_min[0] + (x_idx * x_distance);
      x_idx++;
      coordinates.push([x_coord, y_coord, z_coord]);
    }
    y_idx++;
  }
}
// Use the array of coordinates visualize the probed area
// or mesh..

Converting to Unix Time

Some of Moonraker's APIs return a date represented in Unix time. Most languages have functionality built in to convert Unix time to a workable object or string. For example, in JavaScript one might do something like the following:

for (let resp of result.gcode_store) {
  let date = new Date(resp.time * 1000);
  // Do something with date and resp.message ...
}

Announcements

Moonraker announcements are effectively push notifications that can be used to notify users of important information related the development and status of software in the Klipper ecosystem. This section will provide an overview of how the announcement system works, how to set up a dev environment, and provide recommendations on client implementation.

How announcements work

Moonraker announcements are GitHub issues tagged with the announcement label. GitHub repos may registered with moonlight, which is responsible for generating RSS feeds from GitHub issues using GitHub's REST API. These RSS feeds are hosted on GitHub Pages, for example Moonraker's feed may be found here. By centralizing GitHub API queries in moonlight we are able to poll multiple repos without running into API rate limit issues. Moonlight has has a workflow that checks all registered repos for new announcements every 30 minutes. In theory it would be able to check for announcements in up to 500 repos before exceeding GitHub's API rate limit.

Moonraker's [announcements] component will always check the klipper and moonraker RSS feeds. It is possible to configure additional RSS feeds by adding them to the subscriptions option. The component will poll configured feeds every 30 minutes, resulting in maximum of 1 hour for new announcements to reach all users.

When new issues are tagged with announcement these entries will be parsed and added to the RSS feeds. When the issue is closed they will be removed from the corresponding feed. Moonlight will fetch up to 20 announcements for each feed, if a repo goes over this limit older announcements will be removed.

!!! Note It is also possible for Moonraker to generate announcements itself. For example, if a Moonraker component needs user feedback it may generate an announcement and notify all connected clients. From a client's perspective there is no need to treat announcements differently than any other announcement.

Setting up the dev environment

Moonraker provides configuration to parse announcements from a local folder so that it is possible to manually add and remove entries, allowing client developers to perform integration tests:

# moonraker.conf

[announcements]
dev_mode: True

With dev_mode enabled, Moonraker will look formoonraker.xml and klipper.xml in the following folder:

~/moonraker/.devel/announcement_xml

If moonraker is not installed in the home folder then substitute ~ for the parent folder location. This folder is in a hardcoded location to so as not to expose users to vulnerabilities associated with parsing XML.

It is possible to configure Moonraker to search for your own feeds:

# moonraker.conf

[announcements]
subscription:
  my_project
dev_mode: True

The above configuration would look for my_project.xml in addition to klipper.xml and moonraker.xml. The developer may manually create the xml feeds or they may clone moonlight and leverage its script to generate a feed from issues created on their test repo. When local feeds have been modified one may call the update announcements API to have Moonraker fetch the updates and add/remove entries.

RSS file structure

Moonlight generates RSS feeds in XML format. Below is an example generated from moonlight's own issue tracker:

<?xml version='1.0' encoding='utf-8'?>
<rss version="2.0" xmlns:moonlight="https://arksine.github.io/moonlight">
    <channel>
        <title>arksine/moonlight</title>
        <link>https://github.com/Arksine/moonlight</link>
        <description>RSS Announcements for Moonraker</description>
        <pubDate>Tue, 22 Mar 2022 23:19:04 GMT</pubDate>
        <moonlight:configHash>f2912192bf0d09cf18d8b8af22b2d3501627043e5afa3ebff0e45e4794937901</moonlight:configHash>
        <item>
            <title>Test announcement 3</title>
            <link>https://github.com/Arksine/moonlight/issues/3</link>
            <description>Test Description [with a link](https://moonraker.readthedocs.io).</description>
            <pubDate>Wed, 16 Mar 2022 19:33:39 GMT</pubDate>
            <category>normal</category>
            <guid>arksine/moonlight/issue/3</guid>
        </item>
        <item>
            <title>Announcement Test Two</title>
            <link>https://github.com/Arksine/moonlight/issues/2</link>
            <description>This is a high priority announcement. This line is included in the description.</description>
            <pubDate>Wed, 09 Mar 2022 19:52:59 GMT</pubDate>
            <category>high</category>
            <guid>arksine/moonlight/issue/2</guid>
        </item>
        <item>
            <title>Announcement Test One</title>
            <link>https://github.com/Arksine/moonlight/issues/1</link>
            <description>This is the description.  Anything here should appear in the announcement, up to 512 characters.</description>
            <pubDate>Wed, 09 Mar 2022 19:37:58 GMT</pubDate>
            <category>normal</category>
            <guid>arksine/moonlight/issue/1</guid>
        </item>
    </channel>
</rss>

Each xml file may contain only one <rss> element, and each <rss> element may contain only one channel. All items must be present aside from moonlight:configHash, which is used by the workflow to detect changes to moonlight's configuration. Most elements are self explanatory, developers will be most interested in adding and removing <item> elements, as these are the basis for entries in Moonraker's announcement database.

Generating announcements from your own repo

As mentioned previously, its possible to clone moonlight and use its rss script to generate announcements from issues in your repo:

cd ~
git clone https://github.com/arksine/moonlight
cd moonlight
virtualenv -p /usr/bin/python3 .venv
source .venv/bin/activate
pip install httpx[http2]
deactivate

To add your repo edit ~/moonlight/src/config.json:

{
    "moonraker": {
        "repo_owner": "Arksine",
        "repo_name": "moonraker",
        "description": "API Host For Klipper",
        "authorized_creators": ["Arksine"]
    },
    "klipper": {
        "repo_owner": "Klipper3d",
        "repo_name": "klipper",
        "description": "A 3D Printer Firmware",
        "authorized_creators": ["KevinOConnor"]
    },
    // Add your test repo info here.  It should contain
    // fields matching those in "moonraker" and "klipper"
    // shown above.
}

Once your repo is added, create one or more issues on your GitHub repo tagged with the announcement label. Add the critical label to one if you wish to test high priority announcements. You may need to create these labels in your repo before they can be added.

Now we can use moonlight to generate the xml files:

cd ~/moonlight
source .venv/bin/activate
src/update_rss.py
deactivate

After the script has run it will generate the configured RSS feeds and store them in ~/moonlight/assets. If using this method it may be useful to create a symbolic link to it in Moonraker's devel folder:

cd ~/moonraker
mkdir .devel
cd .devel
ln -s ~/moonlight/assets announcement_xml

If you haven't done so, configure Moonraker to subscribe to your feed and restart the Moonraker service. Otherwise you may call the announcement update API to have Moonraker parse the announcements from your test feed.

Implementation details and recommendations

When Moonraker detects a change to one or more feeds it will fire the announcement update notification. It is also possible to query the API for announcements. Both the notification and the API return a list of announcement entries, where each entry is an object containing the following fields:

  • entry_id: A unique ID derived for each entry. Typically this is in the form of {owner}/{repo}/issue/{issue number}.
  • url: The url to the full announcement. This is generally a link to an issue on GitHub.
  • title: Announcement title, will match the title of the issue on GitHub.
  • description: The first paragraph of the announcement. Anything over 512 characters will be truncated.
  • priority: Can be normal or high. It is recommended that clients immediately alert the user when one or more high priority announcments are present. Issued tagged with the critical label will be assigned a high priority.
  • date: The announcement creation date in unix time.
  • dismissed: If set to true this announcement has been previously dismissed
  • date_dismissed: The date the announcement was dismissed in unix time. If the announcement has not been dismissed this value is null.
  • dismiss_wake: If the announcement was dismissed with a wake_time specified this is the time (in unix time) at which the dismissed state will revert. If the announcement is not dismissed or dismissed indefinitely this value will be null.
  • source: The source from which the announcement was generated. Can be moonlight or internal.
  • feed: The RSS feed for moonlight announcements. For example, this could be Moonraker or Klipper. If the announcement was generated internally this should match the name of the component that generated the announcement.

When a client first connects to Moonraker it is recommended that the list announcements API is called to retrieve the current list of entries. A client may then watch for the announcement update and announcement dismissed notifications and update the UI accordingly.

Client devs should decide how they want to present announcements to users. They could be treated as any other notification, for example a client may have a notification icon that shows the current number of unread announcements. Clients can mark an announcement as read by calling the dismiss announcement API. Any announcement entry with dismissed = true should be considered read.

When a high priority announcement is detected it is recommended that clients present the announcement in a format that is immediately visible to the user. That said, it may be wise to allow users to opt out of this behavior via configuration.

!!! Note If an announcement is dismissed, closed, then reopened the dismissed flag will reset to false. This is expected behavior as announcements are pruned from the database when they are no longer present in feeds. It isn't valid for repo maintaners to re-open a closed announcement. That said, its fine to close and re-open issues during development and testing using repos that are not yet registered with moonlight.