# 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](MANUAL.md), and for setup see [README.md](README.md). The API has two distinct parts: 1. **Moonraker-compatible surface** — a subset of the real [Moonraker](https://moonraker.readthedocs.io/) 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}` (0–100) | | 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"|"stop", ace_id?, target_temp?, duration?}` | ### 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"|"off"}` | | 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](MANUAL.md#power-switch-feature) 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.