Files
KX-Bridge-Release/API.md
viewit f54783ad16 docs: add API.md and MANUAL.md, link them from README
API.md documents the full HTTP/WebSocket surface (Moonraker-compatible
endpoints for Mainsail/Fluidd/OrcaSlicer/moonraker-obico compatibility,
plus the bridge-specific /api and /kx routes) for integrators and plugin
authors.

MANUAL.md is a task-oriented end-user guide covering day-to-day usage:
dashboard, printing, filament/AMS management, multi-printer setup, the
power-switch feature, settings reference, and basic troubleshooting.
2026-08-02 23:02:46 +02:00

15 KiB
Raw Blame History

KX-Bridge HTTP API Reference

This document lists the HTTP and WebSocket surface exposed by kobrax_moonraker_bridge.py. It is a reference for integrators and plugin authors, not a tutorial — for day-to-day usage of the bridge see MANUAL.md, and for setup see README.md.

The API has two distinct parts:

  1. Moonraker-compatible surface — a subset of the real Moonraker HTTP + WebSocket API, implemented just far enough to make Mainsail, Fluidd, OrcaSlicer, and moonraker-obico work against the Kobra X. This is not a full Moonraker implementation — many real Moonraker endpoints/methods do not exist here, and some responses are static stubs that exist only to stop a client from erroring/looping (noted below).
  2. Bridge-specific surface/api/... and /kx/... endpoints for things Moonraker has no concept of: multi-printer management, AMS/ACE filament control, the GCode store, custom filament profile import, Spoolman, and the smart-plug power switch.

Security

There is no authentication on any endpoint. The bridge is designed to be run on a trusted local network only. Do not expose port 7125 (or any additional per-printer port) to the internet — anyone who can reach the port can control the printer, read/delete files, and read /kx/printers credentials indirectly through bridge behavior. /access/api_key returns a hardcoded dummy value purely so moonraker-obico doesn't warn; it is not a real credential.

CORS is enabled (_json_cors / handle_kx_options add Access-Control-Allow-* headers and answer OPTIONS with 204) so the Web UI can call sibling bridge instances directly in multi-printer setups.


Moonraker-compatible endpoints (HTTP)

All responses follow Moonraker's {"result": {...}} envelope unless noted.

Method Path Purpose Notes
GET /server/info Server/klippy status Always reports klippy_connected: true, klippy_state: "ready"
GET /printer/info Printer identity Static hostname/paths; software_version from KLIPPER_VERSION
GET /machine/system_info System info stub Mostly static/placeholder fields
GET /printer/objects/list List available printer objects Keys of _build_printer_objects()
GET /printer/objects/query?objects=... Query object status Comma-separated objects query param, or bare query keys
GET/POST /printer/objects/subscribe Subscribe (HTTP polling variant) Returns full status snapshot immediately
GET /server/files/list List gcode files Only returns the single currently-tracked file (if any)
GET /server/files/metadata?filename=... File metadata (layers, est. time, etc.) Shared logic with WS server.files.metadata; falls back to GCode store / buried-report cache
POST /server/files/upload Upload a gcode file (multipart) Same handler as /api/files/local
POST /printer/print/start?filename=... Start a print Body may include filament_assignments, excluded_objects, auto_leveling
POST /printer/print/pause Pause current print
POST /printer/print/resume Resume current print
POST /printer/print/cancel Cancel current print
GET /access/api_key Dummy API key No real auth exists
GET /machine/update/status Update-manager stub Always busy: false, empty version_info
GET /server/history/list?limit= Print job history Backed by the bridge's own GCodeStore/job DB
GET /server/webcams/list Webcam descriptor Rewrites localhost/127.0.0.1 Host header to the bridge's LAN IP so remote Obico/Mainsail instances get a reachable URL
POST /printer/gcode/script Execute a (very limited) gcode command See _exec_gcode_script; not a general gcode interpreter
GET /server/database/item?namespace=&key= Moonraker "database" KV read Real payload only for lane_data (AMS/filament sync for OrcaSlicer); stub/empty responses for AFC, afc-install, happy_hare, mainsail; in-memory KV for obico
POST /server/database/item Moonraker "database" KV write In-memory only (not persisted across restarts); used by moonraker-obico for its own settings
GET /server/database/list List KV namespaces Static: ["lane_data", "mainsail", "obico"]

OctoPrint-compatibility shim

Method Path Purpose
GET /api/version OctoPrint-style version probe (some tools check this instead of Moonraker)
POST /api/files/local, /api/files/{path} Alias for the same multipart upload handler as /server/files/upload

WebSocket JSON-RPC (/websocket)

Moonraker's JSON-RPC 2.0 protocol over a single /websocket endpoint. On connect the bridge immediately pushes notify_klippy_ready and then periodic notify_status_update notifications. Supported method values:

Method Purpose
printer.info / printer_info Same payload as /printer/info
server.info / server_info Same payload as /server/info
printer.objects.list Same as HTTP equivalent
printer.objects.query / printer.objects.get Object status by requested keys
printer.objects.subscribe Returns a status snapshot (no real push subscription semantics — status pushes happen automatically via notify_status_update)
printer.print.start params.filename
printer.print.pause / .resume / .cancel
machine.system_info Minimal stub
server.files.list Always returns [] over WS (unlike the HTTP version)
printer.gcode.script params.script, same limited executor as the HTTP endpoint
server.connection.identify Returns a dummy connection_id for Obico's handshake
connection.register_remote_method Accepted and ignored (Obico registers a remote-event callback)
server.webcams.list Same shape as HTTP, using the bridge's own LAN IP
server.history.list Job history, same source as /server/history/list
machine.update.status Stub
server.files.metadata Same logic as /server/files/metadata

Any other method is logged and answered with an empty result: {} — it does not error, to avoid breaking clients that probe for optional methods.


Bridge-specific endpoints

All /kx/... (and most /api/...) responses use {"result": ...} on success and {"error": "..."} with a 4xx/5xx status on failure, except where noted.

Printer control (/api/...)

Method Path Purpose Body / Query
POST /api/light Toggle chamber light {on, brightness}
POST /api/fan Set part-cooling fan speed {speed} (0100)
POST /api/connect Manually (re)connect the MQTT client
POST /api/disconnect Manually disconnect
POST /api/restart Restart the bridge process
POST /api/speed Set print speed mode {mode} (int)
POST /api/axis Jog an axis, or {"action":"turnoff"} to disable steppers {axis, move_type, distance}
POST /api/temperature Set nozzle/bed target temps {nozzle?, bed?}; uses a different MQTT path mid-print vs. idle
GET /api/state Full dashboard status snapshot Primary polling endpoint used by the Web UI
GET /api/camera Current camera stream URL
GET /api/camera/stream MJPEG live view multipart/x-mixed-replace, fed from a shared ffmpeg fanout
GET /api/camera/h264 Raw H.264 stream (for Obico)
GET /api/camera/snapshot Last cached JPEG frame Instant, served from RAM
POST /api/camera/start / /api/camera/stop / /api/camera/reset Camera lifecycle control reset clears the 429 backoff and restarts ffmpeg
GET /api/settings Read current config.ini-backed settings
POST /api/settings Write settings, then restart the bridge See config fields below
GET /api/update/check Check Gitea releases for a newer version Branches on nightly/dev/stable channel
POST /api/update/apply Self-update (non-Docker builds only) {tag}
POST /api/file_ready/clear Dismiss the "file ready to print" banner/dialog state
GET /api/log/stream Server-Sent Events log tail
GET /api/log/download Download buffered log as plaintext
GET /serve/{filename} Internal file server used to hand the printer a URL to fetch gcode from Not meant for direct browser use

/api/settings fields (POST body, all optional — merges into existing config.ini): printer_ip, mqtt_port, username, password, mode_id, device_id, power_on_url, power_off_url, power_status_url, default_ams_slot, auto_leveling, vibration_compensation, camera_on_print, web_upload_warning, print_start_dialog, poll_interval, verbose_http_log, printer_name, spoolman_server, spoolman_sync_rate, ace_dry_presets.

AMS / ACE filament control (/api/...)

Method Path Purpose Body
POST /api/ams/set_slot Set material type + color for a slot {index, type, color:[r,g,b]}
POST /api/ams/feed Feed filament in/out {slot_index, type} (1=feed in, 2=feed out)
POST /api/ace/auto_feed Toggle auto-feed for an ACE unit {ace_id, on}
POST /api/ace/dry Start/stop the ACE dryer `{action: "start"

GCode store (bridge-managed uploads) (/kx/files...)

Method Path Purpose
GET /kx/files List files the bridge has stored, with last-print status/duration
DELETE /kx/files/{file_id} Delete a stored file
GET /kx/files/{file_id}/download Download a stored file
POST /kx/files/{file_id}/verify Clear the "web upload, unverified" flag
GET /kx/files/{id}/objects Print-object list + SVG preview (for the pre-print skip feature)
GET /kx/history?limit=&offset= Paginated print job history

Files on the printer's own storage (/kx/printer-files...)

Distinct from the GCode store above — these list/manage files that live on the printer's internal storage (e.g. printed directly from Anycubic Slicer Next, bypassing the bridge).

Method Path Purpose
GET /kx/printer-files List files via the printer's file/listLocal MQTT action
POST /kx/printer-files/delete Delete one or more files: {"filenames": [...]} (single endpoint for single + bulk delete)
GET /kx/printer-files/{filename}/thumbnail Fetch (and cache) a file's embedded gcode thumbnail via file/fileDetails

Printing (/kx/print)

Method Path Purpose Body
POST /kx/print Start a print from a stored GCode-store file {file_id, filament_assignments?, excluded_objects?, auto_leveling?}

filament_assignments is [{slot_index, material, color_hex}, ...]; if omitted, all currently-occupied AMS slots are auto-mapped.

Pre-print / mid-print object skip (/kx/skip...)

Method Path Purpose
POST /kx/skip Skip named objects mid-print: {"names": [...]}
POST /kx/skip/query Re-request the object list from the printer and return merged skip state
GET /kx/skip/state Current skip state (object list, already-skipped names, SVG, filename)

Filament profiles (/kx/filament/...)

Method Path Purpose Body / Query
GET /kx/filament/slots Current AMS slot contents + any user profile override
GET /kx/filament/profiles?type=&vendor= Curated OrcaSlicer filament profile catalog (system + user-imported) Optional filters
GET /kx/filament/profiles/user User-imported profiles only (for the settings management list)
POST /kx/filament/profiles/user Import profiles from a ZIP or .json file(s) (multipart) Multipart field file/files/upload; ZIP entries or bare .json, parsed via orca_filaments.parse_profile_bytes
DELETE /kx/filament/profiles/user?vendor=&name= Delete one user profile (both params) or all (no params)
POST /kx/filament/slots/{idx}/profile Assign (or clear) a fixed profile override for one AMS slot {vendor, name}; empty strings clear the mapping. Selector is (vendor, name), not id — IDs are not unique across the Orca profile catalog
GET/POST /kx/filament/visible_vendors Get/set the vendor visibility filter for the slot profile dropdown POST body {"vendors": [...]}; empty list = show all

Spoolman integration (/kx/spoolman/...)

Method Path Purpose
GET /kx/spoolman/status Whether Spoolman is configured/reachable, server URL, sync rate, current slot→spool map
GET /kx/spoolman/spools Proxied list of spools from the configured Spoolman server
POST /kx/spoolman/active-spool Assign spool IDs to AMS slots: {"slot_map": {"0": 42, "2": 17}} (AMS slot index → Spoolman spool ID)

Multi-printer management (/kx/printers...)

Method Path Purpose Body
GET /kx/printers List all configured printers with online-ish metadata
POST /kx/printers/add Add a printer by IP (credentials auto-fetched from the printer) {printer_ip, name?} — triggers a bridge restart
DELETE /kx/printers/{pid} Remove a printer from config; renumbers remaining [printer_N] sections — triggers a bridge restart
POST /kx/printers/{pid}/power Toggle an external smart plug (Tasmota-style) for a printer `{"action": "on"
GET /kx/printers/{pid}/power-status Query the smart plug's current on/off state

Power switch is not the printer's own power state — it's a plain GET fired at a user-configured power_on_url / power_off_url / power_status_url (e.g. a Tasmota cmnd=Power%20on URL). See MANUAL.md for details. It only exists for printers where power_on_url or power_off_url is set in config; /kx/printers exposes this as has_power_control.

Misc

Method Path Purpose
GET /kx/ui/{name} Serves theme assets (JS/CSS/vendored libs) and translation JSON files under the active UI theme
GET / , /printer{N} Serves the Web UI (index.html with CSS/JS inlined for embedded-webview compatibility, e.g. OrcaSlicer's device tab)
GET /favicon.ico Favicon

Response conventions

  • Moonraker-compatible endpoints wrap results as {"result": {...}} (or {"error": {"code": ..., "message": ...}} for the /server/database/* 404 case) to match the real Moonraker schema.
  • Bridge-specific /api/... and /kx/... endpoints generally return {"result": ...} on success and {"error": "message"} with a non-2xx HTTP status on failure — but this is not universal; check the handler in kobrax_moonraker_bridge.py if exact shape matters (route registrations are near the end of the file, search for r.add_get(/r.add_post(/r.add_delete().
  • Endpoints that trigger a config write (/api/settings, /kx/printers/add, /kx/printers/{pid} DELETE) restart the whole bridge process shortly after responding — clients should expect a brief connection drop.