{"info":{"description":"Desktop automation API for controlling Linux desktops.","title":"desktopkit API","version":"1.0.0"},"openapi":"3.0.3","paths":{"/actions":{"get":{"description":"Returns the most recent actions executed by the server.","parameters":[{"description":"Maximum number of entries to return","in":"query","name":"limit","required":false,"schema":{"default":100,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"example":[{"action":"mouse.click","duration_ms":42,"params":"...","result":"ok","timestamp":"..."}]}},"description":"Success"}},"summary":"Get recent action log","tags":["Actions"]}},"/application/close":{"post":{"description":"Closes the window with the given ID. Lock-pflichtig (globaler Input-Lock). Optionaler Query-Parameter `lock_timeout_ms` (default 10000). Bei Lock-Timeout: HTTP 503 mit {error: \"lock_timeout\", waited_ms, held_by}.\n\nOptional: `verify_*` Felder aktivieren Preflight-Verifikation vor dem Schließen. Nur **Modus B** verfügbar (`verify_rect` erforderlich). Bei Mismatch: kein Close, HTTP 400. Für Details zu den Modi siehe `POST /mouse/click`.","requestBody":{"content":{"application/json":{"example":{"verify_image":"/tmp/imgStore/ref.png","verify_max_diff_ratio":2.0,"verify_patch_size":100,"verify_pixel_delta":30,"verify_rect":"0,0,1920,1080","window_id":12345}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"status":"ok"}}},"description":"Success"}},"summary":"Close an application window","tags":["Application"]}},"/application/open":{"post":{"description":"Launches an application by its executable path, optionally with arguments. Lock-pflichtig (globaler Input-Lock). Optionaler Query-Parameter `lock_timeout_ms` (default 10000). Bei Lock-Timeout: HTTP 503 mit {error: \"lock_timeout\", waited_ms, held_by}.\n\nOptional: `verify_*` Felder aktivieren Preflight-Verifikation vor dem Öffnen. Nur **Modus B** verfügbar (`verify_rect` erforderlich). Bei Mismatch: kein Launch, HTTP 400. Für Details zu den Modi siehe `POST /mouse/click`.","requestBody":{"content":{"application/json":{"example":{"args":["file.txt"],"path":"/usr/bin/gedit","verify_image":"/tmp/imgStore/ref.png","verify_max_diff_ratio":2.0,"verify_patch_size":100,"verify_pixel_delta":30,"verify_rect":"0,0,1920,1080"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"pid":12345,"status":"ok"}}},"description":"Success"}},"summary":"Open an application","tags":["Application"]}},"/application/running":{"get":{"description":"Checks whether a process with the given name is currently running.","parameters":[{"description":"Process name to search for","in":"query","name":"name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"pids":[12345],"running":true}}},"description":"Success"}},"summary":"Check if application is running","tags":["Application"]}},"/clipboard":{"get":{"description":"Returns the current text content of the system clipboard. Optional ?max_bytes (default 1048576, hard cap) truncates oversize content at a UTF-8 boundary; truncated:true is returned when truncation happened. Lock-free.","parameters":[{"description":"Maximum bytes to return (capped at 1 MiB).","in":"query","name":"max_bytes","required":false,"schema":{"default":1048576,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"example":{"length":17,"text":"clipboard content","truncated":false}}},"description":"Success"}},"summary":"Read clipboard contents","tags":["Clipboard"]},"post":{"description":"Sets the system clipboard to the given text. Lock-pflichtig.\n\nOptional: `verify_image` aktiviert Preflight-Verifikation vor dem Clipboard-Write. Nur **Modus B** verfügbar (`verify_rect` erforderlich — kein natürlicher Ankerpunkt). Bei Mismatch: kein Write, HTTP 400. Für Details zu den Modi siehe `POST /mouse/click`.","requestBody":{"content":{"application/json":{"example":{"text":"new content","verify_image":"/tmp/imgStore/ref.png","verify_max_diff_ratio":2.0,"verify_patch_size":100,"verify_pixel_delta":30,"verify_rect":"0,0,800,600"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"status":"ok"}}},"description":"Success"}},"summary":"Write to clipboard","tags":["Clipboard"]}},"/clipboard/capture":{"post":{"description":"Runs a sequential batch of capture steps. Each step optionally focuses a window, clicks, sends Ctrl+A, sends Ctrl+C, sleeps settle_ms (default 150), reads the clipboard, and stores the text in the named slot. If the clipboard text is identical to the pre-copy state, ok=false with error \"clipboard unchanged after copy\" — but the following steps still run. Holds the global input lock for the whole batch. Lock-pflichtig.","requestBody":{"content":{"application/json":{"example":{"captures":[{"copy":true,"focus_window_id":"0x4400003","select_all":true,"settle_ms":150,"slot":"panel_1"}]}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"results":[{"length":482,"ok":true,"slot":"panel_1","text":"...","truncated":false}]}}},"description":"Success"}},"summary":"Batch capture into clipboard slots","tags":["Clipboard"]}},"/clipboard/slots":{"delete":{"description":"Clears the entire in-memory slot map. Returns 204. Lock-pflichtig.","responses":{"200":{"content":{"application/json":{"example":""}},"description":"Success"}},"summary":"Delete all slots","tags":["Clipboard"]},"get":{"description":"Returns metadata for all in-memory clipboard slots (name, length, stored_at). Lock-free. Slots are session-scoped and lost on server restart.","responses":{"200":{"content":{"application/json":{"example":[{"length":482,"name":"panel_1","stored_at":"2026-05-19T10:15:00Z"}]}},"description":"Success"}},"summary":"List clipboard slots","tags":["Clipboard"]}},"/clipboard/slots/{name}":{"delete":{"description":"Removes the named slot if present. Returns 204 either way. Lock-pflichtig.","responses":{"200":{"content":{"application/json":{"example":""}},"description":"Success"}},"summary":"Delete a named slot","tags":["Clipboard"]},"get":{"description":"Returns the full contents of the named slot. 404 if missing. Lock-free.","responses":{"200":{"content":{"application/json":{"example":{"length":482,"name":"panel_1","stored_at":"2026-05-19T10:15:00Z","text":"..."}}},"description":"Success"}},"summary":"Read a clipboard slot","tags":["Clipboard"]},"put":{"description":"Creates or overwrites the named slot with the given text. Text is truncated to 1 MiB at a UTF-8 boundary. Lock-pflichtig. Note: this endpoint does NOT accept `verify_*` fields — the operation is purely in-memory and causes no visible UI change.","requestBody":{"content":{"application/json":{"example":{"text":"collected text"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"length":14,"name":"panel_1"}}},"description":"Success"}},"summary":"Store text in a named slot","tags":["Clipboard"]}},"/clipboard/slots/{name}/restore":{"post":{"description":"Writes the slot's text back into the OS clipboard via desktopkit-clipboard. 404 if the slot is missing. Lock-pflichtig.\n\nOptional body: accepts `verify_*` fields for Preflight-Verifikation vor dem Restore. Nur **Modus B** verfügbar (`verify_rect` erforderlich). Backwards-compatible: empty body (or no body) still works. Bei Mismatch: kein Restore, HTTP 400. Für Details zu den Modi siehe `POST /mouse/click`.","requestBody":{"content":{"application/json":{"example":{"verify_image":"/tmp/imgStore/ref.png","verify_max_diff_ratio":2.0,"verify_patch_size":100,"verify_pixel_delta":30,"verify_rect":"0,0,800,600"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"length":482,"name":"panel_1"}}},"description":"Success"}},"summary":"Restore a slot to the OS clipboard","tags":["Clipboard"]}},"/command":{"post":{"description":"Accepts the normal command envelope (docs/command-api.md) and runs it through the SAME handler path as a Nexus command — asserts, sequence.run, action log and the shared input lock (untimed wait) included. Only served by desktopkit-agent (the route lives in its debug router); the transitional Linux desktopkit-server answers 404. Success for screenshot.capture/.region without params.upload returns raw image bytes; callback.return_response=false returns 204 No Content.","requestBody":{"content":{"application/json":{"example":{"command":"mouse.click","params":{"button":"left","x":100,"y":200}}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":"{\"_command\":\"desktopkit-mouse click --button left --x 100 --y 200\", ...}"}},"description":"Success"}},"summary":"Execute a command envelope (agent only)","tags":["Command-API"]}},"/health":{"get":{"description":"Returns server health status. No authentication required.","responses":{"200":{"content":{"application/json":{"example":{"status":"ok"}}},"description":"Success"}},"summary":"Health check","tags":["System"]}},"/keyboard/hotkey":{"post":{"description":"Presses a hotkey combination. Keys: ctrl, alt, shift, super, tab, enter, escape, backspace, delete, home, end, pageup, pagedown, arrowup/arrowdown/arrowleft/arrowright, f1-f12, {\"char\":\"a\"}. Optional `duration_ms` (1..=10000) holds the combination for that many milliseconds before releasing. Lock-pflichtig (globaler Input-Lock). Optionaler Query-Parameter `lock_timeout_ms` (default 10000). Bei Lock-Timeout: HTTP 503 mit {error: \"lock_timeout\", waited_ms, held_by}.\n\nOptional: `verify_image` aktiviert Preflight-Verifikation vor dem Tastendruck. Nur **Modus B** verfügbar (`verify_rect` erforderlich). Bei Mismatch: kein Tastendruck, HTTP 400. Für Details zu den Modi siehe `POST /mouse/click`.","requestBody":{"content":{"application/json":{"example":{"duration_ms":1500,"keys":["ctrl",{"char":"s"}],"verify_image":"/tmp/imgStore/ref.png","verify_max_diff_ratio":2.0,"verify_patch_size":100,"verify_pixel_delta":30,"verify_rect":"0,0,800,600"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"status":"ok"}}},"description":"Success"}},"summary":"Press key combination","tags":["Keyboard"]}},"/keyboard/type":{"post":{"description":"Types the given text string using simulated keystrokes. Optional `duration_ms` (1..=10000) holds each character for that many milliseconds before releasing. Lock-pflichtig (globaler Input-Lock). Optionaler Query-Parameter `lock_timeout_ms` (default 10000). Bei Lock-Timeout: HTTP 503 mit {error: \"lock_timeout\", waited_ms, held_by}.\n\nOptional: `verify_image` aktiviert Preflight-Verifikation vor dem Tippen. Nur **Modus B** verfügbar (`verify_rect` erforderlich — kein natürlicher Ankerpunkt). Bei Mismatch: kein Tastendruck, HTTP 400. Für Details zu den Modi siehe `POST /mouse/click`.","requestBody":{"content":{"application/json":{"example":{"duration_ms":500,"text":"Hello, World!","verify_image":"/tmp/imgStore/ref.png","verify_max_diff_ratio":2.0,"verify_patch_size":100,"verify_pixel_delta":30,"verify_rect":"0,0,800,600"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"status":"ok"}}},"description":"Success"}},"summary":"Type text","tags":["Keyboard"]}},"/mouse/click":{"post":{"description":"Performs a single mouse click at the current cursor position. Optional `x`/`y` move the cursor before clicking (must be set together). Optional `verify_image` activates pre-flight verification: a reference PNG/WebP is compared against the live screen, and the click is only executed on match. Modus A (default) compares a square patch of side `verify_patch_size` around the click point; Modus B (set `verify_rect`) compares the live rect against the whole reference image. On mismatch the click is NOT executed and the endpoint returns HTTP 400 with `{error, location}` — the `error` string includes the measured diff ratio in the form `\"verify failed: diff_ratio X.XXXX > max Y.YYYY (mode A|B)\"`. Lock-pflichtig (globaler Input-Lock). Optionaler Query-Parameter `lock_timeout_ms` (default 10000). Bei Lock-Timeout: HTTP 503 mit {error: \"lock_timeout\", waited_ms, held_by}.","requestBody":{"content":{"application/json":{"example":{"button":"left","verify_image":"/tmp/imgStore/ok-btn.png","verify_max_diff_ratio":2.0,"verify_patch_size":100,"verify_pixel_delta":30,"verify_rect":"400,200,300,150","x":500,"y":300}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"action":"click","button":"left","diff_ratio":0.003,"max_diff_ratio":0.02,"mode":"A","ok":true,"patch":{"height":100,"width":100},"verified":true,"x":500,"y":300}}},"description":"Success"}},"summary":"Click at current position (optional verify-before-click)","tags":["Mouse"]}},"/mouse/double-click":{"post":{"description":"Performs a double click at the current cursor position. Optional `x`/`y` move the cursor before clicking (must be set together). Optional `verify_image` activates pre-flight verification: a reference PNG/WebP is compared against the live screen, and the click is only executed on match. Modus A (default) compares a square patch of side `verify_patch_size` around the click point; Modus B (set `verify_rect`) compares the live rect against the whole reference image. On mismatch the click is NOT executed and the endpoint returns HTTP 400 with `{error, location}` — the `error` string includes the measured diff ratio in the form `\"verify failed: diff_ratio X.XXXX > max Y.YYYY (mode A|B)\"`. Lock-pflichtig (globaler Input-Lock). Optionaler Query-Parameter `lock_timeout_ms` (default 10000). Bei Lock-Timeout: HTTP 503 mit {error: \"lock_timeout\", waited_ms, held_by}.","requestBody":{"content":{"application/json":{"example":{"button":"left","verify_image":"/tmp/imgStore/ok-btn.png","verify_max_diff_ratio":2.0,"verify_patch_size":100,"verify_pixel_delta":30,"verify_rect":"400,200,300,150","x":500,"y":300}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"action":"double_click","button":"left","diff_ratio":0.003,"max_diff_ratio":0.02,"mode":"A","ok":true,"patch":{"height":100,"width":100},"verified":true,"x":500,"y":300}}},"description":"Success"}},"summary":"Double-click at current position (optional verify-before-click)","tags":["Mouse"]}},"/mouse/down":{"post":{"description":"Presses the given mouse button at the current cursor position and holds it. Pair with `POST /mouse/up` to control press-and-drag manually (e.g. interactive resize, lasso-select). Each request acquires the global Input-Lock for the duration of the xdotool call only — between down and up the lock is NOT held, so other API consumers can interleave; the desktop simply stays in the pressed state. Optionaler Query-Parameter `lock_timeout_ms` (default 10000). Bei Lock-Timeout: HTTP 503 mit {error: \"lock_timeout\", waited_ms, held_by}.\n\nOptional: `verify_image` aktiviert Preflight-Verifikation. Da es keinen natürlichen Ankerpunkt gibt, ist nur **Modus B** verfügbar: `verify_rect` muss angegeben werden. Bei Mismatch: kein Press, HTTP 400. Für Details zu den Modi siehe `POST /mouse/click`.","requestBody":{"content":{"application/json":{"example":{"button":"left","verify_image":"/tmp/imgStore/ref.png","verify_max_diff_ratio":2.0,"verify_patch_size":100,"verify_pixel_delta":30,"verify_rect":"400,200,300,150"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"status":"ok"}}},"description":"Success"}},"summary":"Press mouse button (no release)","tags":["Mouse"]}},"/mouse/drag":{"post":{"description":"Performs a mouse drag operation between two screen positions. Lock-pflichtig (globaler Input-Lock). Optionaler Query-Parameter `lock_timeout_ms` (default 10000). Bei Lock-Timeout: HTTP 503 mit {error: \"lock_timeout\", waited_ms, held_by}.\n\nOptional: `verify_image` aktiviert Preflight-Verifikation. **Modus A** (default): vergleicht Patch der Größe `verify_patch_size` um den Drag-Startpunkt (from_x, from_y). **Modus B**: `verify_rect` setzen für freie Referenzfläche. Bei Mismatch: kein Drag, HTTP 400. Für Details zu den Modi siehe `POST /mouse/click`.","requestBody":{"content":{"application/json":{"example":{"button":"left","from_x":100,"from_y":200,"to_x":300,"to_y":400,"verify_image":"/tmp/imgStore/ref.png","verify_max_diff_ratio":2.0,"verify_patch_size":100,"verify_pixel_delta":30,"verify_rect":null}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"status":"ok"}}},"description":"Success"}},"summary":"Drag from one position to another","tags":["Mouse"]}},"/mouse/move":{"post":{"description":"Moves the mouse cursor to the given absolute screen position. Lock-pflichtig (globaler Input-Lock). Optionaler Query-Parameter `lock_timeout_ms` (default 10000). Bei Lock-Timeout: HTTP 503 mit {error: \"lock_timeout\", waited_ms, held_by}.\n\nOptional: `verify_image` aktiviert Preflight-Verifikation vor der Ausführung. Da es keinen natürlichen Ankerpunkt gibt, ist nur **Modus B** verfügbar: `verify_rect` muss angegeben werden (das Referenzbild wird gegen den definierten Bildschirm-Bereich verglichen). Bei Mismatch: kein Move, HTTP 400. Für die vollständige Modus-A/B-Beschreibung siehe `POST /mouse/click`.","requestBody":{"content":{"application/json":{"example":{"verify_image":"/tmp/imgStore/ref.png","verify_max_diff_ratio":2.0,"verify_patch_size":100,"verify_pixel_delta":30,"verify_rect":"0,0,400,300","x":100,"y":200}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"status":"ok"}}},"description":"Success"}},"summary":"Move cursor to coordinates","tags":["Mouse"]}},"/mouse/scroll":{"post":{"description":"Moves cursor to (x, y) and scrolls by the given deltas. Lock-pflichtig (globaler Input-Lock). Optionaler Query-Parameter `lock_timeout_ms` (default 10000). Bei Lock-Timeout: HTTP 503 mit {error: \"lock_timeout\", waited_ms, held_by}.\n\nOptional: `verify_image` aktiviert Preflight-Verifikation. **Modus A** (default): vergleicht Patch der Größe `verify_patch_size` um den Scroll-Ankerpunkt (x, y) — kein `verify_rect` nötig. **Modus B**: `verify_rect` setzen, um das gesamte Referenzbild gegen einen beliebigen Bildschirmbereich zu vergleichen. Bei Mismatch: kein Scroll, HTTP 400. Für Details zu den Modi siehe `POST /mouse/click`.","requestBody":{"content":{"application/json":{"example":{"delta_x":0,"delta_y":-3,"verify_image":"/tmp/imgStore/ref.png","verify_max_diff_ratio":2.0,"verify_patch_size":100,"verify_pixel_delta":30,"verify_rect":null,"x":500,"y":300}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"status":"ok"}}},"description":"Success"}},"summary":"Scroll at position","tags":["Mouse"]}},"/mouse/up":{"post":{"description":"Releases a mouse button previously held via `POST /mouse/down` at the current cursor position. Calling `up` without a preceding `down` is a no-op (xdotool sends the release event regardless). Lock-pflichtig (globaler Input-Lock). Optionaler Query-Parameter `lock_timeout_ms` (default 10000). Bei Lock-Timeout: HTTP 503 mit {error: \"lock_timeout\", waited_ms, held_by}.\n\nOptional: `verify_image` aktiviert Preflight-Verifikation vor dem Release. Da es keinen natürlichen Ankerpunkt gibt, ist nur **Modus B** verfügbar: `verify_rect` muss angegeben werden. Bei Mismatch: kein Release-Event, HTTP 400. Für Details zu den Modi siehe `POST /mouse/click`.","requestBody":{"content":{"application/json":{"example":{"button":"left","verify_image":"/tmp/imgStore/ref.png","verify_max_diff_ratio":2.0,"verify_patch_size":100,"verify_pixel_delta":30,"verify_rect":"400,200,300,150"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"status":"ok"}}},"description":"Success"}},"summary":"Release a previously-pressed mouse button","tags":["Mouse"]}},"/screens":{"get":{"description":"Returns information about all connected screens/monitors.","responses":{"200":{"content":{"application/json":{"example":{"screens":[{"height":1080,"id":0,"width":1920}]}}},"description":"Success"}},"summary":"List available screens","tags":["Screenshot"]}},"/screenshot":{"get":{"description":"Takes a screenshot of the entire screen and returns it as base64-encoded PNG.","parameters":[{"description":"Screen index (0 = primary)","in":"query","name":"screen_id","required":false,"schema":{"default":0,"type":"integer"}},{"description":"Draw a red ring around the cursor position","in":"query","name":"cursor_ring","required":false,"schema":{"default":false,"type":"boolean"}},{"description":"Wait until the image has stabilised before returning","in":"query","name":"wait_stable","required":false,"schema":{"default":false,"type":"boolean"}},{"description":"Per-pixel |ΔR|+|ΔG|+|ΔB| threshold (requires wait_stable)","in":"query","name":"pixel_delta","required":false,"schema":{"default":30,"type":"integer"}},{"description":"Max percent of changed pixels to count as stable (requires wait_stable)","in":"query","name":"stable_ratio","required":false,"schema":{"default":0.2,"type":"number"}},{"description":"How long the frame must stay stable (requires wait_stable)","in":"query","name":"stable_window_ms","required":false,"schema":{"default":500,"type":"integer"}},{"description":"Max wait time in ms (requires wait_stable)","in":"query","name":"timeout_ms","required":false,"schema":{"default":5000,"type":"integer"}},{"description":"Gap between captures (requires wait_stable)","in":"query","name":"poll_interval_ms","required":false,"schema":{"default":200,"type":"integer"}},{"description":"Min percent change vs t=0 required; unset = no baseline check","in":"query","name":"min_change_ratio","required":false,"schema":{"type":"number"}},{"description":"Rectangle 'x,y,w,h' excluded from diffing. Repeatable. Composes with watch_region via AND-NOT.","explode":true,"in":"query","name":"ignore_region","required":false,"schema":{"items":{"type":"string"},"type":"array"},"style":"form"},{"description":"Rectangle 'x,y,w,h' that must contain the change. Repeatable. Empty (default) = whole frame. When set, only pixels inside any watch_region count toward stable_ratio / min_change_ratio / pixel_delta. Composes with ignore_region (a pixel counts iff inside any watch_region AND inside no ignore_region).","explode":true,"in":"query","name":"watch_region","required":false,"schema":{"items":{"type":"string"},"type":"array"},"style":"form"},{"description":"Activate the brightness+saturation gate on each poll.","in":"query","name":"wait_until_interactive","required":false,"schema":{"default":false,"type":"boolean"}},{"description":"u8 (0..=255), default 215. Max mean luma allowed; higher = considered dimmed.","in":"query","name":"interactive_brightness_max","required":false,"schema":{"default":215,"type":"integer"}},{"description":"u8 (0..=255), default 25. Min mean HSV saturation required; lower = considered dimmed.","in":"query","name":"interactive_saturation_min","required":false,"schema":{"default":25,"type":"integer"}},{"description":"Rectangle 'x,y,w,h'. Region for the means. Default: whole frame.","in":"query","name":"interactive_region","required":false,"schema":{"type":"string"}},{"description":"Upload destination. When set, the binary uploads the image after capture and returns an `upload` field in the response.","in":"query","name":"upload_url","required":false,"schema":{"type":"string"}},{"description":"HTTP method: POST | PUT | PATCH.","in":"query","name":"upload_method","required":false,"schema":{"default":"POST","type":"string"}},{"description":"Body format: raw (image bytes), multipart (form-data with file + metadata fields), base64-json (JSON body with base64 image).","in":"query","name":"upload_format","required":false,"schema":{"default":"raw","type":"string"}},{"description":"Repeatable `key:value` HTTP header. Caller headers override default `X-Desktopkit-*` headers.","explode":true,"in":"query","name":"upload_header","required":false,"schema":{"items":{"type":"string"},"type":"array"},"style":"form"},{"description":"When false and upload succeeds, the base64 `image` field is omitted from the response (only the upload outcome is returned). When upload fails, base64 image is always included as a fallback.","in":"query","name":"upload_include_inline","required":false,"schema":{"default":true,"type":"boolean"}},{"description":"Logical name for the screenshot. Appears in X-Desktopkit-Name (raw), multipart form-field `name`, and JSON key `name`.","in":"query","name":"upload_name","required":false,"schema":{"default":"screenshot","type":"string"}},{"description":"Save the captured image to `/tmp/imgStore/<uuid>.<ext>` and include `saved_path` in the JSON response. Requires `format=png` or `format=webp`; JPEG is rejected at runtime.","in":"query","name":"save_to_store","required":false,"schema":{"default":false,"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"example":{"_debug":{"interactive":{"brightness":197.3,"region":{"height":1080,"width":1920,"x":0,"y":0},"saturation":51.4}},"change_ratio_last":0.0008,"height":1080,"image":"<base64>","interactive":true,"polls":7,"saved_path":"/tmp/imgStore/3f2b9c8d-1e4a-4f7b-9c8d-1e4a4f7b9c8d.png","stable":true,"timed_out":false,"waited_ms":1240,"width":1920}}},"description":"Success"}},"summary":"Capture full screen","tags":["Screenshot"]}},"/screenshot/cursor-position":{"get":{"description":"Returns the current mouse cursor coordinates.","responses":{"200":{"content":{"application/json":{"example":{"x":512,"y":384}}},"description":"Success"}},"summary":"Get current cursor position","tags":["Screenshot"]}},"/screenshot/region":{"get":{"description":"Takes a screenshot of a rectangular region.","parameters":[{"description":"Left edge X coordinate","in":"query","name":"x","required":true,"schema":{"type":"integer"}},{"description":"Top edge Y coordinate","in":"query","name":"y","required":true,"schema":{"type":"integer"}},{"description":"Region width in pixels","in":"query","name":"width","required":true,"schema":{"type":"integer"}},{"description":"Region height in pixels","in":"query","name":"height","required":true,"schema":{"type":"integer"}},{"description":"Wait until the image has stabilised before returning","in":"query","name":"wait_stable","required":false,"schema":{"default":false,"type":"boolean"}},{"description":"Per-pixel |ΔR|+|ΔG|+|ΔB| threshold (requires wait_stable)","in":"query","name":"pixel_delta","required":false,"schema":{"default":30,"type":"integer"}},{"description":"Max percent of changed pixels to count as stable (requires wait_stable)","in":"query","name":"stable_ratio","required":false,"schema":{"default":0.2,"type":"number"}},{"description":"How long the frame must stay stable (requires wait_stable)","in":"query","name":"stable_window_ms","required":false,"schema":{"default":500,"type":"integer"}},{"description":"Max wait time in ms (requires wait_stable)","in":"query","name":"timeout_ms","required":false,"schema":{"default":5000,"type":"integer"}},{"description":"Gap between captures (requires wait_stable)","in":"query","name":"poll_interval_ms","required":false,"schema":{"default":200,"type":"integer"}},{"description":"Min percent change vs t=0 required; unset = no baseline check","in":"query","name":"min_change_ratio","required":false,"schema":{"type":"number"}},{"description":"Rectangle 'x,y,w,h' excluded from diffing. Repeatable. Composes with watch_region via AND-NOT.","explode":true,"in":"query","name":"ignore_region","required":false,"schema":{"items":{"type":"string"},"type":"array"},"style":"form"},{"description":"Rectangle 'x,y,w,h' that must contain the change. Repeatable. Empty (default) = whole frame. When set, only pixels inside any watch_region count toward stable_ratio / min_change_ratio / pixel_delta. Composes with ignore_region (a pixel counts iff inside any watch_region AND inside no ignore_region).","explode":true,"in":"query","name":"watch_region","required":false,"schema":{"items":{"type":"string"},"type":"array"},"style":"form"},{"description":"Activate the brightness+saturation gate on each poll.","in":"query","name":"wait_until_interactive","required":false,"schema":{"default":false,"type":"boolean"}},{"description":"u8 (0..=255), default 215. Max mean luma allowed; higher = considered dimmed.","in":"query","name":"interactive_brightness_max","required":false,"schema":{"default":215,"type":"integer"}},{"description":"u8 (0..=255), default 25. Min mean HSV saturation required; lower = considered dimmed.","in":"query","name":"interactive_saturation_min","required":false,"schema":{"default":25,"type":"integer"}},{"description":"Rectangle 'x,y,w,h'. Region for the means. Default: whole frame.","in":"query","name":"interactive_region","required":false,"schema":{"type":"string"}},{"description":"Upload destination. When set, the binary uploads the image after capture and returns an `upload` field in the response.","in":"query","name":"upload_url","required":false,"schema":{"type":"string"}},{"description":"HTTP method: POST | PUT | PATCH.","in":"query","name":"upload_method","required":false,"schema":{"default":"POST","type":"string"}},{"description":"Body format: raw (image bytes), multipart (form-data with file + metadata fields), base64-json (JSON body with base64 image).","in":"query","name":"upload_format","required":false,"schema":{"default":"raw","type":"string"}},{"description":"Repeatable `key:value` HTTP header. Caller headers override default `X-Desktopkit-*` headers.","explode":true,"in":"query","name":"upload_header","required":false,"schema":{"items":{"type":"string"},"type":"array"},"style":"form"},{"description":"When false and upload succeeds, the base64 `image` field is omitted from the response (only the upload outcome is returned). When upload fails, base64 image is always included as a fallback.","in":"query","name":"upload_include_inline","required":false,"schema":{"default":true,"type":"boolean"}},{"description":"Logical name for the screenshot. Appears in X-Desktopkit-Name (raw), multipart form-field `name`, and JSON key `name`.","in":"query","name":"upload_name","required":false,"schema":{"default":"screenshot","type":"string"}},{"description":"Save the captured image to `/tmp/imgStore/<uuid>.<ext>` and include `saved_path` in the JSON response. Requires `format=png` or `format=webp`; JPEG is rejected at runtime.","in":"query","name":"save_to_store","required":false,"schema":{"default":false,"type":"boolean"}},{"description":"Echo the cursor position as `cursor:{x,y,visible}` in native px. The cursor sprite itself is ALWAYS composited into the image, independent of this flag.","in":"query","name":"render_cursor","required":false,"schema":{"default":false,"type":"boolean"}},{"description":"Coordinate space for the marker_* params below: `native` (pixels) or `grid1000` (0..1000, converted via round(v/1000*native)).","in":"query","name":"coord_space","required":false,"schema":{"default":"native","type":"string"}},{"description":"`crosshair|ring|dot|box`. Draws one target marker at output resolution, after crop+scale. Requires marker_x/marker_y.","in":"query","name":"marker_style","required":false,"schema":{"type":"string"}},{"description":"Marker anchor X. Required (with marker_y) when marker_style is set. Full-screen native coordinates — the region's own x/y offset is subtracted automatically.","in":"query","name":"marker_x","required":false,"schema":{"type":"integer"}},{"description":"Marker anchor Y. Required (with marker_x) when marker_style is set. Full-screen native coordinates — the region's own x/y offset is subtracted automatically.","in":"query","name":"marker_y","required":false,"schema":{"type":"integer"}},{"description":"Output px. Used by `crosshair` (default 32) and `dot` (default 8 when marker_size is unset).","in":"query","name":"marker_size","required":false,"schema":{"default":32,"type":"integer"}},{"description":"Output px. `crosshair` only — distance from the anchor before the arm starts (keeps the target pixel free when > 0).","in":"query","name":"marker_gap","required":false,"schema":{"default":8,"type":"integer"}},{"description":"Output px. `ring` only.","in":"query","name":"marker_radius","required":false,"schema":{"default":16,"type":"integer"}},{"description":"Box width. Required (with marker_h) when marker_style=box.","in":"query","name":"marker_w","required":false,"schema":{"type":"integer"}},{"description":"Box height. Required (with marker_w) when marker_style=box.","in":"query","name":"marker_h","required":false,"schema":{"type":"integer"}},{"description":"Marker fill color. `#RRGGBB` hex, `#` prefix optional (accepted either way).","in":"query","name":"marker_color","required":false,"schema":{"default":"#FF00FF","type":"string"}},{"description":"Marker outline color, drawn as a wider/longer pass under `marker_color` for contrast. `#RRGGBB` hex, `#` prefix optional (accepted either way).","in":"query","name":"marker_outline","required":false,"schema":{"default":"#FFFFFF","type":"string"}},{"description":"Output px. `crosshair`, `ring`, `box`; not used by `dot`.","in":"query","name":"marker_thickness","required":false,"schema":{"default":2,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"example":{"_debug":{"interactive":{"brightness":197.3,"region":{"height":1080,"width":1920,"x":0,"y":0},"saturation":51.4}},"change_ratio_last":0.0008,"height":300,"image":"<base64>","interactive":true,"polls":7,"saved_path":"/tmp/imgStore/3f2b9c8d-1e4a-4f7b-9c8d-1e4a4f7b9c8d.png","stable":true,"timed_out":false,"waited_ms":1240,"width":400}}},"description":"Success"}},"summary":"Capture screen region","tags":["Screenshot"]}},"/screenshots":{"post":{"description":"Captures one or more screenshot variants in a single call. Each variant may set `crop` (clip area), `scale_x`/`scale_y` (resize), `format` (`png`|`jpeg`|`webp`) with optional `jpeg_quality`, and `upload` to deliver the image to an external store. Without `upload.include_inline=true`, successful uploads omit the base64 `image`; on any upload failure the base64 is included as a fallback. The response includes an `upload` object per variant with the store's full HTTP response (status, headers, body). Lock-free; safe to poll concurrently with mutating endpoints. Each variant accepts an `upload` JSON object with fields `{ url, method, format, headers, include_inline, name }` — same semantics as the upload_* query params on GET /screenshot. Each variant additionally accepts `render_cursor` (bool — echo the cursor position as `cursor:{x,y,visible}` in native px; the cursor sprite itself is ALWAYS composited into every screenshot), `markers` (array of `{type: crosshair|ring|dot|box, x, y, …}` objects drawn at output resolution after crop+scale — geometry fields size/gap/radius/thickness/w/h are capped at 10,000 and x/y at ±100,000, HTTP 400 if exceeded) and `coord_space` (`native` default, or `grid1000` — marker coordinates 0..1000 are converted via round(v/1000*native)).","requestBody":{"content":{"application/json":{"example":{"variants":[{"name":"overview"},{"crop":{"height":600,"width":800,"x":400,"y":200},"format":"jpeg","jpeg_quality":70,"name":"calc_zoom","scale_x":2.0,"scale_y":2.0,"upload":{"headers":{"Authorization":"Bearer ..."},"include_inline":false,"url":"https://store.example.com/upload"}}]}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"images":[{"crop":null,"format":"png","height":1080,"image":"<base64>","name":"overview","ok":true,"scale_x":1.0,"scale_y":1.0,"url":null,"width":1920,"window_id":null},{"crop":{"height":600,"width":800,"x":400,"y":200},"format":"jpeg","height":1200,"image":null,"name":"calc_zoom","ok":true,"scale_x":2.0,"scale_y":2.0,"upload":{"ok":true,"response":{"body":"","headers":{"location":"https://store.example.com/files/abc123.jpg"},"status":200},"status":200},"url":null,"width":1600,"window_id":null}],"native_height":1080,"native_width":1920}}},"description":"Success"}},"summary":"Capture multiple variants (crop, scale, format, upload)","tags":["Screenshot"]}},"/sequence":{"post":{"description":"Runs a client-ordered list of input steps while holding the global input lock for the entire batch. Every step object carries `name` (unique) and `type` (discriminator), plus per-step fields listed below. Validates the full step list before acquiring the lock — both schema-level errors (missing required field, unknown step type) and semantic errors (duplicate name, bad enum value) return HTTP 400 with `{error:\"validation_failed\", step?, reason}`. Returns HTTP 200 with per-step `ok`/`duration_ms`/`error` and a top-level `aborted_at`. `on_error` is either `abort` (default) or `continue` and can be overridden per step. Query parameter `lock_timeout_ms` (default 10000) controls how long to wait for the lock; on timeout returns HTTP 503.\n\n**Top-level optional fields:**\n- `verify` — Modus-B-only Preflight-Verifikation applied before the FIRST step (same `verify_image`/`verify_rect`/`verify_patch_size`/`verify_pixel_delta`/`verify_max_diff_ratio` fields as individual endpoints). Mismatch → HTTP 400 before any step runs.\n- `query` — Query Condition map (see below) evaluated before the FIRST step. Failure → HTTP 400 before any step runs.\n\n**Per-step optional fields (all mutating step types):**\nEvery mutating step variant (`window.focus`, `mouse.move`, `mouse.click`, `mouse.double_click`, `mouse.down`, `mouse.up`, `mouse.scroll`, `mouse.drag`, `clipboard.write`, `clipboard.slot_restore`, `application.open`, `application.close`, `dialog.close`, `keyboard.type`, `keyboard.key`) accepts optional per-step `verify` and `query` objects evaluated immediately before that step executes. `sleep` and `screenshot` do NOT accept them (validation error at parse phase).\n\nStep types and their per-step fields:\n- `window.focus`: `window_id` (string).\n- `mouse.move`: `x`, `y` (i32).\n- `mouse.click`: `x?`, `y?` (i32), `button` (\"left\"|\"right\"|\"middle\", default \"left\").\n- `mouse.down` / `mouse.up`: `button` (same enum).\n- `mouse.scroll`: `x`, `y`, `delta_x`, `delta_y` (i32).\n- `mouse.drag`: `from_x`, `from_y`, `to_x`, `to_y` (i32), `button` (same enum). Atomic `xdotool` drag (press-move-release with 50 ms internal wait) — preferred over the `mouse.down` + `mouse.move` + `mouse.up` triplet for apps that distinguish a held drag from three separate events.\n- `clipboard.write`: `text` (string).\n- `clipboard.slot_write`: `slot_name` (string), `text` (string). Writes the text into the named in-memory slot — shared store with the REST `/clipboard/slots/*` endpoints.\n- `clipboard.slot_restore`: `slot_name` (string). Pushes the slot's text back into the OS clipboard.\n- `application.open`: `path` (string), `args` (string array, optional).\n- `application.close`: `window_id` (string).\n- `dialog.close`: `window_id` (string), `wait_dialog_gone_ms` (1..=5000, default 500). Runs 3 server-side escalation stages (Escape → Alt+F4 → focus+window-close), polling `desktopkit-window list` every 50 ms between stages; on success the reached stage is reported as `closed_via` ∈ `\"already-gone\" | \"escape\" | \"alt-f4\" | \"force\"`.\n- `keyboard.type`: `text` (string).\n- `keyboard.key`: `keys` (string, e.g. `\"ctrl+v\"`).\n- `sleep`: `ms` (1..=600000). No `verify`/`query` accepted.\n- `screenshot`: accepts every option that GET /screenshot does — `screen_id`, `crop`, `window_id`, `cursor_ring`, `scale_factor`/`scale_x`/`scale_y`, `format`, `jpeg_quality`, plus the full wait-stable set: `wait_stable` (bool), `pixel_delta`, `stable_ratio`, `stable_window_ms`, `timeout_ms`, `poll_interval_ms`, `min_change_ratio`, `stable_against` (`\"baseline\"|\"last\"`, default \"last\" — \"baseline\" diffs every poll against the first frame, \"last\" diffs against the previous one; any other value is rejected with 400), `ignore_region` (array of `\"x,y,w,h\"` strings — pixels INSIDE the rect are ignored in the change-ratio computation), `watch_region` (array of `\"x,y,w,h\"` strings — when set, ONLY pixels inside the listed rects count toward the change-ratio; combine with `ignore_region` to subtract sub-areas). Plus the wait-until-interactive set: `wait_until_interactive` (bool, default false — activate the brightness+saturation gate on each poll), `interactive_brightness_max` (u8 (0..=255), default 215 — max mean luma allowed; higher = considered dimmed), `interactive_saturation_min` (u8 (0..=255), default 25 — min mean HSV saturation required; lower = considered dimmed), `interactive_region` (string `\"x,y,w,h\"`, default whole frame — region for the means). The captured image and its metadata (`image`, `format`, `width`, `height`, `bytes`, `change_ratio_from_start`, `waited_ms`, `timed_out`, `stable`, `interactive`, `_debug.interactive.{brightness,saturation,region}`, …) are flattened into that step's result. `screenshot` also accepts an `upload` object `{ url, method, format, headers, include_inline, name }` to upload the captured image to an external store after capture; on completion the step result carries the nested `upload` object plus top-level `upload_ok` (bool) and, on failure, `upload_error` (string) — the base64 `image` is always included as a fallback when upload fails. No `verify`/`query` accepted.\n\n---\n\n**Query Conditions — non-visual state checks**\n\nQuery Conditions let you guard steps (or the entire sequence) against non-visual state — the canonical use-case is popup/focus-loss detection before an action.\n\nA `query` value is a JSON object mapping condition keys to expected values. A value is either:\n- A plain string/number (implicit `eq` shortcut): `\"active_window\": \"0x4400003\"`\n- An object with exactly ONE operator key: `\"active_window\": {\"neq\": \"0x9999\"}` or `\"mouse_x\": {\"gt\": 400}` or `\"clipboard_text\": {\"contains\": \"OrderID\"}`\n\nSupported keys and their types:\n- `active_window` (string window-id hex): operators `eq`, `neq`\n- `active_window_x` (int): operators `eq`, `neq`, `gt`, `lt`\n- `active_window_y` (int): operators `eq`, `neq`, `gt`, `lt`\n- `active_window_width` (int): operators `eq`, `neq`, `gt`, `lt`\n- `active_window_height` (int): operators `eq`, `neq`, `gt`, `lt`\n- `mouse_x` (int): operators `eq`, `neq`, `gt`, `lt`\n- `mouse_y` (int): operators `eq`, `neq`, `gt`, `lt`\n- `clipboard_text` (string): operators `eq`, `neq`, `contains`\n\nOperator semantics: `eq`/`neq` exact match (case-sensitive for strings, exact for ints); `gt`/`lt` strict greater/less-than; `contains` case-sensitive substring. Using an unsupported operator for a key (e.g. `contains` on an int key) is a validation error at parse phase.\n\nFailure shape: top-level `query` failure (before any step runs) → HTTP 400 `{error:\"query_failed\", reason:\"<key> expected <op> '<value>', got '<actual>'\"}`. Per-step failure → that step's result has `ok:false`, `error:\"query failed: <key> expected <op> '<value>', got '<actual>'\"`, and (if `on_error:\"abort\"`) subsequent steps are skipped.\n\nCombined `verify` + `query` AND-semantics: visual verify runs first, then query; first failure is reported and short-circuits (the other check is not evaluated).\n\nValidation errors (rejected at parse phase, HTTP 400 before lock acquisition): unknown condition key, operator not supported for key, multi-op object (more than one key), empty op object, `verify`/`query` on `sleep` or `screenshot` step.","parameters":[{"description":"How long to wait for the global input lock before returning 503.","in":"query","name":"lock_timeout_ms","required":false,"schema":{"default":10000,"type":"integer"}}],"requestBody":{"content":{"application/json":{"example":{"on_error":"abort","query":{"active_window":"0x4400003","mouse_x":{"gt":0}},"steps":[{"name":"focus-calc","type":"window.focus","window_id":"0x4400003"},{"name":"paste-order-id","query":{"active_window":"0x4400003"},"slot_name":"current_order","type":"clipboard.slot_restore"},{"keys":"ctrl+v","name":"hotkey-paste","query":{"active_window":"0x4400003","clipboard_text":{"contains":"OrderID"}},"type":"keyboard.key","verify":{"verify_image":"/tmp/imgStore/field-ready.png","verify_max_diff_ratio":1.5,"verify_rect":"400,200,300,100"}},{"delta_x":0,"delta_y":5,"name":"scroll-down","type":"mouse.scroll","x":600,"y":400},{"name":"submit","type":"mouse.click","x":500,"y":400},{"ms":150,"name":"settle","type":"sleep"},{"name":"close-confirm","type":"dialog.close","wait_dialog_gone_ms":800,"window_id":"0x4500001"},{"format":"jpeg","jpeg_quality":80,"name":"snap","type":"screenshot"}],"verify":{"verify_image":"/tmp/imgStore/baseline.png","verify_max_diff_ratio":2.0,"verify_rect":"0,0,1920,1080"}}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"aborted_at":null,"results":[{"duration_ms":12,"name":"focus-calc","ok":true,"type":"window.focus"},{"duration_ms":18,"length":8,"name":"paste-order-id","ok":true,"type":"clipboard.slot_restore"},{"diff_ratio":0.001,"duration_ms":4,"mode":"B","name":"hotkey-paste","ok":true,"type":"keyboard.key","verified":true},{"duration_ms":21,"name":"scroll-down","ok":true,"type":"mouse.scroll"},{"duration_ms":7,"name":"submit","ok":true,"type":"mouse.click"},{"duration_ms":151,"name":"settle","ok":true,"type":"sleep"},{"closed_via":"escape","duration_ms":62,"name":"close-confirm","ok":true,"type":"dialog.close"},{"bytes":184523,"duration_ms":34,"format":"jpeg","height":1080,"image":"<base64>","name":"snap","ok":true,"type":"screenshot","width":1920}],"total_duration_ms":309}}},"description":"Success"}},"summary":"Execute an ordered batch of input steps under the global lock","tags":["Sequence"]}},"/windows":{"get":{"description":"Returns a list of all open windows with their IDs, titles, and bounds. `bounds` is `{ x, y, width, height }` in native screen pixels. Lock-frei (Polling-fähig).","responses":{"200":{"content":{"application/json":{"example":[{"bounds":{"height":600,"width":800,"x":0,"y":0},"id":12345,"is_dialog":false,"is_focused":true,"pid":4321,"process_name":"gnome-terminal","title":"Terminal"}]}},"description":"Success"}},"summary":"List all windows","tags":["Windows"]}},"/windows/dialog":{"get":{"description":"Checks if there is an active dialog or modal window.","responses":{"200":{"content":{"application/json":{"example":{"dialog":null}}},"description":"Success"}},"summary":"Detect active dialog/modal","tags":["Windows"]}},"/windows/focused":{"get":{"description":"Returns information about the currently focused window, including its bounds. Lock-frei.","responses":{"200":{"content":{"application/json":{"example":{"bounds":{"height":600,"width":800,"x":0,"y":0},"id":12345,"is_dialog":false,"is_focused":true,"pid":4321,"process_name":"gnome-terminal","title":"Terminal"}}},"description":"Success"}},"summary":"Get focused window","tags":["Windows"]}},"/windows/{id}/focus":{"post":{"description":"Brings the window with the given ID to the foreground and focuses it. Lock-pflichtig (globaler Input-Lock). Optionaler Query-Parameter `lock_timeout_ms` (default 10000). Bei Lock-Timeout: HTTP 503 mit {error: \"lock_timeout\", waited_ms, held_by}.\n\nOptional body: accepts `verify_*` fields for Preflight-Verifikation vor dem Focus. Nur **Modus B** verfügbar (`verify_rect` erforderlich). Backwards-compatible: empty body (or no body) still works. Bei Mismatch: kein Focus, HTTP 400. Für Details zu den Modi siehe `POST /mouse/click`.","parameters":[{"description":"Window ID","in":"path","name":"id","required":true,"schema":{"type":"integer"}}],"requestBody":{"content":{"application/json":{"example":{"verify_image":"/tmp/imgStore/ref.png","verify_max_diff_ratio":2.0,"verify_patch_size":100,"verify_pixel_delta":30,"verify_rect":"0,0,1920,1080"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"status":"ok"}}},"description":"Success"}},"summary":"Focus a window by ID","tags":["Windows"]}},"/windows/{id}/move":{"post":{"description":"Sets position and size of the given window in one call. Body: `{ \"bounds\": { x, y, width, height } }`. To only move, keep the existing width/height; to only resize, keep the existing x/y. Lock-pflichtig (siehe globalen Lock). Accepts optional `?lock_timeout_ms=<u64>` (default 10000).\n\nOptional: `verify_*` Felder im Body aktivieren Preflight-Verifikation. Nur **Modus B** verfügbar (`verify_rect` erforderlich — kein natürlicher Ankerpunkt). Bei Mismatch: kein Window-Move, HTTP 400. Für Details zu den Modi siehe `POST /mouse/click`.","parameters":[{"description":"Window ID (numeric, e.g. \"12345\")","in":"path","name":"id","required":true,"schema":{"type":"string"}},{"description":"Max ms to wait for the global input lock before returning HTTP 503.","in":"query","name":"lock_timeout_ms","required":false,"schema":{"default":10000,"type":"integer"}}],"requestBody":{"content":{"application/json":{"example":{"bounds":{"height":720,"width":1280,"x":200,"y":100},"verify_image":"/tmp/imgStore/ref.png","verify_max_diff_ratio":2.0,"verify_patch_size":100,"verify_pixel_delta":30,"verify_rect":"0,0,1920,1080"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"bounds":{"height":720,"width":1280,"x":200,"y":100},"id":"12345","ok":true}}},"description":"Success"}},"summary":"Move and resize a window","tags":["Windows"]}}},"servers":[{"url":"/"}],"tags":[{"name":"Screenshot"},{"name":"Mouse"},{"name":"Keyboard"},{"name":"Clipboard"},{"name":"Sequence"},{"name":"Windows"},{"name":"Application"},{"name":"Actions"},{"name":"System"},{"name":"Command-API"}]}