Skip to content
Hoody.com

Display input actions drive a desktop the same way a user does: clicking pixels, pressing keys, dragging windows, and waiting for the UI to settle. Every route is bound to a specific display by the -display-N segment of the hostname; the displayId query parameter overrides the host when needed. State-changing commands enter a 20-deep per-display queue, so input is delivered in order even when many calls arrive at once, while the wait-until admission cap sits outside that queue so waits never block timed key or button releases. Use these routes when an automation needs more than what the higher-level helpers cover.

GET /api/v1/display/input/display-geometry

Section titled “GET /api/v1/display/input/display-geometry”

Return the current display’s pixel dimensions.

NameInTypeRequiredDescription
displayIdqueryintegerNoDisplay ID to use (overrides the *-display-N.* hostname pattern). Valid range: 1 to 999999.
{
"success": true,
"width": 1920,
"height": 1080,
"screen": 0
}
Terminal window
curl -X GET "https://{projectId}-{containerId}-display-1.{server}.containers.hoody.com/api/v1/display/input/display-geometry" \
-H "Authorization: Bearer <token>"

Return the current cursor position and the window it is over.

NameInTypeRequiredDescription
displayIdqueryintegerNoDisplay ID to use (overrides the *-display-N.* hostname pattern). Valid range: 1 to 999999.
{
"success": true,
"x": 640,
"y": 360,
"screen": 0,
"window": 6291468
}
Terminal window
curl -X GET "https://{projectId}-{containerId}-display-1.{server}.containers.hoody.com/api/v1/display/mouse/location" \
-H "Authorization: Bearer <token>"

GET /api/v1/display/window/{windowId}/geometry

Section titled “GET /api/v1/display/window/{windowId}/geometry”

Return the position and size of a window.

NameInTypeRequiredDescription
windowIdpathstringYesWindow ID (decimal or hex).
displayIdqueryintegerNoDisplay ID to use (overrides the *-display-N.* hostname pattern). Valid range: 1 to 999999.
{
"success": true,
"windowId": "6291468",
"x": 100,
"y": 100,
"width": 800,
"height": 600
}
Terminal window
curl -X GET "https://{projectId}-{containerId}-display-1.{server}.containers.hoody.com/api/v1/display/window/6291468/geometry" \
-H "Authorization: Bearer <token>"

GET /api/v1/display/window/{windowId}/name

Section titled “GET /api/v1/display/window/{windowId}/name”

Return the title of a window.

NameInTypeRequiredDescription
windowIdpathstringYesWindow ID (decimal or hex).
displayIdqueryintegerNoDisplay ID to use (overrides the *-display-N.* hostname pattern). Valid range: 1 to 999999.
{
"success": true,
"windowId": "6291468",
"name": "Untitled Document — gedit"
}
Terminal window
curl -X GET "https://{projectId}-{containerId}-display-1.{server}.containers.hoody.com/api/v1/display/window/6291468/name" \
-H "Authorization: Bearer <token>"

Return the window that currently has focus.

NameInTypeRequiredDescription
displayIdqueryintegerNoDisplay ID to use (overrides the *-display-N.* hostname pattern). Valid range: 1 to 999999.
{
"success": true,
"windowId": 6291468
}
Terminal window
curl -X GET "https://{projectId}-{containerId}-display-1.{server}.containers.hoody.com/api/v1/display/window/active" \
-H "Authorization: Bearer <token>"

These endpoints compose several primitives into a single call. Each one enters the same per-display input queue as the underlying keyboard and mouse routes, so a click, drag, or batch is delivered in the order it was sent.

Execute a single named action, optionally with a trailing screenshot. The action path picks which primitive runs; params are validated against the same schema the standalone route uses, so a params rejection here IS a 400 VALIDATION_ERROR, unlike in /input/batch.

NameInTypeRequiredDescription
displayIdqueryintegerNoDisplay ID to use (overrides the *-display-N.* hostname pattern). Valid range: 1 to 999999.
FieldTypeRequiredDescription
actionstringYesOne of mouse/click, mouse/double-click, mouse/move, mouse/move-relative, mouse/down, mouse/up, mouse/scroll, keyboard/type, keyboard/key, keyboard/key-down, keyboard/key-up, input/click-at, input/type-at, input/drag, input/select, input/wait, clipboard/read, clipboard/write, window/focus, window/raise, window/minimize, window/restore, window/move, window/resize, window/close, window/search.
paramsobjectNoAction-specific parameters. Validated against the standalone route’s schema. Default: {}.
screenshotbooleanNoCapture a screenshot after the action. Default: true.
screenshotDelayintegerNoDelay before the screenshot in milliseconds. Default: 100.
screenshotRegionstringNoCrop region in x1,y1,x2,y2 form.
{
"action": "input/click-at",
"params": {
"x": 320,
"y": 240
},
"screenshot": true,
"screenshotDelay": 150
}
{
"success": true,
"action": {
"success": true,
"action": "input/click-at",
"details": {}
},
"screenshot": {
"timestamp": "2024-01-15T10:30:00.000Z",
"image": {
"data": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=",
"mimeType": "image/png",
"dataUrl": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII="
}
}
}
Terminal window
curl -X POST "https://{projectId}-{containerId}-display-1.{server}.containers.hoody.com/api/v1/display/input/act" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"action": "input/click-at",
"params": { "x": 320, "y": 240 },
"screenshot": true
}'

Execute a sequence of actions in order. See the Aside above for how failure is signalled.

NameInTypeRequiredDescription
displayIdqueryintegerNoDisplay ID to use (overrides the *-display-N.* hostname pattern). Valid range: 1 to 999999.
FieldTypeRequiredDescription
actionsarrayYesActions to run, between 1 and 50 entries. Each entry has action (the path) and an optional params object.
{
"actions": [
{ "action": "mouse/move", "params": { "x": 320, "y": 240 } },
{ "action": "mouse/click", "params": { "button": 1 } },
{ "action": "keyboard/type", "params": { "text": "hello" } }
]
}

The envelope is HTTP 200 whether or not an action failed. Inspect success, failed, and skipped.

{
"success": false,
"completed": [
{ "index": 0, "action": "mouse/move", "success": true },
{ "index": 1, "action": "mouse/click", "success": true }
],
"failed": {
"index": 2,
"action": "keyboard/type",
"error": "Window not found"
},
"skipped": [3, 4]
}
Terminal window
curl -X POST "https://{projectId}-{containerId}-display-1.{server}.containers.hoody.com/api/v1/display/input/batch" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"actions": [
{ "action": "mouse/move", "params": { "x": 320, "y": 240 } },
{ "action": "mouse/click", "params": { "button": 1 } },
{ "action": "keyboard/type", "params": { "text": "hello" } }
]
}'

Move the cursor to a point and click it. Multiple clicks at the same point happen in one chained invocation, so the pointer cannot be moved between them.

NameInTypeRequiredDescription
displayIdqueryintegerNoDisplay ID to use (overrides the *-display-N.* hostname pattern). Valid range: 1 to 999999.
FieldTypeRequiredDescription
xintegerYesTarget X coordinate (0-65535).
yintegerYesTarget Y coordinate (0-65535).
buttonintegerNoMouse button (1=left, 2=middle, 3=right, 4-7=extra). Default: 1.
repeatintegerNoNumber of clicks at that point. Default: 1. Must satisfy repeat x delay <= 4000 ms.
delayintegerNoMilliseconds after every click. Defaults to xdotool’s 100 ms. A double-click needs repeat: 2 with a delay under the desktop’s double-click time.
{
"x": 320,
"y": 240,
"button": 1,
"repeat": 2,
"delay": 50
}
{
"success": true,
"action": "click-at",
"details": {}
}
Terminal window
curl -X POST "https://{projectId}-{containerId}-display-1.{server}.containers.hoody.com/api/v1/display/input/click-at" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{ "x": 320, "y": 240, "button": 1, "repeat": 2, "delay": 50 }'

Press a mouse button at one point, drag through several intermediate positions, and release at the end point.

NameInTypeRequiredDescription
displayIdqueryintegerNoDisplay ID to use (overrides the *-display-N.* hostname pattern). Valid range: 1 to 999999.
FieldTypeRequiredDescription
startXintegerYesStarting X coordinate.
startYintegerYesStarting Y coordinate.
endXintegerYesEnding X coordinate.
endYintegerYesEnding Y coordinate.
buttonintegerNoMouse button (1=left, 2=middle, 3=right, 4-7=extra). Default: 1.
stepsintegerNoNumber of intermediate mouse positions for a smooth drag (1-1000).
{
"startX": 100,
"startY": 100,
"endX": 500,
"endY": 400,
"button": 1,
"steps": 20
}
{
"success": true,
"action": "drag",
"details": {}
}
Terminal window
curl -X POST "https://{projectId}-{containerId}-display-1.{server}.containers.hoody.com/api/v1/display/input/drag" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{ "startX": 100, "startY": 100, "endX": 500, "endY": 400, "steps": 20 }'

Emergency release every held key and mouse button. Use this to recover from a stuck modifier or button.

NameInTypeRequiredDescription
displayIdqueryintegerNoDisplay ID to use (overrides the *-display-N.* hostname pattern). Valid range: 1 to 999999.
{
"success": true,
"action": "reset",
"details": {}
}
Terminal window
curl -X POST "https://{projectId}-{containerId}-display-1.{server}.containers.hoody.com/api/v1/display/input/reset" \
-H "Authorization: Bearer <token>"

Click at one point and shift-click at another to select a range. Useful for text-range selection in fields that respond to shift-click.

NameInTypeRequiredDescription
displayIdqueryintegerNoDisplay ID to use (overrides the *-display-N.* hostname pattern). Valid range: 1 to 999999.
FieldTypeRequiredDescription
xintegerYesAnchor X coordinate.
yintegerYesAnchor Y coordinate.
endXintegerYesEnd X coordinate.
endYintegerYesEnd Y coordinate.
{
"x": 100,
"y": 100,
"endX": 500,
"endY": 400
}
{
"success": true,
"action": "select",
"details": {}
}
Terminal window
curl -X POST "https://{projectId}-{containerId}-display-1.{server}.containers.hoody.com/api/v1/display/input/select" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{ "x": 100, "y": 100, "endX": 500, "endY": 400 }'

Move the cursor to a point, click, and type a string. Useful for filling in a single field.

NameInTypeRequiredDescription
displayIdqueryintegerNoDisplay ID to use (overrides the *-display-N.* hostname pattern). Valid range: 1 to 999999.
FieldTypeRequiredDescription
xintegerYesTarget X coordinate.
yintegerYesTarget Y coordinate.
textstringYesText to type (max 10000 characters).
delayintegerNoInter-keystroke delay in milliseconds (0-1000).
{
"x": 320,
"y": 240,
"text": "hello world",
"delay": 12
}
{
"success": true,
"action": "type-at",
"details": {}
}
Terminal window
curl -X POST "https://{projectId}-{containerId}-display-1.{server}.containers.hoody.com/api/v1/display/input/type-at" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{ "x": 320, "y": 240, "text": "hello world", "delay": 12 }'

Sleep for a duration. Useful between actions to give the UI time to settle.

NameInTypeRequiredDescription
displayIdqueryintegerNoDisplay ID to use (overrides the *-display-N.* hostname pattern). Valid range: 1 to 999999.
FieldTypeRequiredDescription
msintegerYesWait duration in milliseconds (50-30000).
screenshotbooleanNoCapture a screenshot after the wait. Default: false.
{
"ms": 500,
"screenshot": false
}
{
"success": true,
"action": "wait",
"details": { "ms": 500 }
}
Terminal window
curl -X POST "https://{projectId}-{containerId}-display-1.{server}.containers.hoody.com/api/v1/display/input/wait" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{ "ms": 500 }'

Block until a window condition holds or the timeout expires, so a caller does not have to poll window/search over HTTP while an application starts up or a dialog closes.

NameInTypeRequiredDescription
displayIdqueryintegerNoDisplay ID to use (overrides the *-display-N.* hostname pattern). Valid range: 1 to 999999.
FieldTypeRequiredDescription
conditionstringYesOne of window-present (wait for a window matching pattern to appear) or window-absent (wait for the last match to go away, or a specific windowId to stop existing).
patternstringNoExtended POSIX regex as xdotool search takes it. Required for window-present. For window-absent give either this or windowId, not both. A pattern xdotool cannot compile is a 400, as is one containing a NUL.
matchstringNoWhich window property pattern is matched against: name (title), class (stable across a window’s life), or classname. Default: name.
onlyVisiblebooleanNoRestrict the search to viewable windows. Sending it with windowId is rejected. Default: false.
windowIdinteger | stringNoWait for this exact window to stop existing. window-absent only, and not together with pattern, match, or onlyVisible.
timeoutMsintegerNoMaximum wait in milliseconds (100-25000). Default: 10000.
pollMsintegerNoGap between observations (100-5000). Default: 250. An explicit value above timeoutMs is rejected; the default is not.
{
"condition": "window-present",
"pattern": "^Settings$",
"match": "name",
"timeoutMs": 5000
}

Returned with success: true and the matched window ids when the condition held, or with success: false and timedOut: true when the timeout expired with the condition unmet. A short timeoutMs that expires inside a single observation comes back as 200 with timedOut: true and polls: 0, which says plainly that nothing was ever observed.

{
"success": true,
"condition": "window-present",
"waitedMs": 1250,
"polls": 5,
"windows": [6291468]
}
Terminal window
curl -X POST "https://{projectId}-{containerId}-display-1.{server}.containers.hoody.com/api/v1/display/input/wait-until" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{ "condition": "window-present", "pattern": "^Settings$", "match": "name", "timeoutMs": 5000 }'

Press one or more key combinations in order. Each entry is sent to the windowed xdotool call together, so ctrl+c lands as a single keystroke.

NameInTypeRequiredDescription
displayIdqueryintegerNoDisplay ID to use (overrides the *-display-N.* hostname pattern). Valid range: 1 to 999999.
FieldTypeRequiredDescription
keysarrayYesKey combinations, for example ["ctrl+c", "Return"]. 1-20 entries, each up to 100 characters.
windowinteger | stringNoTarget window ID (decimal or hex 0x...).
delayintegerNoInter-keystroke delay in milliseconds (0-5000).
clearModifiersbooleanNoClear modifier keys before pressing.
{
"keys": ["ctrl+a", "Delete"]
}
{
"success": true,
"action": "key",
"details": {}
}
Terminal window
curl -X POST "https://{projectId}-{containerId}-display-1.{server}.containers.hoody.com/api/v1/display/keyboard/key" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{ "keys": ["ctrl+a", "Delete"] }'

Press and hold a single key. Pair with /keyboard/key-up to release.

NameInTypeRequiredDescription
displayIdqueryintegerNoDisplay ID to use (overrides the *-display-N.* hostname pattern). Valid range: 1 to 999999.
FieldTypeRequiredDescription
keystringYesX11 keysym (for example Shift_L, ctrl).
windowinteger | stringNoTarget window ID (decimal or hex 0x...).
holdMsintegerNoAuto-release after this many milliseconds (100-60000).
{
"key": "Shift_L",
"holdMs": 1000
}
{
"success": true,
"action": "key-down",
"details": {}
}
Terminal window
curl -X POST "https://{projectId}-{containerId}-display-1.{server}.containers.hoody.com/api/v1/display/keyboard/key-down" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{ "key": "Shift_L", "holdMs": 1000 }'

Release a key previously held by /keyboard/key-down.

NameInTypeRequiredDescription
displayIdqueryintegerNoDisplay ID to use (overrides the *-display-N.* hostname pattern). Valid range: 1 to 999999.
FieldTypeRequiredDescription
keystringYesX11 keysym (max 100 characters).
windowinteger | stringNoTarget window ID (decimal or hex 0x...).
{
"key": "Shift_L"
}
{
"success": true,
"action": "key-up",
"details": {}
}
Terminal window
curl -X POST "https://{projectId}-{containerId}-display-1.{server}.containers.hoody.com/api/v1/display/keyboard/key-up" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{ "key": "Shift_L" }'

Type a string of literal text. Use /keyboard/key for named keys or combinations.

NameInTypeRequiredDescription
displayIdqueryintegerNoDisplay ID to use (overrides the *-display-N.* hostname pattern). Valid range: 1 to 999999.
FieldTypeRequiredDescription
textstringYesText to type (max 10000 characters).
windowinteger | stringNoTarget window ID (decimal or hex 0x...).
delayintegerNoInter-keystroke delay in milliseconds (0-1000).
clearModifiersbooleanNoClear modifier keys before typing.
{
"text": "hello world",
"delay": 12
}
{
"success": true,
"action": "type",
"details": {}
}
Terminal window
curl -X POST "https://{projectId}-{containerId}-display-1.{server}.containers.hoody.com/api/v1/display/keyboard/type" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{ "text": "hello world", "delay": 12 }'

Click a mouse button at the current cursor position.

NameInTypeRequiredDescription
displayIdqueryintegerNoDisplay ID to use (overrides the *-display-N.* hostname pattern). Valid range: 1 to 999999.
FieldTypeRequiredDescription
buttonintegerNoMouse button: 1=left, 2=middle, 3=right, 4-7=extra. Default: 1.
repeatintegerNoNumber of clicks (1-100). Default: 1. Must satisfy repeat x delay <= 4000 ms.
delayintegerNoMilliseconds to wait after every click. Defaults to xdotool’s 100 ms.
windowinteger | stringNoTarget window ID (decimal or hex 0x...).
{
"button": 1,
"repeat": 1,
"delay": 100
}
{
"success": true,
"action": "click",
"details": {}
}
Terminal window
curl -X POST "https://{projectId}-{containerId}-display-1.{server}.containers.hoody.com/api/v1/display/mouse/click" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{ "button": 1 }'

Double-click a mouse button at the current cursor position.

NameInTypeRequiredDescription
displayIdqueryintegerNoDisplay ID to use (overrides the *-display-N.* hostname pattern). Valid range: 1 to 999999.
FieldTypeRequiredDescription
buttonintegerNoMouse button: 1=left, 2=middle, 3=right, 4-7=extra. Default: 1.
windowinteger | stringNoTarget window ID (decimal or hex 0x...).
{
"button": 1
}
{
"success": true,
"action": "double-click",
"details": {}
}
Terminal window
curl -X POST "https://{projectId}-{containerId}-display-1.{server}.containers.hoody.com/api/v1/display/mouse/double-click" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{ "button": 1 }'

Press and hold a mouse button. Pair with /mouse/up to release.

NameInTypeRequiredDescription
displayIdqueryintegerNoDisplay ID to use (overrides the *-display-N.* hostname pattern). Valid range: 1 to 999999.
FieldTypeRequiredDescription
buttonintegerNoMouse button: 1=left, 2=middle, 3=right, 4-7=extra. Default: 1.
windowinteger | stringNoTarget window ID (decimal or hex 0x...).
holdMsintegerNoAuto-release after this many milliseconds (100-60000).
{
"button": 1,
"holdMs": 1000
}
{
"success": true,
"action": "mouse-down",
"details": {}
}
Terminal window
curl -X POST "https://{projectId}-{containerId}-display-1.{server}.containers.hoody.com/api/v1/display/mouse/down" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{ "button": 1, "holdMs": 1000 }'

Move the cursor to an absolute screen position. Coordinates can be negative to address off-screen positions used by multi-monitor setups.

NameInTypeRequiredDescription
displayIdqueryintegerNoDisplay ID to use (overrides the *-display-N.* hostname pattern). Valid range: 1 to 999999.
FieldTypeRequiredDescription
xintegerYesTarget X coordinate (-65535 to 65535).
yintegerYesTarget Y coordinate (-65535 to 65535).
windowinteger | stringNoTarget window ID (decimal or hex 0x...).
screenintegerNoScreen number (0-15).
syncbooleanNoWait for the move to be observed before answering.
{
"x": 320,
"y": 240,
"screen": 0,
"sync": true
}
{
"success": true,
"action": "mouse-move",
"details": {}
}
Terminal window
curl -X POST "https://{projectId}-{containerId}-display-1.{server}.containers.hoody.com/api/v1/display/mouse/move" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{ "x": 320, "y": 240, "screen": 0, "sync": true }'

Move the cursor by an offset from its current position.

NameInTypeRequiredDescription
displayIdqueryintegerNoDisplay ID to use (overrides the *-display-N.* hostname pattern). Valid range: 1 to 999999.
FieldTypeRequiredDescription
xintegerYesHorizontal offset to apply.
yintegerYesVertical offset to apply.
syncbooleanNoWait for the move to be observed before answering.
{
"x": 50,
"y": -20,
"sync": true
}
{
"success": true,
"action": "mouse-move-relative",
"details": {}
}
Terminal window
curl -X POST "https://{projectId}-{containerId}-display-1.{server}.containers.hoody.com/api/v1/display/mouse/move-relative" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{ "x": 50, "y": -20, "sync": true }'

Scroll in a direction. Optionally move the pointer to a specific point first; the move and the wheel events are one chained xdotool invocation, so nothing can move the pointer in between.

NameInTypeRequiredDescription
displayIdqueryintegerNoDisplay ID to use (overrides the *-display-N.* hostname pattern). Valid range: 1 to 999999.
FieldTypeRequiredDescription
directionstringYesOne of up, down, left, right.
clicksintegerNoWheel clicks (1-100). Default: 5. Must satisfy clicks x delay <= 4000 ms.
delayintegerNoMilliseconds between wheel clicks. Defaults to xdotool’s 100 ms.
xintegerNoScroll at this point (0-65535) instead of wherever the pointer happens to be. Must be given together with y.
yintegerNoMust be given together with x (0-65535).
{
"direction": "down",
"clicks": 5,
"x": 320,
"y": 240
}
{
"success": true,
"action": "scroll",
"details": {}
}
Terminal window
curl -X POST "https://{projectId}-{containerId}-display-1.{server}.containers.hoody.com/api/v1/display/mouse/scroll" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{ "direction": "down", "clicks": 5, "x": 320, "y": 240 }'

Release a mouse button previously held by /mouse/down.

NameInTypeRequiredDescription
displayIdqueryintegerNoDisplay ID to use (overrides the *-display-N.* hostname pattern). Valid range: 1 to 999999.
FieldTypeRequiredDescription
buttonintegerNoMouse button: 1=left, 2=middle, 3=right, 4-7=extra. Default: 1.
windowinteger | stringNoTarget window ID (decimal or hex 0x...).
{
"button": 1
}
{
"success": true,
"action": "mouse-up",
"details": {}
}
Terminal window
curl -X POST "https://{projectId}-{containerId}-display-1.{server}.containers.hoody.com/api/v1/display/mouse/up" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{ "button": 1 }'

Ask the X server to close a window.

NameInTypeRequiredDescription
displayIdqueryintegerNoDisplay ID to use (overrides the *-display-N.* hostname pattern). Valid range: 1 to 999999.
FieldTypeRequiredDescription
windowIdinteger | stringYesWindow ID (decimal or hex 0x...).
{
"windowId": 6291468
}
{
"success": true,
"action": "window-close",
"details": {}
}
Terminal window
curl -X POST "https://{projectId}-{containerId}-display-1.{server}.containers.hoody.com/api/v1/display/window/close" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{ "windowId": 6291468 }'

Activate a window and give it X input focus, so that untargeted /keyboard/* input reaches it.

NameInTypeRequiredDescription
displayIdqueryintegerNoDisplay ID to use (overrides the *-display-N.* hostname pattern). Valid range: 1 to 999999.
FieldTypeRequiredDescription
windowIdinteger | stringYesTarget window ID (decimal or hex 0x...).
syncbooleanNoWait for the X server to apply the change before answering. On this endpoint this is what makes a following keyboard/* action land in the window that was just focused.
{
"windowId": 6291468,
"sync": true
}
{
"success": true,
"action": "window-focus",
"details": {
"windowId": 6291468,
"inputFocus": true
}
}
Terminal window
curl -X POST "https://{projectId}-{containerId}-display-1.{server}.containers.hoody.com/api/v1/display/window/focus" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{ "windowId": 6291468, "sync": true }'

Minimize a window. To bring it back, call /window/restore.

NameInTypeRequiredDescription
displayIdqueryintegerNoDisplay ID to use (overrides the *-display-N.* hostname pattern). Valid range: 1 to 999999.
FieldTypeRequiredDescription
windowIdinteger | stringYesTarget window ID (decimal or hex 0x...).
syncbooleanNoWait for the X server to apply the change before answering.
{
"windowId": 6291468,
"sync": true
}
{
"success": true,
"action": "window-minimize",
"details": {}
}
Terminal window
curl -X POST "https://{projectId}-{containerId}-display-1.{server}.containers.hoody.com/api/v1/display/window/minimize" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{ "windowId": 6291468, "sync": true }'

Move a window to a new position. With relative: true, the x and y are interpreted as offsets from the current position.

NameInTypeRequiredDescription
displayIdqueryintegerNoDisplay ID to use (overrides the *-display-N.* hostname pattern). Valid range: 1 to 999999.
FieldTypeRequiredDescription
windowIdinteger | stringYesTarget window ID (decimal or hex 0x...).
xintegerYesTarget X coordinate (or offset when relative is true).
yintegerYesTarget Y coordinate (or offset when relative is true).
syncbooleanNoWait for the X server to apply the change before answering.
relativebooleanNoTreat x and y as offsets from the current position.
{
"windowId": 6291468,
"x": 100,
"y": 100,
"sync": true
}
{
"success": true,
"action": "window-move",
"details": {}
}
Terminal window
curl -X POST "https://{projectId}-{containerId}-display-1.{server}.containers.hoody.com/api/v1/display/window/move" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{ "windowId": 6291468, "x": 100, "y": 100, "sync": true }'

Ask the X server to raise the window.

NameInTypeRequiredDescription
displayIdqueryintegerNoDisplay ID to use (overrides the *-display-N.* hostname pattern). Valid range: 1 to 999999.
FieldTypeRequiredDescription
windowIdinteger | stringYesWindow ID (decimal or hex 0x...).
{
"windowId": 6291468
}
{
"success": true,
"action": "window-raise",
"details": {}
}
Terminal window
curl -X POST "https://{projectId}-{containerId}-display-1.{server}.containers.hoody.com/api/v1/display/window/raise" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{ "windowId": 6291468 }'

Resize a window. The window manager may ignore the request, so use sync: true when the caller needs to know the new size took effect.

NameInTypeRequiredDescription
displayIdqueryintegerNoDisplay ID to use (overrides the *-display-N.* hostname pattern). Valid range: 1 to 999999.
FieldTypeRequiredDescription
windowIdinteger | stringYesTarget window ID (decimal or hex 0x...).
widthintegerYesNew width in pixels.
heightintegerYesNew height in pixels.
syncbooleanNoWait for the X server to apply the change before answering.
useHintsbooleanNoApply the size as a normal hint rather than a forced change.
{
"windowId": 6291468,
"width": 1024,
"height": 768,
"sync": true
}
{
"success": true,
"action": "window-resize",
"details": {}
}
Terminal window
curl -X POST "https://{projectId}-{containerId}-display-1.{server}.containers.hoody.com/api/v1/display/window/resize" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{ "windowId": 6291468, "width": 1024, "height": 768, "sync": true }'

Un-minimize a window minimized by /window/minimize, by the application, or by a user in the display viewer.

NameInTypeRequiredDescription
displayIdqueryintegerNoDisplay ID to use (overrides the *-display-N.* hostname pattern). Valid range: 1 to 999999.
FieldTypeRequiredDescription
windowIdinteger | stringYesX window ID (decimal, or hex like 0x60000c; 32-bit).
syncbooleanNoWait (up to 2 s) until the window manager reports the window as no longer minimized. Defaults to true, unlike the other window actions: the restore request is a message the window manager may ignore, so without waiting the response cannot say whether it worked.
{
"windowId": 6291468,
"sync": true
}
{
"success": true,
"action": "window-restore",
"details": {
"windowId": 6291468,
"previousState": "iconic",
"state": "normal",
"synced": true
}
}
Terminal window
curl -X POST "https://{projectId}-{containerId}-display-1.{server}.containers.hoody.com/api/v1/display/window/restore" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{ "windowId": 6291468, "sync": true }'

Return the window IDs that match a regex against the window name, class, and/or classname.

NameInTypeRequiredDescription
displayIdqueryintegerNoDisplay ID to use (overrides the *-display-N.* hostname pattern). Valid range: 1 to 999999.
FieldTypeRequiredDescription
patternstringYesSearch pattern (regex, max 200 characters).
namebooleanNoMatch against window name/title.
classbooleanNoMatch against window class.
classnamebooleanNoMatch against window classname.
onlyVisiblebooleanNoRestrict the search to viewable windows. This is not a way to skip minimized windows: measured on xpra 6.3.6 and 6.4.4, a window stays viewable after window/minimize, even once xpra reports it iconic. What it does filter is unmapped windows, which on a seamless session means every window while no viewer is attached. Note that GET /windows has a parameter of the same name with a different test: there it drops windows carrying _NET_WM_STATE_HIDDEN, which a minimized window does carry, so that one does exclude minimized windows.
{
"pattern": "Settings$",
"name": true,
"onlyVisible": true
}
{
"success": true,
"windows": [6291468, 6291470]
}
Terminal window
curl -X POST "https://{projectId}-{containerId}-display-1.{server}.containers.hoody.com/api/v1/display/window/search" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{ "pattern": "Settings$", "name": true, "onlyVisible": true }'