Execute a typed sequence of up to 20 deterministic actions in
order, optionally collecting a UI capture per step. On a Lusor
Phone, an API-key chain meters phone minutes before every step; a
402 or 503 stops the chain before that step reaches the phone.
Capture resolution rules
Per-step capture always wins. Top-level capture supplies
the default policy:
'none' (default) — no capture on any step.
'each' — capture on every step.
'final' — capture only on the last step.
Step verbs
tap, swipe, type, key, clear, back, home, recent,
start_app, stop_app, screenshot, wait. Each step has the
same params as the corresponding direct-verb route plus an
optional capture override.
Settling
Steps execute back-to-back with no implicit inter-step delay.
Insert wait steps ({ verb: "wait", params: { duration_ms: N } },
0–60000 ms) where the UI needs time to settle — e.g. after a tap
that opens a screen, or before typing into a freshly focused
field. Cumulative wait duration per chain is capped at 120s so
the worst case stays inside the chain timeout.
A step that completes with ok: false does not stop the chain:
the next step still runs, the top-level ok is true only when every
step succeeded, and each step’s ok shows which one failed.
A step that errors instead aborts the chain. This happens when the
phone cannot be reached, when a step’s capture fails, or when
metering refuses a later step (402/503). The response is then
that error alone, with no per-step results, and the steps before it
have already run on the phone. Read the screen before you retry a
chain.
One step in a chain. The params shape is correlated with the
verb discriminator via OpenAPI 3.1 discriminator.mapping —
each variant carries the exact params shape its verb accepts.
Top-level capture policy for a chain request. Per-step capture
always overrides this default. 'each' captures every step;
'final' captures only the last; 'none' (default) captures
nothing.
{"docsConfig":{"theme":"luma","$schema":"https://mintlify.com/docs.json","name":"Lusor","description":"Run AI agents on real phones, or drive a phone directly, with the Lusor API.","colors":{"primary":"#111111","light":"#FAFAFA","dark":"#111111"},"logo":{"light":"https://mintcdn.com/lusor-ai/Ifu_dlUtLbDafp0r/images/lusor-logo-lightmode@2x.png?fit=max\u0026auto=format\u0026n=Ifu_dlUtLbDafp0r\u0026q=85\u0026s=977cb89acbdf111277711fe79f404fd5","dark":"https://mintcdn.com/lusor-ai/s7jsDGcgmdq30-2k/images/lusor-logo-darkmode@2x.png?fit=max\u0026auto=format\u0026n=s7jsDGcgmdq30-2k\u0026q=85\u0026s=1a44f07d6684fb79a9ae4d593a5b924d","href":"https://lusor.ai"},"favicon":"https://mintcdn.com/lusor-ai/Plbn5wBfbIBBjl9c/favicon.png?fit=max\u0026auto=format\u0026n=Plbn5wBfbIBBjl9c\u0026q=85\u0026s=48f99be162e5dd4fe61028a9631f55f0","api":{"playground":{"display":"interactive"},"examples":{"languages":["curl","javascript","python"]}},"navbar":{"links":[{"href":"https://lusor.ai/pricing","label":"Pricing"}],"primary":{"type":"button","label":"Open Lusor","href":"https://app.lusor.ai"}},"footer":{"socials":{"website":"https://lusor.ai"}},"icons":{"library":"fontawesome"},"contextual":{"options":["assistant","copy","view","download-spec","chatgpt","claude"],"display":"header"},"interaction":{"drilldown":false},"styling":{"latex":false},"navigation":{"pages":[]}},"deployment":{"deploymentMetadataValue":{"subdomain":"lusor-ai","hasAudioNarration":false,"actualSubdomain":"lusor-ai","customDomains":["docs.lusor.ai"],"gitSource":{"type":"github","owner":"lusor-ai","repo":"docs","deployBranch":"main","contentDirectory":"","isPrivate":true,"mountPath":"","label":""},"feedback":{"thumbs":true,"agentFeedback":true},"entitlements":{"AI_CHAT":{"status":"DISABLED"},"WEB_MCP":{"status":"DISABLED"},"NARRATION":{"status":"DISABLED"}},"buildId":"6af3665a77bbd85befb3aca1","clientVersion":"0.0.4102","searchFilterCounts":[{"language":"default","tag":"API reference","count":92},{"language":"default","tag":"Endpoints","count":91},{"language":"default","tag":"Developers","count":26},{"language":"default","tag":"Devices","count":22},{"language":"default","tag":"Sessions","count":17},{"language":"default","tag":"Phones","count":13},{"language":"default","tag":"DeviceVerbs","count":12},{"language":"default","tag":"Help Center","count":11},{"language":"default","tag":"Agents","count":11},{"language":"default","tag":"Agents \u0026 sessions","count":9}]},"assistantConfig":{"enableAskAiButton":false,"enableStarterQuestions":false,"enableContextualStarterQuestions":false,"enableAskAiSearchBar":true},"basePath":"","hasChatPermissions":false,"hasWebMcpPermissions":false,"toggles":[{"name":"kill-isr","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"custom-rbac-roles","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-mintlify-slack","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-integrations-settings","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"rbac-expansion","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-pr-grouping","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"custom-prefix","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"analytics-v7","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"user-flows-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"no-publish-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-onboarding","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"llms-txt-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving-live","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"stripTemperatureMiddleware","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"support-platform-pylon-zendesk","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"instant-rollback","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications-server","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-fable","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fixed-ai-action-pricing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automation-resolve-merge-conflict","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"scoped-publishing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"mintql","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"page-level-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-version-history-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-page-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"full-page-search","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workspace-projects","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"assistant-v5","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fork-pr-previews","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"revalidation-jwt","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-sso-scim","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"hobby-abuse-scan","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"dashboard-inbox","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-signup","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"turbopuffer-dual-write","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-enabled","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"approve-review-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-metadata","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"sso-setup-deadline-banner","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"turbopuffer-serve","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"live-agents","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false}],"googleFontsInlined":false},"customCss":[],"page":{"pagePath":"api-reference/deviceverbs/run-a-chain-of-actions","slug":"/api-reference/deviceverbs/run-a-chain-of-actions","pageMetadata":{"title":"Run a chain of actions","description":"Execute a typed sequence of up to 20 deterministic actions in\norder, optionally collecting a UI capture per step. On a Lusor\nPhone, an API-key chain meters phone minutes before every step; a\n`402` or `503` stops the chain before that step reaches the phone.\n\n## Capture resolution rules\n\nPer-step `capture` always wins. Top-level `capture` supplies\nthe default policy:\n\n - `'none'` (default) — no capture on any step.\n - `'each'` — capture on every step.\n - `'final'` — capture only on the last step.\n\n## Step verbs\n\n`tap`, `swipe`, `type`, `key`, `clear`, `back`, `home`, `recent`,\n`start_app`, `stop_app`, `screenshot`, `wait`. Each step has the\nsame params as the corresponding direct-verb route plus an\noptional `capture` override.\n\n## Settling\n\nSteps execute back-to-back with no implicit inter-step delay.\nInsert `wait` steps (`{ verb: \"wait\", params: { duration_ms: N } }`,\n0–60000 ms) where the UI needs time to settle — e.g. after a tap\nthat opens a screen, or before typing into a freshly focused\nfield. Cumulative wait duration per chain is capped at 120s so\nthe worst case stays inside the chain timeout.\n\nA step that completes with `ok: false` does not stop the chain:\nthe next step still runs, the top-level `ok` is true only when every\nstep succeeded, and each step's `ok` shows which one failed.\n\nA step that errors instead aborts the chain. This happens when the\nphone cannot be reached, when a step's capture fails, or when\nmetering refuses a later step (`402`/`503`). The response is then\nthat error alone, with no per-step results, and the steps before it\nhave already run on the phone. Read the screen before you retry a\nchain.\n","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /v1/workspaces/{workspaceId}/devices/{deviceId}/chain","href":"/api-reference/deviceverbs/run-a-chain-of-actions","autogeneratedByOpenApi":true},"description":{"compiledSource":"\"use strict\";\nconst {Fragment: _Fragment, jsx: _jsx, jsxs: _jsxs} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n const _components = {\n code: \"code\",\n h2: \"h2\",\n li: \"li\",\n p: \"p\",\n ul: \"ul\",\n ..._provideComponents(),\n ...props.components\n };\n return _jsxs(_Fragment, {\n children: [_jsxs(_components.p, {\n children: [\"Execute a typed sequence of up to 20 deterministic actions in\\norder, optionally collecting a UI capture per step. On a Lusor\\nPhone, an API-key chain meters phone minutes before every step; a\\n\", _jsx(_components.code, {\n children: \"402\"\n }), \" or \", _jsx(_components.code, {\n children: \"503\"\n }), \" stops the chain before that step reaches the phone.\"]\n }), \"\\n\", _jsx(_components.h2, {\n children: \"Capture resolution rules\"\n }), \"\\n\", _jsxs(_components.p, {\n children: [\"Per-step \", _jsx(_components.code, {\n children: \"capture\"\n }), \" always wins. Top-level \", _jsx(_components.code, {\n children: \"capture\"\n }), \" supplies\\nthe default policy:\"]\n }), \"\\n\", _jsxs(_components.ul, {\n children: [\"\\n\", _jsxs(_components.li, {\n children: [_jsx(_components.code, {\n children: \"'none'\"\n }), \" (default) — no capture on any step.\"]\n }), \"\\n\", _jsxs(_components.li, {\n children: [_jsx(_components.code, {\n children: \"'each'\"\n }), \" — capture on every step.\"]\n }), \"\\n\", _jsxs(_components.li, {\n children: [_jsx(_components.code, {\n children: \"'final'\"\n }), \" — capture only on the last step.\"]\n }), \"\\n\"]\n }), \"\\n\", _jsx(_components.h2, {\n children: \"Step verbs\"\n }), \"\\n\", _jsxs(_components.p, {\n children: [_jsx(_components.code, {\n children: \"tap\"\n }), \", \", _jsx(_components.code, {\n children: \"swipe\"\n }), \", \", _jsx(_components.code, {\n children: \"type\"\n }), \", \", _jsx(_components.code, {\n children: \"key\"\n }), \", \", _jsx(_components.code, {\n children: \"clear\"\n }), \", \", _jsx(_components.code, {\n children: \"back\"\n }), \", \", _jsx(_components.code, {\n children: \"home\"\n }), \", \", _jsx(_components.code, {\n children: \"recent\"\n }), \",\\n\", _jsx(_components.code, {\n children: \"start_app\"\n }), \", \", _jsx(_components.code, {\n children: \"stop_app\"\n }), \", \", _jsx(_components.code, {\n children: \"screenshot\"\n }), \", \", _jsx(_components.code, {\n children: \"wait\"\n }), \". Each step has the\\nsame params as the corresponding direct-verb route plus an\\noptional \", _jsx(_components.code, {\n children: \"capture\"\n }), \" override.\"]\n }), \"\\n\", _jsx(_components.h2, {\n children: \"Settling\"\n }), \"\\n\", _jsxs(_components.p, {\n children: [\"Steps execute back-to-back with no implicit inter-step delay.\\nInsert \", _jsx(_components.code, {\n children: \"wait\"\n }), \" steps (\", _jsx(_components.code, {\n children: \"{ verb: \\\"wait\\\", params: { duration_ms: N } }\"\n }), \",\\n0–60000 ms) where the UI needs time to settle — e.g. after a tap\\nthat opens a screen, or before typing into a freshly focused\\nfield. Cumulative wait duration per chain is capped at 120s so\\nthe worst case stays inside the chain timeout.\"]\n }), \"\\n\", _jsxs(_components.p, {\n children: [\"A step that completes with \", _jsx(_components.code, {\n children: \"ok: false\"\n }), \" does not stop the chain:\\nthe next step still runs, the top-level \", _jsx(_components.code, {\n children: \"ok\"\n }), \" is true only when every\\nstep succeeded, and each step’s \", _jsx(_components.code, {\n children: \"ok\"\n }), \" shows which one failed.\"]\n }), \"\\n\", _jsxs(_components.p, {\n children: [\"A step that errors instead aborts the chain. This happens when the\\nphone cannot be reached, when a step’s capture fails, or when\\nmetering refuses a later step (\", _jsx(_components.code, {\n children: \"402\"\n }), \"/\", _jsx(_components.code, {\n children: \"503\"\n }), \"). The response is then\\nthat error alone, with no per-step results, and the steps before it\\nhave already run on the phone. Read the screen before you retry a\\nchain.\"]\n })]\n });\n}\nfunction MDXContent(props = {}) {\n const {wrapper: MDXLayout} = {\n ..._provideComponents(),\n ...props.components\n };\n return MDXLayout ? _jsx(MDXLayout, {\n ...props,\n children: _jsx(_createMdxContent, {\n ...props\n })\n }) : _createMdxContent(props);\n}\nreturn {\n default: MDXContent\n};\n","frontmatter":{},"scope":{}},"pageType":"default","mdx":{"mdxSource":{"compiledSource":"\"use strict\";const{Fragment:_Fragment,jsx:_jsx}=arguments[0];const{useMDXComponents:_provideComponents}=arguments[0];function _createMdxContent(props){return _jsx(_Fragment,{})}function MDXContent(props={}){const{wrapper:MDXLayout}={..._provideComponents(),...props.components};return MDXLayout?_jsx(MDXLayout,{...props,children:_jsx(_createMdxContent,{...props})}):_createMdxContent(props)}return{default:MDXContent}","frontmatter":{},"scope":{"config":{},"pageMetadata":{"title":"Run a chain of actions","description":"Execute a typed sequence of up to 20 deterministic actions in\norder, optionally collecting a UI capture per step. On a Lusor\nPhone, an API-key chain meters phone minutes before every step; a\n`402` or `503` stops the chain before that step reaches the phone.\n\n## Capture resolution rules\n\nPer-step `capture` always wins. Top-level `capture` supplies\nthe default policy:\n\n - `'none'` (default) — no capture on any step.\n - `'each'` — capture on every step.\n - `'final'` — capture only on the last step.\n\n## Step verbs\n\n`tap`, `swipe`, `type`, `key`, `clear`, `back`, `home`, `recent`,\n`start_app`, `stop_app`, `screenshot`, `wait`. Each step has the\nsame params as the corresponding direct-verb route plus an\noptional `capture` override.\n\n## Settling\n\nSteps execute back-to-back with no implicit inter-step delay.\nInsert `wait` steps (`{ verb: \"wait\", params: { duration_ms: N } }`,\n0–60000 ms) where the UI needs time to settle — e.g. after a tap\nthat opens a screen, or before typing into a freshly focused\nfield. Cumulative wait duration per chain is capped at 120s so\nthe worst case stays inside the chain timeout.\n\nA step that completes with `ok: false` does not stop the chain:\nthe next step still runs, the top-level `ok` is true only when every\nstep succeeded, and each step's `ok` shows which one failed.\n\nA step that errors instead aborts the chain. This happens when the\nphone cannot be reached, when a step's capture fails, or when\nmetering refuses a later step (`402`/`503`). The response is then\nthat error alone, with no per-step results, and the steps before it\nhave already run on the phone. Read the screen before you retry a\nchain.\n","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /v1/workspaces/{workspaceId}/devices/{deviceId}/chain","href":"/api-reference/deviceverbs/run-a-chain-of-actions","autogeneratedByOpenApi":true}}},"mdxSourceWithNoJs":null},"mdxExtracts":{"tableOfContents":[],"codeExamples":{}},"jsLinks":[],"openApiReferenceData":{"operation":{"operationId":"deviceChain","summary":"Run a chain of actions","description":"Execute a typed sequence of up to 20 deterministic actions in\norder, optionally collecting a UI capture per step. On a Lusor\nPhone, an API-key chain meters phone minutes before every step; a\n`402` or `503` stops the chain before that step reaches the phone.\n\n## Capture resolution rules\n\nPer-step `capture` always wins. Top-level `capture` supplies\nthe default policy:\n\n - `'none'` (default) — no capture on any step.\n - `'each'` — capture on every step.\n - `'final'` — capture only on the last step.\n\n## Step verbs\n\n`tap`, `swipe`, `type`, `key`, `clear`, `back`, `home`, `recent`,\n`start_app`, `stop_app`, `screenshot`, `wait`. Each step has the\nsame params as the corresponding direct-verb route plus an\noptional `capture` override.\n\n## Settling\n\nSteps execute back-to-back with no implicit inter-step delay.\nInsert `wait` steps (`{ verb: \"wait\", params: { duration_ms: N } }`,\n0–60000 ms) where the UI needs time to settle — e.g. after a tap\nthat opens a screen, or before typing into a freshly focused\nfield. Cumulative wait duration per chain is capped at 120s so\nthe worst case stays inside the chain timeout.\n\nA step that completes with `ok: false` does not stop the chain:\nthe next step still runs, the top-level `ok` is true only when every\nstep succeeded, and each step's `ok` shows which one failed.\n\nA step that errors instead aborts the chain. This happens when the\nphone cannot be reached, when a step's capture fails, or when\nmetering refuses a later step (`402`/`503`). The response is then\nthat error alone, with no per-step results, and the steps before it\nhave already run on the phone. Read the screen before you retry a\nchain.\n","tags":["DeviceVerbs"],"parameters":["d4891d7b-0cd3-49b2-a1c5-57336910fb94","260caf6c-cb30-4362-991a-4cb1fd9d89c0"],"requestBody":"4bb9eeb0-2d9a-42d8-a748-1feac0ec74a0","responses":{"200":"9162cd91-cc23-4998-9222-024b7117983b","400":"0b49e671-a0d2-446e-876f-97acd534793c","401":"86b357f1-2927-4ad0-9f0d-8cdb6347ff29","402":"efb58477-92e1-4407-abb7-d1e2a2b43b86","404":"8927aeeb-d036-48ab-bc88-1574aad2332e","409":"87e63fe9-cfc3-4217-8ba4-c4ef5d84266e","503":"594084c1-6a15-4f87-b25b-30638a48c636"},"method":"post","type":"path","servers":["67414a81-b86b-4d15-b96f-3a390c272e81"],"security":["e990c9c7-7adf-4c43-a478-c17a739371f3","a66fdb89-a491-49fa-b34f-5bf4ba59f929"],"path":"/v1/workspaces/{workspaceId}/devices/{deviceId}/chain","baseUrlOptions":["https://api.lusor.ai"],"title":"Run a chain of actions","codeSamples":[],"requestExampleLanguages":["bash","javascript","python"],"requiredOnlyExamples":false,"requestExampleType":"generated","responseExampleType":"generated"},"dependencies":{"parameters":{"d4891d7b-0cd3-49b2-a1c5-57336910fb94":{"name":"workspaceId","in":"path","required":true,"schema":{"type":"string","format":"uuid","isRequired":true,"description":"Workspace UUID. Caller must have access.","uniqueKey":"","typeLabel":"string\u003cuuid>"},"description":"Workspace UUID. Caller must have access."},"260caf6c-cb30-4362-991a-4cb1fd9d89c0":{"name":"deviceId","in":"path","required":true,"schema":{"type":"string","isRequired":true,"description":"Device id (paired into the workspace).","uniqueKey":"","typeLabel":"string"},"description":"Device id (paired into the workspace)."}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["steps"],"properties":{"steps":{"type":"array","minItems":1,"maxItems":20,"items":{"oneOf":[{"type":"object","description":"One step in a chain. The `params` shape is correlated with the\n`verb` discriminator via OpenAPI 3.1 `discriminator.mapping` —\neach variant carries the exact params shape its verb accepts.\n","required":["verb","params"],"properties":{"verb":{"type":"string","enum":["tap"],"isRequired":true,"uniqueKey":"steps.items.[INDEX].oneOf.0.verb","typeLabel":"enum\u003cstring>"},"params":{"oneOf":[{"type":"object","description":"Step `params` for a `tap` step — the `TapInput` shape without\n`capture`, which is a sibling field of `params` on the step. Provide\n`index`, or `x`+`y`, or both; when both are supplied `index` wins.\nSupplying neither is a 400, and `x` without `y` is a 400 only when\nno `index` is supplied.\n","required":["index"],"properties":{"index":{"type":"integer","minimum":1,"isRequired":true,"uniqueKey":"steps.items.[INDEX].oneOf.0.params.oneOf.0.index","typeLabel":"integer"},"x":{"type":"number","uniqueKey":"steps.items.[INDEX].oneOf.0.params.oneOf.0.x","typeLabel":"number"},"y":{"type":"number","uniqueKey":"steps.items.[INDEX].oneOf.0.params.oneOf.0.y","typeLabel":"number"},"stealth":{"type":"boolean","uniqueKey":"steps.items.[INDEX].oneOf.0.params.oneOf.0.stealth","typeLabel":"boolean"}},"isRequired":true,"uniqueKey":"steps.items.[INDEX].oneOf.0.params.oneOf.0","typeLabel":"object"},{"type":"object","description":"Step `params` for a `tap` step — the `TapInput` shape without\n`capture`, which is a sibling field of `params` on the step. Provide\n`index`, or `x`+`y`, or both; when both are supplied `index` wins.\nSupplying neither is a 400, and `x` without `y` is a 400 only when\nno `index` is supplied.\n","required":["x","y"],"properties":{"x":{"type":"number","isRequired":true,"uniqueKey":"steps.items.[INDEX].oneOf.0.params.oneOf.1.x","typeLabel":"number"},"y":{"type":"number","isRequired":true,"uniqueKey":"steps.items.[INDEX].oneOf.0.params.oneOf.1.y","typeLabel":"number"},"index":{"type":"integer","minimum":1,"uniqueKey":"steps.items.[INDEX].oneOf.0.params.oneOf.1.index","typeLabel":"integer"},"stealth":{"type":"boolean","uniqueKey":"steps.items.[INDEX].oneOf.0.params.oneOf.1.stealth","typeLabel":"boolean"}},"isRequired":true,"uniqueKey":"steps.items.[INDEX].oneOf.0.params.oneOf.1","typeLabel":"object"}],"isRequired":true,"uniqueKey":"steps.items.[INDEX].oneOf.0.params","typeLabel":"object"},"capture":{"oneOf":[{"type":"boolean","description":"`capture: boolean | CaptureOptions`. `true` captures with\ndefaults; an object lets the caller override individual knobs.\n`false` or omitted = no capture.\n","uniqueKey":"steps.items.[INDEX].oneOf.0.capture.oneOf.0","typeLabel":"boolean"},{"type":"object","description":"`capture: boolean | CaptureOptions`. `true` captures with\ndefaults; an object lets the caller override individual knobs.\n`false` or omitted = no capture.\n","properties":{"ui":{"type":"boolean","description":"Capture UI element tree (default true when `capture` is set).","uniqueKey":"steps.items.[INDEX].oneOf.0.capture.oneOf.1.ui","typeLabel":"boolean"},"screenshot":{"type":"boolean","description":"When true, the response includes `screenshot_url`, a link to\nthe `GET /screenshot` endpoint. That endpoint takes a new\nscreenshot each time it is fetched, so the image shows the\nscreen at fetch time, not the moment after the action.\n","uniqueKey":"steps.items.[INDEX].oneOf.0.capture.oneOf.1.screenshot","typeLabel":"boolean"},"verbosity":{"type":"string","enum":["compact","default","full"],"description":"Presentation tier for `capture.elements`. `default` is the same\nelement tree Lusor's own agent reads. `compact` drops indentation +\nnon-interactive nodes for 60-70% fewer tokens. `full` includes every\nflag.\n","uniqueKey":"steps.items.[INDEX].oneOf.0.capture.oneOf.1.verbosity","typeLabel":"enum\u003cstring>"},"only":{"type":"string","enum":["all","clickable","focused","editable"],"description":"Subset filter applied before index assignment.\n","uniqueKey":"steps.items.[INDEX].oneOf.0.capture.oneOf.1.only","typeLabel":"enum\u003cstring>"},"min_size_px":{"type":"integer","minimum":0,"description":"Drop elements smaller than N pixels.","uniqueKey":"steps.items.[INDEX].oneOf.0.capture.oneOf.1.min_size_px","typeLabel":"integer"},"include_keyboard":{"type":"boolean","description":"Include the soft-input/keyboard subtree (default false).","uniqueKey":"steps.items.[INDEX].oneOf.0.capture.oneOf.1.include_keyboard","typeLabel":"boolean"},"max_depth":{"type":"integer","minimum":1,"maximum":50,"description":"Cap on the depth of the element tree.","uniqueKey":"steps.items.[INDEX].oneOf.0.capture.oneOf.1.max_depth","typeLabel":"integer"}},"additionalProperties":false,"uniqueKey":"steps.items.[INDEX].oneOf.0.capture.oneOf.1","typeLabel":"object"}],"uniqueKey":"steps.items.[INDEX].oneOf.0.capture","typeLabel":"boolean | object"}},"uniqueKey":"steps.items.[INDEX].oneOf.0","typeLabel":"object"},{"type":"object","description":"One step in a chain. The `params` shape is correlated with the\n`verb` discriminator via OpenAPI 3.1 `discriminator.mapping` —\neach variant carries the exact params shape its verb accepts.\n","required":["verb","params"],"properties":{"verb":{"type":"string","enum":["swipe"],"isRequired":true,"uniqueKey":"steps.items.[INDEX].oneOf.1.verb","typeLabel":"enum\u003cstring>"},"params":{"type":"object","required":["startX","startY","endX","endY"],"properties":{"startX":{"type":"number","isRequired":true,"uniqueKey":"steps.items.[INDEX].oneOf.1.params.startX","typeLabel":"number"},"startY":{"type":"number","isRequired":true,"uniqueKey":"steps.items.[INDEX].oneOf.1.params.startY","typeLabel":"number"},"endX":{"type":"number","isRequired":true,"uniqueKey":"steps.items.[INDEX].oneOf.1.params.endX","typeLabel":"number"},"endY":{"type":"number","isRequired":true,"uniqueKey":"steps.items.[INDEX].oneOf.1.params.endY","typeLabel":"number"},"durationMs":{"type":"integer","minimum":1,"maximum":60000,"uniqueKey":"steps.items.[INDEX].oneOf.1.params.durationMs","typeLabel":"integer"},"stealth":{"type":"boolean","uniqueKey":"steps.items.[INDEX].oneOf.1.params.stealth","typeLabel":"boolean"}},"isRequired":true,"uniqueKey":"steps.items.[INDEX].oneOf.1.params","typeLabel":"object"},"capture":{"oneOf":[{"type":"boolean","description":"`capture: boolean | CaptureOptions`. `true` captures with\ndefaults; an object lets the caller override individual knobs.\n`false` or omitted = no capture.\n","uniqueKey":"steps.items.[INDEX].oneOf.1.capture.oneOf.0","typeLabel":"boolean"},{"type":"object","description":"`capture: boolean | CaptureOptions`. `true` captures with\ndefaults; an object lets the caller override individual knobs.\n`false` or omitted = no capture.\n","properties":{"ui":{"type":"boolean","description":"Capture UI element tree (default true when `capture` is set).","uniqueKey":"steps.items.[INDEX].oneOf.1.capture.oneOf.1.ui","typeLabel":"boolean"},"screenshot":{"type":"boolean","description":"When true, the response includes `screenshot_url`, a link to\nthe `GET /screenshot` endpoint. That endpoint takes a new\nscreenshot each time it is fetched, so the image shows the\nscreen at fetch time, not the moment after the action.\n","uniqueKey":"steps.items.[INDEX].oneOf.1.capture.oneOf.1.screenshot","typeLabel":"boolean"},"verbosity":{"type":"string","enum":["compact","default","full"],"description":"Presentation tier for `capture.elements`. `default` is the same\nelement tree Lusor's own agent reads. `compact` drops indentation +\nnon-interactive nodes for 60-70% fewer tokens. `full` includes every\nflag.\n","uniqueKey":"steps.items.[INDEX].oneOf.1.capture.oneOf.1.verbosity","typeLabel":"enum\u003cstring>"},"only":{"type":"string","enum":["all","clickable","focused","editable"],"description":"Subset filter applied before index assignment.\n","uniqueKey":"steps.items.[INDEX].oneOf.1.capture.oneOf.1.only","typeLabel":"enum\u003cstring>"},"min_size_px":{"type":"integer","minimum":0,"description":"Drop elements smaller than N pixels.","uniqueKey":"steps.items.[INDEX].oneOf.1.capture.oneOf.1.min_size_px","typeLabel":"integer"},"include_keyboard":{"type":"boolean","description":"Include the soft-input/keyboard subtree (default false).","uniqueKey":"steps.items.[INDEX].oneOf.1.capture.oneOf.1.include_keyboard","typeLabel":"boolean"},"max_depth":{"type":"integer","minimum":1,"maximum":50,"description":"Cap on the depth of the element tree.","uniqueKey":"steps.items.[INDEX].oneOf.1.capture.oneOf.1.max_depth","typeLabel":"integer"}},"additionalProperties":false,"uniqueKey":"steps.items.[INDEX].oneOf.1.capture.oneOf.1","typeLabel":"object"}],"uniqueKey":"steps.items.[INDEX].oneOf.1.capture","typeLabel":"boolean | object"}},"uniqueKey":"steps.items.[INDEX].oneOf.1","typeLabel":"object"},{"type":"object","description":"One step in a chain. The `params` shape is correlated with the\n`verb` discriminator via OpenAPI 3.1 `discriminator.mapping` —\neach variant carries the exact params shape its verb accepts.\n","required":["verb","params"],"properties":{"verb":{"type":"string","enum":["type"],"isRequired":true,"uniqueKey":"steps.items.[INDEX].oneOf.2.verb","typeLabel":"enum\u003cstring>"},"params":{"type":"object","required":["text"],"properties":{"text":{"type":"string","minLength":1,"maxLength":8192,"isRequired":true,"uniqueKey":"steps.items.[INDEX].oneOf.2.params.text","typeLabel":"string"},"clear":{"type":"boolean","uniqueKey":"steps.items.[INDEX].oneOf.2.params.clear","typeLabel":"boolean"},"stealth":{"type":"boolean","uniqueKey":"steps.items.[INDEX].oneOf.2.params.stealth","typeLabel":"boolean"}},"isRequired":true,"uniqueKey":"steps.items.[INDEX].oneOf.2.params","typeLabel":"object"},"capture":{"oneOf":[{"type":"boolean","description":"`capture: boolean | CaptureOptions`. `true` captures with\ndefaults; an object lets the caller override individual knobs.\n`false` or omitted = no capture.\n","uniqueKey":"steps.items.[INDEX].oneOf.2.capture.oneOf.0","typeLabel":"boolean"},{"type":"object","description":"`capture: boolean | CaptureOptions`. `true` captures with\ndefaults; an object lets the caller override individual knobs.\n`false` or omitted = no capture.\n","properties":{"ui":{"type":"boolean","description":"Capture UI element tree (default true when `capture` is set).","uniqueKey":"steps.items.[INDEX].oneOf.2.capture.oneOf.1.ui","typeLabel":"boolean"},"screenshot":{"type":"boolean","description":"When true, the response includes `screenshot_url`, a link to\nthe `GET /screenshot` endpoint. That endpoint takes a new\nscreenshot each time it is fetched, so the image shows the\nscreen at fetch time, not the moment after the action.\n","uniqueKey":"steps.items.[INDEX].oneOf.2.capture.oneOf.1.screenshot","typeLabel":"boolean"},"verbosity":{"type":"string","enum":["compact","default","full"],"description":"Presentation tier for `capture.elements`. `default` is the same\nelement tree Lusor's own agent reads. `compact` drops indentation +\nnon-interactive nodes for 60-70% fewer tokens. `full` includes every\nflag.\n","uniqueKey":"steps.items.[INDEX].oneOf.2.capture.oneOf.1.verbosity","typeLabel":"enum\u003cstring>"},"only":{"type":"string","enum":["all","clickable","focused","editable"],"description":"Subset filter applied before index assignment.\n","uniqueKey":"steps.items.[INDEX].oneOf.2.capture.oneOf.1.only","typeLabel":"enum\u003cstring>"},"min_size_px":{"type":"integer","minimum":0,"description":"Drop elements smaller than N pixels.","uniqueKey":"steps.items.[INDEX].oneOf.2.capture.oneOf.1.min_size_px","typeLabel":"integer"},"include_keyboard":{"type":"boolean","description":"Include the soft-input/keyboard subtree (default false).","uniqueKey":"steps.items.[INDEX].oneOf.2.capture.oneOf.1.include_keyboard","typeLabel":"boolean"},"max_depth":{"type":"integer","minimum":1,"maximum":50,"description":"Cap on the depth of the element tree.","uniqueKey":"steps.items.[INDEX].oneOf.2.capture.oneOf.1.max_depth","typeLabel":"integer"}},"additionalProperties":false,"uniqueKey":"steps.items.[INDEX].oneOf.2.capture.oneOf.1","typeLabel":"object"}],"uniqueKey":"steps.items.[INDEX].oneOf.2.capture","typeLabel":"boolean | object"}},"uniqueKey":"steps.items.[INDEX].oneOf.2","typeLabel":"object"},{"type":"object","description":"One step in a chain. The `params` shape is correlated with the\n`verb` discriminator via OpenAPI 3.1 `discriminator.mapping` —\neach variant carries the exact params shape its verb accepts.\n","required":["verb","params"],"properties":{"verb":{"type":"string","enum":["key"],"isRequired":true,"uniqueKey":"steps.items.[INDEX].oneOf.3.verb","typeLabel":"enum\u003cstring>"},"params":{"type":"object","required":["keyCode"],"properties":{"keyCode":{"type":"integer","minimum":0,"maximum":2000,"isRequired":true,"uniqueKey":"steps.items.[INDEX].oneOf.3.params.keyCode","typeLabel":"integer"}},"isRequired":true,"uniqueKey":"steps.items.[INDEX].oneOf.3.params","typeLabel":"object"},"capture":{"oneOf":[{"type":"boolean","description":"`capture: boolean | CaptureOptions`. `true` captures with\ndefaults; an object lets the caller override individual knobs.\n`false` or omitted = no capture.\n","uniqueKey":"steps.items.[INDEX].oneOf.3.capture.oneOf.0","typeLabel":"boolean"},{"type":"object","description":"`capture: boolean | CaptureOptions`. `true` captures with\ndefaults; an object lets the caller override individual knobs.\n`false` or omitted = no capture.\n","properties":{"ui":{"type":"boolean","description":"Capture UI element tree (default true when `capture` is set).","uniqueKey":"steps.items.[INDEX].oneOf.3.capture.oneOf.1.ui","typeLabel":"boolean"},"screenshot":{"type":"boolean","description":"When true, the response includes `screenshot_url`, a link to\nthe `GET /screenshot` endpoint. That endpoint takes a new\nscreenshot each time it is fetched, so the image shows the\nscreen at fetch time, not the moment after the action.\n","uniqueKey":"steps.items.[INDEX].oneOf.3.capture.oneOf.1.screenshot","typeLabel":"boolean"},"verbosity":{"type":"string","enum":["compact","default","full"],"description":"Presentation tier for `capture.elements`. `default` is the same\nelement tree Lusor's own agent reads. `compact` drops indentation +\nnon-interactive nodes for 60-70% fewer tokens. `full` includes every\nflag.\n","uniqueKey":"steps.items.[INDEX].oneOf.3.capture.oneOf.1.verbosity","typeLabel":"enum\u003cstring>"},"only":{"type":"string","enum":["all","clickable","focused","editable"],"description":"Subset filter applied before index assignment.\n","uniqueKey":"steps.items.[INDEX].oneOf.3.capture.oneOf.1.only","typeLabel":"enum\u003cstring>"},"min_size_px":{"type":"integer","minimum":0,"description":"Drop elements smaller than N pixels.","uniqueKey":"steps.items.[INDEX].oneOf.3.capture.oneOf.1.min_size_px","typeLabel":"integer"},"include_keyboard":{"type":"boolean","description":"Include the soft-input/keyboard subtree (default false).","uniqueKey":"steps.items.[INDEX].oneOf.3.capture.oneOf.1.include_keyboard","typeLabel":"boolean"},"max_depth":{"type":"integer","minimum":1,"maximum":50,"description":"Cap on the depth of the element tree.","uniqueKey":"steps.items.[INDEX].oneOf.3.capture.oneOf.1.max_depth","typeLabel":"integer"}},"additionalProperties":false,"uniqueKey":"steps.items.[INDEX].oneOf.3.capture.oneOf.1","typeLabel":"object"}],"uniqueKey":"steps.items.[INDEX].oneOf.3.capture","typeLabel":"boolean | object"}},"uniqueKey":"steps.items.[INDEX].oneOf.3","typeLabel":"object"},{"type":"object","description":"One step in a chain. The `params` shape is correlated with the\n`verb` discriminator via OpenAPI 3.1 `discriminator.mapping` —\neach variant carries the exact params shape its verb accepts.\n","required":["verb"],"properties":{"verb":{"type":"string","enum":["clear"],"isRequired":true,"uniqueKey":"steps.items.[INDEX].oneOf.4.verb","typeLabel":"enum\u003cstring>"},"params":{"type":"object","description":"Empty params object for verbs without inputs (`clear`, `back`,\n`home`, `recent`, `screenshot`). Server treats both `params: {}`\nand an omitted `params` as equivalent.\n","uniqueKey":"steps.items.[INDEX].oneOf.4.params","typeLabel":"object"},"capture":{"oneOf":[{"type":"boolean","description":"`capture: boolean | CaptureOptions`. `true` captures with\ndefaults; an object lets the caller override individual knobs.\n`false` or omitted = no capture.\n","uniqueKey":"steps.items.[INDEX].oneOf.4.capture.oneOf.0","typeLabel":"boolean"},{"type":"object","description":"`capture: boolean | CaptureOptions`. `true` captures with\ndefaults; an object lets the caller override individual knobs.\n`false` or omitted = no capture.\n","properties":{"ui":{"type":"boolean","description":"Capture UI element tree (default true when `capture` is set).","uniqueKey":"steps.items.[INDEX].oneOf.4.capture.oneOf.1.ui","typeLabel":"boolean"},"screenshot":{"type":"boolean","description":"When true, the response includes `screenshot_url`, a link to\nthe `GET /screenshot` endpoint. That endpoint takes a new\nscreenshot each time it is fetched, so the image shows the\nscreen at fetch time, not the moment after the action.\n","uniqueKey":"steps.items.[INDEX].oneOf.4.capture.oneOf.1.screenshot","typeLabel":"boolean"},"verbosity":{"type":"string","enum":["compact","default","full"],"description":"Presentation tier for `capture.elements`. `default` is the same\nelement tree Lusor's own agent reads. `compact` drops indentation +\nnon-interactive nodes for 60-70% fewer tokens. `full` includes every\nflag.\n","uniqueKey":"steps.items.[INDEX].oneOf.4.capture.oneOf.1.verbosity","typeLabel":"enum\u003cstring>"},"only":{"type":"string","enum":["all","clickable","focused","editable"],"description":"Subset filter applied before index assignment.\n","uniqueKey":"steps.items.[INDEX].oneOf.4.capture.oneOf.1.only","typeLabel":"enum\u003cstring>"},"min_size_px":{"type":"integer","minimum":0,"description":"Drop elements smaller than N pixels.","uniqueKey":"steps.items.[INDEX].oneOf.4.capture.oneOf.1.min_size_px","typeLabel":"integer"},"include_keyboard":{"type":"boolean","description":"Include the soft-input/keyboard subtree (default false).","uniqueKey":"steps.items.[INDEX].oneOf.4.capture.oneOf.1.include_keyboard","typeLabel":"boolean"},"max_depth":{"type":"integer","minimum":1,"maximum":50,"description":"Cap on the depth of the element tree.","uniqueKey":"steps.items.[INDEX].oneOf.4.capture.oneOf.1.max_depth","typeLabel":"integer"}},"additionalProperties":false,"uniqueKey":"steps.items.[INDEX].oneOf.4.capture.oneOf.1","typeLabel":"object"}],"uniqueKey":"steps.items.[INDEX].oneOf.4.capture","typeLabel":"boolean | object"}},"uniqueKey":"steps.items.[INDEX].oneOf.4","typeLabel":"object"},{"type":"object","description":"One step in a chain. The `params` shape is correlated with the\n`verb` discriminator via OpenAPI 3.1 `discriminator.mapping` —\neach variant carries the exact params shape its verb accepts.\n","required":["verb"],"properties":{"verb":{"type":"string","enum":["back"],"isRequired":true,"uniqueKey":"steps.items.[INDEX].oneOf.5.verb","typeLabel":"enum\u003cstring>"},"params":{"type":"object","description":"Empty params object for verbs without inputs (`clear`, `back`,\n`home`, `recent`, `screenshot`). Server treats both `params: {}`\nand an omitted `params` as equivalent.\n","uniqueKey":"steps.items.[INDEX].oneOf.5.params","typeLabel":"object"},"capture":{"oneOf":[{"type":"boolean","description":"`capture: boolean | CaptureOptions`. `true` captures with\ndefaults; an object lets the caller override individual knobs.\n`false` or omitted = no capture.\n","uniqueKey":"steps.items.[INDEX].oneOf.5.capture.oneOf.0","typeLabel":"boolean"},{"type":"object","description":"`capture: boolean | CaptureOptions`. `true` captures with\ndefaults; an object lets the caller override individual knobs.\n`false` or omitted = no capture.\n","properties":{"ui":{"type":"boolean","description":"Capture UI element tree (default true when `capture` is set).","uniqueKey":"steps.items.[INDEX].oneOf.5.capture.oneOf.1.ui","typeLabel":"boolean"},"screenshot":{"type":"boolean","description":"When true, the response includes `screenshot_url`, a link to\nthe `GET /screenshot` endpoint. That endpoint takes a new\nscreenshot each time it is fetched, so the image shows the\nscreen at fetch time, not the moment after the action.\n","uniqueKey":"steps.items.[INDEX].oneOf.5.capture.oneOf.1.screenshot","typeLabel":"boolean"},"verbosity":{"type":"string","enum":["compact","default","full"],"description":"Presentation tier for `capture.elements`. `default` is the same\nelement tree Lusor's own agent reads. `compact` drops indentation +\nnon-interactive nodes for 60-70% fewer tokens. `full` includes every\nflag.\n","uniqueKey":"steps.items.[INDEX].oneOf.5.capture.oneOf.1.verbosity","typeLabel":"enum\u003cstring>"},"only":{"type":"string","enum":["all","clickable","focused","editable"],"description":"Subset filter applied before index assignment.\n","uniqueKey":"steps.items.[INDEX].oneOf.5.capture.oneOf.1.only","typeLabel":"enum\u003cstring>"},"min_size_px":{"type":"integer","minimum":0,"description":"Drop elements smaller than N pixels.","uniqueKey":"steps.items.[INDEX].oneOf.5.capture.oneOf.1.min_size_px","typeLabel":"integer"},"include_keyboard":{"type":"boolean","description":"Include the soft-input/keyboard subtree (default false).","uniqueKey":"steps.items.[INDEX].oneOf.5.capture.oneOf.1.include_keyboard","typeLabel":"boolean"},"max_depth":{"type":"integer","minimum":1,"maximum":50,"description":"Cap on the depth of the element tree.","uniqueKey":"steps.items.[INDEX].oneOf.5.capture.oneOf.1.max_depth","typeLabel":"integer"}},"additionalProperties":false,"uniqueKey":"steps.items.[INDEX].oneOf.5.capture.oneOf.1","typeLabel":"object"}],"uniqueKey":"steps.items.[INDEX].oneOf.5.capture","typeLabel":"boolean | object"}},"uniqueKey":"steps.items.[INDEX].oneOf.5","typeLabel":"object"},{"type":"object","description":"One step in a chain. The `params` shape is correlated with the\n`verb` discriminator via OpenAPI 3.1 `discriminator.mapping` —\neach variant carries the exact params shape its verb accepts.\n","required":["verb"],"properties":{"verb":{"type":"string","enum":["home"],"isRequired":true,"uniqueKey":"steps.items.[INDEX].oneOf.6.verb","typeLabel":"enum\u003cstring>"},"params":{"type":"object","description":"Empty params object for verbs without inputs (`clear`, `back`,\n`home`, `recent`, `screenshot`). Server treats both `params: {}`\nand an omitted `params` as equivalent.\n","uniqueKey":"steps.items.[INDEX].oneOf.6.params","typeLabel":"object"},"capture":{"oneOf":[{"type":"boolean","description":"`capture: boolean | CaptureOptions`. `true` captures with\ndefaults; an object lets the caller override individual knobs.\n`false` or omitted = no capture.\n","uniqueKey":"steps.items.[INDEX].oneOf.6.capture.oneOf.0","typeLabel":"boolean"},{"type":"object","description":"`capture: boolean | CaptureOptions`. `true` captures with\ndefaults; an object lets the caller override individual knobs.\n`false` or omitted = no capture.\n","properties":{"ui":{"type":"boolean","description":"Capture UI element tree (default true when `capture` is set).","uniqueKey":"steps.items.[INDEX].oneOf.6.capture.oneOf.1.ui","typeLabel":"boolean"},"screenshot":{"type":"boolean","description":"When true, the response includes `screenshot_url`, a link to\nthe `GET /screenshot` endpoint. That endpoint takes a new\nscreenshot each time it is fetched, so the image shows the\nscreen at fetch time, not the moment after the action.\n","uniqueKey":"steps.items.[INDEX].oneOf.6.capture.oneOf.1.screenshot","typeLabel":"boolean"},"verbosity":{"type":"string","enum":["compact","default","full"],"description":"Presentation tier for `capture.elements`. `default` is the same\nelement tree Lusor's own agent reads. `compact` drops indentation +\nnon-interactive nodes for 60-70% fewer tokens. `full` includes every\nflag.\n","uniqueKey":"steps.items.[INDEX].oneOf.6.capture.oneOf.1.verbosity","typeLabel":"enum\u003cstring>"},"only":{"type":"string","enum":["all","clickable","focused","editable"],"description":"Subset filter applied before index assignment.\n","uniqueKey":"steps.items.[INDEX].oneOf.6.capture.oneOf.1.only","typeLabel":"enum\u003cstring>"},"min_size_px":{"type":"integer","minimum":0,"description":"Drop elements smaller than N pixels.","uniqueKey":"steps.items.[INDEX].oneOf.6.capture.oneOf.1.min_size_px","typeLabel":"integer"},"include_keyboard":{"type":"boolean","description":"Include the soft-input/keyboard subtree (default false).","uniqueKey":"steps.items.[INDEX].oneOf.6.capture.oneOf.1.include_keyboard","typeLabel":"boolean"},"max_depth":{"type":"integer","minimum":1,"maximum":50,"description":"Cap on the depth of the element tree.","uniqueKey":"steps.items.[INDEX].oneOf.6.capture.oneOf.1.max_depth","typeLabel":"integer"}},"additionalProperties":false,"uniqueKey":"steps.items.[INDEX].oneOf.6.capture.oneOf.1","typeLabel":"object"}],"uniqueKey":"steps.items.[INDEX].oneOf.6.capture","typeLabel":"boolean | object"}},"uniqueKey":"steps.items.[INDEX].oneOf.6","typeLabel":"object"},{"type":"object","description":"One step in a chain. The `params` shape is correlated with the\n`verb` discriminator via OpenAPI 3.1 `discriminator.mapping` —\neach variant carries the exact params shape its verb accepts.\n","required":["verb"],"properties":{"verb":{"type":"string","enum":["recent"],"isRequired":true,"uniqueKey":"steps.items.[INDEX].oneOf.7.verb","typeLabel":"enum\u003cstring>"},"params":{"type":"object","description":"Empty params object for verbs without inputs (`clear`, `back`,\n`home`, `recent`, `screenshot`). Server treats both `params: {}`\nand an omitted `params` as equivalent.\n","uniqueKey":"steps.items.[INDEX].oneOf.7.params","typeLabel":"object"},"capture":{"oneOf":[{"type":"boolean","description":"`capture: boolean | CaptureOptions`. `true` captures with\ndefaults; an object lets the caller override individual knobs.\n`false` or omitted = no capture.\n","uniqueKey":"steps.items.[INDEX].oneOf.7.capture.oneOf.0","typeLabel":"boolean"},{"type":"object","description":"`capture: boolean | CaptureOptions`. `true` captures with\ndefaults; an object lets the caller override individual knobs.\n`false` or omitted = no capture.\n","properties":{"ui":{"type":"boolean","description":"Capture UI element tree (default true when `capture` is set).","uniqueKey":"steps.items.[INDEX].oneOf.7.capture.oneOf.1.ui","typeLabel":"boolean"},"screenshot":{"type":"boolean","description":"When true, the response includes `screenshot_url`, a link to\nthe `GET /screenshot` endpoint. That endpoint takes a new\nscreenshot each time it is fetched, so the image shows the\nscreen at fetch time, not the moment after the action.\n","uniqueKey":"steps.items.[INDEX].oneOf.7.capture.oneOf.1.screenshot","typeLabel":"boolean"},"verbosity":{"type":"string","enum":["compact","default","full"],"description":"Presentation tier for `capture.elements`. `default` is the same\nelement tree Lusor's own agent reads. `compact` drops indentation +\nnon-interactive nodes for 60-70% fewer tokens. `full` includes every\nflag.\n","uniqueKey":"steps.items.[INDEX].oneOf.7.capture.oneOf.1.verbosity","typeLabel":"enum\u003cstring>"},"only":{"type":"string","enum":["all","clickable","focused","editable"],"description":"Subset filter applied before index assignment.\n","uniqueKey":"steps.items.[INDEX].oneOf.7.capture.oneOf.1.only","typeLabel":"enum\u003cstring>"},"min_size_px":{"type":"integer","minimum":0,"description":"Drop elements smaller than N pixels.","uniqueKey":"steps.items.[INDEX].oneOf.7.capture.oneOf.1.min_size_px","typeLabel":"integer"},"include_keyboard":{"type":"boolean","description":"Include the soft-input/keyboard subtree (default false).","uniqueKey":"steps.items.[INDEX].oneOf.7.capture.oneOf.1.include_keyboard","typeLabel":"boolean"},"max_depth":{"type":"integer","minimum":1,"maximum":50,"description":"Cap on the depth of the element tree.","uniqueKey":"steps.items.[INDEX].oneOf.7.capture.oneOf.1.max_depth","typeLabel":"integer"}},"additionalProperties":false,"uniqueKey":"steps.items.[INDEX].oneOf.7.capture.oneOf.1","typeLabel":"object"}],"uniqueKey":"steps.items.[INDEX].oneOf.7.capture","typeLabel":"boolean | object"}},"uniqueKey":"steps.items.[INDEX].oneOf.7","typeLabel":"object"},{"type":"object","description":"One step in a chain. The `params` shape is correlated with the\n`verb` discriminator via OpenAPI 3.1 `discriminator.mapping` —\neach variant carries the exact params shape its verb accepts.\n","required":["verb","params"],"properties":{"verb":{"type":"string","enum":["start_app"],"isRequired":true,"uniqueKey":"steps.items.[INDEX].oneOf.8.verb","typeLabel":"enum\u003cstring>"},"params":{"type":"object","required":["package"],"properties":{"package":{"type":"string","minLength":1,"maxLength":255,"pattern":"^[A-Za-z][A-Za-z0-9_]*(\\.[A-Za-z][A-Za-z0-9_]*)+$","description":"Same constraint as `StartAppInput.package` — a case-insensitive\ndotted Java identifier, validated before dispatch.\n","isRequired":true,"uniqueKey":"steps.items.[INDEX].oneOf.8.params.package","typeLabel":"string"},"activity":{"type":"string","minLength":1,"maxLength":255,"pattern":"^\\.?[A-Za-z0-9_]+(\\.[A-Za-z0-9_]+)*$","description":"Relative-or-fully-qualified Android activity name; a leading `.`\nis accepted. Same regex as `StartAppInput.activity`.\n","uniqueKey":"steps.items.[INDEX].oneOf.8.params.activity","typeLabel":"string"}},"isRequired":true,"uniqueKey":"steps.items.[INDEX].oneOf.8.params","typeLabel":"object"},"capture":{"oneOf":[{"type":"boolean","description":"`capture: boolean | CaptureOptions`. `true` captures with\ndefaults; an object lets the caller override individual knobs.\n`false` or omitted = no capture.\n","uniqueKey":"steps.items.[INDEX].oneOf.8.capture.oneOf.0","typeLabel":"boolean"},{"type":"object","description":"`capture: boolean | CaptureOptions`. `true` captures with\ndefaults; an object lets the caller override individual knobs.\n`false` or omitted = no capture.\n","properties":{"ui":{"type":"boolean","description":"Capture UI element tree (default true when `capture` is set).","uniqueKey":"steps.items.[INDEX].oneOf.8.capture.oneOf.1.ui","typeLabel":"boolean"},"screenshot":{"type":"boolean","description":"When true, the response includes `screenshot_url`, a link to\nthe `GET /screenshot` endpoint. That endpoint takes a new\nscreenshot each time it is fetched, so the image shows the\nscreen at fetch time, not the moment after the action.\n","uniqueKey":"steps.items.[INDEX].oneOf.8.capture.oneOf.1.screenshot","typeLabel":"boolean"},"verbosity":{"type":"string","enum":["compact","default","full"],"description":"Presentation tier for `capture.elements`. `default` is the same\nelement tree Lusor's own agent reads. `compact` drops indentation +\nnon-interactive nodes for 60-70% fewer tokens. `full` includes every\nflag.\n","uniqueKey":"steps.items.[INDEX].oneOf.8.capture.oneOf.1.verbosity","typeLabel":"enum\u003cstring>"},"only":{"type":"string","enum":["all","clickable","focused","editable"],"description":"Subset filter applied before index assignment.\n","uniqueKey":"steps.items.[INDEX].oneOf.8.capture.oneOf.1.only","typeLabel":"enum\u003cstring>"},"min_size_px":{"type":"integer","minimum":0,"description":"Drop elements smaller than N pixels.","uniqueKey":"steps.items.[INDEX].oneOf.8.capture.oneOf.1.min_size_px","typeLabel":"integer"},"include_keyboard":{"type":"boolean","description":"Include the soft-input/keyboard subtree (default false).","uniqueKey":"steps.items.[INDEX].oneOf.8.capture.oneOf.1.include_keyboard","typeLabel":"boolean"},"max_depth":{"type":"integer","minimum":1,"maximum":50,"description":"Cap on the depth of the element tree.","uniqueKey":"steps.items.[INDEX].oneOf.8.capture.oneOf.1.max_depth","typeLabel":"integer"}},"additionalProperties":false,"uniqueKey":"steps.items.[INDEX].oneOf.8.capture.oneOf.1","typeLabel":"object"}],"uniqueKey":"steps.items.[INDEX].oneOf.8.capture","typeLabel":"boolean | object"}},"uniqueKey":"steps.items.[INDEX].oneOf.8","typeLabel":"object"},{"type":"object","description":"One step in a chain. The `params` shape is correlated with the\n`verb` discriminator via OpenAPI 3.1 `discriminator.mapping` —\neach variant carries the exact params shape its verb accepts.\n","required":["verb","params"],"properties":{"verb":{"type":"string","enum":["stop_app"],"isRequired":true,"uniqueKey":"steps.items.[INDEX].oneOf.9.verb","typeLabel":"enum\u003cstring>"},"params":{"type":"object","required":["package"],"properties":{"package":{"type":"string","minLength":1,"maxLength":255,"pattern":"^[A-Za-z][A-Za-z0-9_]*(\\.[A-Za-z][A-Za-z0-9_]*)+$","description":"Same constraint as `StopAppInput.package`; validated against the\nsame regex as the `start_app` step.\n","isRequired":true,"uniqueKey":"steps.items.[INDEX].oneOf.9.params.package","typeLabel":"string"}},"isRequired":true,"uniqueKey":"steps.items.[INDEX].oneOf.9.params","typeLabel":"object"},"capture":{"oneOf":[{"type":"boolean","description":"`capture: boolean | CaptureOptions`. `true` captures with\ndefaults; an object lets the caller override individual knobs.\n`false` or omitted = no capture.\n","uniqueKey":"steps.items.[INDEX].oneOf.9.capture.oneOf.0","typeLabel":"boolean"},{"type":"object","description":"`capture: boolean | CaptureOptions`. `true` captures with\ndefaults; an object lets the caller override individual knobs.\n`false` or omitted = no capture.\n","properties":{"ui":{"type":"boolean","description":"Capture UI element tree (default true when `capture` is set).","uniqueKey":"steps.items.[INDEX].oneOf.9.capture.oneOf.1.ui","typeLabel":"boolean"},"screenshot":{"type":"boolean","description":"When true, the response includes `screenshot_url`, a link to\nthe `GET /screenshot` endpoint. That endpoint takes a new\nscreenshot each time it is fetched, so the image shows the\nscreen at fetch time, not the moment after the action.\n","uniqueKey":"steps.items.[INDEX].oneOf.9.capture.oneOf.1.screenshot","typeLabel":"boolean"},"verbosity":{"type":"string","enum":["compact","default","full"],"description":"Presentation tier for `capture.elements`. `default` is the same\nelement tree Lusor's own agent reads. `compact` drops indentation +\nnon-interactive nodes for 60-70% fewer tokens. `full` includes every\nflag.\n","uniqueKey":"steps.items.[INDEX].oneOf.9.capture.oneOf.1.verbosity","typeLabel":"enum\u003cstring>"},"only":{"type":"string","enum":["all","clickable","focused","editable"],"description":"Subset filter applied before index assignment.\n","uniqueKey":"steps.items.[INDEX].oneOf.9.capture.oneOf.1.only","typeLabel":"enum\u003cstring>"},"min_size_px":{"type":"integer","minimum":0,"description":"Drop elements smaller than N pixels.","uniqueKey":"steps.items.[INDEX].oneOf.9.capture.oneOf.1.min_size_px","typeLabel":"integer"},"include_keyboard":{"type":"boolean","description":"Include the soft-input/keyboard subtree (default false).","uniqueKey":"steps.items.[INDEX].oneOf.9.capture.oneOf.1.include_keyboard","typeLabel":"boolean"},"max_depth":{"type":"integer","minimum":1,"maximum":50,"description":"Cap on the depth of the element tree.","uniqueKey":"steps.items.[INDEX].oneOf.9.capture.oneOf.1.max_depth","typeLabel":"integer"}},"additionalProperties":false,"uniqueKey":"steps.items.[INDEX].oneOf.9.capture.oneOf.1","typeLabel":"object"}],"uniqueKey":"steps.items.[INDEX].oneOf.9.capture","typeLabel":"boolean | object"}},"uniqueKey":"steps.items.[INDEX].oneOf.9","typeLabel":"object"},{"type":"object","description":"One step in a chain. The `params` shape is correlated with the\n`verb` discriminator via OpenAPI 3.1 `discriminator.mapping` —\neach variant carries the exact params shape its verb accepts.\n","required":["verb"],"properties":{"verb":{"type":"string","enum":["screenshot"],"isRequired":true,"uniqueKey":"steps.items.[INDEX].oneOf.10.verb","typeLabel":"enum\u003cstring>"},"params":{"type":"object","description":"Empty params object for verbs without inputs (`clear`, `back`,\n`home`, `recent`, `screenshot`). Server treats both `params: {}`\nand an omitted `params` as equivalent.\n","uniqueKey":"steps.items.[INDEX].oneOf.10.params","typeLabel":"object"},"capture":{"oneOf":[{"type":"boolean","description":"`capture: boolean | CaptureOptions`. `true` captures with\ndefaults; an object lets the caller override individual knobs.\n`false` or omitted = no capture.\n","uniqueKey":"steps.items.[INDEX].oneOf.10.capture.oneOf.0","typeLabel":"boolean"},{"type":"object","description":"`capture: boolean | CaptureOptions`. `true` captures with\ndefaults; an object lets the caller override individual knobs.\n`false` or omitted = no capture.\n","properties":{"ui":{"type":"boolean","description":"Capture UI element tree (default true when `capture` is set).","uniqueKey":"steps.items.[INDEX].oneOf.10.capture.oneOf.1.ui","typeLabel":"boolean"},"screenshot":{"type":"boolean","description":"When true, the response includes `screenshot_url`, a link to\nthe `GET /screenshot` endpoint. That endpoint takes a new\nscreenshot each time it is fetched, so the image shows the\nscreen at fetch time, not the moment after the action.\n","uniqueKey":"steps.items.[INDEX].oneOf.10.capture.oneOf.1.screenshot","typeLabel":"boolean"},"verbosity":{"type":"string","enum":["compact","default","full"],"description":"Presentation tier for `capture.elements`. `default` is the same\nelement tree Lusor's own agent reads. `compact` drops indentation +\nnon-interactive nodes for 60-70% fewer tokens. `full` includes every\nflag.\n","uniqueKey":"steps.items.[INDEX].oneOf.10.capture.oneOf.1.verbosity","typeLabel":"enum\u003cstring>"},"only":{"type":"string","enum":["all","clickable","focused","editable"],"description":"Subset filter applied before index assignment.\n","uniqueKey":"steps.items.[INDEX].oneOf.10.capture.oneOf.1.only","typeLabel":"enum\u003cstring>"},"min_size_px":{"type":"integer","minimum":0,"description":"Drop elements smaller than N pixels.","uniqueKey":"steps.items.[INDEX].oneOf.10.capture.oneOf.1.min_size_px","typeLabel":"integer"},"include_keyboard":{"type":"boolean","description":"Include the soft-input/keyboard subtree (default false).","uniqueKey":"steps.items.[INDEX].oneOf.10.capture.oneOf.1.include_keyboard","typeLabel":"boolean"},"max_depth":{"type":"integer","minimum":1,"maximum":50,"description":"Cap on the depth of the element tree.","uniqueKey":"steps.items.[INDEX].oneOf.10.capture.oneOf.1.max_depth","typeLabel":"integer"}},"additionalProperties":false,"uniqueKey":"steps.items.[INDEX].oneOf.10.capture.oneOf.1","typeLabel":"object"}],"uniqueKey":"steps.items.[INDEX].oneOf.10.capture","typeLabel":"boolean | object"}},"uniqueKey":"steps.items.[INDEX].oneOf.10","typeLabel":"object"},{"type":"object","description":"One step in a chain. The `params` shape is correlated with the\n`verb` discriminator via OpenAPI 3.1 `discriminator.mapping` —\neach variant carries the exact params shape its verb accepts.\n","required":["verb","params"],"properties":{"verb":{"type":"string","enum":["wait"],"isRequired":true,"uniqueKey":"steps.items.[INDEX].oneOf.11.verb","typeLabel":"enum\u003cstring>"},"params":{"type":"object","required":["duration_ms"],"properties":{"duration_ms":{"type":"integer","minimum":0,"maximum":60000,"description":"Milliseconds to pause before the next step runs. Bounded to\n60s per wait step; cumulative wait duration across all wait\nsteps in one chain must be ≤ 120s. Chains have no\nimplicit inter-step delay — insert `wait` steps where UI\nsettling is needed (after taps that trigger animations,\nbefore taps that follow screen transitions).\n","isRequired":true,"uniqueKey":"steps.items.[INDEX].oneOf.11.params.duration_ms","typeLabel":"integer"}},"isRequired":true,"uniqueKey":"steps.items.[INDEX].oneOf.11.params","typeLabel":"object"},"capture":{"oneOf":[{"type":"boolean","description":"`capture: boolean | CaptureOptions`. `true` captures with\ndefaults; an object lets the caller override individual knobs.\n`false` or omitted = no capture.\n","uniqueKey":"steps.items.[INDEX].oneOf.11.capture.oneOf.0","typeLabel":"boolean"},{"type":"object","description":"`capture: boolean | CaptureOptions`. `true` captures with\ndefaults; an object lets the caller override individual knobs.\n`false` or omitted = no capture.\n","properties":{"ui":{"type":"boolean","description":"Capture UI element tree (default true when `capture` is set).","uniqueKey":"steps.items.[INDEX].oneOf.11.capture.oneOf.1.ui","typeLabel":"boolean"},"screenshot":{"type":"boolean","description":"When true, the response includes `screenshot_url`, a link to\nthe `GET /screenshot` endpoint. That endpoint takes a new\nscreenshot each time it is fetched, so the image shows the\nscreen at fetch time, not the moment after the action.\n","uniqueKey":"steps.items.[INDEX].oneOf.11.capture.oneOf.1.screenshot","typeLabel":"boolean"},"verbosity":{"type":"string","enum":["compact","default","full"],"description":"Presentation tier for `capture.elements`. `default` is the same\nelement tree Lusor's own agent reads. `compact` drops indentation +\nnon-interactive nodes for 60-70% fewer tokens. `full` includes every\nflag.\n","uniqueKey":"steps.items.[INDEX].oneOf.11.capture.oneOf.1.verbosity","typeLabel":"enum\u003cstring>"},"only":{"type":"string","enum":["all","clickable","focused","editable"],"description":"Subset filter applied before index assignment.\n","uniqueKey":"steps.items.[INDEX].oneOf.11.capture.oneOf.1.only","typeLabel":"enum\u003cstring>"},"min_size_px":{"type":"integer","minimum":0,"description":"Drop elements smaller than N pixels.","uniqueKey":"steps.items.[INDEX].oneOf.11.capture.oneOf.1.min_size_px","typeLabel":"integer"},"include_keyboard":{"type":"boolean","description":"Include the soft-input/keyboard subtree (default false).","uniqueKey":"steps.items.[INDEX].oneOf.11.capture.oneOf.1.include_keyboard","typeLabel":"boolean"},"max_depth":{"type":"integer","minimum":1,"maximum":50,"description":"Cap on the depth of the element tree.","uniqueKey":"steps.items.[INDEX].oneOf.11.capture.oneOf.1.max_depth","typeLabel":"integer"}},"additionalProperties":false,"uniqueKey":"steps.items.[INDEX].oneOf.11.capture.oneOf.1","typeLabel":"object"}],"uniqueKey":"steps.items.[INDEX].oneOf.11.capture","typeLabel":"boolean | object"}},"uniqueKey":"steps.items.[INDEX].oneOf.11","typeLabel":"object"}],"uniqueKey":"steps.items.[INDEX]","typeLabel":"object"},"isRequired":true,"uniqueKey":"steps","typeLabel":"object[]"},"capture":{"type":"string","enum":["each","final","none"],"description":"Top-level capture policy for a chain request. Per-step `capture`\nalways overrides this default. `'each'` captures every step;\n`'final'` captures only the last; `'none'` (default) captures\nnothing.\n","uniqueKey":"capture","typeLabel":"enum\u003cstring>"}},"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"steps":[{"verb":"tap","params":{"index":2,"x":123,"y":123,"stealth":true},"capture":true}]}}},"exampleType":"generated"}},"exampleType":"generated"},"responses":{"9162cd91-cc23-4998-9222-024b7117983b":{"description":"Chain executed","content":{"application/json":{"schema":{"type":"object","required":["ok","steps"],"properties":{"ok":{"type":"boolean","description":"True iff every step's `ok` was true.\n","isRequired":true,"uniqueKey":"ok","typeLabel":"boolean"},"steps":{"type":"array","items":{"type":"object","required":["verb","ok","exit_code","status"],"properties":{"ok":{"type":"boolean","isRequired":true,"uniqueKey":"steps.items.[INDEX].ok","typeLabel":"boolean"},"exit_code":{"type":"integer","description":"`0` on success, non-zero on failure. Currently derived from\n`ok`; it does not carry the command's own exit code.\n","isRequired":true,"uniqueKey":"steps.items.[INDEX].exit_code","typeLabel":"integer"},"status":{"type":"string","isRequired":true,"uniqueKey":"steps.items.[INDEX].status","typeLabel":"string"},"verb":{"type":"string","enum":["tap","swipe","type","key","clear","back","home","recent","start_app","stop_app","screenshot","wait"],"description":"Verb discriminator for a chain step.","isRequired":true,"uniqueKey":"steps.items.[INDEX].verb","typeLabel":"enum\u003cstring>"},"commandId":{"type":"string","uniqueKey":"steps.items.[INDEX].commandId","typeLabel":"string"},"durationMs":{"oneOf":[{"type":"integer","uniqueKey":"steps.items.[INDEX].durationMs.oneOf.0","typeLabel":"integer"},{"type":"null","uniqueKey":"steps.items.[INDEX].durationMs.oneOf.1","typeLabel":"null"}],"uniqueKey":"steps.items.[INDEX].durationMs","typeLabel":"integer | null"},"message":{"type":"string","uniqueKey":"steps.items.[INDEX].message","typeLabel":"string"},"resolved":{"type":"object","properties":{"x":{"type":"integer","uniqueKey":"steps.items.[INDEX].resolved.x","typeLabel":"integer"},"y":{"type":"integer","uniqueKey":"steps.items.[INDEX].resolved.y","typeLabel":"integer"},"index":{"type":"integer","uniqueKey":"steps.items.[INDEX].resolved.index","typeLabel":"integer"}},"uniqueKey":"steps.items.[INDEX].resolved","typeLabel":"object"},"cleared":{"type":"boolean","uniqueKey":"steps.items.[INDEX].cleared","typeLabel":"boolean"},"capture":{"type":"object","description":"Capture payload. All inner fields are optional and present iff\nthe corresponding source was captured:\n - `elements` / `element_count` / `screen_dimensions` — set iff\n `capture.ui` was true.\n - `screenshot_url` — set iff `capture.screenshot` was true.\n\nA screenshot-only capture (no UI) returns just `screenshot_url`;\na UI-only capture returns the tree + count + dimensions; a full\ncapture returns everything.\n\nThe action has already run when the capture is taken. On a single\naction endpoint, a failed capture still returns `200` with\n`capture: { failed: true, error }`, so a retry does not repeat a\nnon-idempotent action. Inside a chain, a failed capture aborts the\nchain with an error instead (see `POST …/chain`).\n","properties":{"failed":{"type":"boolean","description":"Present and `true` only when the capture failed on a single action endpoint.","uniqueKey":"steps.items.[INDEX].capture.failed","typeLabel":"boolean"},"error":{"type":"string","description":"Why the capture failed. Present only with `failed`.","uniqueKey":"steps.items.[INDEX].capture.error","typeLabel":"string"},"elements":{"type":"string","description":"Formatted element tree. Present iff `capture.ui` was true.\nThe exact shape depends on `capture.verbosity`.\n","uniqueKey":"steps.items.[INDEX].capture.elements","typeLabel":"string"},"element_count":{"type":"integer","minimum":0,"description":"Number of `[N]`-indexed interactive elements. Present iff\n`capture.ui` was true.\n","uniqueKey":"steps.items.[INDEX].capture.element_count","typeLabel":"integer"},"screen_dimensions":{"type":"object","description":"Device screen size derived from the UI walk's bounding box.\nPresent iff `capture.ui` was true.\n","required":["width","height"],"properties":{"width":{"type":"integer","minimum":0,"isRequired":true,"uniqueKey":"steps.items.[INDEX].capture.screen_dimensions.width","typeLabel":"integer"},"height":{"type":"integer","minimum":0,"isRequired":true,"uniqueKey":"steps.items.[INDEX].capture.screen_dimensions.height","typeLabel":"integer"}},"uniqueKey":"steps.items.[INDEX].capture.screen_dimensions","typeLabel":"object"},"screenshot_url":{"type":"string","description":"Present iff `capture.screenshot` was true. Links to the\n`GET /screenshot` endpoint, which needs the same API key and\ntakes a new screenshot when fetched (metered on a Lusor Phone\nlike any read). Fetch it before the next action if you want the\nscreen this action left behind.\n","uniqueKey":"steps.items.[INDEX].capture.screenshot_url","typeLabel":"string"}},"uniqueKey":"steps.items.[INDEX].capture","typeLabel":"object"}},"uniqueKey":"steps.items.[INDEX]","typeLabel":"object"},"isRequired":true,"uniqueKey":"steps","typeLabel":"object[]"}},"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"ok":true,"steps":[{"ok":true,"exit_code":123,"status":"\u003cstring>","verb":"tap","commandId":"\u003cstring>","durationMs":123,"message":"\u003cstring>","resolved":{"x":123,"y":123,"index":123},"cleared":true,"capture":{"failed":true,"error":"\u003cstring>","elements":"\u003cstring>","element_count":1,"screen_dimensions":{"width":1,"height":1},"screenshot_url":"\u003cstring>"}}]}}},"exampleType":"generated"}},"exampleType":"generated"},"0b49e671-a0d2-446e-876f-97acd534793c":{"description":"Request validation failed. Either `validation_error` with per-field\n`details`, or `bad_request` with a `message`, depending on the\nendpoint.\n","content":{"application/json":{"schema":{"oneOf":[{"type":"object","required":["error","details"],"properties":{"error":{"type":"string","example":"validation_error","isRequired":true,"uniqueKey":"oneOf.0.error","typeLabel":"string"},"details":{"type":"object","additionalProperties":true,"isRequired":true,"uniqueKey":"oneOf.0.details","typeLabel":"object"}},"uniqueKey":"oneOf.0","typeLabel":"object"},{"type":"object","required":["error","message"],"properties":{"error":{"type":"string","isRequired":true,"uniqueKey":"oneOf.1.error","typeLabel":"string"},"message":{"type":"string","isRequired":true,"uniqueKey":"oneOf.1.message","typeLabel":"string"}},"uniqueKey":"oneOf.1","typeLabel":"object"}],"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"error":"validation_error","details":{}}}},"exampleType":"generated"}},"exampleType":"generated"},"86b357f1-2927-4ad0-9f0d-8cdb6347ff29":{"description":"Authentication required or invalid credentials.","content":{"application/json":{"schema":{"type":"object","required":["error","message"],"properties":{"error":{"type":"string","isRequired":true,"uniqueKey":"error","typeLabel":"string"},"message":{"type":"string","isRequired":true,"uniqueKey":"message","typeLabel":"string"}},"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"error":"\u003cstring>","message":"\u003cstring>"}}},"exampleType":"generated"}},"exampleType":"generated"},"efb58477-92e1-4407-abb7-d1e2a2b43b86":{"description":"Billing refused a step (`credits_exhausted` or\n`billing_required`). That step and the ones after it were not\nsent; steps before it may already have run.\n","content":{"application/json":{"schema":{"type":"object","required":["error","message"],"properties":{"error":{"type":"string","isRequired":true,"uniqueKey":"error","typeLabel":"string"},"message":{"type":"string","isRequired":true,"uniqueKey":"message","typeLabel":"string"}},"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"error":"\u003cstring>","message":"\u003cstring>"}}},"exampleType":"generated"}},"exampleType":"generated"},"8927aeeb-d036-48ab-bc88-1574aad2332e":{"description":"Resource not found.","content":{"application/json":{"schema":{"type":"object","required":["error","message"],"properties":{"error":{"type":"string","isRequired":true,"uniqueKey":"error","typeLabel":"string"},"message":{"type":"string","isRequired":true,"uniqueKey":"message","typeLabel":"string"}},"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"error":"\u003cstring>","message":"\u003cstring>"}}},"exampleType":"generated"}},"exampleType":"generated"},"87e63fe9-cfc3-4217-8ba4-c4ef5d84266e":{"description":"`internet_route_inactive`: this Lusor Phone's Internet connection is\nnot active yet. Retry once it is.\n","content":{"application/json":{"schema":{"type":"object","required":["error","message"],"properties":{"error":{"type":"string","isRequired":true,"uniqueKey":"error","typeLabel":"string"},"message":{"type":"string","isRequired":true,"uniqueKey":"message","typeLabel":"string"}},"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"error":"\u003cstring>","message":"\u003cstring>"}}},"exampleType":"generated"}},"exampleType":"generated"},"594084c1-6a15-4f87-b25b-30638a48c636":{"description":"`meter_unavailable`: metering could not continue, so that step\nand the ones after it were not sent. Steps before it may already\nhave run; read the screen before retrying.\n","content":{"application/json":{"schema":{"type":"object","required":["error","message"],"properties":{"error":{"type":"string","isRequired":true,"uniqueKey":"error","typeLabel":"string"},"message":{"type":"string","isRequired":true,"uniqueKey":"message","typeLabel":"string"}},"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"error":"\u003cstring>","message":"\u003cstring>"}}},"exampleType":"generated"}},"exampleType":"generated"}},"security":{"e990c9c7-7adf-4c43-a478-c17a739371f3":{"ApiKey":{"type":"apiKey","in":"header","name":"X-Api-Key","description":"Workspace API key, created in the dashboard under Settings → API Keys.","scopes":[],"schemeName":"ApiKey"}},"a66fdb89-a491-49fa-b34f-5bf4ba59f929":{"BearerAuth":{"type":"http","scheme":"bearer","description":"The same workspace API key, sent as `Authorization: Bearer \u003cyour API key>`.","scopes":[],"schemeName":"BearerAuth"}}},"servers":{"67414a81-b86b-4d15-b96f-3a390c272e81":{"url":"https://api.lusor.ai","description":"Production"}},"processedSecurityOptions":[{"schemes":[{"scheme":{"type":"apiKey","in":"header","name":"X-Api-Key","description":"Workspace API key, created in the dashboard under Settings → API Keys.","scopes":[],"schemeName":"ApiKey"},"schema":{"title":"X-Api-Key","type":"string","description":"Workspace API key, created in the dashboard under Settings → API Keys.","isRequired":true,"typeLabel":"string","deprecated":false},"schemeName":"ApiKey","name":"X-Api-Key"}],"title":"ApiKey"},{"schemes":[{"scheme":{"type":"http","scheme":"bearer","description":"The same workspace API key, sent as `Authorization: Bearer \u003cyour API key>`.","scopes":[],"schemeName":"BearerAuth"},"schema":{"title":"Bearer Auth","type":"string","isRequired":true,"description":"The same workspace API key, sent as `Authorization: Bearer \u003cyour API key>`.","format":"bearer","typeLabel":"string\u003cbearer>","deprecated":false},"schemeName":"BearerAuth","name":"Authorization"}],"title":"BearerAuth"}]},"originalFileLocation":"api-reference/openapi.yaml"},"subdomain":"lusor-ai","siteName":"Lusor","title":"Run a chain of actions - Lusor","navMaps":{"firstHrefInVersion":{},"firstHrefInLanguage":{}},"lastModified":"2026-11-10T18:45:52.077Z","originalFileLocation":"api-reference/deviceverbs/run-a-chain-of-actions.mdx"},"headHtml":"\u003cscript data-mint-head>(function(){var d=document.documentElement,p=null;if(!p){try{p=localStorage.getItem(\"isDarkMode\")}catch(e){}if(p==='true')p='dark';else if(p==='false')p='light';if(p!=='light'\u0026\u0026p!=='dark'\u0026\u0026p!=='system')p=\"system\"}var r=p==='system'?(matchMedia(\"(prefers-color-scheme: dark)\").matches?'dark':'light'):p;d.classList.remove(r==='dark'?'light':'dark');d.classList.add(r);d.setAttribute(\"data-theme-preference\",p)})();\u003c/script>\u003cmeta data-mint-head name=\"description\" content=\"Execute a typed sequence of up to 20 deterministic actions in order, optionally collecting a UI capture per step. On a Lusor Phone, an API-key chain meters phone minutes before every step; a 402 or 503 stops the chain before that step reaches the phone. ## Capture resolution rules Per-step capture always wins. Top-level capture supplies the default policy: - \u0026#x27;none\u0026#x27; (default) — no capture on any step. - \u0026#x27;each\u0026#x27; — capture on every step. - \u0026#x27;final\u0026#x27; — capture only on the last step. ## Step verbs tap, swipe, type, key, clear, back, home, recent, start_app, stop_app, screenshot, wait. Each step has the same params as the corresponding direct-verb route plus an optional capture override. ## Settling Steps execute back-to-back with no implicit inter-step delay. Insert wait steps ({ verb: \u0026quot;wait\u0026quot;, params: { duration_ms: N } }, 0–60000 ms) where the UI needs time to settle — e.g. after a tap that opens a screen, or before typing into a freshly focused field. Cumulative wait duration per chain is capped at 120s so the worst case stays inside the chain timeout. A step that completes with ok: false does not stop the chain: the next step still runs, the top-level ok is true only when every step succeeded, and each step\u0026#x27;s ok shows which one failed. A step that errors instead aborts the chain. This happens when the phone cannot be reached, when a step\u0026#x27;s capture fails, or when metering refuses a later step (402/503). The response is then that error alone, with no per-step results, and the steps before it have already run on the phone. Read the screen before you retry a chain.\">\u003cmeta data-mint-head name=\"application-name\" content=\"Lusor\">\u003cmeta data-mint-head name=\"generator\" content=\"Mintlify\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/lusor-ai/IpfY-Q6QPFVhWwzn/_generated/favicon/android-chrome-192x192.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"apple-touch-icon\" type=\"image/png\" sizes=\"180x180\" href=\"/mintlify-assets/_mintlify/favicons/lusor-ai/IpfY-Q6QPFVhWwzn/_generated/favicon/apple-touch-icon.png\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/lusor-ai/IpfY-Q6QPFVhWwzn/_generated/favicon/favicon-16x16.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/lusor-ai/IpfY-Q6QPFVhWwzn/_generated/favicon/favicon-32x32.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/lusor-ai/IpfY-Q6QPFVhWwzn/_generated/favicon/favicon.ico\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/lusor-ai/IpfY-Q6QPFVhWwzn/_generated/favicon-dark/android-chrome-192x192.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/lusor-ai/IpfY-Q6QPFVhWwzn/_generated/favicon-dark/favicon-16x16.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/lusor-ai/IpfY-Q6QPFVhWwzn/_generated/favicon-dark/favicon-32x32.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/lusor-ai/IpfY-Q6QPFVhWwzn/_generated/favicon-dark/favicon.ico\" media=\"(prefers-color-scheme: dark)\">\u003cmeta data-mint-head property=\"og:title\" content=\"Run a chain of actions - Lusor\">\u003cmeta data-mint-head property=\"og:description\" content=\"Execute a typed sequence of up to 20 deterministic actions in order, optionally collecting a UI capture per step. On a Lusor Phone, an API-key chain meters phone minutes before every step; a 402 or 503 stops the chain before that step reaches the phone. ## Capture resolution rules Per-step capture always wins. Top-level capture supplies the default policy: - \u0026#x27;none\u0026#x27; (default) — no capture on any step. - \u0026#x27;each\u0026#x27; — capture on every step. - \u0026#x27;final\u0026#x27; — capture only on the last step. ## Step verbs tap, swipe, type, key, clear, back, home, recent, start_app, stop_app, screenshot, wait. Each step has the same params as the corresponding direct-verb route plus an optional capture override. ## Settling Steps execute back-to-back with no implicit inter-step delay. Insert wait steps ({ verb: \u0026quot;wait\u0026quot;, params: { duration_ms: N } }, 0–60000 ms) where the UI needs time to settle — e.g. after a tap that opens a screen, or before typing into a freshly focused field. Cumulative wait duration per chain is capped at 120s so the worst case stays inside the chain timeout. A step that completes with ok: false does not stop the chain: the next step still runs, the top-level ok is true only when every step succeeded, and each step\u0026#x27;s ok shows which one failed. A step that errors instead aborts the chain. This happens when the phone cannot be reached, when a step\u0026#x27;s capture fails, or when metering refuses a later step (402/503). The response is then that error alone, with no per-step results, and the steps before it have already run on the phone. Read the screen before you retry a chain.\">\u003cmeta data-mint-head property=\"og:site_name\" content=\"Lusor\">\u003cmeta data-mint-head property=\"og:url\" content=\"https://docs.lusor.ai/api-reference/deviceverbs/run-a-chain-of-actions\">\u003cmeta data-mint-head property=\"og:type\" content=\"website\">\u003cmeta data-mint-head property=\"og:image\" content=\"https://lusor-ai.mintlify.site/_mintlify/api/og/v2?division=DeviceVerbs\u0026amp;title=Run+a+chain+of+actions\u0026amp;description=Execute+a+typed+sequence+of+up+to+20+deterministic+actions+in%0Aorder%2C+optionally+collecting+a+UI+capture+per+step.+On+a+Lusor%0APhone%2C+an+API-key+chain+meters+phon\u0026amp;theme=11044ab09cca21353c9d0db7\u0026amp;signature=93aa273d67d6ed669f1923a01e9e595dedf98ce27ecc20ec633f53d60a797d8c\">\u003cmeta data-mint-head property=\"og:image:width\" content=\"1200\">\u003cmeta data-mint-head property=\"og:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"twitter:card\" content=\"summary_large_image\">\u003cmeta data-mint-head name=\"twitter:title\" content=\"Run a chain of actions - Lusor\">\u003cmeta data-mint-head name=\"twitter:description\" content=\"Execute a typed sequence of up to 20 deterministic actions in order, optionally collecting a UI capture per step. On a Lusor Phone, an API-key chain meters phone minutes before every step; a 402 or 503 stops the chain before that step reaches the phone. ## Capture resolution rules Per-step capture always wins. Top-level capture supplies the default policy: - \u0026#x27;none\u0026#x27; (default) — no capture on any step. - \u0026#x27;each\u0026#x27; — capture on every step. - \u0026#x27;final\u0026#x27; — capture only on the last step. ## Step verbs tap, swipe, type, key, clear, back, home, recent, start_app, stop_app, screenshot, wait. Each step has the same params as the corresponding direct-verb route plus an optional capture override. ## Settling Steps execute back-to-back with no implicit inter-step delay. Insert wait steps ({ verb: \u0026quot;wait\u0026quot;, params: { duration_ms: N } }, 0–60000 ms) where the UI needs time to settle — e.g. after a tap that opens a screen, or before typing into a freshly focused field. Cumulative wait duration per chain is capped at 120s so the worst case stays inside the chain timeout. A step that completes with ok: false does not stop the chain: the next step still runs, the top-level ok is true only when every step succeeded, and each step\u0026#x27;s ok shows which one failed. A step that errors instead aborts the chain. This happens when the phone cannot be reached, when a step\u0026#x27;s capture fails, or when metering refuses a later step (402/503). The response is then that error alone, with no per-step results, and the steps before it have already run on the phone. Read the screen before you retry a chain.\">\u003cmeta data-mint-head name=\"twitter:image\" content=\"https://lusor-ai.mintlify.site/_mintlify/api/og/v2?division=DeviceVerbs\u0026amp;title=Run+a+chain+of+actions\u0026amp;description=Execute+a+typed+sequence+of+up+to+20+deterministic+actions+in%0Aorder%2C+optionally+collecting+a+UI+capture+per+step.+On+a+Lusor%0APhone%2C+an+API-key+chain+meters+phon\u0026amp;theme=11044ab09cca21353c9d0db7\u0026amp;signature=93aa273d67d6ed669f1923a01e9e595dedf98ce27ecc20ec633f53d60a797d8c\">\u003cmeta data-mint-head name=\"twitter:image:width\" content=\"1200\">\u003cmeta data-mint-head name=\"twitter:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"msapplication-config\" content=\"/mintlify-assets/_mintlify/favicons/lusor-ai/IpfY-Q6QPFVhWwzn/_generated/favicon/browserconfig.xml\">\u003cmeta data-mint-head name=\"apple-mobile-web-app-title\" content=\"Lusor\">\u003cmeta data-mint-head name=\"msapplication-TileColor\" content=\"#111111\">\u003clink data-mint-head rel=\"canonical\" href=\"https://docs.lusor.ai/api-reference/deviceverbs/run-a-chain-of-actions\">\u003clink data-mint-head rel=\"alternate\" type=\"application/xml\" href=\"/sitemap.xml\">\u003clink data-mint-head rel=\"alternate\" type=\"text/markdown\" href=\"/api-reference/deviceverbs/run-a-chain-of-actions.md\">\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https://docs.lusor.ai/#organization\",\"name\":\"Lusor\",\"url\":\"https://docs.lusor.ai\",\"logo\":{\"@type\":\"ImageObject\",\"url\":\"https://mintcdn.com/lusor-ai/Ifu_dlUtLbDafp0r/images/lusor-logo-lightmode@2x.png?fit=max\u0026auto=format\u0026n=Ifu_dlUtLbDafp0r\u0026q=85\u0026s=977cb89acbdf111277711fe79f404fd5\"}},{\"@type\":\"WebSite\",\"@id\":\"https://docs.lusor.ai#website\",\"name\":\"Lusor\",\"url\":\"https://docs.lusor.ai\",\"publisher\":{\"@id\":\"https://docs.lusor.ai/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https://docs.lusor.ai/api-reference/deviceverbs/run-a-chain-of-actions#webpage\",\"url\":\"https://docs.lusor.ai/api-reference/deviceverbs/run-a-chain-of-actions\",\"name\":\"Run a chain of actions\",\"description\":\"Execute a typed sequence of up to 20 deterministic actions in order, optionally collecting a UI capture per step. On a Lusor Phone, an API-key chain meters phone minutes before every step; a 402 or 503 stops the chain before that step reaches the phone. ## Capture resolution rules Per-step capture always wins. Top-level capture supplies the default policy: - 'none' (default) — no capture on any step. - 'each' — capture on every step. - 'final' — capture only on the last step. ## Step verbs tap, swipe, type, key, clear, back, home, recent, start_app, stop_app, screenshot, wait. Each step has the same params as the corresponding direct-verb route plus an optional capture override. ## Settling Steps execute back-to-back with no implicit inter-step delay. Insert wait steps ({ verb: \\\"wait\\\", params: { duration_ms: N } }, 0–60000 ms) where the UI needs time to settle — e.g. after a tap that opens a screen, or before typing into a freshly focused field. Cumulative wait duration per chain is capped at 120s so the worst case stays inside the chain timeout. A step that completes with ok: false does not stop the chain: the next step still runs, the top-level ok is true only when every step succeeded, and each step's ok shows which one failed. A step that errors instead aborts the chain. This happens when the phone cannot be reached, when a step's capture fails, or when metering refuses a later step (402/503). The response is then that error alone, with no per-step results, and the steps before it have already run on the phone. Read the screen before you retry a chain.\",\"dateModified\":\"2026-11-10T18:45:52.077Z\",\"isPartOf\":{\"@id\":\"https://docs.lusor.ai#website\"},\"breadcrumb\":{\"@id\":\"https://docs.lusor.ai/api-reference/deviceverbs/run-a-chain-of-actions#breadcrumb\"}},{\"@type\":\"BreadcrumbList\",\"@id\":\"https://docs.lusor.ai/api-reference/deviceverbs/run-a-chain-of-actions#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Endpoints\",\"item\":\"https://docs.lusor.ai/api-reference/sessions/get-session-detail\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"DeviceVerbs\",\"item\":\"https://docs.lusor.ai/api-reference/deviceverbs/trigger-screenshot-capture-aware-verb\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Run a chain of actions\",\"item\":\"https://docs.lusor.ai/api-reference/deviceverbs/run-a-chain-of-actions\"}]},{\"@type\":[\"TechArticle\",\"APIReference\"],\"@id\":\"https://docs.lusor.ai/api-reference/deviceverbs/run-a-chain-of-actions#apireference\",\"headline\":\"Run a chain of actions\",\"name\":\"Run a chain of actions\",\"description\":\"Execute a typed sequence of up to 20 deterministic actions in order, optionally collecting a UI capture per step. On a Lusor Phone, an API-key chain meters phone minutes before every step; a 402 or 503 stops the chain before that step reaches the phone. ## Capture resolution rules Per-step capture always wins. Top-level capture supplies the default policy: - 'none' (default) — no capture on any step. - 'each' — capture on every step. - 'final' — capture only on the last step. ## Step verbs tap, swipe, type, key, clear, back, home, recent, start_app, stop_app, screenshot, wait. Each step has the same params as the corresponding direct-verb route plus an optional capture override. ## Settling Steps execute back-to-back with no implicit inter-step delay. Insert wait steps ({ verb: \\\"wait\\\", params: { duration_ms: N } }, 0–60000 ms) where the UI needs time to settle — e.g. after a tap that opens a screen, or before typing into a freshly focused field. Cumulative wait duration per chain is capped at 120s so the worst case stays inside the chain timeout. A step that completes with ok: false does not stop the chain: the next step still runs, the top-level ok is true only when every step succeeded, and each step's ok shows which one failed. A step that errors instead aborts the chain. This happens when the phone cannot be reached, when a step's capture fails, or when metering refuses a later step (402/503). The response is then that error alone, with no per-step results, and the steps before it have already run on the phone. Read the screen before you retry a chain.\",\"url\":\"https://docs.lusor.ai/api-reference/deviceverbs/run-a-chain-of-actions\",\"mainEntityOfPage\":{\"@id\":\"https://docs.lusor.ai/api-reference/deviceverbs/run-a-chain-of-actions#webpage\"},\"dateModified\":\"2026-11-10T18:45:52.077Z\",\"publisher\":{\"@id\":\"https://docs.lusor.ai/#organization\"},\"isPartOf\":{\"@id\":\"https://docs.lusor.ai#website\"}}]}\u003c/script>\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@type\":\"WebSite\",\"name\":\"Lusor\",\"publisher\":{\"@type\":\"Organization\",\"name\":\"Lusor\"},\"provider\":{\"@type\":\"Organization\",\"name\":\"Mintlify\",\"url\":\"https://mintlify.com\"}}\u003c/script>","agentPointerHref":"/api-reference/deviceverbs/run-a-chain-of-actions.md","siteName":"Lusor","nav":{"global":null,"tabs":[{"tab":"Developers","pages":[{"title":"Developers","href":""}]},{"tab":"Help Center","pages":[{"title":"Help Center","href":"/help"}]},{"tab":"Build with AI","pages":[{"title":"Build with AI","href":"/connect"}]},{"tab":"API reference","groups":[{"group":"Overview","pages":[{"title":"API reference","href":"/api-reference/introduction"}]},{"group":"Endpoints","pages":[{"group":"Sessions","pages":[{"title":"Get session detail","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /v1/sessions/{id}","href":"/api-reference/sessions/get-session-detail"},{"title":"Rename a session","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml patch /v1/sessions/{id}","href":"/api-reference/sessions/rename-a-session"},{"title":"Get session events","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /v1/sessions/{id}/events","href":"/api-reference/sessions/get-session-events"},{"title":"Get the detailed step breakdown (session JSON)","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /v1/sessions/{id}/breakdown","href":"/api-reference/sessions/get-the-detailed-step-breakdown-session-json"},{"title":"List sessions for device","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /v1/workspaces/{workspaceId}/devices/{deviceId}/sessions","href":"/api-reference/sessions/list-sessions-for-device"},{"title":"Create a new session on this device","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /v1/workspaces/{workspaceId}/devices/{deviceId}/sessions","href":"/api-reference/sessions/create-a-new-session-on-this-device"},{"title":"List sessions","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /v1/sessions","href":"/api-reference/sessions/list-sessions"},{"title":"Get session status (lightweight)","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /v1/sessions/{id}/status","href":"/api-reference/sessions/get-session-status-lightweight"},{"title":"Get session artifacts (screenshots + ui-states + output)","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /v1/sessions/{id}/artifacts","href":"/api-reference/sessions/get-session-artifacts-screenshots-+-ui-states-+-output"},{"title":"Cancel a running session","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /v1/sessions/{id}/stop","href":"/api-reference/sessions/cancel-a-running-session"},{"title":"Get one captured UI state of a session","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /v1/sessions/{id}/ui-states/{file}","href":"/api-reference/sessions/get-one-captured-ui-state-of-a-session"},{"title":"Cancel a queued follow-up or queued agent turn","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml delete /v1/sessions/{id}/queue/{invocationId}","href":"/api-reference/sessions/cancel-a-queued-follow-up-or-queued-agent-turn"},{"title":"Send a follow-up message to a session","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /v1/sessions/{id}/continue","href":"/api-reference/sessions/send-a-follow-up-message-to-a-session"},{"title":"Answer the agent's question (request_human)","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /v1/sessions/{id}/hitl","href":"/api-reference/sessions/answer-the-agents-question-request_human"},{"title":"Get the session's video recording","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /v1/sessions/{id}/recording","href":"/api-reference/sessions/get-the-sessions-video-recording"},{"title":"Get the session's step-by-step replay","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /v1/sessions/{id}/replay","href":"/api-reference/sessions/get-the-sessions-step-by-step-replay"},{"title":"Download one replay frame (PNG)","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /v1/sessions/{id}/replay/frame","href":"/api-reference/sessions/download-one-replay-frame-png"}]},{"group":"Skills","pages":[{"title":"List skills","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /v1/skills","href":"/api-reference/skills/list-skills"},{"title":"Create a skill","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /v1/skills","href":"/api-reference/skills/create-a-skill"},{"title":"Get a skill","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /v1/skills/{id}","href":"/api-reference/skills/get-a-skill"},{"title":"Delete a skill","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml delete /v1/skills/{id}","href":"/api-reference/skills/delete-a-skill"},{"title":"Update a skill","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml patch /v1/skills/{id}","href":"/api-reference/skills/update-a-skill"}]},{"group":"Secrets","pages":[{"title":"List the secrets saved in a workspace","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /v1/workspaces/{workspaceId}/vault","href":"/api-reference/secrets/list-the-secrets-saved-in-a-workspace"}]},{"group":"PhoneNumbers","pages":[{"title":"List workspace phone numbers","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /v1/workspaces/{workspaceId}/numbers","href":"/api-reference/phonenumbers/list-workspace-phone-numbers"},{"title":"Get one workspace phone number","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /v1/workspaces/{workspaceId}/numbers/{phoneNumberId}","href":"/api-reference/phonenumbers/get-one-workspace-phone-number"},{"title":"Page stored SMS messages for a workspace number","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /v1/workspaces/{workspaceId}/numbers/{phoneNumberId}/messages","href":"/api-reference/phonenumbers/page-stored-sms-messages-for-a-workspace-number"}]},{"group":"Emails","pages":[{"title":"List the workspace's Agent Mail addresses","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /v1/emails/addresses","href":"/api-reference/emails/list-the-workspaces-agent-mail-addresses"},{"title":"Page stored inbound mail for a workspace address","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /v1/emails/messages","href":"/api-reference/emails/page-stored-inbound-mail-for-a-workspace-address"}]},{"group":"Devices","pages":[{"title":"List devices in the key's workspace","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /v1/devices","href":"/api-reference/devices/list-devices-in-the-keys-workspace"},{"title":"List devices in a workspace","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /v1/workspaces/{workspaceId}/devices","href":"/api-reference/devices/list-devices-in-a-workspace"},{"title":"Preview deploying Lusor Phones","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /v1/workspaces/{workspaceId}/devices/deploy/preview","href":"/api-reference/devices/preview-deploying-lusor-phones"},{"title":"Deploy the quoted Lusor Phones","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /v1/workspaces/{workspaceId}/devices/deploy","href":"/api-reference/devices/deploy-the-quoted-lusor-phones"},{"title":"Preview removing a Lusor Phone","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /v1/workspaces/{workspaceId}/devices/{deviceId}/remove/preview","href":"/api-reference/devices/preview-removing-a-lusor-phone"},{"title":"Remove a Lusor Phone","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /v1/workspaces/{workspaceId}/devices/{deviceId}/remove","href":"/api-reference/devices/remove-a-lusor-phone"},{"title":"Get a Lusor Phone's location and timezone","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /v1/workspaces/{workspaceId}/devices/{deviceId}/geo","href":"/api-reference/devices/get-a-lusor-phones-location-and-timezone"},{"title":"Set a Lusor Phone's location and timezone","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml put /v1/workspaces/{workspaceId}/devices/{deviceId}/geo","href":"/api-reference/devices/set-a-lusor-phones-location-and-timezone"},{"title":"Restore a Lusor Phone's automatic location","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml delete /v1/workspaces/{workspaceId}/devices/{deviceId}/geo","href":"/api-reference/devices/restore-a-lusor-phones-automatic-location"},{"title":"Get which agents are using, queued for, or attached to a phone","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /v1/workspaces/{workspaceId}/devices/{deviceId}/occupancy","href":"/api-reference/devices/get-which-agents-are-using-queued-for-or-attached-to-a-phone"},{"title":"List the countries a Lusor Phone's Internet can exit from","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /v1/workspaces/{workspaceId}/internet/locations","href":"/api-reference/devices/list-the-countries-a-lusor-phones-internet-can-exit-from"},{"title":"Get a Lusor Phone's Internet exit country and route","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /v1/workspaces/{workspaceId}/devices/{deviceId}/internet-location","href":"/api-reference/devices/get-a-lusor-phones-internet-exit-country-and-route"},{"title":"Get a Lusor Phone's static IP status","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /v1/workspaces/{workspaceId}/devices/{deviceId}/static-ip","href":"/api-reference/devices/get-a-lusor-phones-static-ip-status"},{"title":"Get a Lusor Phone's wipe-and-reset progress","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /v1/workspaces/{workspaceId}/devices/{deviceId}/reset","href":"/api-reference/devices/get-a-lusor-phones-wipe-and-reset-progress"},{"title":"Get device UI state","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /v1/workspaces/{workspaceId}/devices/{deviceId}/state","href":"/api-reference/devices/get-device-ui-state"},{"title":"Get fresh device screenshot (binary PNG)","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /v1/workspaces/{workspaceId}/devices/{deviceId}/screenshot","href":"/api-reference/devices/get-fresh-device-screenshot-binary-png"},{"title":"Get a Lusor Phone's language","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /v1/workspaces/{workspaceId}/devices/{deviceId}/language","href":"/api-reference/devices/get-a-lusor-phones-language"},{"title":"Set a Lusor Phone's language","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml put /v1/workspaces/{workspaceId}/devices/{deviceId}/language","href":"/api-reference/devices/set-a-lusor-phones-language"},{"title":"Get a Lusor Phone's identity","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /v1/workspaces/{workspaceId}/devices/{deviceId}/identity","href":"/api-reference/devices/get-a-lusor-phones-identity"},{"title":"Set a Lusor Phone's identity","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml put /v1/workspaces/{workspaceId}/devices/{deviceId}/identity","href":"/api-reference/devices/set-a-lusor-phones-identity"},{"title":"Get a Lusor Phone's last advertising-ID reset","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /v1/workspaces/{workspaceId}/devices/{deviceId}/advertising-id","href":"/api-reference/devices/get-a-lusor-phones-last-advertising-id-reset"},{"title":"Reset a Lusor Phone's advertising ID","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /v1/workspaces/{workspaceId}/devices/{deviceId}/advertising-id/reset","href":"/api-reference/devices/reset-a-lusor-phones-advertising-id"}]},{"group":"DeviceVerbs","pages":[{"title":"Trigger screenshot (capture-aware verb)","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /v1/workspaces/{workspaceId}/devices/{deviceId}/screenshot","href":"/api-reference/deviceverbs/trigger-screenshot-capture-aware-verb"},{"title":"Tap on device","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /v1/workspaces/{workspaceId}/devices/{deviceId}/tap","href":"/api-reference/deviceverbs/tap-on-device"},{"title":"Swipe gesture on device","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /v1/workspaces/{workspaceId}/devices/{deviceId}/swipe","href":"/api-reference/deviceverbs/swipe-gesture-on-device"},{"title":"Type text into focused field","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /v1/workspaces/{workspaceId}/devices/{deviceId}/type","href":"/api-reference/deviceverbs/type-text-into-focused-field"},{"title":"Press a key on device","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /v1/workspaces/{workspaceId}/devices/{deviceId}/key","href":"/api-reference/deviceverbs/press-a-key-on-device"},{"title":"Clear focused field","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /v1/workspaces/{workspaceId}/devices/{deviceId}/clear","href":"/api-reference/deviceverbs/clear-focused-field"},{"title":"Press Back key","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /v1/workspaces/{workspaceId}/devices/{deviceId}/back","href":"/api-reference/deviceverbs/press-back-key"},{"title":"Press Home key","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /v1/workspaces/{workspaceId}/devices/{deviceId}/home","href":"/api-reference/deviceverbs/press-home-key"},{"title":"Press Recent Apps key","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /v1/workspaces/{workspaceId}/devices/{deviceId}/recent","href":"/api-reference/deviceverbs/press-recent-apps-key"},{"title":"Launch an app","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /v1/workspaces/{workspaceId}/devices/{deviceId}/apps/start","href":"/api-reference/deviceverbs/launch-an-app"},{"title":"Force-stop an app","description":"Force-stop an Android app by package name. The `package` is\nvalidated the same way as `apps/start`.\n\nOptionally include `capture: true | CaptureOptions` to\nreturn a fresh element tree + screen dimensions in the same\nround trip.\n","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /v1/workspaces/{workspaceId}/devices/{deviceId}/apps/stop","href":"/api-reference/deviceverbs/force-stop-an-app"},{"title":"Run a chain of actions","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /v1/workspaces/{workspaceId}/devices/{deviceId}/chain","href":"/api-reference/deviceverbs/run-a-chain-of-actions"}]},{"group":"Shell","pages":[{"title":"Run a restricted shell command","description":"Last-resort shell access. The command is checked against a\nserver-side denylist (shell metacharacters such as `|`, `;`, `\u0026`\nand backticks are refused anywhere in the string) and every\nattempt, allowed or denied, is audit-logged. The response reports\nwhether the command ran; command output is not returned.\n","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /v1/workspaces/{workspaceId}/devices/{deviceId}/shell","href":"/api-reference/shell/run-a-restricted-shell-command"}]},{"group":"LiveView","pages":[{"title":"Start a live view of the session's phone","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /v1/sessions/{id}/stream/start","href":"/api-reference/liveview/start-a-live-view-of-the-sessions-phone"},{"title":"Re-arm a live view","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /v1/sessions/{id}/stream/connect","href":"/api-reference/liveview/re-arm-a-live-view"},{"title":"Extend a live view's liveness","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /v1/sessions/{id}/stream/keepalive","href":"/api-reference/liveview/extend-a-live-views-liveness"},{"title":"Ask the phone for a fresh keyframe","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /v1/sessions/{id}/stream/request_frame","href":"/api-reference/liveview/ask-the-phone-for-a-fresh-keyframe"},{"title":"Send a WebRTC answer or ICE candidate to the phone","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /v1/sessions/{id}/stream/signal","href":"/api-reference/liveview/send-a-webrtc-answer-or-ice-candidate-to-the-phone"},{"title":"Stop a live view","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /v1/sessions/{id}/stream/stop","href":"/api-reference/liveview/stop-a-live-view"},{"title":"Get the ICE servers for a live view","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /v1/sessions/{id}/stream/ice-servers","href":"/api-reference/liveview/get-the-ice-servers-for-a-live-view"},{"title":"Receive the phone's WebRTC signaling (Server-Sent Events)","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /v1/sessions/{id}/stream/events","href":"/api-reference/liveview/receive-the-phones-webrtc-signaling-server-sent-events"}]},{"group":"Datasets","pages":[{"title":"Promote one session run's list to a Dataset","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /v1/sessions/{id}/datasets","href":"/api-reference/datasets/promote-one-session-runs-list-to-a-dataset"},{"title":"List Datasets visible to the caller","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /v1/datasets","href":"/api-reference/datasets/list-datasets-visible-to-the-caller"},{"title":"Get a Dataset","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /v1/datasets/{id}","href":"/api-reference/datasets/get-a-dataset"},{"title":"Delete a Dataset","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml delete /v1/datasets/{id}","href":"/api-reference/datasets/delete-a-dataset"},{"title":"Update a Dataset (rename and/or replace output)","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml patch /v1/datasets/{id}","href":"/api-reference/datasets/update-a-dataset-rename-andor-replace-output"}]},{"group":"Agents","pages":[{"title":"List active agents","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /v1/agents","href":"/api-reference/agents/list-active-agents"},{"title":"Create an agent","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /v1/agents","href":"/api-reference/agents/create-an-agent"},{"title":"Get or create the workspace's primary agent","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /v1/agents/primary","href":"/api-reference/agents/get-or-create-the-workspaces-primary-agent"},{"title":"List agents recoverable within the 30-day restore window","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /v1/agents/trash","href":"/api-reference/agents/list-agents-recoverable-within-the-30-day-restore-window"},{"title":"Get an agent, attachments, and the newest page of turns","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /v1/agents/{id}","href":"/api-reference/agents/get-an-agent-attachments-and-the-newest-page-of-turns"},{"title":"Archive an agent for 30 days","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml delete /v1/agents/{id}","href":"/api-reference/agents/archive-an-agent-for-30-days"},{"title":"Update an agent and atomically replace its attachment set","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml patch /v1/agents/{id}","href":"/api-reference/agents/update-an-agent-and-atomically-replace-its-attachment-set"},{"title":"Restore an archived agent within its 30-day window","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /v1/agents/{id}/restore","href":"/api-reference/agents/restore-an-archived-agent-within-its-30-day-window"},{"title":"Read one older page of an agent's turn history","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /v1/agents/{id}/turns","href":"/api-reference/agents/read-one-older-page-of-an-agents-turn-history"},{"title":"Submit a turn to an agent","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /v1/agents/{id}/turns","href":"/api-reference/agents/submit-a-turn-to-an-agent"},{"title":"Cancel a turn that is still waiting for its device","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /v1/agents/{id}/turns/{sessionId}/cancel","href":"/api-reference/agents/cancel-a-turn-that-is-still-waiting-for-its-device"}]},{"group":"Workspaces","pages":[{"title":"Get a workspace","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /v1/workspaces/{workspaceId}","href":"/api-reference/workspaces/get-a-workspace"}]},{"group":"Catalog","pages":[{"title":"List installable catalog apps","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /v1/catalog/apps","href":"/api-reference/catalog/list-installable-catalog-apps"},{"title":"Get a catalog app's icon (binary image)","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /v1/catalog/apps/{package}/icon","href":"/api-reference/catalog/get-a-catalog-apps-icon-binary-image"}]},{"group":"Health","pages":[{"title":"Health check","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /v1/health","href":"/api-reference/health/health-check"}]}]}]},{"tab":"Changelog","pages":[{"title":"Changelog","href":"/changelog"}]}]},"basePath":"","title":"Run a chain of actions - Lusor","buildId":"dpl_596ePT575z4qnAFksq1biRW97aLY","deploymentId":"dpl_596ePT575z4qnAFksq1biRW97aLY","dynamics":["c2aa737661","b0f84f53ff","a9bb46feb3","2b790eda92"],"chunks":["OpenApiReferenceProvider-C9Wu0MeN.js","utils-jWgu-6Qf.js","cloneDeep-izs3Hzxb.js","_Uint8Array-BVIqJ90l.js","isObjectLike-C8vmzPEN.js","isArray-Dcu1dQ5t.js","utils-DBD8f9qn.js","toString-BX-iyh8G.js","isSymbol-CSH9U2Gm.js","addUniqueKeysToSchema-BGuX1ui5.js","snippetPresets-Evy63nQB.js","style-to-object-BY3JEAdk.js","v4-DIgz8zy6.js","conditional-requirements-CFM0id0Q.js","Page-D6S0Yh6q.js","ApiExamples-BQHO1lnV.js","isEqual-BfaiBbcl.js","usePlaygroundInputsStore-B6C8m-t_.js","shallow-BG4cT0fH.js","getApiPlaygroundDisplay-CgEPrE-D.js","CodeSnippet-CU8JyZ9N.js","CodeSnippets-BnxHU32T.js","getPastedJson-CwiYOonh.js","icon-DYDpWmDf.js","MethodPill-C-J-l7_c.js","DuplicateIcon-B6ARwg9w.js","createIcon-Dsv4MtDq.js","DynamicMarkdown-CtasenyM.js","SectionHeading-YNcgYwjB.js","axios-vUo_bRtp.js","Markdown-CwLx6PAg.js","clsx-C3kuh_dz.js","lib-DuNMoZ05.js","lib-B8HbPgcC.js","html-void-elements-mCSPHezU.js","dist-CmKHfscc.js","katex-YMM-FMeD.js","marked.esm-CZWythHk.js","AssistantPageLink-U3mI6Ljh.js"]}