{"openapi":"3.1.0","info":{"title":"Droidrun Cloud","version":"v1","description":"Droidrun Cloud API","contact":{"name":"Droidrun","email":"support@droidrun.ai"}},"servers":[{"url":"https://api.mobilerun.ai","description":"Droidrun Cloud API"}],"security":[{"bearerAuth":[]}],"tags":[{"name":"Tasks","description":"Tasks API","x-group":"Tasks"},{"name":"Credentials","x-group":"Phones"},{"name":"Proxies","x-group":"BYO Proxy"},{"name":"Apps","x-group":"Phones"},{"name":"Devices"},{"name":"Tools/Apps"},{"name":"Tools/Browser"},{"name":"Tools/Misc"},{"name":"Tools/SIM"},{"name":"Tools/Files"},{"name":"Tools/Navigation"},{"name":"Profiles"},{"name":"Tools/Proxy"},{"name":"Tools/Recordings"},{"name":"Tools/Screenshots"},{"name":"Device Traffic"},{"name":"Triggers","x-group":"Workflows"},{"name":"Action Catalog","x-group":"Workflows"},{"name":"Actions","x-group":"Workflows"},{"name":"Discovery","x-group":"Workflows"},{"name":"Flows","x-group":"Workflows"},{"name":"Agent Workflows"},{"name":"Flow Actions","x-group":"Workflows"},{"name":"Events","x-group":"Workflows"},{"name":"Executions","x-group":"Workflows"},{"name":"Timezones"},{"name":"Chat"},{"name":"Files"},{"description":"Mobilerun Connect country coverage information","name":"Countries","x-group":"Mobilerun Proxy"},{"description":"Manage your Mobilerun Connect Proxies","name":"Connect Proxies","x-group":"Mobilerun Proxy"},{"description":"Retrieve your Mobilerun Connect connection history","name":"Connections","x-group":"Mobilerun Proxy"},{"description":"Manage your Mobilerun Connect Socks Users","name":"Users","x-group":"Mobilerun Proxy"},{"name":"Webhook Deliveries","x-group":"Webhooks"},{"name":"Webhook Integrations","x-group":"Webhooks"},{"name":"Webhooks","x-group":"Webhooks"},{"name":"Messages"},{"name":"Numbers"},{"name":"Mailboxes","x-group":"Connectivity"},{"name":"Mailbox Messages","x-group":"Connectivity"}],"paths":{"/tasks":{"post":{"tags":["Tasks"],"summary":"Run Task","description":"Create and dispatch a new agent task. Returns the task ID and device stream details.","operationId":"run_task_tasks_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskCreatedResponse"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnauthorizedResponse"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Forbidden"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Conflict"},"412":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Precondition Failed"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unprocessable Content"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Service Unavailable"}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string","minLength":1,"maxLength":128},{"type":"null"}],"title":"Idempotency-Key"}}]},"get":{"tags":["Tasks"],"summary":"List Tasks","description":"List tasks with optional filtering, sorting, and pagination.","operationId":"list_tasks_tasks_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResult_TaskListItem_"}}}},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnauthorizedResponse"}}},"description":"Unauthorized"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unprocessable Content"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal Server Error"}},"parameters":[{"name":"mine","in":"query","required":false,"schema":{"type":"boolean","description":"Only tasks created by the calling user.","default":false,"title":"Mine"},"description":"Only tasks created by the calling user."},{"name":"createdBy","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Only tasks created by this user id.","title":"Createdby"},"description":"Only tasks created by this user id."},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/TaskStatus"},{"type":"null"}],"title":"Status"}},{"name":"source","in":"query","required":false,"schema":{"anyOf":[{"enum":["api","agent"],"type":"string"},{"type":"null"}],"description":"Only tasks created via the API ('api') or spawned by an agent step ('agent').","title":"Source"},"description":"Only tasks created via the API ('api') or spawned by an agent step ('agent')."},{"name":"query","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":128},{"type":"null"}],"description":"Search in task description.","title":"Query"},"description":"Search in task description."},{"name":"orderBy","in":"query","required":false,"schema":{"anyOf":[{"enum":["id","createdAt","finishedAt","status"],"type":"string"},{"type":"null"}],"default":"createdAt","title":"Orderby"}},{"name":"orderByDirection","in":"query","required":false,"schema":{"enum":["asc","desc"],"type":"string","default":"desc","title":"Orderbydirection"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"pageSize","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Pagesize"}}]}},"/tasks/stream":{"post":{"tags":["Tasks"],"summary":"Run Streamed Task","description":"Create and dispatch a new agent task, returning an SSE stream of task events. Cancels the task if the client disconnects.","operationId":"run_streamed_task_tasks_stream_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskCreate"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{}},"text/event-stream":{}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnauthorizedResponse"}}}},"402":{"description":"Payment Required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"412":{"description":"Precondition Failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Unprocessable Content","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Service Unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/tasks/{task_id}/cancel":{"post":{"tags":["Tasks"],"summary":"Stop Task","description":"Cancel a running task. Returns an error if the task is already in a terminal state.","operationId":"stop_task_tasks__task_id__cancel_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskCancelResponse"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnauthorizedResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Conflict"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unprocessable Content"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal Server Error"}},"parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Task Id"}}]}},"/tasks/{task_id}/message":{"post":{"tags":["Tasks"],"summary":"Send Message","description":"Send a message to a running agent task. The message ID is delivered via SSE (UserMessageEvent with action=queued).","operationId":"send_message_tasks__task_id__message_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskMessageCreate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskMessageResponse"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnauthorizedResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unprocessable Content"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal Server Error"}},"parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Task Id"}}]}},"/tasks/{task_id}/attach":{"get":{"tags":["Tasks"],"summary":"Attach Task","description":"Attach to a running task and receive its events as an SSE stream.","operationId":"attach_task_tasks__task_id__attach_get","responses":{"200":{"description":"Successful Response","content":{"text/event-stream":{}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnauthorizedResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unprocessable Content"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal Server Error"}},"parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Task Id"}}]}},"/tasks/{task_id}/status":{"get":{"tags":["Tasks"],"summary":"Get Task Status","description":"Get the status of a task.","operationId":"get_task_status_tasks__task_id__status_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskStatusResponse"}}}},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnauthorizedResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unprocessable Content"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal Server Error"}},"parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Task Id"}}]}},"/tasks/{task_id}/trajectory":{"get":{"tags":["Tasks"],"summary":"Get Task Trajectory","description":"Get the trajectory of a task.","operationId":"get_task_trajectory_tasks__task_id__trajectory_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskTrajectoryResponse"}}}},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnauthorizedResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unprocessable Content"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal Server Error"}},"parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Task Id"}}]}},"/tasks/{task_id}/ui_states":{"get":{"tags":["Tasks"],"summary":"Get Task Ui States","description":"List all UI state URLs for a task.","operationId":"get_task_ui_states_tasks__task_id__ui_states_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MediaListResponse"}}}},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnauthorizedResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unprocessable Content"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal Server Error"}},"parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Task Id"}}]}},"/tasks/{task_id}/ui_states/{index}":{"get":{"tags":["Tasks"],"summary":"Get Task Ui State","description":"Get a specific UI state by index.","operationId":"get_task_ui_state_tasks__task_id__ui_states__index__get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MediaResponse"}}}},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnauthorizedResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unprocessable Content"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal Server Error"}},"parameters":[{"name":"index","in":"path","required":true,"schema":{"type":"integer","title":"Index"}},{"name":"task_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Task Id"}}]}},"/tasks/{task_id}/screenshots":{"get":{"tags":["Tasks"],"summary":"Get Task Screenshots","description":"List all screenshot URLs for a task.","operationId":"get_task_screenshots_tasks__task_id__screenshots_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MediaListResponse"}}}},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnauthorizedResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unprocessable Content"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal Server Error"}},"parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Task Id"}}]}},"/tasks/{task_id}/screenshots/{index}":{"get":{"tags":["Tasks"],"summary":"Get Task Screenshot","description":"Get a specific screenshot by index.","operationId":"get_task_screenshot_tasks__task_id__screenshots__index__get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MediaResponse"}}}},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnauthorizedResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unprocessable Content"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal Server Error"}},"parameters":[{"name":"index","in":"path","required":true,"schema":{"type":"integer","title":"Index"}},{"name":"task_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Task Id"}}]}},"/tasks/{task_id}":{"get":{"tags":["Tasks"],"summary":"Get Task","description":"Get full details of a task by ID.","operationId":"get_task_tasks__task_id__get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskResponse"}}}},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnauthorizedResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unprocessable Content"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal Server Error"}},"parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Task Id"}}]}},"/credentials/onepassword":{"get":{"tags":["Credentials"],"operationId":"retrieveOnePasswordConnection","summary":"Get 1Password connection","responses":{"200":{"description":"Connection metadata","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/OnePasswordConnection"}},"required":["data"]}}}},"400":{"description":"Bad Request — invalid_request, package_exists, create_failed, update_failed, protocol_change_not_allowed (legacy body + additive code/message), or a generic request validation failure","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/CredentialErrorResponse"},{"$ref":"#/components/schemas/ApiErrorEnvelope"}]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"409":{"description":"Conflict (legacy body + additive code/message)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CredentialErrorResponse"}}}},"429":{"description":"Credential source rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CredentialErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InternalServerError"}}}},"502":{"description":"Credential source unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CredentialErrorResponse"}}}}}},"put":{"tags":["Credentials"],"operationId":"connectOnePassword","summary":"Connect a 1Password service account","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"serviceAccountToken":{"type":"string","maxLength":4096}},"required":["serviceAccountToken"]}}}},"responses":{"200":{"description":"Connected","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/OnePasswordConnection"}},"required":["data"]}}}},"400":{"description":"Bad Request — invalid_request, package_exists, create_failed, update_failed, protocol_change_not_allowed (legacy body + additive code/message), or a generic request validation failure","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/CredentialErrorResponse"},{"$ref":"#/components/schemas/ApiErrorEnvelope"}]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"409":{"description":"Conflict (legacy body + additive code/message)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CredentialErrorResponse"}}}},"429":{"description":"Credential source rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CredentialErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InternalServerError"}}}},"502":{"description":"Credential source unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CredentialErrorResponse"}}}}}},"delete":{"tags":["Credentials"],"operationId":"disconnectOnePassword","summary":"Disconnect 1Password","responses":{"200":{"description":"Disconnected","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}}}},"400":{"description":"Bad Request — invalid_request, package_exists, create_failed, update_failed, protocol_change_not_allowed (legacy body + additive code/message), or a generic request validation failure","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/CredentialErrorResponse"},{"$ref":"#/components/schemas/ApiErrorEnvelope"}]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"409":{"description":"Conflict (legacy body + additive code/message)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CredentialErrorResponse"}}}},"429":{"description":"Credential source rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CredentialErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InternalServerError"}}}},"502":{"description":"Credential source unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CredentialErrorResponse"}}}}}}},"/credentials/onepassword/vaults/{vaultId}/items":{"get":{"tags":["Credentials"],"operationId":"listOnePasswordItems","summary":"List 1Password item metadata","responses":{"200":{"description":"Item metadata","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/OnePasswordItem"}}},"required":["data"]}}}},"400":{"description":"Bad Request — invalid_request, package_exists, create_failed, update_failed, protocol_change_not_allowed (legacy body + additive code/message), or a generic request validation failure","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/CredentialErrorResponse"},{"$ref":"#/components/schemas/ApiErrorEnvelope"}]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"409":{"description":"Conflict (legacy body + additive code/message)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CredentialErrorResponse"}}}},"429":{"description":"Credential source rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CredentialErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InternalServerError"}}}},"502":{"description":"Credential source unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CredentialErrorResponse"}}}}},"parameters":[{"schema":{"type":"string","minLength":1},"required":true,"name":"vaultId","in":"path"}]}},"/credentials/onepassword/vaults/{vaultId}/items/{itemId}/fields":{"get":{"tags":["Credentials"],"operationId":"listOnePasswordFields","summary":"List 1Password field metadata","responses":{"200":{"description":"Field metadata","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/OnePasswordField"}}},"required":["data"]}}}},"400":{"description":"Bad Request — invalid_request, package_exists, create_failed, update_failed, protocol_change_not_allowed (legacy body + additive code/message), or a generic request validation failure","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/CredentialErrorResponse"},{"$ref":"#/components/schemas/ApiErrorEnvelope"}]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"409":{"description":"Conflict (legacy body + additive code/message)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CredentialErrorResponse"}}}},"429":{"description":"Credential source rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CredentialErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InternalServerError"}}}},"502":{"description":"Credential source unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CredentialErrorResponse"}}}}},"parameters":[{"schema":{"type":"string","minLength":1},"required":true,"name":"vaultId","in":"path"},{"schema":{"type":"string","minLength":1},"required":true,"name":"itemId","in":"path"}]}},"/credentials/packages/{packageName}/links":{"post":{"tags":["Credentials"],"operationId":"linkOnePasswordCredential","summary":"Link a 1Password item to a credential","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"credentialName":{"type":"string","minLength":3,"maxLength":50,"pattern":"^[a-z0-9_-]+$"},"vaultId":{"type":"string","minLength":1},"itemId":{"type":"string","minLength":1},"fieldMap":{"type":"array","items":{"type":"object","properties":{"fieldType":{"type":"string","enum":["email","username","password","api_token","phone_number","two_factor_secret","backup_codes"]},"fieldId":{"type":"string","minLength":1}},"required":["fieldType","fieldId"]},"minItems":1}},"required":["credentialName","vaultId","itemId","fieldMap"]}}}},"responses":{"200":{"description":"Linked credential","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Credential"}},"required":["data"]}}}},"400":{"description":"Bad Request — invalid_request, package_exists, create_failed, update_failed, protocol_change_not_allowed (legacy body + additive code/message), or a generic request validation failure","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/CredentialErrorResponse"},{"$ref":"#/components/schemas/ApiErrorEnvelope"}]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"409":{"description":"Conflict (legacy body + additive code/message)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CredentialErrorResponse"}}}},"429":{"description":"Credential source rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CredentialErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InternalServerError"}}}},"502":{"description":"Credential source unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CredentialErrorResponse"}}}}},"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":200},"required":true,"name":"packageName","in":"path"}]}},"/credentials":{"get":{"summary":"List credentials","description":"Returns a paginated list of all credentials belonging to the authenticated user across every package. Accepts standard pagination query parameters and responds with the credential items plus pagination metadata.","operationId":"listAllUserCredentials","tags":["Credentials"],"responses":{"200":{"description":"Credentials retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CredentialList"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"429":{"description":"Credential source rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CredentialErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InternalServerError"}}}}},"parameters":[{"schema":{"type":"integer","exclusiveMinimum":0,"default":1},"required":false,"name":"page","in":"query"},{"schema":{"type":"integer","exclusiveMinimum":0,"default":10},"required":false,"name":"pageSize","in":"query"}]}},"/credentials/packages":{"get":{"summary":"List packages","description":"Returns the names of all packages (apps) the authenticated owner has credentials grouped under. Use this to discover which `packageName` values are valid for the per-package credential routes.","operationId":"listPackages","tags":["Credentials"],"responses":{"200":{"description":"Packages fetched successfully","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PackageSchema"}}},"required":["data"]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"429":{"description":"Credential source rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CredentialErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InternalServerError"}}}}}},"post":{"summary":"Initialize a new package/app","description":"Creates a new package (identified by `packageName`) under which credentials can be grouped. Returns a conflict if a package with the same name already exists for the user.","operationId":"initializePackage","tags":["Credentials"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PackageSchema"}}}},"responses":{"200":{"description":"Package initialized","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"message":{"type":"string"},"data":{"$ref":"#/components/schemas/PackageSchema"}},"required":["success","message","data"]}}}},"400":{"description":"Bad Request — invalid_request, package_exists, create_failed, update_failed, protocol_change_not_allowed (legacy body + additive code/message), or a generic request validation failure","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/CredentialErrorResponse"},{"$ref":"#/components/schemas/ApiErrorEnvelope"}]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"409":{"description":"Conflict (legacy body + additive code/message)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CredentialErrorResponse"}}}},"429":{"description":"Credential source rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CredentialErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InternalServerError"}}}}}}},"/credentials/packages/{packageName}":{"get":{"summary":"List credentials for a specific package","description":"Returns all credentials stored under the given `packageName`. Each credential includes its name, secret path, and the list of fields it holds.","operationId":"listPackageCredentials","tags":["Credentials"],"responses":{"200":{"description":"Package credentials fetched successfully","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Credential"}}},"required":["data"]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"404":{"description":"Not Found — credential_not_found, proxy_not_found (legacy body + additive code/message)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CredentialErrorResponse"}}}},"429":{"description":"Credential source rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CredentialErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InternalServerError"}}}}},"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":200},"required":true,"name":"packageName","in":"path"}]},"post":{"summary":"Create a credential","description":"Creates a credential under the given package with a `credentialName` and at least one field. Each field has a `fieldType` (email, username, password, api_token, phone_number, two_factor_secret, or backup_codes) and a value.","operationId":"createCredentialWithFields","tags":["Credentials"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"credentialName":{"type":"string","minLength":3,"maxLength":50,"pattern":"^[a-z0-9_-]+$"},"fields":{"type":"array","items":{"type":"object","properties":{"fieldType":{"type":"string","enum":["email","username","password","api_token","phone_number","two_factor_secret","backup_codes"]},"value":{"type":"string","minLength":1}},"required":["fieldType","value"]},"minItems":1}},"required":["credentialName","fields"]}}}},"responses":{"200":{"description":"Credential created","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"message":{"type":"string"},"data":{"$ref":"#/components/schemas/Credential"}},"required":["success","message","data"]}}}},"400":{"description":"Bad Request — invalid_request, package_exists, create_failed, update_failed, protocol_change_not_allowed (legacy body + additive code/message), or a generic request validation failure","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/CredentialErrorResponse"},{"$ref":"#/components/schemas/ApiErrorEnvelope"}]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"409":{"description":"Conflict (legacy body + additive code/message)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CredentialErrorResponse"}}}},"429":{"description":"Credential source rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CredentialErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InternalServerError"}}}}},"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":200},"required":true,"name":"packageName","in":"path"}]}},"/credentials/packages/{packageName}/credentials/{credentialName}":{"delete":{"summary":"Delete a credential and all its fields","description":"Permanently deletes the credential identified by `packageName` and `credentialName`, removing all of its fields. Returns the deleted credential.","operationId":"deleteCredential","tags":["Credentials"],"responses":{"200":{"description":"Credential deleted successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"message":{"type":"string"},"data":{"$ref":"#/components/schemas/Credential"}},"required":["success","message","data"]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"404":{"description":"Not Found — credential_not_found, proxy_not_found (legacy body + additive code/message)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CredentialErrorResponse"}}}},"429":{"description":"Credential source rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CredentialErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InternalServerError"}}}}},"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":200},"required":true,"name":"packageName","in":"path"},{"schema":{"type":"string","minLength":3,"maxLength":50,"pattern":"^[a-z0-9_-]+$"},"required":true,"name":"credentialName","in":"path"}]}},"/credentials/packages/{packageName}/credentials/{credentialName}/fields/{fieldType}":{"delete":{"summary":"Delete a field from a credential","description":"Removes a single field of the given `fieldType` from the specified credential while leaving the credential itself intact. Returns the updated credential.","operationId":"deleteCredentialField","tags":["Credentials"],"responses":{"200":{"description":"Field deleted successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"message":{"type":"string"},"data":{"$ref":"#/components/schemas/Credential"}},"required":["success","message","data"]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"404":{"description":"Not Found — credential_not_found, proxy_not_found (legacy body + additive code/message)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CredentialErrorResponse"}}}},"409":{"description":"Conflict (legacy body + additive code/message)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CredentialErrorResponse"}}}},"429":{"description":"Credential source rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CredentialErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InternalServerError"}}}}},"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":200},"required":true,"name":"packageName","in":"path"},{"schema":{"type":"string","minLength":3,"maxLength":50,"pattern":"^[a-z0-9_-]+$"},"required":true,"name":"credentialName","in":"path"},{"schema":{"type":"string","enum":["email","username","password","api_token","phone_number","two_factor_secret","backup_codes"]},"required":true,"name":"fieldType","in":"path"}]},"patch":{"summary":"Update the value of a credential field","description":"Updates the value of an existing field on a credential, identified by `packageName`, `credentialName`, and `fieldType` in the path. The body carries the new value and returns the updated credential.","operationId":"updateCredentialFieldValue","tags":["Credentials"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCredentialFieldBody"}}}},"responses":{"200":{"description":"Field value updated","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"message":{"type":"string"},"data":{"$ref":"#/components/schemas/Credential"}},"required":["success","message","data"]}}}},"400":{"description":"Bad Request — invalid_request, package_exists, create_failed, update_failed, protocol_change_not_allowed (legacy body + additive code/message), or a generic request validation failure","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/CredentialErrorResponse"},{"$ref":"#/components/schemas/ApiErrorEnvelope"}]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"404":{"description":"Not Found — credential_not_found, proxy_not_found (legacy body + additive code/message)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CredentialErrorResponse"}}}},"409":{"description":"Conflict (legacy body + additive code/message)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CredentialErrorResponse"}}}},"429":{"description":"Credential source rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CredentialErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InternalServerError"}}}}},"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":200},"required":true,"name":"packageName","in":"path"},{"schema":{"type":"string","minLength":3,"maxLength":50,"pattern":"^[a-z0-9_-]+$"},"required":true,"name":"credentialName","in":"path"},{"schema":{"type":"string","enum":["email","username","password","api_token","phone_number","two_factor_secret","backup_codes"]},"required":true,"name":"fieldType","in":"path"}]}},"/credentials/packages/{packageName}/credentials/{credentialName}/fields":{"post":{"summary":"Add a credential field","description":"Adds a single field to an existing credential. The body specifies a `fieldType` (one of the supported field types) and its value. Returns a conflict if a field of that type already exists on the credential.","operationId":"addCredentialField","tags":["Credentials"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCredentialFieldBody"}}}},"responses":{"200":{"description":"Field added","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"message":{"type":"string"},"data":{"$ref":"#/components/schemas/Credential"}},"required":["success","message","data"]}}}},"400":{"description":"Bad Request — invalid_request, package_exists, create_failed, update_failed, protocol_change_not_allowed (legacy body + additive code/message), or a generic request validation failure","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/CredentialErrorResponse"},{"$ref":"#/components/schemas/ApiErrorEnvelope"}]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"404":{"description":"Not Found — credential_not_found, proxy_not_found (legacy body + additive code/message)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CredentialErrorResponse"}}}},"409":{"description":"Conflict (legacy body + additive code/message)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CredentialErrorResponse"}}}},"429":{"description":"Credential source rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CredentialErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InternalServerError"}}}}},"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":200},"required":true,"name":"packageName","in":"path"},{"schema":{"type":"string","minLength":3,"maxLength":50,"pattern":"^[a-z0-9_-]+$"},"required":true,"name":"credentialName","in":"path"}]}},"/proxies":{"get":{"summary":"List proxy configs","description":"Returns all proxy configs for the authenticated user. An optional `protocol` query parameter (`socks5` or `wireguard`) filters the results by proxy type.","operationId":"listProxies","tags":["Proxies"],"responses":{"200":{"description":"Proxies retrieved successfully","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ProxyConfig"}}},"required":["data"]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InternalServerError"}}}}},"parameters":[{"schema":{"type":"string","enum":["socks5","wireguard"]},"required":false,"name":"protocol","in":"query"}]},"post":{"summary":"Create a proxy config","description":"Creates a proxy config. The body is a discriminated union on `protocol`: `socks5` requires name, host, port, user, and password, while `wireguard` requires name and a config string. Returns the created config with its generated `proxyId`.","operationId":"createProxy","tags":["Proxies"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProxyBody"}}}},"responses":{"200":{"description":"Proxy created","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"message":{"type":"string"},"data":{"$ref":"#/components/schemas/ProxyConfig"}},"required":["success","message","data"]}}}},"400":{"description":"Bad Request — invalid_request, package_exists, create_failed, update_failed, protocol_change_not_allowed (legacy body + additive code/message), or a generic request validation failure","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/CredentialErrorResponse"},{"$ref":"#/components/schemas/ApiErrorEnvelope"}]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InternalServerError"}}}}}}},"/proxies/{proxyId}":{"get":{"summary":"Get a proxy config","description":"Fetches a single proxy config by its `proxyId`. The response shape depends on the proxy's `protocol` (socks5 or wireguard). Returns not found if no matching config exists.","operationId":"getProxy","tags":["Proxies"],"responses":{"200":{"description":"Proxy fetched successfully","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ProxyConfig"}},"required":["data"]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"404":{"description":"Not Found — credential_not_found, proxy_not_found (legacy body + additive code/message)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CredentialErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InternalServerError"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"proxyId","in":"path"}]},"put":{"summary":"Update a proxy config","description":"Replaces the proxy config identified by `proxyId` with the provided body. As with creation, the body is a `protocol`-discriminated union of socks5 or wireguard fields. Returns the updated config.","operationId":"updateProxy","tags":["Proxies"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProxyBody"}}}},"responses":{"200":{"description":"Proxy updated","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"message":{"type":"string"},"data":{"$ref":"#/components/schemas/ProxyConfig"}},"required":["success","message","data"]}}}},"400":{"description":"Bad Request — invalid_request, package_exists, create_failed, update_failed, protocol_change_not_allowed (legacy body + additive code/message), or a generic request validation failure","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/CredentialErrorResponse"},{"$ref":"#/components/schemas/ApiErrorEnvelope"}]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"404":{"description":"Not Found — credential_not_found, proxy_not_found (legacy body + additive code/message)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CredentialErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InternalServerError"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"proxyId","in":"path"}]},"delete":{"summary":"Delete a proxy config","description":"Permanently deletes the proxy config identified by `proxyId` and returns the deleted config. Returns not found if no matching config exists.","operationId":"deleteProxy","tags":["Proxies"],"responses":{"200":{"description":"Proxy deleted successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"message":{"type":"string"},"data":{"$ref":"#/components/schemas/ProxyConfig"}},"required":["success","message","data"]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"404":{"description":"Not Found — credential_not_found, proxy_not_found (legacy body + additive code/message)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CredentialErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InternalServerError"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"proxyId","in":"path"}]}},"/apps":{"get":{"tags":["Apps"],"summary":"List apps","operationId":"listApps","description":"Retrieves a paginated list of apps with filtering and search capabilities","responses":{"200":{"description":"Apps retrieved successfully","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/PublicAppWithVersion"}},"pagination":{"$ref":"#/components/schemas/Pagination"},"count":{"type":"object","properties":{"availableCount":{"type":"number"},"queuedCount":{"type":"number"},"failedCount":{"type":"number"},"totalCount":{"type":"number"}},"required":["availableCount","queuedCount","failedCount","totalCount"]}},"required":["items","pagination","count"]}}}},"400":{"description":"Bad Request or request validation failure","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/AppsApiErrorResponse"},{"$ref":"#/components/schemas/ApiErrorEnvelope"}]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/ApiErrorEnvelope"},{"$ref":"#/components/schemas/AppsLegacyUnauthorizedError"}]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppsInternalServerError"}}}}},"parameters":[{"schema":{"type":"integer","minimum":1,"default":1},"required":false,"name":"page","in":"query"},{"schema":{"type":"integer","minimum":1,"default":10},"required":false,"name":"pageSize","in":"query"},{"schema":{"type":"string","enum":["all","queued","available","failed","pruned"],"default":"all"},"required":false,"name":"status","in":"query"},{"schema":{"type":"string","enum":["all","android","ios"],"default":"all"},"required":false,"name":"platform","in":"query"},{"schema":{"type":"string"},"required":false,"name":"query","in":"query"},{"schema":{"type":"string","enum":["createdAt","name"],"default":"createdAt"},"required":false,"name":"sortBy","in":"query"},{"schema":{"type":"string","enum":["asc","desc"],"default":"desc"},"required":false,"name":"order","in":"query"}]}},"/apps/create-signed-upload-url":{"post":{"tags":["Apps"],"summary":"Create a signed upload URL for an app","operationId":"createSignedUploadUrlPublic","description":"Creates or updates an app and returns pre-signed upload URLs for each file. Honours an optional `Idempotency-Key` header: a retry with the same key and body returns the same app and version with freshly signed URLs and `Idempotent-Replayed: true`, and never creates a second version. An Idempotency-Key is honoured for 7 days; after that it behaves like a fresh request. A replay whose version was deleted is a 404; a replay whose version already left the queued state is a 409 `idempotency_key_consumed`; a replay that cannot get the version lock within 5 s is a 409 `idempotency_request_in_progress`. Every response produced by a replay, including those 404/409 errors, carries `Idempotent-Replayed: true`. A same-key request still in flight after a 5 s wait is a 409 `idempotency_request_in_progress` (retry after `Retry-After`). If signing fails, nothing is persisted (with or without a key) and the same request, key included, can be retried.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"bundleId":{"type":"string","minLength":1,"maxLength":255,"pattern":"^[a-zA-Z][a-zA-Z0-9_]*(\\.[a-zA-Z][a-zA-Z0-9_-]*)+$"},"platform":{"type":"string","enum":["android","ios"],"default":"android"},"displayName":{"type":"string","minLength":1},"versionCode":{"type":"number"},"versionName":{"type":"string","minLength":1},"country":{"type":"string","default":"US","description":"Country code for Search Results","example":"US"},"description":{"type":"string"},"iconURL":{"anyOf":[{"type":"string"},{"type":"string","format":"uri"},{"type":"string"}]},"targetSdk":{"type":"number"},"developerName":{"type":"string"},"files":{"type":"array","items":{"type":"object","properties":{"fileName":{"type":"string","minLength":1,"pattern":"^[^/\\\\]+\\.(apk|xapk|apks|ipa)$/i"},"contentType":{"type":"string","enum":["application/vnd.android.package-archive","application/octet-stream","application/zip"]},"sha256":{"type":"string","pattern":"^[a-f0-9]{64}$/i"}},"required":["fileName","contentType"]},"minItems":1}},"required":["bundleId","displayName","versionCode","versionName","files"]}}}},"responses":{"200":{"description":"Signed upload URL created successfully","headers":{"Idempotent-Replayed":{"description":"Present and `true` when this response replays an earlier request with the same Idempotency-Key.","schema":{"type":"string","enum":["true"]}}},"content":{"application/json":{"schema":{"type":"object","properties":{"versionId":{"type":"string","format":"uuid","description":"App version ID"},"appId":{"type":"string","format":"uuid","description":"App ID"},"r2UploadUrls":{"type":"array","items":{"type":"object","properties":{"fileName":{"type":"string"},"r2UploadUrl":{"type":"string","format":"uri"}},"required":["fileName","r2UploadUrl"]},"description":"Pre-signed upload URLs for uploading app files"}},"required":["versionId","appId","r2UploadUrls"]}}}},"400":{"description":"Bad Request: malformed Idempotency-Key (`invalid_idempotency_key`), request validation failure, or generic bad request","content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"code":{"type":"string","enum":["invalid_idempotency_key"]},"message":{"type":"string"},"traceId":{"type":"string"},"retryAfterSeconds":{"type":"number"}},"required":["code","message"]},{"$ref":"#/components/schemas/AppsApiErrorResponse"},{"$ref":"#/components/schemas/ApiErrorEnvelope"}]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/ApiErrorEnvelope"},{"$ref":"#/components/schemas/AppsLegacyUnauthorizedError"}]}}}},"404":{"description":"Not Found","headers":{"Idempotent-Replayed":{"description":"Present and `true` when this 404 replays an Idempotency-Key whose resource has since been deleted.","schema":{"type":"string","enum":["true"]}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppsApiErrorResponse"}}}},"409":{"description":"Conflict: `idempotency_request_in_progress` (retry), `idempotency_key_consumed` (do not retry) or a generic conflict","headers":{"x-should-retry":{"description":"`true` for idempotency_request_in_progress, `false` for idempotency_key_consumed.","schema":{"type":"string","enum":["true","false"]}},"Retry-After":{"description":"Seconds to wait before retrying; set for idempotency_request_in_progress.","schema":{"type":"integer"},"example":1},"Idempotent-Replayed":{"description":"Present and `true` when the 409 comes from a replay (idempotency_key_consumed, or a replay waiting on the version lock).","schema":{"type":"string","enum":["true"]}}},"content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"code":{"type":"string","enum":["idempotency_request_in_progress"]},"message":{"type":"string"},"traceId":{"type":"string"},"retryAfterSeconds":{"type":"number"}},"required":["code","message"]},{"type":"object","properties":{"code":{"type":"string","enum":["idempotency_key_consumed"]},"message":{"type":"string"},"traceId":{"type":"string"},"retryAfterSeconds":{"type":"number"}},"required":["code","message"]},{"$ref":"#/components/schemas/AppsApiErrorResponse"}]}}}},"422":{"description":"Idempotency-Key was reused with a different request body (`idempotency_key_reused`)","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string","enum":["idempotency_key_reused"]},"message":{"type":"string"},"traceId":{"type":"string"},"retryAfterSeconds":{"type":"number"}},"required":["code","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppsInternalServerError"}}}}},"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":255,"pattern":"^[\\x21-\\x7E]{1,255}$","description":"Idempotency-Key: 1-255 printable ASCII characters. Same key with a different request body is a 422 idempotency_key_reused. A retryable in-flight duplicate is a 409 with Retry-After and x-should-retry: true; a terminal duplicate is a 409 with x-should-retry: false. A replay returns the current resource state with Idempotent-Replayed: true.","example":"b3f6a9f0-6f1a-4e9a-9e7a-9c9b6b6a5a3f"},"required":false,"description":"Idempotency-Key: 1-255 printable ASCII characters. Same key with a different request body is a 422 idempotency_key_reused. A retryable in-flight duplicate is a 409 with Retry-After and x-should-retry: true; a terminal duplicate is a 409 with x-should-retry: false. A replay returns the current resource state with Idempotent-Replayed: true.","name":"idempotency-key","in":"header"}]}},"/apps/{id}/confirm-upload":{"post":{"tags":["Apps"],"summary":"Confirm successful app upload","operationId":"confirmUploadPublic","description":"Verifies the uploaded files and sets the app version status to available. Idempotent: replaying confirmation for an already-available version returns the same successful response without re-verifying the files.","responses":{"200":{"description":"Upload confirmed","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"message":{"type":"string"}},"required":["success","message"]}}}},"400":{"description":"Bad request. Request validation returns the shared `{ code: \"validation_error\", message, details, traceId? }` envelope. Other bad requests use the generic `{ code: \"bad_request\", message }` body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfirmUploadBadRequest"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/ApiErrorEnvelope"},{"$ref":"#/components/schemas/AppsLegacyUnauthorizedError"}]}}}},"402":{"description":"Out of storage","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StorageLimitReachedErrorEnvelope"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppsApiErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppsInternalServerError"}}}},"503":{"description":"Storage check temporarily unavailable","headers":{"Retry-After":{"schema":{"type":"integer"},"example":30}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StorageCheckUnavailableErrorEnvelope"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}]}},"/apps/{id}/mark-failed":{"post":{"tags":["Apps"],"summary":"Mark app upload as failed","operationId":"markUploadFailedPublic","description":"Sets the app status to failed.","responses":{"200":{"description":"App marked as failed","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"message":{"type":"string"}},"required":["success","message"]}}}},"400":{"description":"Bad Request or request validation failure","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/AppsApiErrorResponse"},{"$ref":"#/components/schemas/ApiErrorEnvelope"}]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/ApiErrorEnvelope"},{"$ref":"#/components/schemas/AppsLegacyUnauthorizedError"}]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppsInternalServerError"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}]}},"/apps/storage-usage":{"get":{"tags":["Apps"],"summary":"Get the user’s storage usage","operationId":"getStorageUsage","description":"Returns the user’s storage allowance in bytes: bytes used, bytes included in the plan, the hard maximum (included + max purchasable overage; null = unlimited) and whether usage above the included amount is billed as overage. With storage billing off there is no limit: only usedBytes is set.","responses":{"200":{"description":"Storage usage retrieved successfully","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/StorageUsage"}},"required":["data"]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/ApiErrorEnvelope"},{"$ref":"#/components/schemas/AppsLegacyUnauthorizedError"}]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppsInternalServerError"}}}},"503":{"description":"Storage check temporarily unavailable","headers":{"Retry-After":{"schema":{"type":"integer"},"example":30}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StorageCheckUnavailableErrorEnvelope"}}}}}}},"/apps/{id}":{"get":{"tags":["Apps"],"summary":"Get app by ID","operationId":"getAppByIdPublic","description":"Retrieves an app by its ID","responses":{"200":{"description":"App retrieved successfully","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/App"}},"required":["data"]}}}},"400":{"description":"Bad Request or request validation failure","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/AppsApiErrorResponse"},{"$ref":"#/components/schemas/ApiErrorEnvelope"}]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/ApiErrorEnvelope"},{"$ref":"#/components/schemas/AppsLegacyUnauthorizedError"}]}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppsApiErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppsInternalServerError"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}]},"delete":{"tags":["Apps"],"summary":"Delete uploaded app","operationId":"deleteAppPublic","description":"Deletes an uploaded app by ID. Removes its files and metadata.","responses":{"200":{"description":"App deleted","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"message":{"type":"string"}},"required":["success","message"]}}}},"400":{"description":"Bad Request or request validation failure","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/AppsApiErrorResponse"},{"$ref":"#/components/schemas/ApiErrorEnvelope"}]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/ApiErrorEnvelope"},{"$ref":"#/components/schemas/AppsLegacyUnauthorizedError"}]}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppsApiErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppsInternalServerError"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}]}},"/apps/{id}/versions":{"get":{"tags":["Apps"],"summary":"List versions for an app","operationId":"listAppVersions","description":"Retrieves all versions of an app visible to the user (own uploads + system versions)","responses":{"200":{"description":"Versions retrieved successfully","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PublicAppVersion"}}},"required":["data"]}}}},"400":{"description":"Bad Request or request validation failure","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/AppsApiErrorResponse"},{"$ref":"#/components/schemas/ApiErrorEnvelope"}]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/ApiErrorEnvelope"},{"$ref":"#/components/schemas/AppsLegacyUnauthorizedError"}]}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppsApiErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppsInternalServerError"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}]}},"/devices":{"get":{"description":"Returns a paginated list of the user's devices along with pagination metadata. By default every device except terminated and unknown-state ones is listed, including stopped and maintenance devices; narrow with e.g. `state=ready` or `state=stopped,maintenance`, and pass `state=terminated` or `state=unknown` to see those.","operationId":"list-devices","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResponseDeviceInfo"}}},"description":"OK"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"List devices","tags":["Devices"],"x-mint":{"content":"Returns a paginated list of your devices with pagination metadata.\n\n## Default state filter\n\nWithout a `state` parameter the list contains devices in these states:\n`creating`, `assigned`, `ready`, `rebooting`, `migrating`, `resetting`,\n`maintenance` and `stopped`. A stopped device or a device in maintenance\nstill exists and is listed.\n\n```http\nGET /v1/devices\n```\n\nDevices in the `terminated` or `unknown` state are hidden unless you request\nthem:\n\n```http\nGET /v1/devices?state=terminated\n```\n\n## Filter by state\n\nPass one or more states to narrow the list. Separate states with commas:\n\n```http\nGET /v1/devices?state=stopped,maintenance\n```\n\nRepeating the parameter (`?state=stopped&state=maintenance`) returns the same\nresult. To list only devices that can run a task right now, request\n`state=ready`.\n\nA stopped device keeps its data and is not billed. Start it again with\n`POST /v1/devices/{deviceId}/resume`.\n\n## Filter by creation start\n\n`createdAfter` includes devices created at or after the RFC3339 timestamp.\n\n```http\nGET /v1/devices?createdAfter=2026-10-01T00:00:00Z\n```\n\n## Filter by creation end\n\n`createdBefore` includes devices created before the RFC3339 timestamp. The\nend is exclusive. When both bounds are set, `createdAfter` must be earlier\nthan `createdBefore`; an equal or inverted range returns 400.\n\n```http\nGET /v1/devices?createdAfter=2026-10-01T00:00:00Z&createdBefore=2026-10-02T00:00:00Z\n```\n\nBoth date filters combine with state, type, name, createdBy and other existing\nfilters in the same paginated query. Pagination totals reflect every filter.\n"},"parameters":[{"description":"Filter by current device state. Comma-separated (state=ready,stopped). Defaults to every state except terminated and unknown, so stopped and maintenance devices are listed; pass state=terminated or state=unknown to see those.","explode":false,"in":"query","name":"state","schema":{"default":["creating","assigned","ready","rebooting","migrating","resetting","maintenance","stopped"],"description":"Filter by current device state. Comma-separated (state=ready,stopped). Defaults to every state except terminated and unknown, so stopped and maintenance devices are listed; pass state=terminated or state=unknown to see those.","items":{"enum":["creating","assigned","ready","rebooting","migrating","resetting","terminated","maintenance","stopped","unknown"],"type":"string"},"type":["array","null"]}},{"description":"Canonical device type. Retired dedicated_* aliases are no longer accepted. Availability depends on the deployment.","explode":false,"in":"query","name":"type","schema":{"description":"Canonical device type. Retired dedicated_* aliases are no longer accepted. Availability depends on the deployment.","enum":["android_cloud_phone","android_physical_phone","ios_stealth_phone","ios_phone","android_emulator","ios_simulator","device_slot"],"type":"string"}},{"description":"Filter by the device's platform as served in the platform field (runtime, announced, else type-derived).","explode":false,"in":"query","name":"platform","schema":{"description":"Filter by the device's platform as served in the platform field (runtime, announced, else type-derived).","enum":["android","ios"],"type":"string"}},{"explode":false,"in":"query","name":"country","schema":{"type":"string"}},{"explode":false,"in":"query","name":"name","schema":{"type":"string"}},{"description":"Case-insensitive search: matches devices whose name contains the term or whose ID starts with it. Combined with all other filters.","explode":false,"in":"query","name":"search","schema":{"description":"Case-insensitive search: matches devices whose name contains the term or whose ID starts with it. Combined with all other filters.","maxLength":200,"type":"string"}},{"explode":false,"in":"query","name":"providerId","schema":{"type":"string"}},{"description":"When true, only return devices created by the authenticated caller.","explode":false,"in":"query","name":"mine","schema":{"default":false,"description":"When true, only return devices created by the authenticated caller.","type":"boolean"}},{"description":"Filter to devices created by this user id. Mutually exclusive with mine.","explode":false,"in":"query","name":"createdBy","schema":{"description":"Filter to devices created by this user id. Mutually exclusive with mine.","type":"string"}},{"description":"Include devices created at or after this RFC3339 timestamp.","explode":false,"in":"query","name":"createdAfter","schema":{"description":"Include devices created at or after this RFC3339 timestamp.","format":"date-time","type":"string"}},{"description":"Include devices created before this RFC3339 timestamp (exclusive). Must be later than createdAfter when both are set.","explode":false,"in":"query","name":"createdBefore","schema":{"description":"Include devices created before this RFC3339 timestamp (exclusive). Must be later than createdAfter when both are set.","format":"date-time","type":"string"}},{"explode":false,"in":"query","name":"page","schema":{"default":1,"format":"int64","type":"integer"}},{"explode":false,"in":"query","name":"pageSize","schema":{"default":20,"format":"int64","type":"integer"}},{"explode":false,"in":"query","name":"orderBy","schema":{"default":"createdAt","enum":["id","createdAt","updatedAt","assignedAt","gridPosition"],"type":"string"}},{"explode":false,"in":"query","name":"orderByDirection","schema":{"default":"desc","enum":["asc","desc"],"type":"string"}}]},"post":{"description":"Requests a new device from the specification in the request body. Optional query parameters select the canonical device type, country, billing mode, and base profile. Returns the device, its resolved billing strategy, and its stream token.","operationId":"create-device","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeviceSpec"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeviceInfo"}}},"description":"OK","headers":{"Idempotent-Replayed":{"schema":{"description":"\"true\" when the response was answered from an earlier request with the same Idempotency-Key; no new device was created.","type":"string"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainError"}}},"description":"Bad Request. Code `invalid_idempotency_key`: the Idempotency-Key header is not 1-255 printable ASCII characters without spaces."},"402":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Payment Required"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainError"}}},"description":"Not Found. Only for a replayed Idempotency-Key whose device has since been terminated, deleted or transferred to another owner.","headers":{"Idempotent-Replayed":{"description":"Always `true` on this response.","schema":{"type":"string"}}}},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainError"}}},"description":"Conflict. Code `idempotency_request_in_progress`: the first request with this Idempotency-Key is still running. Retryable.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"string"}},"x-should-retry":{"description":"`true`: retry the same request.","schema":{"type":"string"}}}},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainError"}},"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity. Request validation failures, and domain errors such as `idempotency_key_reused` (the Idempotency-Key was already used with a different request) or `DEVICE_TYPE_UNAVAILABLE`."},"429":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Too Many Requests"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"summary":"Provision a new device","tags":["Devices"],"x-mint":{"content":"Requests a new device from the specification in the request body. The response\nincludes the device, its resolved `billingStrategy`, and its stream token.\n\n## Choose a device type\n\nUse **`android_cloud_phone`** for the cloud Android phone offering. For example:\n\n```http\nPOST /v1/devices?deviceType=android_cloud_phone&billing=minute\nContent-Type: application/json\n\n{}\n```\n\nSend your normal API authentication with this request. Explicit minute billing\nstill requires sufficient minute balance and an available concurrency allowance.\n\nThe separate **`android_emulator`** type uses the Limrun emulator backend; it is\nnot another name for the cloud Android phone. It is deployment-gated and is not\npart of the standard provisionable offering. Likewise, `ios_simulator` and other\nspecialized backends are available only when enabled in the deployment. A known\ntype that is not available for creation returns **`DEVICE_TYPE_UNAVAILABLE`\n(HTTP 422)**. This is different from temporary fleet exhaustion.\n\nUse canonical identifiers only. The old `dedicated_*` aliases have been retired\nand are rejected with HTTP 422 and guidance naming the canonical replacement.\nChanging to that replacement does not enable an unavailable backend.\n\n## Choose a billing mode\n\n| Mode | Admission behavior |\n| --- | --- |\n| `auto` (default) | Tries subscription billing first. If the customer has **no subscription entitlement**, or **all subscription slots are in use**, tries minute billing when enabled for this type. If subscription billing is disabled, uses minute billing directly when enabled. |\n| `subscription` | Requires subscription billing to be enabled, an active entitlement, and a free subscription slot. Never falls back to minutes. |\n| `minute` | Uses minute billing only. Requires that mode to be enabled, sufficient minute balance, and an available minute concurrency allowance where configured. |\n\nA missing subscription and exhausted subscription slots are distinct denials,\nbut both allow `auto` to try minutes. **Billing-service failures and\nindeterminate responses never trigger fallback.** When neither mode is enabled,\ncreation is denied. Fallback is another admission attempt, not a guarantee that\ncreation will succeed.\n\nAn explicit subscription request without entitlement returns\n`SUBSCRIPTION_REQUIRED` (HTTP 402). When minute billing is enabled, the message\nsuggests explicitly selecting `billing=minute`, subject to its own checks.\n\nA minute-billed request whose cloud-phone minute balance is exhausted (the\nplan's minute feature is spent, not a generic credits shortfall) returns\n`MINUTE_BALANCE_EXHAUSTED` (HTTP 402). The remedy is a plan upgrade, a one-off\nminute top-up, or the next billing period, not a credits top-up. Minute-billed concurrency limits keep the\ngeneric `PAYMENT_REQUIRED` (HTTP 402) shape.\n\n## Idempotency\n\nSend an optional `Idempotency-Key` header (1-255 printable ASCII characters, no\nspaces) to make a retry safe. Retrying with the same key and the same request\nreturns the same device, with the original status, its current state and\n`Idempotent-Replayed: true`; no second device is created or billed.\n\n- The same key with a different request (device type, country, billing, profile\n  or spec) returns `422 idempotency_key_reused`.\n- While the first request is still running, a retry returns\n  `409 idempotency_request_in_progress` with `Retry-After: 1`; retry shortly.\n- If the device has since been terminated, deleted or transferred to another\n  owner, the retry returns `404` (still marked `Idempotent-Replayed: true`) and\n  never a stream token.\n- A create that is **denied before any device exists** (for example a billing or\n  capacity denial) frees the key, so a retry re-evaluates the request. This\n  matches the fleet engine, where a failed create leaves the key free.\n- A create that fails **after the device was announced** (for example a provider\n  error) binds the key to that device instead, so a retry can never create a\n  second one: the retry is a replay (`404` if that device is already terminated).\n  This is a deliberate deviation from \"a failed create always frees the key\";\n  use a new key to start over.\n- A create that is cancelled because it ran too long follows the same rule: the\n  key stays bound only if a device was created, and is otherwise freed.\n- A malformed key returns `400 invalid_idempotency_key`. Without the header the\n  endpoint behaves exactly as before.\n\nKeys are scoped to your account and kept for at least 24 hours.\n"},"parameters":[{"description":"Use android_cloud_phone for a cloud Android phone. Only canonical identifiers are accepted. Other backends are deployment-specific; recognized but unavailable types return DEVICE_TYPE_UNAVAILABLE (422). Retired dedicated_* aliases are rejected with a canonical replacement.","example":"android_cloud_phone","explode":false,"in":"query","name":"deviceType","schema":{"description":"Use android_cloud_phone for a cloud Android phone. Only canonical identifiers are accepted. Other backends are deployment-specific; recognized but unavailable types return DEVICE_TYPE_UNAVAILABLE (422). Retired dedicated_* aliases are rejected with a canonical replacement.","examples":["android_cloud_phone"],"type":"string"}},{"description":"ISO 3166-1 alpha-2 country code. If omitted the system picks the country with the most availability.","explode":false,"in":"query","name":"country","schema":{"description":"ISO 3166-1 alpha-2 country code. If omitted the system picks the country with the most availability.","type":"string"}},{"description":"Profile ID to use as device spec","explode":false,"in":"query","name":"profileId","schema":{"description":"Profile ID to use as device spec","type":"string"}},{"description":"Optional device template, e.g. onboarding. The device gets the template's Android version and preinstalled apps and is ready in seconds when a prepared phone is available; otherwise it boots with the same setup. Country, name and proxy still come from this request. Cannot be combined with profileId, apps or androidVersion. Omit it to create from the request alone.","example":"onboarding","explode":false,"in":"query","name":"template","schema":{"description":"Optional device template, e.g. onboarding. The device gets the template's Android version and preinstalled apps and is ready in seconds when a prepared phone is available; otherwise it boots with the same setup. Country, name and proxy still come from this request. Cannot be combined with profileId, apps or androidVersion. Omit it to create from the request alone.","examples":["onboarding"],"maxLength":80,"type":"string"}},{"description":"Optional. 1-255 printable ASCII characters without spaces. Retrying with the same key and request returns the same device instead of creating another one; see the Idempotency section of the create-device guide.","in":"header","name":"Idempotency-Key","schema":{"description":"Optional. 1-255 printable ASCII characters without spaces. Retrying with the same key and request returns the same device instead of creating another one; see the Idempotency section of the create-device guide.","maxLength":255,"minLength":1,"pattern":"^[!-~]{1,255}$","type":"string"}},{"description":"Billing mode. 'auto' tries subscription first, then minute billing if no subscription entitlement exists or all subscription slots are in use, provided minute billing is enabled. When subscription billing is disabled, auto uses minutes directly. Billing-service failures never trigger fallback. 'subscription' requires an available subscription slot and never falls back. 'minute' uses minute billing only, subject to balance and concurrency checks. Modes depend on the device type's billing configuration.","explode":false,"in":"query","name":"billing","schema":{"default":"auto","description":"Billing mode. 'auto' tries subscription first, then minute billing if no subscription entitlement exists or all subscription slots are in use, provided minute billing is enabled. When subscription billing is disabled, auto uses minutes directly. Billing-service failures never trigger fallback. 'subscription' requires an available subscription slot and never falls back. 'minute' uses minute billing only, subject to balance and concurrency checks. Modes depend on the device type's billing configuration.","enum":["auto","subscription","minute"],"type":"string"}}]}},"/devices/count":{"get":{"deprecated":true,"description":"Deprecated: use GET /devices/summary instead. Returns the number of active claimed devices for the user, broken down by device type, in the legacy response shape.","operationId":"count-devices","responses":{"200":{"content":{"application/json":{"schema":{"additionalProperties":{"format":"int64","type":"integer"},"type":"object"}}},"description":"OK"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"Count claimed devices","tags":["Devices"]}},"/devices/summary":{"get":{"description":"Returns the total number of the user's devices and counts grouped by current state and device type.","operationId":"summary-devices","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SummaryOutputBody"}}},"description":"OK"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"Summarize claimed devices","tags":["Devices"],"parameters":[{"explode":false,"in":"query","name":"state","schema":{"items":{"enum":["creating","assigned","ready","rebooting","migrating","resetting","terminated","maintenance","stopped","unknown"],"type":"string"},"type":["array","null"]}}]}},"/devices/{deviceId}":{"delete":{"description":"Terminates the device and releases its resources. For a personal (BYOD) device the owner (API key or user) can instead remove the phone from the account so anyone can pair it again; the phone must be disconnected first, otherwise the request is rejected with 409 BYOD_DEVICE_CONNECTED. Other subscription-billed devices are service-managed and require a service key. The optional `terminateAt` and `previousDeviceId` body fields also require a service key; requests that set them without one are rejected with 401.","operationId":"terminate-device","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TerminateInputBody"}}}},"responses":{"204":{"description":"No Content"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Conflict"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"summary":"Terminate a device","tags":["Devices"],"x-mint":{"content":"Terminates the device and releases its resources.\n\n## Personal (BYOD) devices\n\nA personal device is your own phone, connected through the Mobilerun app. It\ncannot be terminated: it reconnects on its own. Instead, `DELETE` removes the\nphone from your account. Afterwards anyone can pair it again, including you.\n\nThe phone must be disconnected first. If it is still connected, the request\nfails with `409 BYOD_DEVICE_CONNECTED`:\n\n```json\n{\n  \"code\": \"BYOD_DEVICE_CONNECTED\",\n  \"message\": \"BYOD device is connected; disconnect the phone before removing it\"\n}\n```\n\nClose the app or log out on the phone, wait until the device shows as\noffline, then send the request again.\n"},"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}}]},"get":{"description":"Returns the current state and metadata for a single device, including its lifecycle state, type, stream URL, billing strategy, and timestamps. A stream token is included while the device is active.","operationId":"get-device","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeviceInfo"}}},"description":"OK"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"Get device info","tags":["Devices"],"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}}]}},"/devices/{deviceId}/apps":{"get":{"description":"Returns detailed information about apps installed on the device, including package name and label. System and protected apps are excluded unless the corresponding query parameters are set.","operationId":"list-apps","responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/AppInfo"},"type":["array","null"]}}},"description":"OK"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"List apps","tags":["Tools/Apps"],"x-mint":{"content":"The detailed counterpart to `list-packages`: each entry carries the package name plus a label, version info, and an `isSystemApp` flag.\n\n<Note>\nOnly `packageName` is guaranteed — depending on the device type, label and version fields can be empty.\n</Note>\n\nOn iOS devices, entries are keyed by bundle identifier, Apple's built-in apps never appear, and `versionCode` is always `0`.\n\nOnly when `includeUpdates=true`: `availableUpdate` is present when a newer version exists for an Android non-system app in the device owner's library. It is returned as `{versionCode, versionName, country}` using the same resolution as `install-app` with only `packageName`. This lookup is best effort with a shared 1.5-second budget; Absent means up to date or unknown (including lookup failures, system apps, protected apps, and iOS). By default, no app library lookups are made and `availableUpdate` is omitted.\n"},"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"header","name":"X-Device-Display-ID","schema":{"default":0,"format":"int64","minimum":0,"type":"integer"}},{"explode":false,"in":"query","name":"includeSystemApps","schema":{"default":false,"type":"boolean"}},{"explode":false,"in":"query","name":"includeProtectedApps","schema":{"default":false,"type":"boolean"}},{"description":"Resolve availableUpdate for Android user apps (one library lookup per app). Off by default.","explode":false,"in":"query","name":"includeUpdates","schema":{"default":false,"description":"Resolve availableUpdate for Android user apps (one library lookup per app). Off by default.","type":"boolean"}}]},"post":{"description":"Requests an app install on the device. The request body must supply exactly one of an Android packageName, an iOS bundleId, or an https apkUrl: the device downloads and installs the APK itself; supported on Android cloud phones with the on-device installer, otherwise 409 APP_URL_INSTALL_UNSUPPORTED. URL installs are not stored in your app library, protected-package checks do not apply, and devices-api never logs the URL — your own tooling may. For packageName installs, optional country and versionCode select an exact regional uploaded Android version, and protected packages are rejected. background (default false) selects the response contract: false installs inline and returns the outcome directly (200 on success, an error status on failure); true accepts the request and runs the download + install in the background, returning 202 immediately — poll list-app-installs for the backend's view of that attempt's status. Refuses with 409 once 2 other installs are already running on the device, in either mode; a repeat request for an app that already has an install running is also refused with 409 rather than superseding it — retry once that attempt reaches a terminal state. Synchronous failures report APP_DOWNLOAD_FAILED (502) when the app file cannot be downloaded or APP_INSTALL_TIMEOUT (504) when the install times out.","operationId":"install-app","requestBody":{"content":{"application/json":{"schema":{"oneOf":[{"additionalProperties":false,"properties":{"background":{"default":false,"description":"true: return 202 immediately and install in the background (poll list-app-installs). false/omitted: install inline and return the outcome directly (200 on success, an error status on failure).","type":"boolean"},"bundleId":{"description":"iOS bundle identifier (e.g. com.example.app)","minLength":1,"type":"string"},"country":{"description":"Optional ISO 3166-1 alpha-2 country of the uploaded app version (e.g. MY or SG).","pattern":"^[A-Za-z]{2}$","type":"string"},"versionCode":{"description":"Optional exact app-library version code. Use with country when multiple regional versions share an identifier.","minimum":1,"type":"integer"}},"required":["bundleId"],"type":"object"},{"additionalProperties":false,"properties":{"background":{"default":false,"description":"true: return 202 immediately and install in the background (poll list-app-installs). false/omitted: install inline and return the outcome directly (200 on success, an error status on failure).","type":"boolean"},"country":{"description":"Optional ISO 3166-1 alpha-2 country of the uploaded app version (e.g. MY or SG).","pattern":"^[A-Za-z]{2}$","type":"string"},"packageName":{"description":"Android package name (e.g. com.example.app)","minLength":1,"type":"string"},"versionCode":{"description":"Optional exact app-library version code. Use with country when multiple regional versions share an identifier.","minimum":1,"type":"integer"}},"required":["packageName"],"type":"object"},{"additionalProperties":false,"properties":{"apkUrl":{"description":"HTTPS APK URL downloaded and installed by the device; not stored in your app library.","type":"string"},"background":{"default":false,"description":"true: return 202 immediately and install in the background (poll list-app-installs). false/omitted: install inline and return the outcome directly (200 on success, an error status on failure).","type":"boolean"}},"required":["apkUrl"],"type":"object"}],"properties":{"apkUrl":{"description":"HTTPS APK URL downloaded and installed by the device; not stored in your app library.","type":"string"},"background":{"default":false,"description":"true: return 202 immediately and install in the background (poll list-app-installs). false/omitted: install inline and return the outcome directly (200 on success, an error status on failure).","type":"boolean"},"bundleId":{"description":"iOS bundle identifier (e.g. com.example.app)","minLength":1,"type":"string"},"country":{"description":"Optional ISO 3166-1 alpha-2 country of the uploaded app version (e.g. MY or SG).","pattern":"^[A-Za-z]{2}$","type":"string"},"packageName":{"description":"Android package name (e.g. com.example.app)","minLength":1,"type":"string"},"versionCode":{"description":"Optional exact app-library version code. Use with country when multiple regional versions share an identifier.","minimum":1,"type":"integer"}},"type":"object"}}},"required":true},"responses":{"200":{"description":"Install finished synchronously (background omitted or false)."},"202":{"description":"Accepted"},"409":{"description":"On-device URL installer unavailable (APP_URL_INSTALL_UNSUPPORTED), an install for this app is already running, or the device install concurrency limit was reached."},"502":{"description":"APP_DOWNLOAD_FAILED: the device could not download the app file."},"504":{"description":"APP_INSTALL_TIMEOUT: the app install did not finish in time."}},"summary":"Install app","tags":["Tools/Apps"],"x-mint":{"content":"Requests an app install on the device. `background` (default `false`) selects the response contract:\n\n- `background: false` (default) — installs inline; the response is the actual outcome: `200` on success, an error status on failure.\n- `background: true` — accepts the request and runs the download + install in the background; a `202` response means the request was accepted, not that the app is installed yet — poll `list-apps` until the app appears, or poll `list-app-installs` for the backend's view of the install attempt itself (useful while the device is offline or crashed, when `list-apps` can't be called at all).\n\nBoth modes are subject to the same concurrency cap: a request is refused with `409 Conflict` once 2 other installs are already running on the device. A repeat request for an app that already has an install running is also refused with `409 Conflict` rather than superseding it — retry once that attempt reaches a terminal state.\n\nProvide **exactly one** of:\n\n- `packageName` — Android package name. Resolved against the device owner's app library, so upload the APK first.\n- `bundleId` — iOS bundle identifier (e.g. `com.example.app`) or a numeric App Store ID. The app is installed from the App Store.\n\nUploaded Android app versions may additionally be selected with:\n\n- `country` — ISO 3166-1 alpha-2 country stored on the uploaded version (for example, `MY` or `SG`).\n- `versionCode` — exact uploaded app version code.\n\nPass both fields when the app library contains multiple regional versions for the same package name. Omitting them preserves the legacy lookup behavior, including Apps API's default `US` country.\n\n### Updating an installed app\n\nCall `install-app` again with `packageName` to update an installed Android app; for regional versions, also pass `country` and `versionCode` from `availableUpdate`, read via `list-apps?includeUpdates=true`. Installation uses `-r`, keeping app data. Android rejects downgrades, and an update with a different signing key fails with `adb_install_failed`.\n\n<Warning>\nProtected system packages cannot be installed over. Requests targeting a protected package fail with `403 Forbidden`.\n</Warning>\n"},"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"header","name":"X-Device-Display-ID","schema":{"default":0,"format":"int64","minimum":0,"type":"integer"}}]}},"/devices/{deviceId}/apps/installs":{"get":{"description":"Reports the backend's durable view of background app-install attempts on this device — status reflects the install ATTEMPT, not device ground truth; list-apps remains authoritative for what is actually installed. Terminal and projected timeout records are kept ~15 minutes. Not gated on device readiness, so it also answers while the device is offline or crashed.","operationId":"list-app-installs","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListAppInstallsOutputBody"}}},"description":"OK"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"List app installs","tags":["Tools/Apps"],"x-mint":{"content":"Reports the backend's view of background app-install attempts on this device — one entry per `(platform, appId)` pair that has an `install-app` attempt in progress or recently finished.\n\n<Warning>\n`status` reflects the install **attempt**, not device ground truth. It is `running` from the moment `install-app` returns `202`, then flips to `succeeded` or `failed` once the background download + install finishes. If a `running` attempt passes its background deadline without a terminal update, this endpoint reports it as `failed` with `errorClass: \"timeout\"`. `list-apps` remains authoritative for what is actually installed — a `succeeded` entry here is a strong signal, not a guarantee. On iOS MDM devices specifically, `succeeded` only means the MDM `InstallApplication` command was accepted by the device's MDM channel — the device may still be downloading or installing, or may yet fail on-device — so `list-apps` remains the authoritative check there too.\n</Warning>\n\nUnlike most `Tools/Apps` endpoints, this one is **not gated on device readiness** — it answers from durable install records, not from the device, so it also works while the device is offline, crashed, or otherwise unreachable. That's the situation this endpoint exists to surface: an install that fails because the device dropped mid-download has no other way to be observed by a caller.\n\nOn failure, `errorClass` narrows down what went wrong from a small closed set:\n\n- `download_failed` — fetching the app asset failed\n- `adb_install_failed` — the download succeeded but `adb install-multiple` failed\n- `timeout` — the attempt exceeded its background time budget\n- `panic` — the install goroutine panicked\n- `failed` — anything else\n\n<Note>\nTerminal (`succeeded`/`failed`) records are returned for roughly 15 minutes after their last update. A `running` record that passes its background deadline is projected as `failed` with `errorClass: \"timeout\"` and remains visible for roughly 15 minutes after that deadline. Older records are omitted from this endpoint's response.\n</Note>\n\nRecords are scoped to the tenant that owned the device when the install attempt started: after an ownership transfer (e.g. reassignment or a BYOD re-pair), the new owner cannot see the previous tenant's install attempts, even while those records are still within their retention window above.\n"},"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"header","name":"X-Device-Display-ID","schema":{"default":0,"format":"int64","minimum":0,"type":"integer"}}]}},"/devices/{deviceId}/apps/open-deep-link":{"post":{"description":"Opens a deep link on the device. On Android the link is dispatched as an intent — packageName optionally pins it to a specific app and action overrides the default android.intent.action.VIEW. On iOS the URL is opened directly and the optional fields must be omitted. Protected packages are rejected.","operationId":"open-deep-link","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenDeepLinkArgs"}}},"required":true},"responses":{"204":{"description":"No Content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"Open a deep link","tags":["Tools/Apps"],"x-mint":{"content":"Opens a deep link on the device, e.g. `myapp://profile/42` or an HTTPS app link such as `https://example.com/item/7`.\n\nOn Android the link is dispatched as an intent. By default any app that handles the link can receive it (`android.intent.action.VIEW`); pass `packageName` to pin the intent to a specific app, or `action` to dispatch a different intent action. Requests targeting a protected package fail with `403 Forbidden`.\n\nOn iOS the URL is opened directly by the system. `packageName` and `action` are Android-only and fail with an unsupported-feature error when set; `bundleId` is reserved for targeting a specific iOS app and is not yet supported.\n"},"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"header","name":"X-Device-Display-ID","schema":{"default":0,"format":"int64","minimum":0,"type":"integer"}}]}},"/devices/{deviceId}/apps/{packageName}":{"delete":{"description":"Uninstalls the app identified by the path package name from the device. Protected packages cannot be deleted.","operationId":"delete-app","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/None"}}},"required":true},"responses":{"204":{"description":"No Content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"Delete app","tags":["Tools/Apps"],"x-mint":{"content":"On Android, the path parameter is the package name (e.g. `com.example.app`); on iOS, pass the app's bundle identifier instead.\n\nDeleting an app does not touch your app library — an uploaded APK stays there, so you can reinstall the app later with `install-app`.\n\nRequests targeting a protected package fail with `403 Forbidden`.\n"},"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"header","name":"X-Device-Display-ID","schema":{"default":0,"format":"int64","minimum":0,"type":"integer"}},{"in":"path","name":"packageName","required":true,"schema":{"type":"string"}}]},"patch":{"description":"Force-stops the app identified by the path package name. When clearData is set in the request body, the app's data is also cleared. Protected packages cannot be stopped.","operationId":"stop-app","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StopAppArgs"}}},"required":true},"responses":{"204":{"description":"No Content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"Stop app","tags":["Tools/Apps"],"x-mint":{"content":"Stopping kills every process and service of the app immediately — the same as **Force stop** in Android settings.\n\n<Warning>\n`clearData: true` additionally wipes the app's local storage (databases, preferences, cache) — the same as **Clear data** in Android settings. This is irreversible and typically signs you out of the app.\n</Warning>\n\nRequests targeting a protected package fail with `403 Forbidden`. Not supported on iOS devices.\n"},"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"header","name":"X-Device-Display-ID","schema":{"default":0,"format":"int64","minimum":0,"type":"integer"}},{"in":"path","name":"packageName","required":true,"schema":{"type":"string"}}]},"put":{"description":"Launches the app identified by the path package name, optionally starting a specific activity given in the request body. Protected packages cannot be started.","operationId":"start-app","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartAppArgs"}}},"required":true},"responses":{"204":{"description":"No Content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"Start app","tags":["Tools/Apps"],"x-mint":{"content":"Starting an app that is already running brings it to the foreground.\n\nOmit `activity` to launch the app's default (launcher) activity. To open a specific screen, pass the fully qualified activity class name, e.g. `com.example.app.MainActivity`.\n\nRequests targeting a protected package fail with `403 Forbidden`. Not supported on iOS devices — the request fails with an unsupported-feature error.\n"},"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"header","name":"X-Device-Display-ID","schema":{"default":0,"format":"int64","minimum":0,"type":"integer"}},{"in":"path","name":"packageName","required":true,"schema":{"type":"string"}}]}},"/devices/{deviceId}/apps/{packageName}/permissions/{permission}":{"delete":{"description":"Revokes an Android runtime permission from the package named in the path. The permission is given by its short name (e.g. POST_NOTIFICATIONS).","operationId":"revoke-permission","responses":{"204":{"description":"No Content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"Revoke app permission","tags":["Tools/Apps"],"x-mint":{"content":"Revokes the permission directly, without any user interaction on the device. Counterpart to `grant-permission`.\n\nThe short name expands to the full Android permission string: `POST_NOTIFICATIONS` becomes `android.permission.POST_NOTIFICATIONS`.\n\nNot supported on iOS devices — the request fails with an unsupported-feature error.\n"},"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"header","name":"X-Device-Display-ID","schema":{"default":0,"format":"int64","minimum":0,"type":"integer"}},{"in":"path","name":"packageName","required":true,"schema":{"type":"string"}},{"description":"Android runtime permission, short name (e.g. POST_NOTIFICATIONS).","in":"path","name":"permission","required":true,"schema":{"description":"Android runtime permission, short name (e.g. POST_NOTIFICATIONS).","enum":["POST_NOTIFICATIONS"],"type":"string"}}]},"put":{"description":"Grants an Android runtime permission to the package named in the path. The permission is given by its short name (e.g. POST_NOTIFICATIONS).","operationId":"grant-permission","responses":{"204":{"description":"No Content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"Grant app permission","tags":["Tools/Apps"],"x-mint":{"content":"Grants the permission directly — the app will not prompt the user for it on the device.\n\nThe short name expands to the full Android permission string: `POST_NOTIFICATIONS` becomes `android.permission.POST_NOTIFICATIONS`. The target app must already be installed.\n\nNot supported on iOS devices — the request fails with an unsupported-feature error. Use `revoke-permission` to take the permission back.\n"},"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"header","name":"X-Device-Display-ID","schema":{"default":0,"format":"int64","minimum":0,"type":"integer"}},{"in":"path","name":"packageName","required":true,"schema":{"type":"string"}},{"description":"Android runtime permission, short name (e.g. POST_NOTIFICATIONS).","in":"path","name":"permission","required":true,"schema":{"description":"Android runtime permission, short name (e.g. POST_NOTIFICATIONS).","enum":["POST_NOTIFICATIONS"],"type":"string"}}]}},"/devices/{deviceId}/browser/execute-script":{"post":{"description":"Evaluates a JavaScript expression exactly once in the device's single, confirmed foreground Chrome tab via the Chrome DevTools Protocol and returns its JSON-serialized result. A responsive browser state without exactly one visible page returns DEVICE_NO_BROWSER_TARGET (400). Transient discovery, page-dial, or visibility-probe transport failures return CDP_TRANSPORT_UNAVAILABLE (503) with Retry-After and an executionOutcome; the service may start Chrome once and retry selection before Runtime.evaluate, but dial or probe recovery is skipped for a backgrounded Chrome, and a user script is never retried after its write or read. Devices without browser support return an unsupported-feature error.","operationId":"browser-execute-script","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecuteScriptArgs"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecuteScriptOutputBody"}}},"description":"OK"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"Execute JavaScript in the device's Chrome browser (CDP)","tags":["Tools/Browser"],"x-mint":{"content":"The script is a single JavaScript expression, not a function body — skip the top-level `return` and wrap multi-statement logic in an IIFE:\n\n```js\n(() => { const links = [...document.querySelectorAll('a')]; return links.map(a => a.href); })()\n```\n\nThe result must be JSON-serializable: `undefined` comes back as `null`, and `NaN`, `Infinity`, and `-0` are returned as strings. Scripts run in Chrome itself — in-app WebViews are not reachable. iOS devices don't support browser control and fail with `400`.\n\nIf CDP discovery, page connection, or the foreground visibility probe fails before `Runtime.evaluate` is sent, the service may start Chrome once and retry target selection. Dial and probe recovery only starts Chrome when it is already the foreground app (or the Chrome CDP socket itself is unavailable), so a backgrounded browser still fails closed. The response keeps the `CDP_TRANSPORT_UNAVAILABLE` `503` contract and reports the phase and recovery result in its details when recovery was attempted. A selection deadline shortfall, or failures while writing or reading `Runtime.evaluate`, is never replayed.\n\n<Tip>\nFor a persistent session or full DevTools protocol access, connect a Playwright- or Puppeteer-style CDP client to the raw websocket at `/devices/{deviceId}/browser/cdp` instead of issuing one-shot calls.\n</Tip>\n"},"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"header","name":"X-Device-Display-ID","schema":{"default":0,"format":"int64","minimum":0,"type":"integer"}}]}},"/devices/{deviceId}/capabilities":{"get":{"description":"Returns the set of capabilities supported by this device. Used to determine which tools and features are available for the device.","operationId":"get-device-capabilities","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CapabilityInfo"}}},"description":"OK"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"Get capabilities for a specific device","tags":["Devices"],"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}}]}},"/devices/{deviceId}/clipboard":{"get":{"description":"Returns the current text content of the device's clipboard. Devices without clipboard support return an unsupported-feature error.","operationId":"get-clipboard","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClipboardBody"}}},"description":"OK"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"Get device clipboard","tags":["Tools/Misc"],"x-mint":{"content":"Reads the device's primary clipboard as plain text — whatever was last copied on the device or written through the set-clipboard endpoint.\n\n`text` is an empty string when the clipboard is empty or its current content is not text.\n\nOn phones, Android only grants clipboard access to the selected input method: the read requires the Mobilerun keyboard to be selected on the device, and answers `409 DEVICE_CLIPBOARD_KEYBOARD_REQUIRED` until it is.\n"},"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"header","name":"X-Device-Display-ID","schema":{"default":0,"format":"int64","minimum":0,"type":"integer"}}]},"post":{"description":"Replaces the device's clipboard content with the text in the request body; an empty text clears the clipboard. Devices without clipboard support return an unsupported-feature error.","operationId":"set-clipboard","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetClipboardArgs"}}},"required":true},"responses":{"204":{"description":"No Content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"Set device clipboard","tags":["Tools/Misc"],"x-mint":{"content":"Replaces the device's primary clipboard with the given plain text, exactly as if it had been copied on the device — a paste in any app inserts it.\n\nSending an empty `text` clears the clipboard.\n"},"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"header","name":"X-Device-Display-ID","schema":{"default":0,"format":"int64","minimum":0,"type":"integer"}}]}},"/devices/{deviceId}/esim":{"delete":{"description":"Deletes the eSIM subscription identified by the subId query parameter from the device.","operationId":"delete-esim","responses":{"204":{"description":"No Content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"Delete eSIM subscription","tags":["Tools/SIM"],"x-mint":{"content":"Get the `subId` from list-esim.\n\n<Warning>\nDeletion is permanent. To use the plan on this device again, the profile must be downloaded again with configure-esim.\n</Warning>\n"},"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"header","name":"X-Device-Display-ID","schema":{"default":0,"format":"int64","minimum":0,"type":"integer"}},{"explode":false,"in":"query","name":"subId","required":true,"schema":{"format":"int64","type":"integer"}}]},"get":{"description":"Returns the eSIM subscriptions currently provisioned on the device.","operationId":"list-esim","responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/ESimSubscription"},"type":["array","null"]}}},"description":"OK"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"List eSIM subscriptions","tags":["Tools/SIM"],"x-mint":{"content":"Start here: the `subId` of each entry is what the other SIM endpoints take (enable, delete, and APN calls). The list may also include physical SIM slots — entries with `isEmbedded: false` are not eSIM profiles.\n"},"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"header","name":"X-Device-Display-ID","schema":{"default":0,"format":"int64","minimum":0,"type":"integer"}}]},"post":{"description":"Download profile and/or enable subscription.","operationId":"configure-esim","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfigureESimBody"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ESimSubscription"}}},"description":"OK"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"Configure eSIM","tags":["Tools/SIM"],"x-mint":{"content":"Returns the newly installed subscription — keep its `subId` for later enable, delete, and APN calls. With `enable: true` the profile is activated in the same call; otherwise enable it later with enable-esim.\n\n`smDpAddr` is the bare SM-DP+ address, not a full activation code. Given `LPA:1$smdp.example.com$MATCH-123`, pass `smdp.example.com` as `smDpAddr` and `MATCH-123` as `matchingId`; a fourth segment would be `confirmationCode`.\n\neSIM operations run one at a time per device — a concurrent call fails instead of queueing.\n"},"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"header","name":"X-Device-Display-ID","schema":{"default":0,"format":"int64","minimum":0,"type":"integer"}}]},"put":{"description":"Enables the eSIM subscription identified by the subId in the request body so it becomes the active subscription.","operationId":"enable-esim","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnableESimBody"}}},"required":true},"responses":{"204":{"description":"No Content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"Enable an eSIM subscription","tags":["Tools/SIM"],"x-mint":{"content":"Use the `subId` from list-esim or from the configure-esim response. If you passed `enable: true` to configure-esim, the new profile is already active and this call is unnecessary.\n\n<Note>\nOn iOS this re-requests the plan from the carrier rather than switching profiles — iOS provides no way to deactivate an active eSIM.\n</Note>\n"},"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"header","name":"X-Device-Display-ID","schema":{"default":0,"format":"int64","minimum":0,"type":"integer"}}]}},"/devices/{deviceId}/esim/apn":{"get":{"description":"Returns the access point names (APNs) configured for the device's active eSIM subscriptions.","operationId":"list-esim-apns","responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/ESimAPN"},"type":["array","null"]}}},"description":"OK"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"List APNs for active subscriptions","tags":["Tools/SIM"],"x-mint":{"content":"Use an entry's `id` as `apnId` in select-esim-apn; `isPreferred` marks the APN currently in use. On Android the list covers all APNs of the active subscriptions, including carrier-provisioned ones; on iOS it shows only APNs created through this API.\n"},"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"header","name":"X-Device-Display-ID","schema":{"default":0,"format":"int64","minimum":0,"type":"integer"}}]},"post":{"description":"Creates an access point name (APN) from the request body and applies it to the given eSIM subscription. Type, protocol, and roaming protocol default to common values when omitted.","operationId":"set-esim-apn","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetAPNBody"}}},"required":true},"responses":{"204":{"description":"No Content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"Create and set an APN for an eSIM subscription","tags":["Tools/SIM"],"x-mint":{"content":"`subId` comes from list-esim. Defaults when omitted: `name` takes the `apn` value; `type` is `default,supl`; `protocol` and `roamingProtocol` are `IPV4V6`.\n\nOn iOS the new APN becomes active immediately, replacing the previous one. On Android it is only created — and the response doesn't return its id — so call list-esim-apns to find it, then select-esim-apn to make it preferred.\n"},"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"header","name":"X-Device-Display-ID","schema":{"default":0,"format":"int64","minimum":0,"type":"integer"}}]},"put":{"description":"Marks an existing APN, identified by apnId, as the preferred APN for the given eSIM subscription in the request body.","operationId":"select-esim-apn","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SelectAPNBody"}}},"required":true},"responses":{"204":{"description":"No Content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"Select an existing APN as preferred","tags":["Tools/SIM"],"x-mint":{"content":"Get `apnId` from the `id` field of list-esim-apns and `subId` from list-esim. Use it after set-esim-apn on Android, where new APNs are not preferred automatically.\n\n<Note>\niOS APNs apply device-wide, so `subId` is ignored there.\n</Note>\n"},"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"header","name":"X-Device-Display-ID","schema":{"default":0,"format":"int64","minimum":0,"type":"integer"}}]}},"/devices/{deviceId}/esim/roaming":{"put":{"description":"Enables or disables data roaming for the device's eSIM based on the enabled flag in the request body.","operationId":"set-esim-roaming","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetRoamingBody"}}},"required":true},"responses":{"204":{"description":"No Content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"Toggle eSIM data roaming","tags":["Tools/SIM"],"x-mint":{"content":"Roaming is a device-wide setting — it is not scoped to a `subId`. Check the effect with get-esim-status, which reports `dataRoamingEnabled` per subscription. On iOS this toggles voice roaming along with data roaming.\n"},"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"header","name":"X-Device-Display-ID","schema":{"default":0,"format":"int64","minimum":0,"type":"integer"}}]}},"/devices/{deviceId}/esim/status":{"get":{"description":"Returns the connectivity status of the device's eSIM subscriptions.","operationId":"get-esim-status","responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/ESimStatus"},"type":["array","null"]}}},"description":"OK"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"Get eSIM connectivity status","tags":["Tools/SIM"],"x-mint":{"content":"Where list-esim shows what is provisioned, this shows how each active subscription is connecting. Poll it after enable-esim, set-esim-roaming, or an APN change to confirm mobile data actually came up (`dataState`, `networkType`) and that roaming flags took effect.\n"},"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"header","name":"X-Device-Display-ID","schema":{"default":0,"format":"int64","minimum":0,"type":"integer"}}]}},"/devices/{deviceId}/files":{"delete":{"description":"Deletes the file at the path given in the path query parameter from the device.","operationId":"delete-file","responses":{"204":{"description":"No Content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"Delete file","tags":["Tools/Files"],"x-mint":{"content":"Removes the file at `path`, rooted at the device's shared storage, e.g. `/Download/report.pdf`. Deletion is immediate and permanent — there is no trash to recover from.\n\nThe endpoint targets individual files; to clear out a directory, list it and delete its files one by one.\n"},"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"header","name":"X-Device-Display-ID","schema":{"default":0,"format":"int64","minimum":0,"type":"integer"}},{"explode":false,"in":"query","name":"path","required":true,"schema":{"type":"string"}}]},"get":{"description":"Lists the files at the directory path given in the path query parameter, returning each entry's metadata along with the path and total count.","operationId":"list-files","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FileListBody"}}},"description":"OK"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"List files","tags":["Tools/Files"],"x-mint":{"content":"`path` is a directory path rooted at the device's shared storage — `/` is the storage root (primary external storage on Android devices), e.g. `/Download`. The response contains the directory's direct entries only — it does not recurse into subdirectories.\n\nFile access is available on Android devices only; file requests against an iOS device fail with `400`.\n\n<Note>\nDepending on the device type, some entry metadata (`owner`, `group`, `permissions`, `hardLinks`) may be zeroed rather than reflect real values.\n</Note>\n# Invalid directories\n\nOn hosted Android Phones, nonexistent directories return `404 DEVICE_PATH_NOT_FOUND`, files used\nas directories return `422 DEVICE_PATH_NOT_DIRECTORY`, and unreadable directories\nreturn `403 DEVICE_PATH_FORBIDDEN`. A readable empty directory remains a successful\nlisting with zero entries. Paths retain the external-storage scope: `/` means\nprimary shared storage, and `/data/...` does not grant app-private filesystem access.\n"},"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"header","name":"X-Device-Display-ID","schema":{"default":0,"format":"int64","minimum":0,"type":"integer"}},{"explode":false,"in":"query","name":"path","required":true,"schema":{"type":"string"}}]},"post":{"description":"Uploads a file to the device via multipart form data, writing it into the directory given by the path query parameter using the uploaded file's name.","operationId":"upload-file","requestBody":{"content":{"multipart/form-data":{"encoding":{"file":{"contentType":"application/octet-stream"}},"schema":{"properties":{"file":{"contentEncoding":"binary","contentMediaType":"application/octet-stream","format":"binary","type":"string"}},"required":["file"],"type":"object"}}}},"responses":{"204":{"description":"No Content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"Upload file","tags":["Tools/Files"],"x-mint":{"content":"`path` is the destination **directory**, not the full file path — the file is written there under its original uploaded filename. Paths are rooted at the device's shared storage (`/` is the storage root): uploading `report.pdf` with `path=/Download` creates `/Download/report.pdf`.\n\n<Tip>\nFile access runs without root and stays within the device's shared storage tree; protected system paths are not reachable.\n</Tip>\n"},"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"header","name":"X-Device-Display-ID","schema":{"default":0,"format":"int64","minimum":0,"type":"integer"}},{"explode":false,"in":"query","name":"path","required":true,"schema":{"type":"string"}}]}},"/devices/{deviceId}/files/download":{"get":{"description":"Pulls the file at the given path query parameter from the device and returns its raw bytes as an octet-stream.","operationId":"download-file","responses":{"200":{"content":{"application/json":{"schema":{"contentEncoding":"base64","type":"string"}}},"description":"OK","headers":{"Content-Type":{"schema":{"type":"string"}}}},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"Download file","tags":["Tools/Files"],"x-mint":{"content":"Returns the file's raw bytes in the response body. The `Content-Type` is always `application/octet-stream` regardless of the file's actual type, and no filename header is set — derive the name from the `path` you requested.\n\nThe whole file arrives in a single response; range requests are not supported.\n\nErrors: a missing file returns `404 DEVICE_PATH_NOT_FOUND`; a directory returns `422 DEVICE_PATH_NOT_FILE`.\n"},"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"header","name":"X-Device-Display-ID","schema":{"default":0,"format":"int64","minimum":0,"type":"integer"}},{"explode":false,"in":"query","name":"path","required":true,"schema":{"type":"string"}}]}},"/devices/{deviceId}/fingerprint":{"get":{"description":"Returns a live snapshot of the device's spoofed identity, including model, display, identifiers, and carrier. Devices without fingerprint support return an unsupported-feature error.","operationId":"device-fingerprint","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FingerprintResult"}}},"description":"OK"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"Device fingerprint snapshot","tags":["Tools/Misc"],"x-mint":{"content":"The snapshot reflects what apps running on the device observe.\n\nSections are collected independently and best-effort: values the device cannot report come back empty instead of failing the request — treat empty fields as \"unknown\", not as an error.\n"},"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"header","name":"X-Device-Display-ID","schema":{"default":0,"format":"int64","minimum":0,"type":"integer"}}]}},"/devices/{deviceId}/global":{"post":{"description":"Performs a global system action on the device, such as navigating back or going to the home screen, identified by an action code.","operationId":"global","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GlobalArgs"}}},"required":true},"responses":{"204":{"description":"No Content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"Perform a global action","tags":["Tools/Navigation"],"x-mint":{"content":"Action codes follow Android's accessibility global actions:\n\n- `1` — back\n- `2` — home\n- `3` — recents (app switcher)\n\nThese three work on every Android device. Higher codes — `4` (notifications), `5` (quick settings), `6` (power dialog), `8` (lock screen) — are device-dependent and rejected with an error where unsupported.\n"},"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"header","name":"X-Device-Display-ID","schema":{"default":0,"format":"int64","minimum":0,"type":"integer"}}]}},"/devices/{deviceId}/keyboard":{"delete":{"description":"Clears the contents of the currently focused text input field.","operationId":"clear-input","responses":{"204":{"description":"No Content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"Clear input","tags":["Tools/Navigation"],"x-mint":{"content":"Clears whatever text the currently focused input field contains. Make sure an editable field has focus first — check `phone_state.isEditable` and `focusedElement` in the UI state response.\n\nWhen you're replacing a field's contents, the input text endpoint's `clear` flag does the same thing in one call.\n"},"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"header","name":"X-Device-Display-ID","schema":{"default":0,"format":"int64","minimum":0,"type":"integer"}}]},"post":{"description":"Types text into the focused input field. The optional completionMode defaults to accepted for backwards-compatible low latency; committed additionally waits for the complete text or a quiescent UI state.","operationId":"input-text","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KeyboardInputArgs"}}},"required":true},"responses":{"204":{"description":"No Content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"Input text","tags":["Tools/Navigation"],"x-mint":{"content":"Text goes to the currently focused input field — tap a field first, and confirm focus via the UI state response (`phone_state.focusedElement` and `keyboardVisible`).\n\n`wpm` and `errorRate` are humanize tuning knobs, and each applies to a different class of device: devices with human-like input support honor `errorRate` and ignore `wpm`; all other devices honor `wpm` and ignore `errorRate`.\n\n`completionMode` is optional and defaults to `accepted`, which preserves the existing behavior and returns after the device input provider accepts the operation. Use `committed` when the next action depends on the complete value being visible: the request then waits until the focused field contains the full expected text or the focused UI state remains unchanged for a bounded stability window. Devices without accessibility read-back reject `committed` before typing.\n\nSet `humanize: true` for human-like typing where the device supports it. Deprecated alias: `stealth`. If both are sent they must agree, otherwise the request is rejected with 422.\n"},"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"header","name":"X-Device-Display-ID","schema":{"default":0,"format":"int64","minimum":0,"type":"integer"}}]},"put":{"description":"Sends a single Android key event to the device, identified by its key code.","operationId":"input-key","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KeyboardKeyArgs"}}},"required":true},"responses":{"204":{"description":"No Content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"Input key","tags":["Tools/Navigation"],"x-mint":{"content":"Key codes are standard Android `KeyEvent` codes — for example `66` (Enter) or `4` (Back).\n\nA common pattern: type into a field with the input text endpoint, then send `66` to submit it.\n"},"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"header","name":"X-Device-Display-ID","schema":{"default":0,"format":"int64","minimum":0,"type":"integer"}}]}},"/devices/{deviceId}/kiosk":{"delete":{"description":"Disables Android lock-task (kiosk) mode on the device, releasing it from the locked app.","operationId":"disable-kiosk","responses":{"204":{"description":"No Content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"Disable kiosk (lock-task) mode","tags":["Tools/Misc"],"x-mint":{"content":"The previously locked app keeps running — the device is unpinned, but the app is not stopped.\n\nAndroid only: iOS devices return an unsupported-feature error.\n"},"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"header","name":"X-Device-Display-ID","schema":{"default":0,"format":"int64","minimum":0,"type":"integer"}}]},"put":{"description":"Locks the device to the package named in the request body using Android lock-task (kiosk) mode, preventing the user from leaving the app.","operationId":"enable-kiosk","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnableKioskArgs"}}},"required":true},"responses":{"204":{"description":"No Content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"Enable kiosk (lock-task) mode","tags":["Tools/Misc"],"x-mint":{"content":"The app must already be running in the foreground — kiosk mode locks the device to the app's existing task, and the call fails if the package has no task. Launch it first, e.g. with the start-app endpoint.\n\nLocking is applied once and is not restored automatically; re-enable it after a reboot or reset.\n\n<Note>\nAndroid only. iOS devices return an unsupported-feature error.\n</Note>\n"},"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"header","name":"X-Device-Display-ID","schema":{"default":0,"format":"int64","minimum":0,"type":"integer"}}]}},"/devices/{deviceId}/language":{"get":{"description":"Returns the device's current language/locale as a BCP-47 locale string.","operationId":"get-language","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LanguageBody"}}},"description":"OK"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"Get device language/locale","tags":["Tools/Misc"],"x-mint":{"content":"Most devices report a BCP-47 tag like `de-DE`, but some use an underscore separator (`zh_CN` instead of `zh-CN`) — normalize before comparing.\n"},"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"header","name":"X-Device-Display-ID","schema":{"default":0,"format":"int64","minimum":0,"type":"integer"}}]},"post":{"description":"Sets the device language/locale to the BCP-47 locale in the request body. An optional restart flag applies the change immediately by restarting the zygote instead of waiting for the next reboot.","operationId":"set-language","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetLanguageArgs"}}},"required":true},"responses":{"204":{"description":"No Content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"Set device language/locale","tags":["Tools/Misc"],"x-mint":{"content":"Include a region subtag — use `de-DE` rather than `de` — since some devices reject language-only locales. Script subtags may be dropped: `zh-Hans-CN` is applied as `zh-CN`.\n\nIf the device cannot apply the requested locale, the call fails with a verification error instead of silently keeping the old language.\n"},"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"header","name":"X-Device-Display-ID","schema":{"default":0,"format":"int64","minimum":0,"type":"integer"}}]}},"/devices/{deviceId}/location":{"delete":{"description":"Clears any simulated GPS location and restores the device's default location behavior. Devices without geo support return an unsupported-feature error.","operationId":"reset-location","responses":{"204":{"description":"No Content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"Reset the device location to default","tags":["Tools/Misc"],"x-mint":{"content":"On cloud devices this re-points the simulated position at the platform default — New York City (`40.7128, -74.0060`) — it does not disable location simulation.\n"},"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"header","name":"X-Device-Display-ID","schema":{"default":0,"format":"int64","minimum":0,"type":"integer"}}]},"get":{"description":"Returns the device's current simulated GPS location as latitude and longitude. Devices without geo support return an unsupported-feature error.","operationId":"get-location","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Location"}}},"description":"OK"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"Get device location","tags":["Tools/Misc"],"x-mint":{"content":"If the device cannot report a position yet, the call still succeeds and returns latitude and longitude `0` — treat `0,0` as \"not available\", not as a real coordinate.\n"},"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"header","name":"X-Device-Display-ID","schema":{"default":0,"format":"int64","minimum":0,"type":"integer"}}]},"post":{"description":"Sets the device's simulated GPS location to the latitude and longitude in the request body. Devices without geo support return an unsupported-feature error.","operationId":"set-location","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Location"}}},"required":true},"responses":{"204":{"description":"No Content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"Set device location","tags":["Tools/Misc"],"x-mint":{"content":"Coordinates are decimal degrees; negative latitude is south, negative longitude is west. The new position applies to the running device immediately.\n\nThis changes the simulated GPS position only — the device's IP-based geolocation is determined by its proxy.\n\n<Note>\nConnecting a proxy with `smartIp: true` overwrites the position to match the proxy's exit IP.\n</Note>\n"},"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"header","name":"X-Device-Display-ID","schema":{"default":0,"format":"int64","minimum":0,"type":"integer"}}]}},"/devices/{deviceId}/name":{"put":{"description":"Sets the display name for a device from the name in the request body and returns the updated device.","operationId":"update-device-name","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateNameInputBody"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeviceInfo"}}},"description":"OK"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"Update device name","tags":["Devices"],"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}}]}},"/devices/{deviceId}/overlay":{"get":{"description":"Returns whether the accessibility overlay is currently visible on the device.","operationId":"overlay-visible","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OverlayVisibleBody"}}},"description":"OK"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"Check if overlay is visible","tags":["Tools/Misc"],"x-mint":{"content":"Reports the state of the visual overlay that the device's automation service can draw over the screen.\n\n<Note>\nNot every device draws an overlay. Devices without one always report `visible: false`.\n</Note>\n"},"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"header","name":"X-Device-Display-ID","schema":{"default":0,"format":"int64","minimum":0,"type":"integer"}}]},"post":{"description":"Shows or hides the accessibility overlay on the device based on the visibility flag in the request body.","operationId":"set-overlay-visible","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetOverlayVisibleArgs"}}},"required":true},"responses":{"204":{"description":"No Content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"Set overlay visibility","tags":["Tools/Misc"],"x-mint":{"content":"While visible, the overlay is part of the screen output: screenshots include it unless you pass `hideOverlay=true` to the screenshot endpoint.\n\n<Note>\nDevices that don't draw an overlay fail this call and always report `visible: false` on the read side.\n</Note>\n"},"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"header","name":"X-Device-Display-ID","schema":{"default":0,"format":"int64","minimum":0,"type":"integer"}}]}},"/devices/{deviceId}/packages":{"get":{"description":"Returns the package names of apps installed on the device. System and protected packages are excluded unless the corresponding query parameters are set.","operationId":"list-packages","responses":{"200":{"content":{"application/json":{"schema":{"items":{"type":"string"},"type":["array","null"]}}},"description":"OK"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"List packages","tags":["Tools/Apps"],"x-mint":{"content":"Returns bare package names. Use `list-apps` when you also need labels and version info.\n\nProtected packages are the platform's own device-management apps: they stay hidden unless you set `includeProtectedPackages=true`, and other app endpoints reject them with `403 Forbidden` anyway.\n\nOn iOS devices, entries are bundle identifiers and `includeSystemPackages` has no effect — Apple's built-in apps are never listed.\n"},"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"header","name":"X-Device-Display-ID","schema":{"default":0,"format":"int64","minimum":0,"type":"integer"}},{"explode":false,"in":"query","name":"includeSystemPackages","schema":{"default":false,"type":"boolean"}},{"explode":false,"in":"query","name":"includeProtectedPackages","schema":{"default":false,"type":"boolean"}}]}},"/devices/{deviceId}/profile":{"put":{"operationId":"apply-profile","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApplyProfileInputBody"}}},"required":true},"responses":{"204":{"description":"No Content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"Apply a profile to a device","tags":["Profiles"],"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"header","name":"X-Device-Display-ID","schema":{"default":0,"format":"int64","minimum":0,"type":"integer"}}]}},"/devices/{deviceId}/proxy":{"delete":{"description":"Disconnects the device's active proxy connection and clears its stored proxy state. Returns successfully if no proxy is connected.","operationId":"disconnect-proxy","responses":{"204":{"description":"No Content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"Disconnect proxy","tags":["Tools/Proxy"],"x-mint":{"content":"After disconnecting, the device's traffic uses its direct network connection again.\n\n<Note>\nDisconnecting does not revert `smartIp` changes — the device keeps the location, time zone, locale, and carrier settings that were aligned to the previous proxy's exit IP.\n</Note>\n\n<Note>\nOn some device types, disconnecting always restarts the device to remove the proxy.\n</Note>\n"},"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"header","name":"X-Device-Display-ID","schema":{"default":0,"format":"int64","minimum":0,"type":"integer"}}]},"get":{"description":"Returns the device's current proxy connection state, including whether a proxy is connected and its protocol and name.","operationId":"get-proxy","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetProxyInfo"}}},"description":"OK"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"Get proxy connection state","tags":["Tools/Proxy"],"x-mint":{"content":"The `connected` flag is a live check against the device, not just stored state — it can be `false` while `protocol` and `name` still describe a configured proxy whose link has dropped.\n\nProxy host and credentials are never returned; you only get back the protocol and the `name` you supplied when connecting.\n"},"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"header","name":"X-Device-Display-ID","schema":{"default":0,"format":"int64","minimum":0,"type":"integer"}}]},"post":{"description":"Routes the device's traffic through a SOCKS5 proxy supplied in the request body, replacing any existing connection. A smartIp option can be used to select an IP automatically; the legacy flat host/port/user/password fields remain supported.","operationId":"connect-proxy","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectProxyBody"}}},"required":true},"responses":{"204":{"description":"No Content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"Connect proxy","tags":["Tools/Proxy"],"x-mint":{"content":"Provide **exactly one** proxy definition: the `socks5` object, the deprecated flat `host`/`port`/`user`/`password` fields (all four required together), or a Mobilerun Connect `connect` reference (see below). Sending more than one fails validation.\n\n## Mobilerun Connect proxies\n\nInstead of passing credentials, reference a Mobilerun Connect proxy:\n\n```json\n{ \"connect\": { \"id\": \"0d5a…\" } }\n```\n\nfetches the credentials of an existing Connect proxy owned by the device's\nowner (it must be `active` or `cancelling`), while\n\n```json\n{ \"connect\": { \"country\": \"us\" } }\n```\n\nprovisions a rotating **residential** proxy in that country — or reuses the\none previously provisioned for this device when it is still active and in\nthe same country. Provisioning waits up to 60 s for the proxy to become\nactive. If payment is required first, the request fails with\n`402 PAYMENT_REQUIRED` and a `paymentUrl` detail pointing to checkout.\n\nWith `smartIp: true`, the exit-IP precheck probes the proxy for up to ~45 s,\nso a freshly provisioned proxy that is still being routed passes without\ncaller-side retries. If the precheck still fails, the error tells you why:\n\n- `409 CONNECT_PROXY_NOT_ACTIVE` — the proxy is not (or no longer) serving\n  traffic, e.g. still provisioning. Transient while provisioning: retry in a\n  few seconds.\n- A denial that keeps failing while the proxy is `active` usually means the\n  organization is out of prepaid proxy data — but the gateway returns the\n  same denial for short internal hiccups, so it surfaces as a generic error\n  rather than a billing one. Check your proxy data balance if retries keep\n  failing.\n\nPass exactly one of `id` or `country`, and don't combine `connect` with\n`socks5` or the legacy flat fields. `smartIp` works with all variants.\n\nA proxy provisioned via `country` stays with the device and is cancelled\nautomatically when the device is terminated. Proxies referenced by `id`\nare never cancelled by this API.\n\nWith `smartIp: true`, the API geolocates the proxy's exit IP through the proxy itself and aligns the device to match — GPS location, time zone, locale, and (unless an eSIM is active) mobile carrier and network type.\n\n<Warning>\nA smart IP failure leaves your existing proxy untouched, but a failure while connecting the new proxy can leave the device with no proxy at all. Check the proxy state before retrying.\n</Warning>\n\n<Note>\nOn some device types, an upstream switch on an already-proxied device applies live with no interruption, but the first time a device gets a proxy the device restarts to pick it up.\n</Note>\n"},"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"header","name":"X-Device-Display-ID","schema":{"default":0,"format":"int64","minimum":0,"type":"integer"}}]}},"/devices/{deviceId}/reboot":{"post":{"description":"Triggers a reboot of the device. The device transitions through its reboot lifecycle and becomes ready again once the restart completes. Only devices whose capabilities report `reboot=true` can be rebooted. Personal (BYOD) devices cannot be rebooted remotely: the request is refused with 400 `DEVICE_TOOL_UNSUPPORTED` and nothing happens on the device.","operationId":"reboot-device","responses":{"204":{"description":"No Content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"Reboot a device","tags":["Devices"],"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}}]}},"/devices/{deviceId}/recordings":{"get":{"operationId":"list-device-recordings","responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/RecordingInfo"},"type":["array","null"]}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"summary":"List device recordings","tags":["Tools/Recordings"],"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"explode":false,"in":"query","name":"type","schema":{"type":"string"}},{"explode":false,"in":"query","name":"status","schema":{"type":"string"}}]},"post":{"operationId":"start-device-recording","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartInputBody"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecordingInfo"}}},"description":"Created"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Conflict"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"summary":"Start a device recording","tags":["Tools/Recordings"],"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}}]}},"/devices/{deviceId}/recordings/{recordingId}":{"delete":{"operationId":"delete-device-recording","responses":{"204":{"description":"No Content"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Conflict"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"summary":"Delete a device recording","tags":["Tools/Recordings"],"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"path","name":"recordingId","required":true,"schema":{"type":"string"}}]},"get":{"operationId":"get-device-recording","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecordingInfo"}}},"description":"OK"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"summary":"Get a device recording","tags":["Tools/Recordings"],"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"path","name":"recordingId","required":true,"schema":{"type":"string"}}]},"post":{"operationId":"stop-device-recording","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecordingInfo"}}},"description":"OK"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Conflict"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"summary":"Stop a device recording","tags":["Tools/Recordings"],"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"path","name":"recordingId","required":true,"schema":{"type":"string"}}]}},"/devices/{deviceId}/recordings/{recordingId}/screenshots":{"get":{"description":"Screenshots saved into the recording with `GET /devices/{deviceId}/screenshot?save=true`, oldest first, each with a presigned download URL.","operationId":"list-device-recording-screenshots","responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/Item"},"type":["array","null"]}}},"description":"OK"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"410":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Gone"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"summary":"List a device recording's saved screenshots","tags":["Tools/Recordings"],"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"path","name":"recordingId","required":true,"schema":{"type":"string"}}]}},"/devices/{deviceId}/recordings/{recordingId}/trajectory":{"get":{"operationId":"get-device-recording-trajectory","responses":{"200":{"description":"OK"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Conflict"},"410":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Gone"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"summary":"Get a device recording trajectory","tags":["Tools/Recordings"],"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"path","name":"recordingId","required":true,"schema":{"type":"string"}}]}},"/devices/{deviceId}/recordings/{recordingId}/video":{"get":{"operationId":"get-device-recording-video","responses":{"302":{"description":"Found","headers":{"Location":{"schema":{"type":"string"}}}},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Conflict"},"410":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Gone"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"summary":"Get a device recording video","tags":["Tools/Recordings"],"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"path","name":"recordingId","required":true,"schema":{"type":"string"}}]}},"/devices/{deviceId}/reset":{"post":{"description":"Resets the device. The optional body `mode` selects what is erased: `full` is a factory reset that erases installed apps, accounts and storage and gives the device a new identity; `identity` gives the device a new fingerprint and keeps its apps and data. When `mode` is omitted the reset is `full`, or `identity` on devices whose capabilities report `factoryReset=false`. A mode the device does not support (see `factoryReset` / `identityReset` in the device capabilities) is refused with 400 `DEVICE_TOOL_UNSUPPORTED`; legacy devices accept an explicit mode only when it is the one their capabilities advertise, and always accept a reset without a mode. The device transitions through its reset lifecycle before becoming ready again.","operationId":"reset-device","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResetRequest"}}}},"responses":{"204":{"description":"No Content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"Reset a device to a fresh state","tags":["Devices"],"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}}]}},"/devices/{deviceId}/resume":{"post":{"description":"Wakes a parked device: backend readiness and any required capacity are preflighted, the same device starts running again, and per-minute billing resumes. On a device that is not parked this is a no-op ready transition.","operationId":"resume-device","responses":{"204":{"description":"No Content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"Resume (unpark) a stopped device","tags":["Devices"],"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}}]}},"/devices/{deviceId}/screenshot":{"get":{"deprecated":true,"description":"Deprecated: use POST /devices/{deviceId}/screenshots. Captures the device screen and returns it as a PNG image. An optional hideOverlay query parameter excludes the accessibility overlay from the capture.","operationId":"take-screenshot","responses":{"200":{"content":{"application/json":{"schema":{"contentEncoding":"base64","type":"string"}}},"description":"OK","headers":{"Content-Type":{"schema":{"type":"string"}},"X-Screenshot-Saved":{"schema":{"description":"Set when save=true: \"true\" if the screenshot was stored, otherwise \"false\".","type":"string"}}}},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"Take screenshot","tags":["Tools/Navigation"],"x-mint":{"content":"Deprecated: use `POST /devices/{deviceId}/screenshots` to capture a screenshot. Existing callers can continue using this endpoint and migrate in a follow-up.\n\nThe response body is the PNG image itself (`Content-Type: image/png`), not a JSON wrapper.\n\nThe accessibility overlay is the on-screen element-highlight layer controlled by the set overlay visibility endpoint. If you've enabled it, pass `hideOverlay=true` to capture a clean frame; on devices whose capture path sits below the overlay, the flag has no effect either way.\n\nPass `save=true` to also store the captured PNG as device media. If the device has an active recording owned by the device owner, the screenshot is saved into that recording and inherits its retention. Otherwise it is saved standalone for seven days. Without `save=true`, no screenshot is stored.\n\nThe PNG response is unchanged; `X-Screenshot-Saved` is `true` when both the object and its metadata were stored, and `false` if storage limits or a save failure prevented persistence. A failed save does not fail screenshot capture. The device screenshots endpoints list saved screenshots, open their images, and delete individual screenshots. Recording screenshots remain available through the existing list recording screenshots endpoint and are also deleted with the recording.\n"},"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"header","name":"X-Device-Display-ID","schema":{"default":0,"format":"int64","minimum":0,"type":"integer"}},{"explode":false,"in":"query","name":"hideOverlay","schema":{"default":false,"type":"boolean"}},{"description":"Store the screenshot as device media: in the owner's active recording, or standalone for 7 days. Without save=true nothing is stored. The PNG response is unchanged; X-Screenshot-Saved reports whether it was stored.","explode":false,"in":"query","name":"save","schema":{"default":false,"description":"Store the screenshot as device media: in the owner's active recording, or standalone for 7 days. Without save=true nothing is stored. The PNG response is unchanged; X-Screenshot-Saved reports whether it was stored.","type":"boolean"}}]}},"/devices/{deviceId}/screenshots":{"get":{"description":"Saved screenshots, newest first. Pass nextCursor as cursor to retrieve the next page.","operationId":"list-device-screenshots","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeviceScreenshotList"}}},"description":"OK"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Bad Request"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"summary":"List device screenshots","tags":["Tools/Screenshots"],"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"explode":false,"in":"query","name":"cursor","schema":{"maxLength":256,"type":"string"}},{"explode":false,"in":"query","name":"limit","schema":{"default":50,"format":"int64","maximum":200,"minimum":1,"type":"integer"}}]},"post":{"description":"Captures the device screen and returns it as a PNG image. Pass save=true to store it as device media.","operationId":"capture-device-screenshot","responses":{"200":{"content":{"application/json":{"schema":{"contentEncoding":"base64","type":"string"}}},"description":"OK","headers":{"Content-Type":{"schema":{"type":"string"}},"X-Screenshot-Id":{"schema":{"description":"ID of the saved screenshot; omitted when nothing was saved.","type":"string"}},"X-Screenshot-Saved":{"schema":{"description":"Set when save=true: \"true\" if the screenshot was stored, otherwise \"false\".","type":"string"}}}},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"Capture a device screenshot","tags":["Tools/Screenshots"],"x-mint":{"content":"The response body is the PNG image itself (`Content-Type: image/png`), not a JSON wrapper.\n\nThe accessibility overlay is the on-screen element-highlight layer controlled by the set overlay visibility endpoint. If you've enabled it, pass `hideOverlay=true` to capture a clean frame; on devices whose capture path sits below the overlay, the flag has no effect either way.\n\nPass `save=true` to also store the captured PNG as device media. If the device has an active recording owned by the device owner, the screenshot is saved into that recording and inherits its retention. Otherwise it is saved standalone for seven days. Without `save=true`, no screenshot is stored.\n\n`X-Screenshot-Id` contains the saved screenshot ID only when persistence succeeds. The PNG response is unchanged; `X-Screenshot-Saved` is `true` when both the object and its metadata were stored, and `false` if storage limits or a save failure prevented persistence. A failed save does not fail screenshot capture. The device screenshots endpoints list saved screenshots, open their images, and delete individual screenshots. Recording screenshots remain available through the existing list recording screenshots endpoint and are also deleted with the recording.\n"},"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"header","name":"X-Device-Display-ID","schema":{"default":0,"format":"int64","minimum":0,"type":"integer"}},{"explode":false,"in":"query","name":"hideOverlay","schema":{"default":false,"type":"boolean"}},{"description":"Store the screenshot as device media: in the owner's active recording, or standalone for 7 days. Without save=true nothing is stored. The PNG response is unchanged; X-Screenshot-Saved reports whether it was stored.","explode":false,"in":"query","name":"save","schema":{"default":false,"description":"Store the screenshot as device media: in the owner's active recording, or standalone for 7 days. Without save=true nothing is stored. The PNG response is unchanged; X-Screenshot-Saved reports whether it was stored.","type":"boolean"}}]}},"/devices/{deviceId}/screenshots/{screenshotId}":{"delete":{"operationId":"delete-device-screenshot","responses":{"204":{"description":"No Content"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"summary":"Delete a device screenshot","tags":["Tools/Screenshots"],"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"path","name":"screenshotId","required":true,"schema":{"type":"string"}}]}},"/devices/{deviceId}/screenshots/{screenshotId}/image":{"get":{"description":"Redirects to a presigned PNG URL valid for 15 minutes.","operationId":"get-device-screenshot-image","responses":{"302":{"description":"Found","headers":{"Location":{"schema":{"type":"string"}}}},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Not Found"},"410":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Gone"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Internal Server Error"}},"summary":"Get a device screenshot image","tags":["Tools/Screenshots"],"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"path","name":"screenshotId","required":true,"schema":{"type":"string"}}]}},"/devices/{deviceId}/stop":{"post":{"description":"Parks the device: its data, apps and identity are kept, but nothing runs and nothing is billed until it is resumed. Only devices whose capabilities report stop=true support this; others return 404.","operationId":"stop-device","responses":{"204":{"description":"No Content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"Stop (park) a device","tags":["Devices"],"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}}]}},"/devices/{deviceId}/swipe":{"post":{"description":"Swipes from a start coordinate to an end coordinate over the given duration in milliseconds. An optional humanize flag applies human-like jitter and curved paths on devices that support it. With holdMs > 0 the request returns 422 when combined with humanize, when duration + holdMs exceeds 9000 ms, or on devices that do not support it.","operationId":"swipe","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SwipeArgs"}}},"required":true},"responses":{"204":{"description":"No Content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"Swipe","tags":["Tools/Navigation"],"x-mint":{"content":"With `humanize: true`, the gesture is humanized: start and end points shift randomly (up to ±5 and ±15 pixels), the duration gets ±10% jitter, and supported devices trace a curved path with micro-jitter instead of a straight line. Devices with human-like input support inject the whole gesture with human motor timing instead.\n\nA humanized swipe covering less than ~5 pixels is treated as a long press with slight drift.\n\nDeprecated alias: `stealth`. If both are sent they must agree, otherwise the request is rejected with 422. `holdMs` cannot be combined with `humanize`; that combination is rejected with 422 `SWIPE_HOLD_HUMANIZE_CONFLICT`.\n"},"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"header","name":"X-Device-Display-ID","schema":{"default":0,"format":"int64","minimum":0,"type":"integer"}}]}},"/devices/{deviceId}/tap":{"post":{"description":"Taps the device screen at the given x/y coordinates. An optional humanize flag routes the tap through human-like input on devices that support it.","operationId":"tap","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TapByCoordinatesArgs"}}},"required":true},"responses":{"204":{"description":"No Content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"Tap by coordinates","tags":["Tools/Navigation"],"x-mint":{"content":"Coordinates are absolute screen pixels — the same space as `boundsInScreen` in the UI state response, so you can read an element's bounds and tap the center of its box.\n\nWith `humanize: true`, devices that support human-like input inject the tap with human motor timing rather than a plain synthetic event.\n\nDeprecated alias: `stealth`. If both are sent they must agree, otherwise the request is rejected with 422.\n"},"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"header","name":"X-Device-Display-ID","schema":{"default":0,"format":"int64","minimum":0,"type":"integer"}}]}},"/devices/{deviceId}/tasks":{"get":{"description":"Returns a paginated list of tasks that have run on the device, along with pagination metadata.","operationId":"list-device-tasks","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResponseTask"}}},"description":"OK"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"List tasks for a device","tags":["Devices"],"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"explode":false,"in":"query","name":"page","schema":{"default":1,"format":"int64","type":"integer"}},{"explode":false,"in":"query","name":"pageSize","schema":{"default":20,"format":"int64","type":"integer"}},{"explode":false,"in":"query","name":"orderBy","schema":{"default":"createdAt","enum":["id","createdAt","updatedAt","assignedAt"],"type":"string"}},{"explode":false,"in":"query","name":"orderByDirection","schema":{"default":"desc","enum":["asc","desc"],"type":"string"}}]}},"/devices/{deviceId}/time":{"get":{"description":"Returns the device's current wall-clock time as an RFC 3339 timestamp.","operationId":"device-time","responses":{"200":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"OK"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"Device time","tags":["Tools/Misc"],"x-mint":{"content":"The timestamp is read live from the device's own clock, not from the API server.\n\n<Tip>\nDon't infer the device's timezone from the timestamp's UTC offset — it isn't guaranteed to match the device's setting. Use the get-timezone endpoint for that.\n</Tip>\n"},"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"header","name":"X-Device-Display-ID","schema":{"default":0,"format":"int64","minimum":0,"type":"integer"}}]}},"/devices/{deviceId}/timezone":{"get":{"description":"Returns the device's current timezone identifier. Devices that do not support timezone control return an unsupported-feature error.","operationId":"get-timezone","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TimeZoneBody"}}},"description":"OK"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"Get device timezone","tags":["Tools/Misc"],"x-mint":{"content":"The identifier is an IANA timezone name, e.g. `Europe/Berlin`.\n\n`timezone` is `null` when the device doesn't report one — for example when no timezone has been set yet.\n"},"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"header","name":"X-Device-Display-ID","schema":{"default":0,"format":"int64","minimum":0,"type":"integer"}}]},"post":{"description":"Sets the device timezone to the identifier in the request body. Devices that do not support timezone control return an unsupported-feature error.","operationId":"set-timezone","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetTimeZoneArgs"}}},"required":true},"responses":{"204":{"description":"No Content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"Set device timezone","tags":["Tools/Misc"],"x-mint":{"content":"Provide an IANA timezone identifier, e.g. `Europe/Berlin` or `America/New_York`.\n\nThe change applies immediately; no reboot is needed.\n"},"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"header","name":"X-Device-Display-ID","schema":{"default":0,"format":"int64","minimum":0,"type":"integer"}}]}},"/devices/{deviceId}/traffic/sessions":{"get":{"operationId":"list-device-traffic-sessions","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResponseSession"}}},"description":"OK"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"List device traffic sessions","tags":["Device Traffic"],"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"explode":false,"in":"query","name":"page","schema":{"default":1,"format":"int64","minimum":1,"type":"integer"}},{"explode":false,"in":"query","name":"pageSize","schema":{"default":20,"format":"int64","maximum":100,"minimum":1,"type":"integer"}}]},"post":{"description":"Starts one live-only decoded HTTP/1.1, HTTP/2, HTTP/3 and WebSocket traffic session.","operationId":"create-device-traffic-session","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSessionBody"}}},"required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Session"}}},"description":"Accepted"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"Start device traffic inspection","tags":["Device Traffic"],"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"header","name":"Idempotency-Key","required":true,"schema":{"maxLength":255,"minLength":1,"type":"string"}}]}},"/devices/{deviceId}/traffic/sessions/{sessionId}":{"delete":{"operationId":"delete-device-traffic-session","responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Session"}}},"description":"Accepted"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"Stop device traffic inspection","tags":["Device Traffic"],"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"path","name":"sessionId","required":true,"schema":{"type":"string"}}]},"get":{"description":"Returns status and the device stream credential for a live session.","operationId":"get-device-traffic-session","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Session"}}},"description":"OK"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"Get a device traffic session","tags":["Device Traffic"],"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"path","name":"sessionId","required":true,"schema":{"type":"string"}}]}},"/devices/{deviceId}/ui-state":{"get":{"description":"Returns the current accessibility UI state of the device as a structured tree of on-screen elements. An optional filter query reduces the result to interactive elements.","operationId":"ui-state","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AndroidState"}}},"description":"OK"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"UI state","tags":["Tools/Navigation"],"x-mint":{"content":"Alongside the main `a11y_tree`, the response carries a separate `ime_tree` for the on-screen keyboard window, `phone_state` (foreground app, focused element, keyboard visibility), and `device_context` (screen bounds, display density).\n\n<Tip>\nElement `boundsInScreen` values are in the same pixel space the tap and swipe endpoints use — read an element's bounds and tap the center of its box for element-driven automation.\n</Tip>\n"},"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}},{"in":"header","name":"X-Device-Display-ID","schema":{"default":0,"format":"int64","minimum":0,"type":"integer"}},{"explode":false,"in":"query","name":"filter","schema":{"default":false,"type":"boolean"}}]}},"/devices/{deviceId}/wait":{"get":{"description":"Blocks until the device reaches the ready state, then returns the same payload as Get device info. The call returns early with an error if the wait is cancelled or times out.","operationId":"wait-for-device-ready","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeviceInfo"}}},"description":"OK"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorModel"}}},"description":"Error"}},"summary":"Wait for device to be ready","tags":["Devices"],"parameters":[{"in":"path","name":"deviceId","required":true,"schema":{"type":"string"}}]}},"/triggers":{"post":{"tags":["Triggers"],"summary":"Create a trigger","operationId":"createTrigger","description":"Create a trigger with an activation type of `event`, `schedule`, or `custom`. Each type requires its own fields (e.g. `eventType` and optional `conditions` for events, `scheduleRule` and `timezone` for schedules, `customPayloadSchema` for custom triggers); mismatched fields are rejected.\n\nSupports an optional `Idempotency-Key` header (1-255 printable ASCII characters). Replays with the same key and an identical body return the original 201; a changed body under the same key returns 422 `idempotency_key_reused`.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTriggerBody"}}}},"responses":{"201":{"description":"Trigger created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Trigger"}},"required":["data"]}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}}},"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":255,"pattern":"^[\\x21-\\x7E]{1,255}$","description":"Idempotency-Key: 1-255 printable ASCII characters. Same key with a different request body is a 422 idempotency_key_reused. A retryable in-flight duplicate is a 409 with Retry-After and x-should-retry: true; a terminal duplicate is a 409 with x-should-retry: false. A replay returns the current resource state with Idempotent-Replayed: true.","example":"b3f6a9f0-6f1a-4e9a-9e7a-9c9b6b6a5a3f"},"required":false,"description":"Idempotency-Key: 1-255 printable ASCII characters. Same key with a different request body is a 422 idempotency_key_reused. A retryable in-flight duplicate is a 409 with Retry-After and x-should-retry: true; a terminal duplicate is a 409 with x-should-retry: false. A replay returns the current resource state with Idempotent-Replayed: true.","name":"idempotency-key","in":"header"}]},"get":{"tags":["Triggers"],"summary":"List triggers","operationId":"listTriggers","description":"Return a paginated list of triggers. Supports filtering by `activation` and `eventType`, free-text `search`, and ordering by name, createdAt, or updatedAt.","responses":{"200":{"description":"List triggers","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Trigger"}},"pagination":{"$ref":"#/components/schemas/Pagination"}},"required":["items","pagination"]}}}}},"parameters":[{"schema":{"type":"integer","exclusiveMinimum":0,"default":1},"required":false,"name":"page","in":"query"},{"schema":{"type":"integer","exclusiveMinimum":0,"default":10},"required":false,"name":"pageSize","in":"query"},{"schema":{"type":"string","enum":["event","schedule","custom"]},"required":false,"name":"activation","in":"query"},{"schema":{"type":"string"},"required":false,"name":"eventType","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":256},"required":false,"name":"search","in":"query"},{"schema":{"type":"string","enum":["name","createdAt","updatedAt"],"default":"createdAt"},"required":false,"name":"orderBy","in":"query"},{"schema":{"type":"string","enum":["asc","desc"],"default":"desc"},"required":false,"name":"orderByDirection","in":"query"}]}},"/triggers/{triggerId}":{"get":{"tags":["Triggers"],"summary":"Get a trigger","operationId":"getTrigger","description":"Fetch a single trigger by its ID, including its activation type and type-specific configuration. Returns 404 if no trigger matches.","responses":{"200":{"description":"Trigger details","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Trigger"}},"required":["data"]}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"triggerId","in":"path"}]},"patch":{"tags":["Triggers"],"summary":"Update a trigger","operationId":"updateTrigger","description":"Partially update a trigger; all fields are optional. When `activation` is changed, the type-specific field rules are re-validated. Returns 404 if the trigger does not exist.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTriggerBody"}}}},"responses":{"200":{"description":"Trigger updated","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Trigger"}},"required":["data"]}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"triggerId","in":"path"}]},"delete":{"tags":["Triggers"],"summary":"Delete a trigger","operationId":"deleteTrigger","description":"Delete a trigger by its ID. Returns 404 if no trigger matches.","responses":{"200":{"description":"Trigger deleted","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"triggerId","in":"path"}]}},"/triggers/{triggerId}/fire":{"post":{"tags":["Triggers"],"summary":"Fire a custom trigger with payload","operationId":"fireCustomTrigger","description":"Invoke a custom trigger directly with an arbitrary JSON payload.\n\nFan-out: a trigger may be referenced by multiple flows (workflows). Firing it enqueues one execution per enabled, non-deleted flow attached to this trigger, each receiving the same payload. The `enqueuedCount` in the response reports how many were enqueued (0 if no flows are attached, or if all matching flows are gated by a cooldown).\n\nPayload validation:\n- If the trigger has a `customPayloadSchema`, the payload is validated against it (JSON Schema).\n- If no schema is configured, the payload only needs to be a JSON object — any keys and values are accepted.\n\nOnly triggers with `activation = \"custom\"` can be fired through this endpoint; event and schedule triggers return 409.\n\nSupports an optional `Idempotency-Key` header (1-255 printable ASCII characters), which maps to the derived `invocationId` used for fan-out deduplication. The payload is bound to the key on the first accepted fire, before fan-out. A repeat with the same key and an identical payload returns 202 with `Idempotent-Replayed: true` (`deduplicated: true` when flows were skipped; `enqueuedCount` counts only executions enqueued by that call); a changed payload under the same key returns 422 `idempotency_key_reused`.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FireCustomTriggerBody"}}}},"responses":{"202":{"description":"Custom trigger fired; one execution enqueued per enabled flow attached to this trigger","content":{"application/json":{"schema":{"type":"object","properties":{"invocationId":{"type":"string","format":"uuid","description":"Unique ID for this fire invocation (derived from the `Idempotency-Key` header when one is sent, otherwise generated)."},"enqueuedCount":{"type":"integer","minimum":0,"description":"Number of flow executions enqueued. May be 0 if no flows are attached to this trigger, if all attached flows are currently in cooldown, or if every attached flow was deduplicated."},"deduplicated":{"type":"boolean","description":"True when at least one attached flow was skipped because it already had an execution for this (flow, invocationId). Only ever true when the request carried an `Idempotency-Key`."}},"required":["invocationId","enqueuedCount","deduplicated"]}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"409":{"description":"Trigger exists but is not of type \"custom\"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerNotFireableError"}}}},"422":{"description":"Payload validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PayloadValidationError"}}}},"429":{"description":"Too Many Requests","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"triggerId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"pattern":"^[\\x21-\\x7E]{1,255}$","description":"Idempotency-Key: 1-255 printable ASCII characters. Same key with a different request body is a 422 idempotency_key_reused. A retryable in-flight duplicate is a 409 with Retry-After and x-should-retry: true; a terminal duplicate is a 409 with x-should-retry: false. A replay returns the current resource state with Idempotent-Replayed: true.","example":"b3f6a9f0-6f1a-4e9a-9e7a-9c9b6b6a5a3f"},"required":false,"description":"Idempotency-Key: 1-255 printable ASCII characters. Same key with a different request body is a 422 idempotency_key_reused. A retryable in-flight duplicate is a 409 with Retry-After and x-should-retry: true; a terminal duplicate is a 409 with x-should-retry: false. A replay returns the current resource state with Idempotent-Replayed: true.","name":"idempotency-key","in":"header"}]}},"/action-catalog":{"get":{"tags":["Action Catalog"],"summary":"List action catalog entries","operationId":"listActionCatalog","description":"Return a paginated list of catalog entries — the service/method templates that actions are created from, each carrying its parameter schema. Supports filtering by `service`.","responses":{"200":{"description":"List catalog entries","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/ActionCatalogEntry"}},"pagination":{"$ref":"#/components/schemas/Pagination"}},"required":["items","pagination"]}}}}},"parameters":[{"schema":{"type":"integer","exclusiveMinimum":0,"default":1},"required":false,"name":"page","in":"query"},{"schema":{"type":"integer","exclusiveMinimum":0,"default":10},"required":false,"name":"pageSize","in":"query"},{"schema":{"type":"string","enum":["tasks_api","devices_api","agents_api","webhooks","integrations_api"]},"required":false,"name":"service","in":"query"}]}},"/action-catalog/{catalogEntryId}":{"get":{"tags":["Action Catalog"],"summary":"Get a catalog entry","operationId":"getActionCatalogEntry","description":"Fetch a single action catalog entry by its ID, including its service, method, and parameter schema. Returns 404 if no entry matches.","responses":{"200":{"description":"Catalog entry details","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ActionCatalogEntry"}},"required":["data"]}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"catalogEntryId","in":"path"}]}},"/actions":{"post":{"tags":["Actions"],"summary":"Create an action","operationId":"createAction","description":"Create a reusable action from a catalog entry (`catalogEntryId`), with an optional `params` object supplying the values for that entry's service method. Returns 400 if the params are invalid for the chosen catalog entry.\n\nSupports an optional `Idempotency-Key` header (1-255 printable ASCII characters). Replays with the same key and an identical body return the original 201; a changed body under the same key returns 422 `idempotency_key_reused`.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateActionBody"}}}},"responses":{"201":{"description":"Action created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Action"}},"required":["data"]}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}}},"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":255,"pattern":"^[\\x21-\\x7E]{1,255}$","description":"Idempotency-Key: 1-255 printable ASCII characters. Same key with a different request body is a 422 idempotency_key_reused. A retryable in-flight duplicate is a 409 with Retry-After and x-should-retry: true; a terminal duplicate is a 409 with x-should-retry: false. A replay returns the current resource state with Idempotent-Replayed: true.","example":"b3f6a9f0-6f1a-4e9a-9e7a-9c9b6b6a5a3f"},"required":false,"description":"Idempotency-Key: 1-255 printable ASCII characters. Same key with a different request body is a 422 idempotency_key_reused. A retryable in-flight duplicate is a 409 with Retry-After and x-should-retry: true; a terminal duplicate is a 409 with x-should-retry: false. A replay returns the current resource state with Idempotent-Replayed: true.","name":"idempotency-key","in":"header"}]},"get":{"tags":["Actions"],"summary":"List actions","operationId":"listActions","description":"Return a paginated list of actions. Supports filtering by `service`, free-text `search`, and ordering by name, createdAt, or updatedAt.","responses":{"200":{"description":"List actions","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Action"}},"pagination":{"$ref":"#/components/schemas/Pagination"}},"required":["items","pagination"]}}}}},"parameters":[{"schema":{"type":"integer","exclusiveMinimum":0,"default":1},"required":false,"name":"page","in":"query"},{"schema":{"type":"integer","exclusiveMinimum":0,"default":10},"required":false,"name":"pageSize","in":"query"},{"schema":{"type":"string","enum":["tasks_api","devices_api","agents_api","webhooks","integrations_api"]},"required":false,"name":"service","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":256},"required":false,"name":"search","in":"query"},{"schema":{"type":"string","enum":["name","createdAt","updatedAt"],"default":"createdAt"},"required":false,"name":"orderBy","in":"query"},{"schema":{"type":"string","enum":["asc","desc"],"default":"desc"},"required":false,"name":"orderByDirection","in":"query"}]}},"/actions/{actionId}":{"get":{"tags":["Actions"],"summary":"Get an action","operationId":"getAction","description":"Fetch a single action by its ID, including its configured service, method, and params. Returns 404 if no action matches.","responses":{"200":{"description":"Action details","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Action"}},"required":["data"]}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"actionId","in":"path"}]},"patch":{"tags":["Actions"],"summary":"Update an action","operationId":"updateAction","description":"Partially update an action's name, description, or params; all fields are optional. Returns 404 if the action does not exist.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateActionBody"}}}},"responses":{"200":{"description":"Action updated","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Action"}},"required":["data"]}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"actionId","in":"path"}]},"delete":{"tags":["Actions"],"summary":"Delete an action","operationId":"deleteAction","description":"Delete an action by its ID. Returns 404 if no action matches.","responses":{"200":{"description":"Action deleted","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"actionId","in":"path"}]}},"/actions/services":{"get":{"tags":["Actions","Discovery"],"summary":"List available services","operationId":"listServices","description":"Return the names of the services that actions can be built against. Use these values to look up each service's allowed methods.","responses":{"200":{"description":"Available services","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"string"}}},"required":["data"]}}}}}}},"/actions/services/{service}/methods":{"get":{"tags":["Actions","Discovery"],"summary":"List allowed methods for a service","operationId":"listServiceMethods","description":"Return the methods allowed for the given service, each with its parameter definitions (name, type, whether required, description, and optional default/example). Returns 404 if the service is unknown.","responses":{"200":{"description":"Allowed methods","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ServiceMethod"}}},"required":["data"]}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}}},"parameters":[{"schema":{"type":"string","minLength":1},"required":true,"name":"service","in":"path"}]}},"/flows/template-context":{"get":{"tags":["Flows"],"summary":"Get flow template context","operationId":"getFlowTemplateContext","responses":{"200":{"description":"Flow template context","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/FlowTemplateContext"}},"required":["data"]}}}}},"parameters":[{"schema":{"type":"integer","minimum":2,"maximum":3},"required":false,"name":"templateResolutionVersion","in":"query"}]}},"/flows/validate":{"post":{"tags":["Flows"],"summary":"Validate a flow","operationId":"validateFlow","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":256},"description":{"type":"string","maxLength":2048},"triggerId":{"type":"string","format":"uuid"},"enabled":{"type":"boolean","default":true},"deviceIds":{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":256,"default":[]},"cooldownSeconds":{"type":["integer","null"],"minimum":0},"cooldownScope":{"type":"string","enum":["flow","device"],"default":"flow"},"notifyWebhookId":{"type":["string","null"],"format":"uuid"},"notifyOnSuccess":{"type":"boolean","default":false},"notifyOnFailure":{"type":"boolean","default":false},"healthMonitoringEnabled":{"type":"boolean","default":true},"selfHealingEnabled":{"type":"boolean"},"selfHealingMaxAttempts":{"type":"integer","minimum":1,"maximum":5,"default":2},"recordingEnabled":{"type":"boolean"},"recordingPolicy":{"type":"object","properties":{"mode":{"$ref":"#/components/schemas/RecordingPolicyMode"}},"required":["mode"],"additionalProperties":false},"delivery":{"type":"object","properties":{"destination":{"type":"string","enum":["mobilerun","one_drive","google_drive"]},"folder":{"type":"string","minLength":1,"maxLength":1024,"description":"not allowed when destination is mobilerun"},"recording":{"type":"object","properties":{"filename":{"type":"string","minLength":1,"maxLength":255}},"required":["filename"],"additionalProperties":false},"screenshots":{"type":"object","properties":{},"additionalProperties":false}},"required":["destination"],"additionalProperties":false},"actions":{"type":"array","items":{"anyOf":[{"$ref":"#/components/schemas/FlowActionInput"},{"$ref":"#/components/schemas/FlowDraftActionInput"}]},"minItems":1}},"required":["name","actions"],"additionalProperties":false}}}},"responses":{"200":{"description":"Flow validation result","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/FlowValidateResponse"}},"required":["data"]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}}},"required":["error","details"]}}}}}}},"/flows":{"post":{"tags":["Flows"],"summary":"Create a flow","operationId":"createFlow","description":"Create a flow that binds a trigger (`triggerId`) to an ordered list of actions, with at least one action required. Optional settings include target `deviceIds`, a cooldown (`cooldownSeconds`/`cooldownScope`), and webhook notifications on success or failure.\n\nSupports an optional `Idempotency-Key` header (1-255 printable ASCII characters). Replays with the same key and an identical body return the original 201; a changed body under the same key returns 422 `idempotency_key_reused`.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFlowBody"}}}},"responses":{"201":{"description":"Flow created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Flow"}},"required":["data"]}}}},"400":{"description":"Template reference validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowTemplateReferenceInvalidError"}}}},"404":{"description":"Flow not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowNotFoundError"}}}},"409":{"description":"The target agent bucket has reached its routine limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowRoutineLimitError"}}}}},"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":255,"pattern":"^[\\x21-\\x7E]{1,255}$","description":"Idempotency-Key: 1-255 printable ASCII characters. Same key with a different request body is a 422 idempotency_key_reused. A retryable in-flight duplicate is a 409 with Retry-After and x-should-retry: true; a terminal duplicate is a 409 with x-should-retry: false. A replay returns the current resource state with Idempotent-Replayed: true.","example":"b3f6a9f0-6f1a-4e9a-9e7a-9c9b6b6a5a3f"},"required":false,"description":"Idempotency-Key: 1-255 printable ASCII characters. Same key with a different request body is a 422 idempotency_key_reused. A retryable in-flight duplicate is a 409 with Retry-After and x-should-retry: true; a terminal duplicate is a 409 with x-should-retry: false. A replay returns the current resource state with Idempotent-Replayed: true.","name":"idempotency-key","in":"header"}]},"get":{"tags":["Flows"],"summary":"List flows","operationId":"listFlows","description":"Return a paginated list of flows. Supports filtering by `agentId` (UUID or `unassigned`; omit for all buckets), `triggerId`, `enabled`, one or more health `status` values (healthy, failing, blocked), `mine` (flows created by the calling actor), `createdBy` (flows created by a given actor id — mutually exclusive with `mine`), plus free-text `search` and ordering.","responses":{"200":{"description":"List flows","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Flow"}},"pagination":{"$ref":"#/components/schemas/Pagination"}},"required":["items","pagination"]}}}}},"parameters":[{"schema":{"type":"integer","exclusiveMinimum":0,"default":1},"required":false,"name":"page","in":"query"},{"schema":{"type":"integer","exclusiveMinimum":0,"default":10},"required":false,"name":"pageSize","in":"query"},{"schema":{"type":"string","format":"uuid"},"required":false,"name":"triggerId","in":"query"},{"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"string","enum":["unassigned"]}],"description":"Agent bucket UUID or unassigned. Omit on list to include every bucket; omit on capacity for unassigned."},"required":false,"description":"Agent bucket UUID or unassigned. Omit on list to include every bucket; omit on capacity for unassigned.","name":"agentId","in":"query"},{"schema":{"type":"string","enum":["true","false"],"description":"Only include flows with this enabled state."},"required":false,"description":"Only include flows with this enabled state.","name":"enabled","in":"query"},{"schema":{"type":"string","enum":["true","false"],"description":"Only include flows created by you."},"required":false,"description":"Only include flows created by you.","name":"mine","in":"query"},{"schema":{"type":"string","format":"uuid"},"required":false,"name":"createdBy","in":"query"},{"schema":{"type":"array","items":{"type":"string","enum":["healthy","failing","blocked"]}},"required":false,"name":"status","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":256},"required":false,"name":"search","in":"query"},{"schema":{"type":"string","enum":["name","createdAt","updatedAt"],"default":"createdAt"},"required":false,"name":"orderBy","in":"query"},{"schema":{"type":"string","enum":["asc","desc"],"default":"desc"},"required":false,"name":"orderByDirection","in":"query"}]}},"/flows/capacity":{"get":{"tags":["Flows"],"summary":"Get routine capacity","operationId":"getFlowCapacity","description":"Returns the environment routine limit and remaining capacity for this owner and agent bucket, counting enabled and disabled non-deleted flows. Omit agentId (or use unassigned) for the unassigned bucket. This is advisory; create and clone enforce admission under a bucket lock.","responses":{"200":{"description":"Routine capacity retrieved","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/FlowCapacity"}},"required":["data"]}}}}},"parameters":[{"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"string","enum":["unassigned"]}],"description":"Agent bucket UUID or unassigned. Omit on list to include every bucket; omit on capacity for unassigned."},"required":false,"description":"Agent bucket UUID or unassigned. Omit on list to include every bucket; omit on capacity for unassigned.","name":"agentId","in":"query"}]}},"/flows/{flowId}":{"get":{"tags":["Flows"],"summary":"Get a flow","operationId":"getFlow","description":"Fetch a single flow by its ID, including its trigger binding, configuration, and current status. Returns 404 if no flow matches.","responses":{"200":{"description":"Flow details","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Flow"}},"required":["data"]}}}},"404":{"description":"Flow not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowNotFoundError"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"flowId","in":"path"}]},"patch":{"tags":["Flows"],"summary":"Update a flow","operationId":"updateFlow","description":"Partially update a flow's settings — name, trigger binding, enabled state, target devices, cooldown, or notifications; all fields are optional. Actions are managed through the flow-actions endpoints, not here. Returns 404 if the flow does not exist.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateFlowBody"}}}},"responses":{"200":{"description":"Flow updated","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Flow"}},"required":["data"]}}}},"400":{"description":"Template reference validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowTemplateReferenceInvalidError"}}}},"404":{"description":"Flow not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowNotFoundError"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"flowId","in":"path"}]},"delete":{"tags":["Flows"],"summary":"Archive a flow","operationId":"deleteFlow","description":"Terminally archive a flow by its ID. Archived flows cannot be restored and are hidden from customer reads. Repeating the request is idempotent for the owner.","responses":{"200":{"description":"Flow archived","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}}}},"404":{"description":"Flow not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowNotFoundError"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"flowId","in":"path"}]}},"/flows/{flowId}/activate":{"post":{"tags":["Flows"],"summary":"Activate a verified flow","operationId":"activateFlow","description":"Activate a disabled flow only when the supplied verification execution succeeded and the flow graph has not changed since verification. Repeating activation is idempotent for an already-enabled flow.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivateFlowBody"}}}},"responses":{"200":{"description":"Flow activated","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Flow"}},"required":["data"]}}}},"404":{"description":"Flow not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowNotFoundError"}}}},"409":{"description":"Verification is missing, not successful, or stale","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowVerificationError"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"flowId","in":"path"}]}},"/flows/{flowId}/clone":{"post":{"tags":["Flows"],"summary":"Clone a flow","operationId":"cloneFlow","description":"Create a copy of an existing flow, including its actions and settings. The optional body can override the new flow's `name` and target `deviceIds`. Returns 404 if the source flow does not exist.\n\nSupports an optional `Idempotency-Key` header (1-255 printable ASCII characters). Replays with the same key and an identical body return the original 201; a changed body under the same key returns 422 `idempotency_key_reused`.","requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CloneFlowBody"}}}},"responses":{"201":{"description":"Flow cloned","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Flow"}},"required":["data"]}}}},"404":{"description":"Flow not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowNotFoundError"}}}},"409":{"description":"The target agent bucket has reached its routine limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowRoutineLimitError"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"flowId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"pattern":"^[\\x21-\\x7E]{1,255}$","description":"Idempotency-Key: 1-255 printable ASCII characters. Same key with a different request body is a 422 idempotency_key_reused. A retryable in-flight duplicate is a 409 with Retry-After and x-should-retry: true; a terminal duplicate is a 409 with x-should-retry: false. A replay returns the current resource state with Idempotent-Replayed: true.","example":"b3f6a9f0-6f1a-4e9a-9e7a-9c9b6b6a5a3f"},"required":false,"description":"Idempotency-Key: 1-255 printable ASCII characters. Same key with a different request body is a 422 idempotency_key_reused. A retryable in-flight duplicate is a 409 with Retry-After and x-should-retry: true; a terminal duplicate is a 409 with x-should-retry: false. A replay returns the current resource state with Idempotent-Replayed: true.","name":"idempotency-key","in":"header"}]}},"/flows/{flowId}/dry-run":{"post":{"tags":["Flows"],"summary":"Dry-run a flow","operationId":"dryRunFlow","description":"Simulate this flow firing without storing events, enqueuing jobs, or consuming cooldown/rate-limit slots.\n\nWorks for every trigger activation type:\n- `event`: validates the payload against the event catalog schema and evaluates the trigger conditions.\n- `custom`: validates the payload against the custom payload schema (conditions do not apply).\n- `schedule`: ignores the payload and reports the next fire time.\n\nThe response reports `wouldFire` — whether the flow would actually run right now — alongside the gates that decide it (enabled, device attached, blocked, cooldown). `rateLimited` is informational and is not folded into `wouldFire`.","requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DryRunFlowBody"}}}},"responses":{"200":{"description":"Dry-run result","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/FlowDryRunResult"}},"required":["data"]}}}},"404":{"description":"Flow not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowNotFoundError"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}}},"required":["error","details"]}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"flowId","in":"path"}]}},"/flows/{flowId}/repairs":{"get":{"tags":["Flows","Agent Workflows"],"summary":"List self-healing repair episodes","operationId":"listWorkflowRepairs","responses":{"200":{"description":"Workflow repair episodes","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/WorkflowRepairEpisode"}}},"required":["data"]}}}},"404":{"description":"Flow not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowNotFoundError"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"flowId","in":"path"}]}},"/flows/{flowId}/actions":{"get":{"tags":["Flows","Flow Actions"],"summary":"List actions for a flow","operationId":"listFlowActions","description":"Return the ordered list of actions attached to a flow, including any nested child actions. Returns 404 if the flow does not exist.","responses":{"200":{"description":"Flow actions","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/FlowAction"}}},"required":["data"]}}}},"404":{"description":"Flow not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowNotFoundError"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"flowId","in":"path"}]},"put":{"tags":["Flows","Flow Actions"],"summary":"Replace all actions for a flow","operationId":"setFlowActions","description":"Replace a flow's entire action list with the supplied set (at least one required). Each action references an `actionId` and a unique `position`, and may include nested `children`, a `nameOverride`, param `overrides`, and a `continueOnError` flag. Returns 404 if the flow does not exist.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetFlowActionsBody"}}}},"responses":{"200":{"description":"Flow actions replaced","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/FlowAction"}}},"required":["data"]}}}},"400":{"description":"Template reference validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowTemplateReferenceInvalidError"}}}},"404":{"description":"Flow not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowNotFoundError"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"flowId","in":"path"}]},"post":{"tags":["Flows","Flow Actions"],"summary":"Add an action to a flow","operationId":"addFlowAction","description":"Append a single action to a flow at the given `position`, optionally nesting it under a `parentFlowActionId` or supplying its own `children`. Supports a `nameOverride`, param `overrides`, and `continueOnError`. Returns 404 if the flow does not exist.\n\nSupports an optional `Idempotency-Key` header (1-255 printable ASCII characters). Replays with the same key and an identical body return the original 201; a changed body under the same key returns 422 `idempotency_key_reused`.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddFlowActionBody"}}}},"responses":{"201":{"description":"Flow action added","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/FlowAction"}},"required":["data"]}}}},"400":{"description":"Template reference validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowTemplateReferenceInvalidError"}}}},"404":{"description":"Flow not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowNotFoundError"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"flowId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"pattern":"^[\\x21-\\x7E]{1,255}$","description":"Idempotency-Key: 1-255 printable ASCII characters. Same key with a different request body is a 422 idempotency_key_reused. A retryable in-flight duplicate is a 409 with Retry-After and x-should-retry: true; a terminal duplicate is a 409 with x-should-retry: false. A replay returns the current resource state with Idempotent-Replayed: true.","example":"b3f6a9f0-6f1a-4e9a-9e7a-9c9b6b6a5a3f"},"required":false,"description":"Idempotency-Key: 1-255 printable ASCII characters. Same key with a different request body is a 422 idempotency_key_reused. A retryable in-flight duplicate is a 409 with Retry-After and x-should-retry: true; a terminal duplicate is a 409 with x-should-retry: false. A replay returns the current resource state with Idempotent-Replayed: true.","name":"idempotency-key","in":"header"}]}},"/flows/{flowId}/delivery-options":{"get":{"tags":["Flows"],"summary":"Get flow delivery options","operationId":"getFlowDeliveryOptions","description":"Return the recording/delivery readiness for a flow (recording mode, whether delivery can include the recording, whether a files.upload action exists, the first direct OneDrive/Google Drive upload step if any) plus, per destination, whether the flow owner has an active connection. Returns 404 if the flow does not exist.","responses":{"200":{"description":"Flow delivery options","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/FlowDeliveryOptions"}},"required":["data"]}}}},"404":{"description":"Flow not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowNotFoundError"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"flowId","in":"path"}]}},"/flows/{flowId}/actions/{flowActionId}":{"delete":{"tags":["Flows","Flow Actions"],"summary":"Remove an action from a flow","operationId":"removeFlowAction","description":"Remove a single action from a flow by its `flowActionId`. Returns 404 if the flow or flow action does not exist.","responses":{"200":{"description":"Flow action removed","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}}}},"400":{"description":"Template reference validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowTemplateReferenceInvalidError"}}}},"404":{"description":"Flow action not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowActionNotFoundError"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"flowId","in":"path"},{"schema":{"type":"string","format":"uuid"},"required":true,"name":"flowActionId","in":"path"}]}},"/flows/{flowId}/unblock":{"post":{"tags":["Flows"],"summary":"Unblock a flow","description":"Clear a flow's blocked status after fixing the underlying issue. Idempotent — safe to call on already-healthy flows.","operationId":"unblockFlow","responses":{"200":{"description":"Flow unblocked (or already healthy)","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Flow"}},"required":["data"]}}}},"400":{"description":"Flow is still broken — preflight failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowStillBrokenError"}}}},"404":{"description":"Flow not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowNotFoundError"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"flowId","in":"path"}]}},"/flows/{flowId}/verify":{"post":{"tags":["Flows"],"summary":"Verify a flow","operationId":"verifyFlow","description":"Run a bound, deduplicated **verification** of this flow on exactly one device as a real run.\n\nUnlike a normal trigger firing, verification:\n- runs a flow that is `enabled` OR `disabled` (an archived flow returns 404);\n- targets one device (`deviceId`, or the single bound device);\n- is idempotent per `invocationId`: a repeat returns the existing run (`deduplicated: true`, HTTP 200) instead of enqueuing another (HTTP 202);\n- never mutates flow health, `lastTriggeredAt`, or the repair loop.\n\nPer-activation payload gate:\n- `custom`: validates the payload against the custom payload schema (422 on failure).\n- `event`: validates the payload against the event catalog schema and evaluates the trigger conditions; a failing gate returns 409 `conditions_not_met` with the dry-run report.\n- `schedule`: the payload is ignored.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyFlowBody"}}}},"responses":{"200":{"description":"Verification run already existed (deduplicated)","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/VerifyFlowResult"}},"required":["data"]}}}},"202":{"description":"Verification run enqueued","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/VerifyFlowResult"}},"required":["data"]}}}},"404":{"description":"Flow not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowNotFoundError"}}}},"409":{"description":"Event trigger conditions (or payload) not met — the run was not enqueued","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowConditionsNotMetError"}}}},"422":{"description":"Device not selectable (`device_required` / `device_not_bound`) or payload validation failed","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/FlowDeviceSelectionError"},{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}}},"required":["code","message"]}]}}}},"429":{"description":"Too Many Requests","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"flowId","in":"path"}]}},"/flows/{flowId}/run":{"post":{"tags":["Flows"],"summary":"Run a flow now","operationId":"runFlow","description":"Immediately enqueue one live execution on every device bound to the flow, regardless of whether its trigger is event-based, custom, or scheduled.\n\nSupports an optional `Idempotency-Key` header (1-255 printable ASCII characters). The run identity is derived from the key, so a retry never starts a second run. Replays with the same key and an identical body return the original status and the original `executionIds`; a changed body under the same key returns 422 `idempotency_key_reused`.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RunFlowBody"}}}},"responses":{"202":{"description":"Flow executions enqueued","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"enqueuedCount":{"type":"integer","minimum":0},"executionIds":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Ids of the executions this run created. An idempotent replay returns the ids of the original run."}},"required":["enqueuedCount","executionIds"]}},"required":["data"]}}}},"404":{"description":"Flow not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowNotFoundError"}}}},"409":{"description":"Flow is blocked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowBlockedError"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}}},"required":["error","details"]}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"flowId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"pattern":"^[\\x21-\\x7E]{1,255}$","description":"Idempotency-Key: 1-255 printable ASCII characters. Same key with a different request body is a 422 idempotency_key_reused. A retryable in-flight duplicate is a 409 with Retry-After and x-should-retry: true; a terminal duplicate is a 409 with x-should-retry: false. A replay returns the current resource state with Idempotent-Replayed: true.","example":"b3f6a9f0-6f1a-4e9a-9e7a-9c9b6b6a5a3f"},"required":false,"description":"Idempotency-Key: 1-255 printable ASCII characters. Same key with a different request body is a 422 idempotency_key_reused. A retryable in-flight duplicate is a 409 with Retry-After and x-should-retry: true; a terminal duplicate is a 409 with x-should-retry: false. A replay returns the current resource state with Idempotent-Replayed: true.","name":"idempotency-key","in":"header"}]}},"/events/dry-run":{"post":{"tags":["Events"],"summary":"Simulate event matching (dry run)","operationId":"dryRunEvent","description":"Simulate an event against all configured flows. Returns which flows would match and what actions would run, without storing the event or enqueuing jobs.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IngestEventBody"}}}},"responses":{"200":{"description":"Dry-run result","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/DryRunResult"}},"required":["data"]}}}}}}},"/events/ingest":{"post":{"tags":["Events"],"summary":"Ingest an event","operationId":"ingestEvent","description":"Ingest an event for trigger evaluation. Returns immediately with 202 Accepted.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IngestEventBody"}}}},"responses":{"202":{"description":"Event accepted for processing","content":{"application/json":{"schema":{"type":"object","properties":{"eventId":{"type":"string","format":"uuid"}},"required":["eventId"]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}}},"required":["error","details"]}}}},"429":{"description":"Too Many Requests","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}}}}},"/executions":{"get":{"tags":["Executions"],"summary":"List flow executions","operationId":"listExecutions","description":"Return a paginated history of flow executions. Supports filtering by `flowId`, `triggerId`, `invocationId` (the client/verify key), `status`, and a `from`/`to` time range, plus free-text `search` and ordering by startedAt, finishedAt, or status.","responses":{"200":{"description":"Execution history","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/FlowExecutionListItem"}},"pagination":{"$ref":"#/components/schemas/Pagination"}},"required":["items","pagination"]}}}}},"parameters":[{"schema":{"type":"integer","exclusiveMinimum":0,"default":1},"required":false,"name":"page","in":"query"},{"schema":{"type":"integer","exclusiveMinimum":0,"default":10},"required":false,"name":"pageSize","in":"query"},{"schema":{"type":"string","format":"uuid"},"required":false,"name":"flowId","in":"query"},{"schema":{"type":"string","format":"uuid"},"required":false,"name":"triggerId","in":"query"},{"schema":{"type":"string","format":"uuid"},"required":false,"name":"invocationId","in":"query"},{"schema":{"type":"string","enum":["pending","running","success","failed","cancelled","skipped","invalid"]},"required":false,"name":"status","in":"query"},{"schema":{"type":["string","null"],"format":"date-time"},"required":false,"name":"from","in":"query"},{"schema":{"type":["string","null"],"format":"date-time"},"required":false,"name":"to","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":256},"required":false,"name":"search","in":"query"},{"schema":{"type":"string","enum":["startedAt","finishedAt","status"],"default":"startedAt"},"required":false,"name":"orderBy","in":"query"},{"schema":{"type":"string","enum":["asc","desc"],"default":"desc"},"required":false,"name":"orderByDirection","in":"query"}]}},"/executions/metrics":{"get":{"tags":["Executions"],"summary":"Get execution metrics","operationId":"getExecutionMetrics","description":"Return aggregate execution metrics — total count, counts by status, average duration, and the last execution time. Can be scoped by `flowId`, `triggerId`, and a `from`/`to` time range.","responses":{"200":{"description":"Execution metrics","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ExecutionMetrics"}},"required":["data"]}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"required":false,"name":"flowId","in":"query"},{"schema":{"type":"string","format":"uuid"},"required":false,"name":"triggerId","in":"query"},{"schema":{"type":["string","null"],"format":"date-time"},"required":false,"name":"from","in":"query"},{"schema":{"type":["string","null"],"format":"date-time"},"required":false,"name":"to","in":"query"}]}},"/executions/{executionId}":{"get":{"tags":["Executions"],"summary":"Get execution details","operationId":"getExecution","description":"Fetch a single flow execution by its ID, including its status, kind, result or error, and start/finish timestamps. Returns 404 if no execution matches.","responses":{"200":{"description":"Execution details","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/FlowExecutionDetail"}},"required":["data"]}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"executionId","in":"path"}]}},"/executions/{executionId}/screenshots/{screenshotId}":{"get":{"tags":["Executions"],"summary":"Redirect to a freshly signed screenshot URL","operationId":"getExecutionScreenshot","description":"Redirects (302) to a freshly signed, time-limited image URL for a screenshot captured during this execution. Owner-gated: 404 if the execution or the screenshot does not belong to the caller.","responses":{"302":{"description":"Redirect to the signed screenshot image URL"},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"executionId","in":"path"},{"schema":{"type":"string","format":"uuid"},"required":true,"name":"screenshotId","in":"path"}]}},"/executions/{executionId}/abort":{"post":{"tags":["Executions"],"summary":"Abort a running or pending execution","description":"Stops the execution between steps and marks it cancelled. Idempotent-ish: already-terminal executions return 409.","operationId":"abortExecution","responses":{"200":{"description":"Execution aborted","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/FlowExecution"}},"required":["data"]}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"executionId","in":"path"}]}},"/timezones":{"get":{"tags":["Timezones"],"summary":"List supported IANA timezones","operationId":"listTimezones","responses":{"200":{"description":"List of supported IANA timezone identifiers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TimezonesResponse"}}}}}}},"/assistant/chat/message":{"post":{"tags":["Chat"],"summary":"Send a single user message","operationId":"chatMessage","description":"Send a single user message. The response format follows the Accept header: `text/event-stream` for SSE, `application/json` for a buffered assistant reply. Interactive HITL requires `Accept: text/event-stream`: the stream can emit a `tool-hitl-approval` event, whose decision must be delivered to `/assistant/chat/permission`. Buffered JSON responses do not provide an interactive HITL continuation contract. `sessionId` targets a concrete active chat. The resolved chat session ID is returned as `chatSessionId` in the JSON body and as the `X-Chat-Session-Id` response header on the SSE response.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","minLength":1},"agent":{"type":"string"},"model":{"type":"string","minLength":1},"sessionId":{"type":"string","format":"uuid"}},"required":["message","sessionId"]}}}},"responses":{"200":{"description":"Streamed events (SSE) or buffered assistant reply (JSON), selected by Accept.","headers":{"X-Chat-Session-Id":{"description":"Resolved chat session ID for this turn (SSE response).","schema":{"type":"string"}}},"content":{"text/event-stream":{"schema":{"type":"string"}},"application/json":{"schema":{"type":"object","properties":{"assistantText":{"type":"string"},"errorText":{"type":"string"},"chatSessionId":{"type":"string","format":"uuid"}},"required":["assistantText","chatSessionId"]}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"402":{"description":"Insufficient credits — caller must top up before retrying","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatInsufficientCreditsError"}}}},"404":{"description":"Unknown or archived sessionId","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}},"409":{"description":"Another prompt is already in-flight for this user, or the assistant is at its parallel-turn limit (retryable), or this turn id was already used / the turn was rejected (`code: conflict`, `x-should-retry: false`)","headers":{"x-should-retry":{"description":"`false` on a terminal duplicate/rejected turn (`code: conflict`) — do not retry. Absent on the retryable busy states (`session_busy`, `parallel_limit_reached`).","schema":{"type":"string","enum":["false"]}}},"content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string","enum":["session_busy","parallel_limit_reached","conflict"]},"message":{"type":"string"},"details":{"type":"object","properties":{"busySessionId":{"type":"string"},"busyTitle":{"type":"string"},"limit":{"type":"integer"},"active":{"type":"integer"}}}},"required":["code","message"]}}}},"410":{"description":"The session can no longer accept messages because its agent environment is no longer active.","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string","enum":["session_machine_replaced"]},"message":{"type":"string"},"details":{"type":"object","properties":{"recovery":{"type":"string","enum":["handoff"]}},"required":["recovery"]}},"required":["code","message","details"]}}}},"413":{"description":"Request body exceeds the 256 KB limit.","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"503":{"description":"Billing service temporarily unavailable; response includes a `Retry-After` header (seconds) indicating when to retry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatBillingUnavailableError"}}}},"504":{"description":"JSON response timed out after 110s; partial assistantText is returned.","content":{"application/json":{"schema":{"type":"object","properties":{"assistantText":{"type":"string"},"errorText":{"type":"string"},"chatSessionId":{"type":"string","format":"uuid"}},"required":["assistantText","chatSessionId"]}}}}}}},"/assistant/chat/messages":{"get":{"tags":["Chat"],"summary":"List messages for a chat session","operationId":"chatMessages","description":"Return the user's chat history for the given session. History remains readable after the session is no longer active.","responses":{"200":{"description":"User chat history","content":{"application/json":{"schema":{"type":"object","properties":{"turnState":{"type":["object","null"],"properties":{"id":{"type":"string","format":"uuid"},"revision":{"type":"integer","minimum":0},"phase":{"type":"string","enum":["created","running","closed","delivered","failed"]},"outcome":{"type":["string","null"]},"startedAt":{"type":"string"},"claimHeld":{"type":"boolean"},"attachable":{"type":"boolean"},"abortRequested":{"type":"boolean"},"reaping":{"type":"boolean"}},"required":["id","revision","phase","outcome","startedAt","claimHeld","attachable","abortRequested","reaping"]},"messages":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"role":{"type":"string","enum":["user","assistant","system"]},"turnId":{"type":["string","null"],"format":"uuid"},"parts":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"}},"required":["type"],"additionalProperties":{}}},"source":{"type":"string","enum":["cloud","telegram","api","workflow","notification"]},"synthetic":{"type":"boolean"},"feedback":{"type":["boolean","null"]},"createdAt":{"type":"string","format":"date-time"},"userId":{"type":["string","null"],"deprecated":true,"description":"Deprecated: use createdBy."},"createdBy":{"type":["string","null"]},"metadata":{"type":"object","properties":{"steer":{"type":"object","properties":{"agentMessageId":{"type":"string"},"targetRole":{"type":"string","enum":["root","worker"]},"state":{"type":"string","enum":["accepted","consumed","dropped"]},"consumedAt":{"type":"string","format":"date-time"},"dropReason":{"type":"string","enum":["turn_closed","aborted"]}},"required":["agentMessageId","targetRole","state"],"description":"Steer user rows appear directly above the collapsed assistant group of their turn, matching live cloud ordering."},"agentMessageId":{"type":"string"},"turnAnchorMessageId":{"type":"string"},"agentSessionId":{"type":"string"},"agent":{"type":"string"}}}},"required":["id","role","parts"]}},"turnActive":{"type":"boolean"},"lastTurnOutcome":{"type":["string","null"]},"truncated":{"type":"boolean"}},"required":["messages","turnActive"]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"sessionId","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":500},"required":false,"name":"limit","in":"query"}]}},"/assistant/chat/abort":{"post":{"tags":["Chat"],"summary":"Abort the named session's in-flight chat turn","operationId":"chatAbort","description":"Abort the in-flight chat turn owned by `sessionId`. Idempotent. A turn owned by a different session is left untouched (204).","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"sessionId":{"type":"string","format":"uuid"},"expectedTurnId":{"type":"string","format":"uuid"}},"required":["sessionId"]}}}},"responses":{"200":{"description":"Abort accepted","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]}},"required":["ok"]}}}},"204":{"description":"Target cancelled before admission or already stopped"},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}}}}},"/assistant/chat/sessions":{"get":{"tags":["Chat"],"summary":"List the user's named chat or agent-workflow sessions","operationId":"chatSessionsList","description":"Default (`kind` absent or `chat`): active named chat sessions, pinned first then most recent activity — `workflowId` must be absent, or the request 400s. `mine=true` (only valid with `kind=chat`) narrows to sessions the caller created. `kind=agent_workflow`: workflow-linked sessions for one workflow (`workflowId` required, or the request 400s), no status filter, newest episode first.","responses":{"200":{"description":"Sessions for the requested kind","content":{"application/json":{"schema":{"type":"object","properties":{"sessions":{"type":"array","items":{"oneOf":[{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"description":{"type":["string","null"]},"agent":{"type":["string","null"]},"status":{"type":"string"},"createdAt":{"type":"string"},"lastActiveAt":{"type":"string"},"turnActive":{"type":"boolean"},"turnStartedAt":{"type":["string","null"]},"pinned":{"type":"boolean"},"costCents":{"type":"number"},"costUsd":{"type":"number"},"creditsUsed":{"type":["number","null"]},"peakPromptTokens":{"type":["number","null"]},"basePromptTokens":{"type":["number","null"]},"contextExhaustedAt":{"type":["string","null"]},"createdBy":{"type":["string","null"]},"promptStatus":{"type":"string","enum":["ready","machine_replaced"]},"kind":{"type":"string","enum":["chat"]},"workflowId":{"type":"null"},"sourceExecutionId":{"type":"null"},"episode":{"type":"integer","minimum":1}},"required":["id","title","description","agent","status","createdAt","lastActiveAt","turnActive","turnStartedAt","pinned","costCents","costUsd","creditsUsed","peakPromptTokens","basePromptTokens","contextExhaustedAt","promptStatus","kind","workflowId","sourceExecutionId","episode"]},{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"description":{"type":["string","null"]},"agent":{"type":["string","null"]},"status":{"type":"string"},"createdAt":{"type":"string"},"lastActiveAt":{"type":"string"},"turnActive":{"type":"boolean"},"turnStartedAt":{"type":["string","null"]},"pinned":{"type":"boolean"},"costCents":{"type":"number"},"costUsd":{"type":"number"},"creditsUsed":{"type":["number","null"]},"peakPromptTokens":{"type":["number","null"]},"basePromptTokens":{"type":["number","null"]},"contextExhaustedAt":{"type":["string","null"]},"createdBy":{"type":["string","null"]},"promptStatus":{"type":"string","enum":["ready","machine_replaced"]},"kind":{"type":"string","enum":["agent_workflow"]},"workflowId":{"type":"string"},"sourceExecutionId":{"type":"string"},"episode":{"type":"integer","minimum":1}},"required":["id","title","description","agent","status","createdAt","lastActiveAt","turnActive","turnStartedAt","pinned","costCents","costUsd","creditsUsed","peakPromptTokens","basePromptTokens","contextExhaustedAt","promptStatus","kind","workflowId","sourceExecutionId","episode"]}]}}},"required":["sessions"]}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}}},"parameters":[{"schema":{"type":"string","enum":["chat","agent_workflow"]},"required":false,"name":"kind","in":"query"},{"schema":{"type":"string","minLength":1},"required":false,"name":"workflowId","in":"query"},{"schema":{"type":"string","enum":["true","false"]},"required":false,"name":"mine","in":"query"}]},"post":{"tags":["Chat"],"summary":"Create a named chat session","operationId":"chatSessionsCreate","description":"Creates a titled agent session. Setup may occur on the first prompt. Idempotent via the `Idempotency-Key` header — a duplicate submit by the same authenticated caller within the 24-hour idempotency window returns the already-created session instead of a second one. Reusing the same key with a different request body is a 422 `idempotency_key_reused`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":120},"description":{"type":"string","maxLength":280},"agent":{"type":"string","minLength":1,"maxLength":64}},"required":["title"]}}}},"responses":{"200":{"description":"Created session","content":{"application/json":{"schema":{"type":"object","properties":{"session":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"description":{"type":["string","null"]},"agent":{"type":["string","null"]},"status":{"type":"string"},"createdAt":{"type":"string"},"lastActiveAt":{"type":"string"},"turnActive":{"type":"boolean"},"turnStartedAt":{"type":["string","null"]},"pinned":{"type":"boolean"},"costCents":{"type":"number"},"costUsd":{"type":"number"},"creditsUsed":{"type":["number","null"]},"peakPromptTokens":{"type":["number","null"]},"basePromptTokens":{"type":["number","null"]},"contextExhaustedAt":{"type":["string","null"]},"createdBy":{"type":["string","null"]},"promptStatus":{"type":"string","enum":["ready","machine_replaced"]}},"required":["id","title","description","agent","status","createdAt","lastActiveAt","turnActive","turnStartedAt","pinned","costCents","costUsd","creditsUsed","peakPromptTokens","basePromptTokens","contextExhaustedAt","promptStatus"]}},"required":["session"]}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"422":{"description":"Error 422","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string","enum":["idempotency_key_reused"]},"message":{"type":"string"},"traceId":{"type":"string"},"retryAfterSeconds":{"type":"number"}},"required":["code","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}}},"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":255,"pattern":"^[\\x21-\\x7E]{1,255}$","description":"Idempotency-Key: 1-255 printable ASCII characters. Same key with a different request body is a 422 idempotency_key_reused. A retryable in-flight duplicate is a 409 with Retry-After and x-should-retry: true; a terminal duplicate is a 409 with x-should-retry: false. A replay returns the current resource state with Idempotent-Replayed: true.","example":"b3f6a9f0-6f1a-4e9a-9e7a-9c9b6b6a5a3f"},"required":false,"description":"Idempotency-Key: 1-255 printable ASCII characters. Same key with a different request body is a 422 idempotency_key_reused. A retryable in-flight duplicate is a 409 with Retry-After and x-should-retry: true; a terminal duplicate is a 409 with x-should-retry: false. A replay returns the current resource state with Idempotent-Replayed: true.","name":"idempotency-key","in":"header"}]}},"/assistant/chat/sessions/{id}":{"patch":{"tags":["Chat"],"summary":"Rename, archive, or pin a named chat session","operationId":"chatSessionsUpdate","description":"Rename, change status, and/or pin. Title updates apply best-effort. Archiving always clears the pinned flag. `title` is rejected with 409 `code: \"session_title_managed_by_workflow\"` when this chat is bound to a workflow — a bound chat's title is managed by the workflow. Other fields (description, status, pinned) remain updateable; archiving a bound chat stays allowed.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":120},"description":{"type":["string","null"],"maxLength":280},"status":{"type":"string","enum":["active","archived"]},"pinned":{"type":"boolean"}},"additionalProperties":false}}}},"responses":{"200":{"description":"Updated session","content":{"application/json":{"schema":{"type":"object","properties":{"session":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"description":{"type":["string","null"]},"agent":{"type":["string","null"]},"status":{"type":"string"},"createdAt":{"type":"string"},"lastActiveAt":{"type":"string"},"turnActive":{"type":"boolean"},"turnStartedAt":{"type":["string","null"]},"pinned":{"type":"boolean"},"costCents":{"type":"number"},"costUsd":{"type":"number"},"creditsUsed":{"type":["number","null"]},"peakPromptTokens":{"type":["number","null"]},"basePromptTokens":{"type":["number","null"]},"contextExhaustedAt":{"type":["string","null"]},"createdBy":{"type":["string","null"]},"promptStatus":{"type":"string","enum":["ready","machine_replaced"]}},"required":["id","title","description","agent","status","createdAt","lastActiveAt","turnActive","turnStartedAt","pinned","costCents","costUsd","creditsUsed","peakPromptTokens","basePromptTokens","contextExhaustedAt","promptStatus"]}},"required":["session"]}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string","enum":["conflict","session_title_managed_by_workflow"]},"message":{"type":"string"}},"required":["code","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}]}},"/assistant/chat/stream":{"get":{"tags":["Chat"],"summary":"Re-attach to the active turn stream","operationId":"chatStream","description":"Reconnect to the in-flight turn stream. Replays buffered events from the start of the active turn, then continues live until the turn finishes. Responds 204 when no active turn exists for the requested session. Upstream streaming failures return a retryable 503 with `Retry-After`. Resume is best-effort. Does not start an inactive session.","responses":{"200":{"description":"Streamed events (SSE), replayed from turn start","content":{"text/event-stream":{"schema":{"type":"string"}}}},"204":{"description":"No active turn to re-attach to"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"503":{"description":"The active turn exists, but its upstream stream is temporarily unavailable","headers":{"Retry-After":{"description":"Seconds to wait before retrying the stream attach","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatUpstreamUnavailableError"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"sessionId","in":"query"}]}},"/assistant/chat/permission":{"post":{"tags":["Chat"],"summary":"Deliver a HITL approval/rejection to the user's active chat session","operationId":"chatPermission","description":"Deliver a HITL approval/rejection for an in-flight turn. Interactive HITL clients must start the turn with `Accept: text/event-stream`, wait for a `tool-hitl-approval` event, and send its `permissionId` here at `/assistant/chat/permission`. Do not submit approval as free-form user text or as `confirmed: true`. For `devices.reset`, only `once` and `reject` are allowed; the generic `always` response is rejected with HTTP 400.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"permissionId":{"type":"string","minLength":1},"response":{"type":"string","enum":["once","always","reject"]}},"required":["permissionId","response"]}}}},"responses":{"200":{"description":"Permission delivered","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]}},"required":["ok"]}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}}}}},"/assistant/chat/question":{"post":{"tags":["Chat"],"summary":"Deliver a question answer to the user's active chat session","operationId":"chatQuestionReply","description":"Deliver the user's answers to the agent's pending question for an in-flight turn. Idempotent via the `idempotency-key` header.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"questionId":{"type":"string","minLength":1},"answers":{"type":"array","items":{"type":"array","items":{"anyOf":[{"type":"object","properties":{"label":{"type":"string","minLength":1}},"required":["label"],"additionalProperties":false},{"type":"object","properties":{"custom":{"type":"string","minLength":1}},"required":["custom"],"additionalProperties":false},{"type":"object","properties":{"label":{"type":"string","minLength":1},"custom":{"type":"string","minLength":1}},"required":["label","custom"],"additionalProperties":false}]},"minItems":1},"minItems":1}},"required":["questionId","answers"]}}}},"responses":{"200":{"description":"Answer delivered","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]}},"required":["ok"]}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"413":{"description":"Request body exceeds the 256 KB cap for /chat/question","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"502":{"description":"Failed to deliver the answer upstream","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}}}}},"/assistant/chat/question/reject":{"post":{"tags":["Chat"],"summary":"Dismiss an outstanding question without answering","operationId":"chatQuestionReject","description":"Dismiss the agent's pending question. Already-resolved questions return 200 (no-op) so multi-tab dismiss stays idempotent.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"questionId":{"type":"string","minLength":1}},"required":["questionId"]}}}},"responses":{"200":{"description":"Dismiss delivered (or no-op if the question was already resolved)","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]}},"required":["ok"]}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"502":{"description":"Failed to dismiss the question upstream","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}}}}},"/agents/files/upload-url":{"post":{"tags":["Files"],"summary":"Mint a presigned PUT URL for a user file upload","operationId":"filesUploadUrl","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"filename":{"type":"string","minLength":1,"maxLength":255},"mimeType":{"type":"string","minLength":1},"sizeBytes":{"type":"integer","exclusiveMinimum":0},"zone":{"type":"string","enum":["user","skills"]}},"required":["filename","mimeType","sizeBytes"]}}}},"responses":{"200":{"description":"Presigned PUT URL and fileId","content":{"application/json":{"schema":{"type":"object","properties":{"fileId":{"type":"string","format":"uuid"},"putUrl":{"type":"string","format":"uri"},"expiresAt":{"type":"string","format":"date-time"}},"required":["fileId","putUrl","expiresAt"]}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"402":{"description":"Storage limit reached","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string","enum":["storage_limit_reached"]},"message":{"type":"string"},"details":{"type":"object","properties":{"reason":{"type":"string","enum":["storage_limit"]},"usedBytes":{"type":"number"},"quotaBytes":{"type":["number","null"]},"requiredBytes":{"type":"number"}},"required":["reason","usedBytes","quotaBytes","requiredBytes"]}},"required":["code","message","details"]}}}},"422":{"description":"Error 422","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string","enum":["idempotency_key_reused"]},"message":{"type":"string"},"traceId":{"type":"string"},"retryAfterSeconds":{"type":"number"}},"required":["code","message"]}}}},"429":{"description":"Too many pending (unconfirmed) uploads","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string","enum":["pending_uploads_limit"]},"message":{"type":"string"}},"required":["code","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"503":{"description":"Storage check temporarily unavailable","headers":{"Retry-After":{"description":"Seconds to wait before retrying. Always present on this response.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string","enum":["storage_check_unavailable"]},"message":{"type":"string"},"retryAfterSeconds":{"type":"number","enum":[30]}},"required":["code","message"]}}}}},"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":255,"pattern":"^[\\x21-\\x7E]{1,255}$","description":"Idempotency-Key: 1-255 printable ASCII characters. Same key with a different request body is a 422 idempotency_key_reused. A retryable in-flight duplicate is a 409 with Retry-After and x-should-retry: true; a terminal duplicate is a 409 with x-should-retry: false. A replay returns the current resource state with Idempotent-Replayed: true.","example":"b3f6a9f0-6f1a-4e9a-9e7a-9c9b6b6a5a3f"},"required":false,"description":"Idempotency-Key: 1-255 printable ASCII characters. Same key with a different request body is a 422 idempotency_key_reused. A retryable in-flight duplicate is a 409 with Retry-After and x-should-retry: true; a terminal duplicate is a 409 with x-should-retry: false. A replay returns the current resource state with Idempotent-Replayed: true.","name":"idempotency-key","in":"header"}]}},"/agents/files/{fileId}/confirm":{"post":{"tags":["Files"],"summary":"Confirm a file upload by server-side HEAD validation","operationId":"filesConfirm","responses":{"200":{"description":"Upload confirmed and validated","content":{"application/json":{"schema":{"type":"object","properties":{"fileId":{"type":"string","format":"uuid"},"filename":{"type":"string"},"displayName":{"type":["string","null"]},"mimeType":{"type":"string"},"sizeBytes":{"type":"number"},"zone":{"type":"string","enum":["user","agent","workflow","skills"]},"enabled":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"createdBy":{"type":"string","enum":["user","agent","workflow"]},"collectionStatus":{"anyOf":[{"type":"object","properties":{"version":{"type":"number","enum":[1]},"completeness":{"type":"string","enum":["complete","partial","none","unknown"]},"coverage":{"type":"string","enum":["exhaustive","bounded","unknown"]},"endReached":{"type":"boolean"},"resumable":{"type":"boolean"},"records":{"type":"object","properties":{"reported":{"type":"integer","minimum":0},"unit":{"type":"string"}},"required":["reported","unit"],"additionalProperties":false}},"required":["version","completeness","coverage","endReached","resumable","records"],"additionalProperties":false},{"type":"object","properties":{"version":{"type":"number","enum":[1]},"completeness":{"type":"string","enum":["unknown"]},"coverage":{"type":"string","enum":["unknown"]},"endReached":{"type":"boolean","enum":[false]},"resumable":{"type":"boolean","enum":[false]}},"required":["version","completeness","coverage","endReached","resumable"],"additionalProperties":false}]},"state":{"type":"string","enum":["ready"]},"actualSizeBytes":{"type":"number"}},"required":["fileId","filename","displayName","mimeType","sizeBytes","zone","enabled","createdAt","createdBy","state","actualSizeBytes"]}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"410":{"description":"Upload reservation expired; request a new upload URL.","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string","enum":["expired"]},"message":{"type":"string"},"details":{"type":"object","properties":{"fileId":{"type":"string","format":"uuid"}},"required":["fileId"]}},"required":["code","message","details"]}}}},"422":{"description":"The uploaded file is missing or does not match the size or type declared when the upload URL was requested.","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string","enum":["confirm_failed"]},"message":{"type":"string"},"details":{"type":"object","properties":{"fileId":{"type":"string","format":"uuid"},"reason":{"type":"string","enum":["missing","size_mismatch","mime_mismatch"]}},"required":["fileId","reason"]}},"required":["code","message","details"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"fileId","in":"path"}]}},"/agents/files/{fileId}/download":{"get":{"tags":["Files"],"summary":"Download an owned file","description":"Redirects to a short-lived presigned download URL. Missing, non-ready, and files owned by another tenant all return the same 404 response.","operationId":"filesDownload","responses":{"302":{"description":"Redirect to a short-lived presigned download URL","headers":{"Location":{"schema":{"type":"string","format":"uri"}},"Content-Disposition":{"schema":{"type":"string"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"fileId","in":"path"}]}},"/agents/files":{"get":{"tags":["Files"],"summary":"List the user's ready files, optionally filtered by zone","operationId":"filesList","responses":{"200":{"description":"User's ready files","content":{"application/json":{"schema":{"type":"object","properties":{"files":{"type":"array","items":{"type":"object","properties":{"fileId":{"type":"string","format":"uuid"},"filename":{"type":"string"},"displayName":{"type":["string","null"]},"mimeType":{"type":"string"},"sizeBytes":{"type":"number"},"zone":{"type":"string","enum":["user","agent","workflow","skills"]},"enabled":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"createdBy":{"type":"string","enum":["user","agent","workflow"]},"collectionStatus":{"anyOf":[{"type":"object","properties":{"version":{"type":"number","enum":[1]},"completeness":{"type":"string","enum":["complete","partial","none","unknown"]},"coverage":{"type":"string","enum":["exhaustive","bounded","unknown"]},"endReached":{"type":"boolean"},"resumable":{"type":"boolean"},"records":{"type":"object","properties":{"reported":{"type":"integer","minimum":0},"unit":{"type":"string"}},"required":["reported","unit"],"additionalProperties":false}},"required":["version","completeness","coverage","endReached","resumable","records"],"additionalProperties":false},{"type":"object","properties":{"version":{"type":"number","enum":[1]},"completeness":{"type":"string","enum":["unknown"]},"coverage":{"type":"string","enum":["unknown"]},"endReached":{"type":"boolean","enum":[false]},"resumable":{"type":"boolean","enum":[false]}},"required":["version","completeness","coverage","endReached","resumable"],"additionalProperties":false}]}},"required":["fileId","filename","displayName","mimeType","sizeBytes","zone","enabled","createdAt","createdBy"]}},"quota":{"type":"object","properties":{"usedBytes":{"type":"integer","minimum":0},"includedBytes":{"type":["integer","null"],"minimum":0},"maxBytes":{"type":["integer","null"],"minimum":0},"overageAllowed":{"type":"boolean"}},"required":["usedBytes","includedBytes","maxBytes","overageAllowed"]}},"required":["files","quota"]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"503":{"description":"Storage check temporarily unavailable","headers":{"Retry-After":{"description":"Seconds to wait before retrying. Always present on this response.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string","enum":["storage_check_unavailable"]},"message":{"type":"string"},"retryAfterSeconds":{"type":"number","enum":[30]}},"required":["code","message"]}}}}},"parameters":[{"schema":{"type":"string","enum":["user","agent","workflow","skills"]},"required":false,"name":"zone","in":"query"}]}},"/agents/files/{fileId}":{"patch":{"tags":["Files"],"summary":"Update file metadata (skills zone only)","operationId":"filesUpdate","description":"Partial update of `displayName` and/or `enabled`. Only files with `zone=skills` are mutable; other zones return 422 `unsupported_zone`.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"displayName":{"type":["string","null"],"minLength":1,"maxLength":255},"enabled":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Updated file","content":{"application/json":{"schema":{"type":"object","properties":{"fileId":{"type":"string","format":"uuid"},"filename":{"type":"string"},"displayName":{"type":["string","null"]},"mimeType":{"type":"string"},"sizeBytes":{"type":"number"},"zone":{"type":"string","enum":["user","agent","workflow","skills"]},"enabled":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"createdBy":{"type":"string","enum":["user","agent","workflow"]},"collectionStatus":{"anyOf":[{"type":"object","properties":{"version":{"type":"number","enum":[1]},"completeness":{"type":"string","enum":["complete","partial","none","unknown"]},"coverage":{"type":"string","enum":["exhaustive","bounded","unknown"]},"endReached":{"type":"boolean"},"resumable":{"type":"boolean"},"records":{"type":"object","properties":{"reported":{"type":"integer","minimum":0},"unit":{"type":"string"}},"required":["reported","unit"],"additionalProperties":false}},"required":["version","completeness","coverage","endReached","resumable","records"],"additionalProperties":false},{"type":"object","properties":{"version":{"type":"number","enum":[1]},"completeness":{"type":"string","enum":["unknown"]},"coverage":{"type":"string","enum":["unknown"]},"endReached":{"type":"boolean","enum":[false]},"resumable":{"type":"boolean","enum":[false]}},"required":["version","completeness","coverage","endReached","resumable"],"additionalProperties":false}]}},"required":["fileId","filename","displayName","mimeType","sizeBytes","zone","enabled","createdAt","createdBy"]}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"422":{"description":"Zone is not mutable","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string","enum":["unsupported_zone"]},"message":{"type":"string"}},"required":["code","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"fileId","in":"path"}]},"delete":{"tags":["Files"],"summary":"Hard-delete a file","operationId":"filesDelete","responses":{"200":{"description":"Deleted","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]}},"required":["ok"]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"fileId","in":"path"}]}},"/agents/files/{fileId}/pending":{"delete":{"tags":["Files"],"summary":"Cancel a pending upload (transitions to expired, deletes the underlying object)","description":"Soft-cancels an in-flight upload before confirm. Only acts on `pending` uploads — refuses to touch `ready` files, so confirmed files are never removed. Idempotent: `{ cancelled: false }` if the file exists but is no longer pending.","operationId":"filesCancelPending","responses":{"200":{"description":"Cancel result","content":{"application/json":{"schema":{"type":"object","properties":{"cancelled":{"type":"boolean"}},"required":["cancelled"]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"fileId","in":"path"}]}},"/connect/countries":{"get":{"description":"Lookup of countries that can be selected when creating a proxy. Each country lists the proxy types available there; without a ?type filter, every covered country is returned.","operationId":"ListCountries","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CountryList"}}},"description":"Available countries."}},"summary":"List available countries","tags":["Countries"],"parameters":[{"$ref":"#/components/parameters/Page"},{"$ref":"#/components/parameters/PageSize"},{"description":"Filter to countries offering this proxy type.","in":"query","name":"type","schema":{"$ref":"#/components/schemas/ProxyType"}}]}},"/connect/proxies":{"get":{"description":"Returns proxies owned by the caller. Credentials are omitted from the list.","operationId":"ListConnectProxies","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProxyList"}}},"description":"The caller's proxies, without credentials."},"401":{"$ref":"#/components/responses/Unauthorized"}},"summary":"List proxies","tags":["Connect Proxies"],"parameters":[{"$ref":"#/components/parameters/Page"},{"$ref":"#/components/parameters/PageSize"},{"description":"Filter to proxies in this country (ISO 3166-1 alpha-2, lowercase).","in":"query","name":"country","schema":{"format":"country-code","type":"string"}}]},"post":{"description":"Provisions a proxy of the requested type for the caller in the selected country.","operationId":"CreateConnectProxy","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProxyRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProxyWithSecret"}}},"description":"The created proxy, including its password."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"409":{"$ref":"#/components/responses/Conflict"}},"summary":"Create a proxy","tags":["Connect Proxies"],"parameters":[{"description":"Optional idempotency key, unique per owner (1-128 characters after trimming; surrounding whitespace is ignored). Reusing a key returns the originally created proxy with its original credentials, regardless of changed request parameters.","in":"header","name":"Idempotency-Key","schema":{"type":"string"}}]}},"/connect/proxies/{id}":{"delete":{"description":"Deletes the proxy identified by the path ID and releases its provisioning. Returns 404 if no such proxy exists for the caller.","operationId":"DeleteConnectProxy","responses":{"204":{"description":"Proxy deleted."},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"Delete a proxy","tags":["Connect Proxies"],"parameters":[{"$ref":"#/components/parameters/ProxyID"}]},"get":{"description":"Returns the proxy identified by the path ID. The response includes the proxy's password.","operationId":"GetConnectProxy","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProxyWithSecret"}}},"description":"The proxy, including its password."},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"Get proxy by ID","tags":["Connect Proxies"],"parameters":[{"$ref":"#/components/parameters/ProxyID"}]},"patch":{"description":"Renames the proxy identified by the path ID.","operationId":"UpdateConnectProxy","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProxyRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Proxy"}}},"description":"The updated proxy."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"Update a proxy","tags":["Connect Proxies"],"parameters":[{"$ref":"#/components/parameters/ProxyID"}]}},"/connect/proxies/{id}/checkout":{"post":{"description":"Refreshes a pending dedicated proxy's checkout on explicit payment intent. Already-paid proxies (provisioning, active, or cancelling) return their current status without a payment URL. An expired checkout requires a new purchase.","operationId":"CheckoutConnectProxy","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProxyCheckout"}}},"description":"The current payment status and checkout URL, if unpaid."},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProxyCheckoutConflict"}}},"description":"The checkout expired or the proxy is no longer pending payment."}},"summary":"Get a payable checkout for a pending proxy","tags":["Connect Proxies"],"parameters":[{"$ref":"#/components/parameters/ProxyID"}]}},"/connect/proxies/{id}/connections":{"get":{"description":"Returns the connection history recorded for this proxy, one item per connection (aggregated across the connection's lifetime). Supports filtering on every property plus ordering and pagination. Returns 503 when connection history is temporarily unavailable.","operationId":"ListProxyConnections","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectionList"}}},"description":"A page of connections."},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"List Proxy Connections","tags":["Connect Proxies","Connections"],"parameters":[{"$ref":"#/components/parameters/ProxyID"},{"$ref":"#/components/parameters/Page"},{"$ref":"#/components/parameters/PageSize"},{"$ref":"#/components/parameters/ConnSessionId"},{"$ref":"#/components/parameters/ConnUserId"},{"$ref":"#/components/parameters/ConnDstHost"},{"$ref":"#/components/parameters/ConnDstPort"},{"$ref":"#/components/parameters/ConnProtocol"},{"$ref":"#/components/parameters/ConnProvider"},{"$ref":"#/components/parameters/ConnCountry"},{"$ref":"#/components/parameters/ConnCloseReason"},{"$ref":"#/components/parameters/ConnStatus"},{"$ref":"#/components/parameters/ConnStartedAfter"},{"$ref":"#/components/parameters/ConnStartedBefore"},{"$ref":"#/components/parameters/ConnEndedAfter"},{"$ref":"#/components/parameters/ConnEndedBefore"},{"$ref":"#/components/parameters/ConnMinBytesIn"},{"$ref":"#/components/parameters/ConnMaxBytesIn"},{"$ref":"#/components/parameters/ConnMinBytesOut"},{"$ref":"#/components/parameters/ConnMaxBytesOut"},{"$ref":"#/components/parameters/ConnMinTotalBytes"},{"$ref":"#/components/parameters/ConnMaxTotalBytes"},{"$ref":"#/components/parameters/ConnMinDurationMs"},{"$ref":"#/components/parameters/ConnMaxDurationMs"},{"$ref":"#/components/parameters/ConnOrderBy"},{"$ref":"#/components/parameters/ConnOrder"}]}},"/connect/proxies/{id}/ensure-healthy":{"post":{"description":"Checks right now that the proxy's upstream accepts a connection through its current session. If the upstream refuses the session and the proxy is a rotating (sticky-session) proxy, the proxy is moved onto a fresh session that has been checked to work; its credentials and country stay the same, its exit IP changes. Intended for callers that are about to depend on the proxy (e.g. while provisioning a phone). After `rotated`, the gateway uses the new session within about 30 seconds. A `refused` or `unreachable` result is not an error: the response describes the proxy's state.","operationId":"EnsureProxyHealthy","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProxyHealth"}}},"description":"The result of the check."},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}},"summary":"Ensure the proxy's upstream session works","tags":["Connect Proxies"],"parameters":[{"$ref":"#/components/parameters/ProxyID"}]}},"/connect/proxies/{id}/ping":{"get":{"description":"Returns the most recent cached network-latency measurement for the proxy, sampled periodically by connecting through the proxy to a fixed target. `latency` is null when no measurement is available yet (e.g. the proxy is not active, or it has not been sampled since coming online).","operationId":"PingProxy","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProxyLatency"}}},"description":"The proxy's latest latency reading."},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"Latency check","tags":["Connect Proxies"],"parameters":[{"$ref":"#/components/parameters/ProxyID"}]}},"/connect/users":{"get":{"description":"Returns SOCKS5 users owned by the caller. Passwords are omitted from the list.","operationId":"ListUsers","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserList"}}},"description":"The caller's SOCKS5 users, without credentials."},"401":{"$ref":"#/components/responses/Unauthorized"}},"summary":"List SOCKS5 users","tags":["Users"],"parameters":[{"$ref":"#/components/parameters/Page"},{"$ref":"#/components/parameters/PageSize"},{"description":"Filter to users bound to this proxy. Users not bound to it (including unbound users) are excluded.","in":"query","name":"proxyId","schema":{"format":"uuid","type":"string"}}]},"post":{"description":"Creates a SOCKS5 credential, optionally bound to a proxy for dedicated routing. Username and password are generated when omitted.","operationId":"CreateUser","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUserRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserWithSecret"}}},"description":"The created user, including its password."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"}},"summary":"Create a SOCKS5 user","tags":["Users"]}},"/connect/users/{id}":{"delete":{"description":"Deletes the SOCKS5 user identified by the path ID, revoking its credentials and any proxy binding. Returns 404 if no such user exists for the caller.","operationId":"DeleteUser","responses":{"204":{"description":"User deleted."},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"Delete a SOCKS5 user","tags":["Users"],"parameters":[{"$ref":"#/components/parameters/UserID"}]},"get":{"description":"Returns the SOCKS5 user identified by the path ID. The response includes the user's password.","operationId":"GetUser","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserWithSecret"}}},"description":"The user, including its password."},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"Get a SOCKS5 user by ID","tags":["Users"],"parameters":[{"$ref":"#/components/parameters/UserID"}]},"patch":{"description":"Rebind the user to a different proxy (or detach it by passing null).","operationId":"UpdateUser","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUserRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/User"}}},"description":"The updated user."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"Update a SOCKS5 user","tags":["Users"],"parameters":[{"$ref":"#/components/parameters/UserID"}]}},"/connect/users/{id}/connections":{"get":{"description":"Returns the connection history recorded for this user, one item per connection (aggregated across the connection's lifetime). Supports filtering on every property plus ordering and pagination. Returns 503 when connection history is temporarily unavailable.","operationId":"ListUserConnections","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectionList"}}},"description":"A page of connections."},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"List connections by SOCKS5 user","tags":["Users","Connections"],"parameters":[{"$ref":"#/components/parameters/UserID"},{"$ref":"#/components/parameters/Page"},{"$ref":"#/components/parameters/PageSize"},{"$ref":"#/components/parameters/ConnSessionId"},{"$ref":"#/components/parameters/ConnProxyId"},{"$ref":"#/components/parameters/ConnDstHost"},{"$ref":"#/components/parameters/ConnDstPort"},{"$ref":"#/components/parameters/ConnProtocol"},{"$ref":"#/components/parameters/ConnProvider"},{"$ref":"#/components/parameters/ConnCountry"},{"$ref":"#/components/parameters/ConnCloseReason"},{"$ref":"#/components/parameters/ConnStatus"},{"$ref":"#/components/parameters/ConnStartedAfter"},{"$ref":"#/components/parameters/ConnStartedBefore"},{"$ref":"#/components/parameters/ConnEndedAfter"},{"$ref":"#/components/parameters/ConnEndedBefore"},{"$ref":"#/components/parameters/ConnMinBytesIn"},{"$ref":"#/components/parameters/ConnMaxBytesIn"},{"$ref":"#/components/parameters/ConnMinBytesOut"},{"$ref":"#/components/parameters/ConnMaxBytesOut"},{"$ref":"#/components/parameters/ConnMinTotalBytes"},{"$ref":"#/components/parameters/ConnMaxTotalBytes"},{"$ref":"#/components/parameters/ConnMinDurationMs"},{"$ref":"#/components/parameters/ConnMaxDurationMs"},{"$ref":"#/components/parameters/ConnOrderBy"},{"$ref":"#/components/parameters/ConnOrder"}]}},"/webhooks/deliveries":{"get":{"tags":["Webhook Deliveries"],"summary":"List deliveries across all your webhooks","description":"Returns a paginated feed of webhook deliveries across all of your subscriptions, with the originating endpoint URL included on each record. Results can be filtered by delivery status (pending, success, skipped, or dead), by a `since` timestamp, by `eventId` (exact match against the originating event id), and/or by endpoint delivery `kind`.","operationId":"listAllWebhookDeliveries","responses":{"200":{"description":"Deliveries across all of your endpoints","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"endpointId":{"type":"string","format":"uuid"},"eventId":{"type":"string"},"eventType":{"type":"string"},"source":{"type":"string"},"status":{"type":"string","enum":["pending","success","skipped","dead"]},"attempts":{"type":"number"},"lastStatusCode":{"type":["number","null"]},"lastError":{"type":["string","null"]},"durationMs":{"type":["number","null"]},"isTest":{"type":"boolean"},"occurredAt":{"type":"string"},"createdAt":{"type":"string"},"completedAt":{"type":["string","null"]},"createdBy":{"type":["string","null"],"format":"uuid","description":"Id of the parent endpoint's creator. Null when the endpoint row is gone or its creator was never recorded."},"endpointKind":{"type":"string","enum":["http","integration"]},"endpointUrl":{"type":["string","null"],"description":"Delivery URL of the parent webhook; null for `integration` webhooks."},"endpointLabel":{"type":["string","null"],"description":"Integration target label of the parent webhook (e.g. `#ops`); null for `http` webhooks."}},"required":["id","endpointId","eventId","eventType","source","status","attempts","lastStatusCode","lastError","durationMs","isTest","occurredAt","createdAt","completedAt","createdBy","endpointKind","endpointUrl","endpointLabel"]}},"pagination":{"$ref":"#/components/schemas/Pagination"}},"required":["items","pagination"]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookInternalServerError"}}}}},"parameters":[{"schema":{"type":"integer","exclusiveMinimum":0,"default":1},"required":false,"name":"page","in":"query"},{"schema":{"type":"integer","exclusiveMinimum":0,"maximum":100,"default":20},"required":false,"name":"pageSize","in":"query"},{"schema":{"type":"string","enum":["pending","success","skipped","dead"]},"required":false,"name":"status","in":"query"},{"schema":{"type":"string","format":"date-time"},"required":false,"name":"since","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":256,"description":"Exact text match against the originating event id."},"required":false,"description":"Exact text match against the originating event id.","name":"eventId","in":"query"},{"schema":{"type":"string","enum":["http","integration"],"description":"Only include deliveries to endpoints of this kind."},"required":false,"description":"Only include deliveries to endpoints of this kind.","name":"kind","in":"query"}]}},"/webhooks/deliveries/stats":{"get":{"tags":["Webhook Deliveries"],"summary":"Get delivery statistics","description":"Returns aggregate delivery statistics across all of your webhooks, including the total count, a breakdown by status (pending, success, skipped, dead), and the overall success rate. Optional `since` and endpoint delivery `kind` filters narrow the reporting window.","operationId":"getWebhookDeliveryStats","responses":{"200":{"description":"Delivery statistics","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"total":{"type":"number"},"byStatus":{"type":"object","properties":{"pending":{"type":"number"},"success":{"type":"number"},"skipped":{"type":"number"},"dead":{"type":"number"}},"required":["pending","success","skipped","dead"]},"successRate":{"type":["number","null"]}},"required":["total","byStatus","successRate"]}},"required":["data"]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookInternalServerError"}}}}},"parameters":[{"schema":{"type":"string","format":"date-time"},"required":false,"name":"since","in":"query"},{"schema":{"type":"string","enum":["http","integration"],"description":"Only include deliveries to endpoints of this kind."},"required":false,"description":"Only include deliveries to endpoints of this kind.","name":"kind","in":"query"}]}},"/webhooks/{id}/deliveries":{"get":{"tags":["Webhook Deliveries"],"summary":"List deliveries for a webhook","description":"Returns a paginated list of deliveries for a single webhook subscription, identified by its id. Each record reports the event, delivery status, attempt count, and the last response code or error. Results can be filtered by `eventId` (exact match against the originating event id).","operationId":"listWebhookDeliveries","responses":{"200":{"description":"Deliveries","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"endpointId":{"type":"string","format":"uuid"},"eventId":{"type":"string"},"eventType":{"type":"string"},"source":{"type":"string"},"status":{"type":"string","enum":["pending","success","skipped","dead"]},"attempts":{"type":"number"},"lastStatusCode":{"type":["number","null"]},"lastError":{"type":["string","null"]},"durationMs":{"type":["number","null"]},"isTest":{"type":"boolean"},"occurredAt":{"type":"string"},"createdAt":{"type":"string"},"completedAt":{"type":["string","null"]},"createdBy":{"type":["string","null"],"format":"uuid","description":"Id of the parent endpoint's creator. Null when the endpoint row is gone or its creator was never recorded."}},"required":["id","endpointId","eventId","eventType","source","status","attempts","lastStatusCode","lastError","durationMs","isTest","occurredAt","createdAt","completedAt","createdBy"]}},"pagination":{"$ref":"#/components/schemas/Pagination"}},"required":["items","pagination"]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"404":{"description":"Webhook or delivery not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookHttpError"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookInternalServerError"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"required":true,"name":"id","in":"path"},{"schema":{"type":"integer","exclusiveMinimum":0,"default":1},"required":false,"name":"page","in":"query"},{"schema":{"type":"integer","exclusiveMinimum":0,"default":10},"required":false,"name":"pageSize","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":256,"description":"Exact text match against the originating event id."},"required":false,"description":"Exact text match against the originating event id.","name":"eventId","in":"query"}]}},"/webhooks/{id}/deliveries/{deliveryId}":{"get":{"tags":["Webhook Deliveries"],"summary":"Get a delivery with its attempts","description":"Returns a single delivery for a webhook subscription along with the full list of captured attempt records. Each attempt includes the request URL, method, headers and body, whether it was signed, and the response status, headers, and snippet.","operationId":"getWebhookDelivery","responses":{"200":{"description":"Delivery with captured attempts","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"endpointId":{"type":"string","format":"uuid"},"eventId":{"type":"string"},"eventType":{"type":"string"},"source":{"type":"string"},"status":{"type":"string","enum":["pending","success","skipped","dead"]},"attempts":{"type":"array","items":{"type":"object","properties":{"attemptNo":{"type":"number"},"requestUrl":{"type":"string"},"requestMethod":{"type":"string"},"requestHeaders":{"type":["object","null"],"additionalProperties":{"type":"string"}},"requestBody":{"type":["string","null"]},"signed":{"type":"boolean"},"responseStatus":{"type":["number","null"]},"responseHeaders":{"type":["object","null"],"additionalProperties":{"type":"string"}},"responseSnippet":{"type":["string","null"]},"durationMs":{"type":["number","null"]},"error":{"type":["string","null"]},"sentAt":{"type":"string"}},"required":["attemptNo","requestUrl","requestMethod","requestHeaders","requestBody","signed","responseStatus","responseHeaders","responseSnippet","durationMs","error","sentAt"]}},"lastStatusCode":{"type":["number","null"]},"lastError":{"type":["string","null"]},"durationMs":{"type":["number","null"]},"isTest":{"type":"boolean"},"occurredAt":{"type":"string"},"createdAt":{"type":"string"},"completedAt":{"type":["string","null"]},"createdBy":{"type":["string","null"],"format":"uuid","description":"Id of the parent endpoint's creator. Null when the endpoint row is gone or its creator was never recorded."}},"required":["id","endpointId","eventId","eventType","source","status","attempts","lastStatusCode","lastError","durationMs","isTest","occurredAt","createdAt","completedAt","createdBy"]}},"required":["data"]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"404":{"description":"Webhook or delivery not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookHttpError"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookInternalServerError"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"required":true,"name":"id","in":"path"},{"schema":{"type":"string","format":"uuid"},"required":true,"name":"deliveryId","in":"path"}]}},"/webhooks/integrations":{"get":{"tags":["Webhook Integrations"],"summary":"List message integrations","description":"Returns the integrations that can receive webhook events as channel messages (e.g. Slack), with your org's connection state for each. Connect an integration in the Cloud app before creating a webhook for it.","operationId":"listWebhookIntegrations","responses":{"200":{"description":"Message integrations","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"capability":{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":128,"example":"slack.post_message"},"revision":{"type":"integer","minimum":1,"example":1}},"required":["id","revision"],"additionalProperties":false},"label":{"type":"string","example":"Slack"},"connection":{"type":"string","enum":["connected","not_connected","expired"],"description":"Connection state for your org. Only `connected` integrations can be used as a destination."},"connectKey":{"type":"string","description":"Opaque key for the Cloud connect dialog."},"supportsTargets":{"type":"boolean","description":"True when targets (e.g. channels) can be listed via `GET /webhooks/integrations/{capabilityId}/targets`."},"deprecated":{"type":"boolean","description":"True for the previous revision during a switch; prefer the non-deprecated one."},"iconUrl":{"type":["string","null"],"format":"uri","description":"Server-resolved brand logo URL; null when unknown. Show this instead of deriving a logo from connectKey."}},"required":["capability","label","connection","connectKey","supportsTargets","deprecated","iconUrl"]}}},"required":["data"]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookInternalServerError"}}}},"503":{"description":"Integrations are not available right now","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookHttpError"}}}}}}},"/webhooks/integrations/{capabilityId}/targets":{"get":{"tags":["Webhook Integrations"],"summary":"List integration targets","description":"Returns the live list of targets (e.g. Slack channels the connected account is a member of) for an integration. Pass a target's `args` together with the integration `capability` to `POST /webhooks` with `kind: \"integration\"`.","operationId":"listWebhookIntegrationTargets","responses":{"200":{"description":"Integration targets","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"args":{"type":"object","additionalProperties":{},"description":"Pass as `args` when creating an `integration` webhook.","example":{"channelId":"C07ABCDEF"}},"label":{"type":"string","example":"#ops"},"isPrivate":{"type":"boolean"}},"required":["args","label","isPrivate"]}}},"required":["data"]}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"404":{"description":"Integration not found or it has no targets","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookHttpError"}}}},"409":{"description":"The integration is not connected or its connection expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookHttpError"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookInternalServerError"}}}},"503":{"description":"Integrations are not available right now","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookHttpError"}}}}},"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":128,"example":"slack.post_message"},"required":true,"name":"capabilityId","in":"path"},{"schema":{"type":"integer","minimum":1,"example":1},"required":true,"name":"revision","in":"query"}]}},"/webhooks":{"post":{"tags":["Webhooks"],"summary":"Register a webhook subscription","description":"Creates a webhook subscription and an optional list of event types to subscribe to (defaults to all when omitted). `kind: \"http\"` (the default) delivers signed JSON to a URL; the response includes the generated signing secret, which is returned only once at creation time and cannot be retrieved later. `kind: \"integration\"` posts each event as a message into a connected integration target (e.g. a Slack channel): pick the `capability` from `GET /webhooks/integrations` and the `args` from `GET /webhooks/integrations/{capabilityId}/targets`. Integration webhooks have no signing secret. Send an `Idempotency-Key` header to make the create safe to retry: the same key with the same body returns the existing webhook (status 201, `Idempotent-Replayed: true`) instead of creating a second one, and the same key with a different body is a 422. A replayed create does not return the signing secret again; use rotate-secret if the original response was lost. If that webhook was deleted in the meantime, the retry is a 404.","operationId":"createWebhook","requestBody":{"content":{"application/json":{"schema":{"oneOf":[{"type":"object","properties":{"kind":{"type":"string","enum":["http"],"description":"Delivery transport. Omitted ⇒ `http`."},"url":{"type":"string","maxLength":2048,"format":"uri","example":"https://example.com/webhooks/droidrun"},"eventTypes":{"type":"array","items":{"type":"string","minLength":1,"maxLength":256},"maxItems":100,"example":["task.run.completed","task.run.failed"]},"description":{"type":"string","maxLength":500}},"required":["url"]},{"type":"object","properties":{"kind":{"type":"string","enum":["integration"]},"capability":{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":128,"example":"slack.post_message"},"revision":{"type":"integer","minimum":1,"example":1}},"required":["id","revision"],"additionalProperties":false},"args":{"type":"object","additionalProperties":{},"description":"Target args exactly as returned by `GET /webhooks/integrations/{capabilityId}/targets`.","example":{"channelId":"C07ABCDEF"}},"eventTypes":{"type":"array","items":{"type":"string","minLength":1,"maxLength":256},"maxItems":100,"example":["task.run.completed","task.run.failed"]},"description":{"type":"string","maxLength":500}},"required":["kind","capability","args"]}]}}}},"responses":{"201":{"description":"Webhook created (secret shown once for http webhooks). A replayed create (same `Idempotency-Key`, same body) returns the current webhook without `secret` and with `Idempotent-Replayed: true`.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"kind":{"type":"string","enum":["http","integration"],"description":"`http` posts signed JSON to `url`; `integration` posts a message through a connected integration (e.g. a Slack channel)."},"url":{"type":["string","null"],"description":"Delivery URL; null for `integration` webhooks."},"integration":{"type":["object","null"],"properties":{"capability":{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":128,"example":"slack.post_message"},"revision":{"type":"integer","minimum":1,"example":1}},"required":["id","revision"],"additionalProperties":false},"args":{"type":"object","additionalProperties":{}},"label":{"type":"string","description":"Target name at creation time, e.g. `#ops`."}},"required":["capability","args","label"],"description":"Integration target; null for `http` webhooks."},"eventTypes":{"type":"array","items":{"type":"string"}},"state":{"type":"string","enum":["ACTIVE","DISABLED","DELETED"]},"health":{"type":"string","enum":["healthy","failing","blocked"],"description":"System-observed delivery health. `blocked` endpoints are auto-disabled after sustained failure; PATCH state=ACTIVE to re-enable."},"blockedAt":{"type":["string","null"]},"blockedReason":{"type":["string","null"],"description":"Why the webhook was blocked, e.g. `integration_disconnected` (reconnect the integration) or `integration_target_invalid` (the channel is gone or not allowed)."},"signingEnabled":{"type":"boolean","description":"Always false for `integration` webhooks."},"description":{"type":["string","null"]},"createdBy":{"type":["string","null"],"format":"uuid","description":"Id of the actor who created this endpoint. Null when no creator was recorded."},"createdAt":{"type":"string"},"updatedAt":{"type":"string"},"secret":{"type":"string","description":"Signing secret for `http` webhooks — shown only once. Store it now. Absent for `integration` webhooks."}},"required":["id","kind","url","integration","eventTypes","state","health","blockedAt","blockedReason","signingEnabled","description","createdBy","createdAt","updatedAt"]}},"required":["data"]}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"404":{"description":"Integration or integration target not found, or the webhook created under this `Idempotency-Key` was deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookHttpError"}}}},"409":{"description":"A webhook for this URL or integration target already exists, the integration is not connected, or a request with this `Idempotency-Key` is still in progress (`idempotency_request_in_progress`: retry after `Retry-After`)","headers":{"Retry-After":{"schema":{"type":"string","description":"Seconds to wait before retrying; set on `idempotency_request_in_progress` (always `1`).","example":"1"},"required":false,"description":"Seconds to wait before retrying; set on `idempotency_request_in_progress` (always `1`)."},"x-should-retry":{"schema":{"type":"string","description":"`true` on `idempotency_request_in_progress`: the same request may be retried.","example":"true"},"required":false,"description":"`true` on `idempotency_request_in_progress`: the same request may be retried."}},"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/WebhookHttpError"},{"type":"object","properties":{"code":{"type":"string","enum":["idempotency_request_in_progress"]},"message":{"type":"string"},"traceId":{"type":"string"},"retryAfterSeconds":{"type":"number"}},"required":["code","message"]}]}}}},"422":{"description":"The `Idempotency-Key` was already used with a different request body","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string","enum":["idempotency_key_reused"]},"message":{"type":"string"},"traceId":{"type":"string"},"retryAfterSeconds":{"type":"number"}},"required":["code","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookInternalServerError"}}}},"503":{"description":"Integrations are not available right now","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookHttpError"}}}}},"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":255,"pattern":"^[\\x21-\\x7E]{1,255}$","description":"Idempotency-Key: 1-255 printable ASCII characters. Same key with a different request body is a 422 idempotency_key_reused. A retryable in-flight duplicate is a 409 with Retry-After and x-should-retry: true; a terminal duplicate is a 409 with x-should-retry: false. A replay returns the current resource state with Idempotent-Replayed: true.","example":"b3f6a9f0-6f1a-4e9a-9e7a-9c9b6b6a5a3f"},"required":false,"description":"Idempotency-Key: 1-255 printable ASCII characters. Same key with a different request body is a 422 idempotency_key_reused. A retryable in-flight duplicate is a 409 with Retry-After and x-should-retry: true; a terminal duplicate is a 409 with x-should-retry: false. A replay returns the current resource state with Idempotent-Replayed: true.","name":"idempotency-key","in":"header"}]},"get":{"tags":["Webhooks"],"summary":"List your webhook subscriptions","description":"Returns a paginated list of your webhook subscriptions, optionally filtered by status (active, failing, blocked, or disabled), by `search` (a case-insensitive substring match against the URL or description), and/or by delivery `kind`. The response also includes per-status counts across all of your subscriptions (of the requested `kind`, if given; the other filters do not apply to the counts).","operationId":"listWebhooks","responses":{"200":{"description":"Webhook subscriptions","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"kind":{"type":"string","enum":["http","integration"],"description":"`http` posts signed JSON to `url`; `integration` posts a message through a connected integration (e.g. a Slack channel)."},"url":{"type":["string","null"],"description":"Delivery URL; null for `integration` webhooks."},"integration":{"type":["object","null"],"properties":{"capability":{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":128,"example":"slack.post_message"},"revision":{"type":"integer","minimum":1,"example":1}},"required":["id","revision"],"additionalProperties":false},"args":{"type":"object","additionalProperties":{}},"label":{"type":"string","description":"Target name at creation time, e.g. `#ops`."}},"required":["capability","args","label"],"description":"Integration target; null for `http` webhooks."},"eventTypes":{"type":"array","items":{"type":"string"}},"state":{"type":"string","enum":["ACTIVE","DISABLED","DELETED"]},"health":{"type":"string","enum":["healthy","failing","blocked"],"description":"System-observed delivery health. `blocked` endpoints are auto-disabled after sustained failure; PATCH state=ACTIVE to re-enable."},"blockedAt":{"type":["string","null"]},"blockedReason":{"type":["string","null"],"description":"Why the webhook was blocked, e.g. `integration_disconnected` (reconnect the integration) or `integration_target_invalid` (the channel is gone or not allowed)."},"signingEnabled":{"type":"boolean","description":"Always false for `integration` webhooks."},"description":{"type":["string","null"]},"createdBy":{"type":["string","null"],"format":"uuid","description":"Id of the actor who created this endpoint. Null when no creator was recorded."},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","kind","url","integration","eventTypes","state","health","blockedAt","blockedReason","signingEnabled","description","createdBy","createdAt","updatedAt"]}},"pagination":{"$ref":"#/components/schemas/Pagination"},"counts":{"type":"object","properties":{"active":{"type":"number"},"failing":{"type":"number"},"blocked":{"type":"number"},"disabled":{"type":"number"},"total":{"type":"number"}},"required":["active","failing","blocked","disabled","total"]}},"required":["items","pagination","counts"]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookInternalServerError"}}}}},"parameters":[{"schema":{"type":"integer","exclusiveMinimum":0,"default":1},"required":false,"name":"page","in":"query"},{"schema":{"type":"integer","exclusiveMinimum":0,"default":10},"required":false,"name":"pageSize","in":"query"},{"schema":{"type":"string","enum":["active","failing","blocked","disabled"]},"required":false,"name":"status","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":256,"description":"Case-insensitive substring match against the URL or description."},"required":false,"description":"Case-insensitive substring match against the URL or description.","name":"search","in":"query"},{"schema":{"type":"string","enum":["true","false"],"description":"When true, only include webhooks created by you (not just owned by your org)."},"required":false,"description":"When true, only include webhooks created by you (not just owned by your org).","name":"mine","in":"query"},{"schema":{"type":"string","format":"uuid","description":"Only include webhooks created by this actor id. Mutually exclusive with `mine`."},"required":false,"description":"Only include webhooks created by this actor id. Mutually exclusive with `mine`.","name":"createdBy","in":"query"},{"schema":{"type":"string","enum":["http","integration"],"description":"Only include webhooks of this delivery kind."},"required":false,"description":"Only include webhooks of this delivery kind.","name":"kind","in":"query"}]}},"/webhooks/{id}":{"get":{"tags":["Webhooks"],"summary":"Get a webhook subscription","description":"Returns a single webhook subscription by id, including its URL (or integration target), subscribed event types, state, and system-observed delivery health. The signing secret is never included.","operationId":"getWebhook","responses":{"200":{"description":"Webhook subscription","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"kind":{"type":"string","enum":["http","integration"],"description":"`http` posts signed JSON to `url`; `integration` posts a message through a connected integration (e.g. a Slack channel)."},"url":{"type":["string","null"],"description":"Delivery URL; null for `integration` webhooks."},"integration":{"type":["object","null"],"properties":{"capability":{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":128,"example":"slack.post_message"},"revision":{"type":"integer","minimum":1,"example":1}},"required":["id","revision"],"additionalProperties":false},"args":{"type":"object","additionalProperties":{}},"label":{"type":"string","description":"Target name at creation time, e.g. `#ops`."}},"required":["capability","args","label"],"description":"Integration target; null for `http` webhooks."},"eventTypes":{"type":"array","items":{"type":"string"}},"state":{"type":"string","enum":["ACTIVE","DISABLED","DELETED"]},"health":{"type":"string","enum":["healthy","failing","blocked"],"description":"System-observed delivery health. `blocked` endpoints are auto-disabled after sustained failure; PATCH state=ACTIVE to re-enable."},"blockedAt":{"type":["string","null"]},"blockedReason":{"type":["string","null"],"description":"Why the webhook was blocked, e.g. `integration_disconnected` (reconnect the integration) or `integration_target_invalid` (the channel is gone or not allowed)."},"signingEnabled":{"type":"boolean","description":"Always false for `integration` webhooks."},"description":{"type":["string","null"]},"createdBy":{"type":["string","null"],"format":"uuid","description":"Id of the actor who created this endpoint. Null when no creator was recorded."},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","kind","url","integration","eventTypes","state","health","blockedAt","blockedReason","signingEnabled","description","createdBy","createdAt","updatedAt"]}},"required":["data"]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"404":{"description":"Webhook not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookHttpError"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookInternalServerError"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"required":true,"name":"id","in":"path"}]},"patch":{"tags":["Webhooks"],"summary":"Update a webhook subscription","description":"Updates a webhook subscription. Any combination of the subscribed event types, state (ACTIVE or DISABLED), and description may be changed, and at least one field must be supplied. Setting state to ACTIVE re-enables a subscription that was auto-blocked after sustained delivery failures. The URL or integration target cannot be changed; delete and recreate the webhook instead.","operationId":"updateWebhook","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"eventTypes":{"type":"array","items":{"type":"string","minLength":1,"maxLength":256},"maxItems":100},"state":{"type":"string","enum":["ACTIVE","DISABLED"]},"description":{"type":["string","null"],"maxLength":500}}}}}},"responses":{"200":{"description":"Updated webhook subscription","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"kind":{"type":"string","enum":["http","integration"],"description":"`http` posts signed JSON to `url`; `integration` posts a message through a connected integration (e.g. a Slack channel)."},"url":{"type":["string","null"],"description":"Delivery URL; null for `integration` webhooks."},"integration":{"type":["object","null"],"properties":{"capability":{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":128,"example":"slack.post_message"},"revision":{"type":"integer","minimum":1,"example":1}},"required":["id","revision"],"additionalProperties":false},"args":{"type":"object","additionalProperties":{}},"label":{"type":"string","description":"Target name at creation time, e.g. `#ops`."}},"required":["capability","args","label"],"description":"Integration target; null for `http` webhooks."},"eventTypes":{"type":"array","items":{"type":"string"}},"state":{"type":"string","enum":["ACTIVE","DISABLED","DELETED"]},"health":{"type":"string","enum":["healthy","failing","blocked"],"description":"System-observed delivery health. `blocked` endpoints are auto-disabled after sustained failure; PATCH state=ACTIVE to re-enable."},"blockedAt":{"type":["string","null"]},"blockedReason":{"type":["string","null"],"description":"Why the webhook was blocked, e.g. `integration_disconnected` (reconnect the integration) or `integration_target_invalid` (the channel is gone or not allowed)."},"signingEnabled":{"type":"boolean","description":"Always false for `integration` webhooks."},"description":{"type":["string","null"]},"createdBy":{"type":["string","null"],"format":"uuid","description":"Id of the actor who created this endpoint. Null when no creator was recorded."},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","kind","url","integration","eventTypes","state","health","blockedAt","blockedReason","signingEnabled","description","createdBy","createdAt","updatedAt"]}},"required":["data"]}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"404":{"description":"Webhook not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookHttpError"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookInternalServerError"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"required":true,"name":"id","in":"path"}]},"delete":{"tags":["Webhooks"],"summary":"Delete a webhook subscription","description":"Deletes a webhook subscription so it stops receiving deliveries. Returns 204 No Content on success.","operationId":"deleteWebhook","responses":{"204":{"description":"Deleted"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"404":{"description":"Webhook not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookHttpError"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookInternalServerError"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"required":true,"name":"id","in":"path"}]}},"/webhooks/{id}/rotate-secret":{"post":{"tags":["Webhooks"],"summary":"Rotate signing secret","description":"Generates a new signing secret for the webhook subscription and returns it once in the response. The previous secret is replaced immediately, so any signature verification on your endpoint must be updated to use the new value. Only `http` webhooks have a signing secret; for `integration` webhooks this returns 400.","operationId":"rotateWebhookSecret","responses":{"200":{"description":"New signing secret (shown once)","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"kind":{"type":"string","enum":["http","integration"],"description":"`http` posts signed JSON to `url`; `integration` posts a message through a connected integration (e.g. a Slack channel)."},"url":{"type":["string","null"],"description":"Delivery URL; null for `integration` webhooks."},"integration":{"type":["object","null"],"properties":{"capability":{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":128,"example":"slack.post_message"},"revision":{"type":"integer","minimum":1,"example":1}},"required":["id","revision"],"additionalProperties":false},"args":{"type":"object","additionalProperties":{}},"label":{"type":"string","description":"Target name at creation time, e.g. `#ops`."}},"required":["capability","args","label"],"description":"Integration target; null for `http` webhooks."},"eventTypes":{"type":"array","items":{"type":"string"}},"state":{"type":"string","enum":["ACTIVE","DISABLED","DELETED"]},"health":{"type":"string","enum":["healthy","failing","blocked"],"description":"System-observed delivery health. `blocked` endpoints are auto-disabled after sustained failure; PATCH state=ACTIVE to re-enable."},"blockedAt":{"type":["string","null"]},"blockedReason":{"type":["string","null"],"description":"Why the webhook was blocked, e.g. `integration_disconnected` (reconnect the integration) or `integration_target_invalid` (the channel is gone or not allowed)."},"signingEnabled":{"type":"boolean","description":"Always false for `integration` webhooks."},"description":{"type":["string","null"]},"createdBy":{"type":["string","null"],"format":"uuid","description":"Id of the actor who created this endpoint. Null when no creator was recorded."},"createdAt":{"type":"string"},"updatedAt":{"type":"string"},"secret":{"type":"string","description":"Signing secret — shown only once. Store it now."}},"required":["id","kind","url","integration","eventTypes","state","health","blockedAt","blockedReason","signingEnabled","description","createdBy","createdAt","updatedAt","secret"]}},"required":["data"]}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"404":{"description":"Webhook not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookHttpError"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookInternalServerError"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"required":true,"name":"id","in":"path"}]}},"/webhooks/{id}/test":{"post":{"tags":["Webhooks"],"summary":"Send a one-shot test delivery","description":"Sends a single test payload to the webhook subscription URL (or a test message to its integration target) to verify connectivity. The response reports whether the attempt succeeded along with the returned HTTP status code or error, if any.","operationId":"testWebhook","responses":{"200":{"description":"Test delivery result","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"success":{"type":"boolean"},"statusCode":{"type":["number","null"]},"error":{"type":["string","null"]}},"required":["success","statusCode","error"]}},"required":["data"]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"404":{"description":"Webhook not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookHttpError"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookInternalServerError"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"required":true,"name":"id","in":"path"}]}},"/numbers/messages":{"get":{"tags":["Messages"],"summary":"List the caller's own SMS inbox/outbox messages","operationId":"listMessages","description":"Lists SMS messages newest first, with filters for direction, eSIM, phone number, status, and conversation.","responses":{"200":{"description":"Messages retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicMessageListResponse"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"503":{"description":"Messaging is unavailable when phone numbers and all eSIM providers are disabled. See `code` for details.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageErrorResponse"}}}}},"parameters":[{"schema":{"type":"integer","exclusiveMinimum":0,"default":1},"required":false,"name":"page","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"required":false,"name":"pageSize","in":"query"},{"schema":{"type":"string","enum":["all","inbound","outbound"],"default":"all"},"required":false,"name":"direction","in":"query"},{"schema":{"type":"string","format":"uuid"},"required":false,"name":"esimId","in":"query"},{"schema":{"type":"string","format":"uuid"},"required":false,"name":"numberId","in":"query"},{"schema":{"type":"string","enum":["all","received","queued","claimed","sending","sent","sent_unconfirmed","delivered","failed"],"default":"all","description":"Filter by message status. `delivered` and `sent_unconfirmed` are kept for compatibility and are not emitted on current lines."},"required":false,"description":"Filter by message status. `delivered` and `sent_unconfirmed` are kept for compatibility and are not emitted on current lines.","name":"status","in":"query"},{"schema":{"type":"string","minLength":3,"maxLength":64},"required":false,"name":"peerNumber","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":128},"required":false,"name":"peerKey","in":"query"}]}},"/numbers/messages/conversations":{"get":{"tags":["Messages"],"summary":"List the caller's own SMS conversations, one row per thread","operationId":"listConversations","description":"Lists SMS conversations by recent activity. Use both cursor fields from `nextCursor` to fetch the next page.","responses":{"200":{"description":"Conversations retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListConversationsResponse"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"503":{"description":"Messaging is unavailable when phone numbers and all eSIM providers are disabled. See `code` for details.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageErrorResponse"}}}}},"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","format":"uuid"},"required":false,"name":"esimId","in":"query"},{"schema":{"type":"string","format":"uuid"},"required":false,"name":"numberId","in":"query"},{"schema":{"type":"string","format":"date-time"},"required":false,"name":"cursorLastOccurredAt","in":"query"},{"schema":{"type":"string","format":"uuid"},"required":false,"name":"cursorLastMessageId","in":"query"}]}},"/numbers/messages/conversations/read":{"post":{"tags":["Messages"],"summary":"Mark a conversation's inbound messages read up to a cursor","operationId":"markConversationRead","description":"Marks inbound messages in a conversation as read through the supplied cursor. Repeating the request is safe.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarkConversationReadInput"}}}},"responses":{"200":{"description":"Read state updated","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/MarkConversationReadResponse"}},"required":["data"]}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"503":{"description":"Messaging is unavailable when phone numbers and all eSIM providers are disabled. See `code` for details.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageErrorResponse"}}}}}}},"/numbers/messages/{id}":{"get":{"tags":["Messages"],"summary":"Get one of the caller's SMS messages","operationId":"getMessage","description":"Returns one message. For an outbound message that is not yet final, the status may be refreshed once (at most every 30 s) before it is returned; a failed refresh returns the stored message.","responses":{"200":{"description":"Message retrieved","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PublicMessageRow"}},"required":["data"]}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"503":{"description":"Messaging is unavailable when phone numbers and all eSIM providers are disabled. See `code` for details.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageErrorResponse"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"required":true,"name":"id","in":"path"}]}},"/numbers/phones":{"post":{"tags":["Numbers"],"summary":"Purchase a phone number","operationId":"purchaseNumber","description":"Starts a phone-number purchase. Poll the returned phone number for status updates.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicPhonePurchaseInput"}}}},"responses":{"202":{"description":"Number purchase accepted — poll GET /numbers/phones/{id}","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PurchaseAcceptedResponse"}},"required":["data"]}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"409":{"description":"Purchase in progress, or strict included capacity unavailable, or the requested country is temporarily out of stock (out_of_stock)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicPhonePurchaseError"}}}},"422":{"description":"Unsupported country, or the Idempotency-Key was already used for a different request (idempotency_key_reused).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicPhonePurchaseError"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"503":{"description":"Purchase unavailable","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/PublicPhonePurchaseError"},{"$ref":"#/components/schemas/NumberErrorResponse"}]}}}}},"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":255,"pattern":"^[\\x21-\\x7E]{1,255}$","description":"Idempotency-Key: 1-255 printable ASCII characters. Same key with a different request body is a 422 idempotency_key_reused. A retryable in-flight duplicate is a 409 with Retry-After and x-should-retry: true; a terminal duplicate is a 409 with x-should-retry: false. A replay returns the current resource state with Idempotent-Replayed: true.","example":"b3f6a9f0-6f1a-4e9a-9e7a-9c9b6b6a5a3f"},"required":false,"description":"Idempotency-Key: 1-255 printable ASCII characters. Same key with a different request body is a 422 idempotency_key_reused. A retryable in-flight duplicate is a 409 with Retry-After and x-should-retry: true; a terminal duplicate is a 409 with x-should-retry: false. A replay returns the current resource state with Idempotent-Replayed: true.","name":"idempotency-key","in":"header"}]},"get":{"tags":["Numbers"],"summary":"List phone numbers","operationId":"listNumbers","description":"Lists the caller's phone numbers.","responses":{"200":{"description":"Numbers retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicListNumbersResponse"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"503":{"description":"The phone-number service is unavailable. See `code` for details.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NumberErrorResponse"}}}}},"parameters":[{"schema":{"type":"integer","exclusiveMinimum":0,"default":1},"required":false,"name":"page","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"required":false,"name":"pageSize","in":"query"}]}},"/numbers/phones/capacity":{"get":{"tags":["Numbers"],"summary":"Get included phone-number capacity for a country","operationId":"getPhoneCapacity","description":"Returns included phone capacity for a country. Creating a phone is authoritative.","responses":{"200":{"description":"Capacity retrieved","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PhoneCapacityResponse"}},"required":["data"]}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"422":{"description":"Unsupported country","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PhoneCapacityError"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"502":{"description":"Capacity is temporarily unavailable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PhoneCapacityUpstreamError"}}}},"503":{"description":"The phone-number service or capacity information is unavailable.","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/NumberErrorResponse"},{"$ref":"#/components/schemas/PhoneCapacityUpstreamError"}]}}}}},"parameters":[{"schema":{"type":"string","minLength":2,"maxLength":2,"pattern":"^[a-z]{2}$","example":"de","description":"ISO 3166-1 alpha-2 country code from GET /numbers/phones/countries."},"required":true,"description":"ISO 3166-1 alpha-2 country code from GET /numbers/phones/countries.","name":"country","in":"query"}]}},"/numbers/phones/countries":{"get":{"tags":["Numbers"],"summary":"List dedicated-number countries","operationId":"listDedicatedCountries","description":"Lists available countries and current phone-number availability.","responses":{"200":{"description":"Countries retrieved","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ListDedicatedCountriesResponse"}},"required":["data"]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"503":{"description":"The phone-number service is unavailable. See `code` for details.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NumberErrorResponse"}}}}}}},"/numbers/phones/{id}":{"get":{"tags":["Numbers"],"summary":"Get phone number by id","operationId":"getNumber","description":"Retrieves a single phone number.","responses":{"200":{"description":"Number retrieved","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PublicNumber"}},"required":["data"]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"503":{"description":"The phone-number service is unavailable. See `code` for details.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NumberErrorResponse"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"required":true,"name":"id","in":"path"}]},"patch":{"tags":["Numbers"],"summary":"Update a phone number's display label","operationId":"patchNumber","description":"Updates the display label. Omitting `label` leaves it unchanged; null or an empty string clears it.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PatchPhoneInput"}}}},"responses":{"200":{"description":"Number updated","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PublicNumber"}},"required":["data"]}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"503":{"description":"The phone-number service is unavailable. See `code` for details.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NumberErrorResponse"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"required":true,"name":"id","in":"path"}]},"delete":{"tags":["Numbers"],"summary":"Cancel a phone-number purchase or an active rental","operationId":"cancelNumber","description":"Cancels a pending purchase or schedules cancellation of an active paid phone number. Repeating a scheduled cancellation is safe. Returns 409 when cancellation is not available.","responses":{"200":{"description":"Number cancelled","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PublicNumber"}},"required":["data"]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"409":{"description":"The request conflicts with the phone number's current state. See `code` for details.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NumberErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"503":{"description":"The phone-number service is unavailable. See `code` for details.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NumberErrorResponse"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"required":true,"name":"id","in":"path"}]}},"/numbers/phones/{id}/messages":{"get":{"tags":["Numbers"],"summary":"List messages (inbox + outbox) on a number","operationId":"listNumberMessages","description":"Returns SMS messages on the number, inbound and outbound, scoped to the authenticated user. Newest first. Messages stay with the number across device switches.","responses":{"200":{"description":"Messages retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicPhoneMessageListResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"503":{"description":"The phone-number service is unavailable. See `code` for details.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NumberErrorResponse"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"required":true,"name":"id","in":"path"},{"schema":{"type":"integer","exclusiveMinimum":0,"default":1},"required":false,"name":"page","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":200,"default":50},"required":false,"name":"pageSize","in":"query"},{"schema":{"type":"string","enum":["all","inbound","outbound"],"default":"all"},"required":false,"name":"direction","in":"query"},{"schema":{"type":"string","format":"date-time"},"required":false,"name":"since","in":"query"}]},"post":{"tags":["Messages","Numbers"],"summary":"Send an SMS from a number","operationId":"sendNumberMessage","description":"Queues an SMS from one of the caller's numbers that can send. Replaying an Idempotency-Key with the same payload returns the original message, reusing it with a different payload returns 422. 409 capability_unavailable: this number cannot send right now. 422 invalid_recipient / unsupported_destination / body_too_long: the recipient or text does not fit the number. 429 daily_limit_reached: the rolling 24 h limit for the account is used up; 429 rate_limited: too many sends by the owner in a short window; 429 number_rate_limited: too many outbound sends from this number in the configured window (all sends from this number count, including those made on your behalf). 403 send_disabled: self-service SMS send is switched off.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendPhoneMessageInput"}}}},"responses":{"202":{"description":"Outbound message queued","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"esimId":{"type":["string","null"],"format":"uuid"},"direction":{"type":"string","enum":["inbound","outbound"]},"status":{"type":"string","enum":["received","queued","claimed","sending","sent","sent_unconfirmed","delivered","failed"],"description":"Message status. Outbound messages move queued → sending → sent, or end at failed. `sent` means the mobile network accepted the message and is the final success status. `delivered` and `sent_unconfirmed` are kept for compatibility; current lines return no carrier delivery report, so neither is emitted."},"peerNumber":{"type":["string","null"]},"peerKey":{"type":["string","null"]},"body":{"type":["string","null"]},"deliveryStatus":{"type":["string","null"]},"detectedSender":{"type":["string","null"]},"classification":{"$ref":"#/components/schemas/MessageClassification"},"occurredAt":{"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","esimId","direction","status","peerNumber","peerKey","body","deliveryStatus","detectedSender","classification","occurredAt","createdAt"]}},"required":["data"]}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"403":{"description":"Self-service SMS send is not enabled (send_disabled).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageErrorResponse"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"409":{"description":"This number cannot send right now (capability_unavailable).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageErrorResponse"}}}},"422":{"description":"invalid_recipient, unsupported_destination, body_too_long, or the Idempotency-Key was already used for a different request (idempotency_key_reused).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageErrorResponse"}}}},"429":{"description":"Daily limit reached (daily_limit_reached), too many owner sends in a short window (rate_limited), or too many sends from this number (number_rate_limited).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"503":{"description":"The phone-number service is unavailable. See `code` for details.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NumberErrorResponse"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"required":true,"name":"id","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"pattern":"^[\\x21-\\x7E]{1,255}$","description":"Idempotency-Key: 1-255 printable ASCII characters. Same key with a different request body is a 422 idempotency_key_reused. A retryable in-flight duplicate is a 409 with Retry-After and x-should-retry: true; a terminal duplicate is a 409 with x-should-retry: false. A replay returns the current resource state with Idempotent-Replayed: true.","example":"b3f6a9f0-6f1a-4e9a-9e7a-9c9b6b6a5a3f"},"required":false,"description":"Idempotency-Key: 1-255 printable ASCII characters. Same key with a different request body is a 422 idempotency_key_reused. A retryable in-flight duplicate is a 409 with Retry-After and x-should-retry: true; a terminal duplicate is a 409 with x-should-retry: false. A replay returns the current resource state with Idempotent-Replayed: true.","name":"idempotency-key","in":"header"}]}},"/mailboxes/connections":{"post":{"tags":["Mailboxes"],"summary":"Connect a Gmail inbox","operationId":"createMailboxConnection","description":"Links the caller’s Gmail account. Replaying the same Idempotency-Key returns the same mailbox. When Gmail is already active, redirectUrl is null and the mailbox is usable immediately.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMailboxConnectionRequest"}}}},"responses":{"200":{"description":"Gmail mailbox link","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailboxConnection"}}}},"400":{"description":"The Idempotency-Key header is malformed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailboxErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"409":{"description":"Gmail already connected, or the mailbox backend rejected the request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailboxErrorBody"}}}},"422":{"description":"The Idempotency-Key was reused with a different request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailboxErrorResponse"}}}},"429":{"description":"Mailbox backend rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailboxErrorBody"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"503":{"description":"Mailboxes disabled or temporarily unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailboxErrorBody"}}}}},"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":255,"pattern":"^[\\x21-\\x7E]{1,255}$","description":"Idempotency-Key: 1-255 printable ASCII characters. Same key with a different request body is a 422 idempotency_key_reused. A retryable in-flight duplicate is a 409 with Retry-After and x-should-retry: true; a terminal duplicate is a 409 with x-should-retry: false. A replay returns the current resource state with Idempotent-Replayed: true.","example":"b3f6a9f0-6f1a-4e9a-9e7a-9c9b6b6a5a3f"},"required":false,"description":"Idempotency-Key: 1-255 printable ASCII characters. Same key with a different request body is a 422 idempotency_key_reused. A retryable in-flight duplicate is a 409 with Retry-After and x-should-retry: true; a terminal duplicate is a 409 with x-should-retry: false. A replay returns the current resource state with Idempotent-Replayed: true.","name":"idempotency-key","in":"header"}]}},"/mailboxes/connections/{connectionId}":{"get":{"tags":["Mailboxes"],"summary":"Poll a Gmail inbox connection","operationId":"getMailboxConnection","description":"Reports pending, active (with the Gmail address), expired, or removed. connectionId is the mailbox id.","responses":{"200":{"description":"Gmail connection status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailboxConnection"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"503":{"description":"Mailboxes disabled or temporarily unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailboxErrorBody"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"connectionId","in":"path"}]}},"/mailboxes":{"post":{"tags":["Mailboxes"],"summary":"Claim or rent a mailbox","operationId":"createMailbox","description":"Creates a mailbox on the default domain or a connected custom domain. An optional `localPart` selects the address. Replaying the same Idempotency-Key and payload returns the original mailbox. Fresh requests and replays return 202 with the current mailbox state. Poll the mailbox when the response does not yet include a checkout URL.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMailboxRequest"}}}},"responses":{"200":{"description":"Archived mailbox returned (idempotent replay)","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Mailbox"}},"required":["data"]}}}},"201":{"description":"Fresh creates and replays return 202; clients must treat any 2xx response as success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Mailbox"}},"required":["data"]}}}},"202":{"description":"Mailbox creation accepted; poll the mailbox for updates","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Mailbox"}},"required":["data"]}}}},"400":{"description":"The mailbox backend rejected the request, or the Idempotency-Key header is malformed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailboxErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"409":{"description":"Address taken or included capacity unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailboxErrorBody"}}}},"422":{"description":"Invalid, reserved, or disabled custom local part, or the Idempotency-Key was reused with a different request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailboxErrorResponse"}}}},"429":{"description":"A rental cap was reached, or the mailbox backend rate limited the request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailboxErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"502":{"description":"Mailbox backend unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailboxErrorResponse"}}}},"503":{"description":"Mailboxes disabled or billing not configured","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailboxErrorBody"}}}}},"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":255,"pattern":"^[\\x21-\\x7E]{1,255}$","description":"Idempotency-Key: 1-255 printable ASCII characters. Same key with a different request body is a 422 idempotency_key_reused. A retryable in-flight duplicate is a 409 with Retry-After and x-should-retry: true; a terminal duplicate is a 409 with x-should-retry: false. A replay returns the current resource state with Idempotent-Replayed: true.","example":"b3f6a9f0-6f1a-4e9a-9e7a-9c9b6b6a5a3f"},"required":false,"description":"Idempotency-Key: 1-255 printable ASCII characters. Same key with a different request body is a 422 idempotency_key_reused. A retryable in-flight duplicate is a 409 with Retry-After and x-should-retry: true; a terminal duplicate is a 409 with x-should-retry: false. A replay returns the current resource state with Idempotent-Replayed: true.","name":"idempotency-key","in":"header"}]},"get":{"tags":["Mailboxes"],"summary":"List mailboxes","operationId":"listMailboxes","description":"Lists the caller-owned mailboxes with page-based pagination.","responses":{"200":{"description":"Mailboxes retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailboxList"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"503":{"description":"Mailboxes disabled or billing not configured","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailboxErrorBody"}}}}},"parameters":[{"schema":{"type":"integer","exclusiveMinimum":0,"default":1},"required":false,"name":"page","in":"query"},{"schema":{"type":"integer","exclusiveMinimum":0,"default":10},"required":false,"name":"pageSize","in":"query"}]}},"/mailboxes/capacity":{"get":{"tags":["Mailboxes"],"summary":"Get included mailbox capacity","operationId":"getMailboxCapacity","description":"Returns the number of mailboxes currently available through included capacity.","responses":{"200":{"description":"Mailbox capacity retrieved","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/MailboxCapacity"}},"required":["data"]}}}},"400":{"description":"The mailbox backend rejected the request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailboxErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"429":{"description":"Mailbox backend rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailboxErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"502":{"description":"Mailbox backend unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailboxErrorResponse"}}}},"503":{"description":"Mailboxes disabled or billing not configured","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailboxErrorBody"}}}}}}},"/mailboxes/{mailboxId}/disconnect":{"post":{"tags":["Mailboxes"],"summary":"Unlink a Gmail inbox","operationId":"disconnectMailbox","description":"Removes only this mailbox link. The Gmail connection used by your agents stays in place.","responses":{"200":{"description":"Gmail mailbox unlinked","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Mailbox"}},"required":["data"]}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"503":{"description":"Mailboxes disabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailboxErrorBody"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"mailboxId","in":"path"}]}},"/mailboxes/{mailboxId}":{"get":{"tags":["Mailboxes"],"summary":"Get a mailbox","operationId":"getMailbox","responses":{"200":{"description":"Mailbox retrieved","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Mailbox"}},"required":["data"]}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"503":{"description":"Mailboxes disabled or billing not configured","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailboxErrorBody"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"mailboxId","in":"path"}]},"patch":{"tags":["Mailboxes"],"summary":"Update a mailbox label","operationId":"updateMailbox","description":"Updates the label of a mailbox.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMailboxRequest"}}}},"responses":{"200":{"description":"Mailbox updated","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Mailbox"}},"required":["data"]}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"503":{"description":"Mailboxes disabled or billing not configured","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailboxErrorBody"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"mailboxId","in":"path"}]},"delete":{"tags":["Mailboxes"],"summary":"Cancel or archive a mailbox","operationId":"deleteMailbox","description":"Cancels a pending mailbox or schedules an active paid mailbox for cancellation. Existing addresses and messages are retained. Repeating the request is safe. An external inbox (Gmail) cannot be cancelled here; disconnect the link instead.","responses":{"200":{"description":"Cancellation scheduled","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Mailbox"}},"required":["data"]}}}},"400":{"description":"The mailbox backend rejected the request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailboxErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"409":{"description":"External inbox cannot be cancelled; disconnect the link","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailboxErrorBody"}}}},"429":{"description":"Mailbox backend rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailboxErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"502":{"description":"Mailbox backend unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailboxErrorResponse"}}}},"503":{"description":"Mailboxes disabled or billing not configured","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailboxErrorBody"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"mailboxId","in":"path"}]}},"/mailboxes/{mailboxId}/uncancel":{"post":{"tags":["Mailboxes"],"summary":"Undo a scheduled cancellation","operationId":"uncancelMailbox","description":"Withdraws a scheduled cancellation. Only available while cancellation is pending.","responses":{"200":{"description":"Cancellation withdrawn","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Mailbox"}},"required":["data"]}}}},"400":{"description":"The mailbox backend rejected the request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailboxErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"409":{"description":"No cancellation is pending","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailboxErrorBody"}}}},"429":{"description":"Mailbox backend rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailboxErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"502":{"description":"Mailbox backend unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailboxErrorResponse"}}}},"503":{"description":"Mailboxes disabled or billing not configured","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailboxErrorBody"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"mailboxId","in":"path"}]}},"/mailboxes/{mailboxId}/restart":{"post":{"tags":["Mailboxes"],"summary":"Restart rent on an archived mailbox","operationId":"restartMailbox","description":"Restarts an archived mailbox with the same address. Uses included capacity when available unless paid service is requested.","requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RestartMailboxRequest"}}}},"responses":{"202":{"description":"Restart initiated (poll GET for checkout URL)","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Mailbox"}},"required":["data"]}}}},"400":{"description":"The mailbox backend rejected the request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailboxErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"409":{"description":"Mailbox not restartable, address taken, or included capacity unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailboxErrorBody"}}}},"429":{"description":"A rental cap was reached, or the mailbox backend rate limited the request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailboxErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"502":{"description":"Mailbox backend unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailboxErrorResponse"}}}},"503":{"description":"Mailboxes disabled or billing not configured","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailboxErrorBody"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"mailboxId","in":"path"}]}},"/mailboxes/{mailboxId}/otp":{"get":{"tags":["Mailboxes"],"summary":"Get the best OTP candidate","operationId":"getMailboxOtp","description":"Returns the most likely recent OTP for the mailbox. Returns 204 when no matching code is available.","responses":{"200":{"description":"Best OTP candidate","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/MailboxOtp"}},"required":["data"]}}}},"204":{"description":"No matching OTP yet"},"400":{"description":"The mailbox backend rejected the request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailboxErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"409":{"description":"Gmail connection is pending, expired, removed, or the message is too large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailboxErrorBody"}}}},"429":{"description":"Mailbox backend rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailboxErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"502":{"description":"Mailbox backend unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailboxErrorResponse"}}}},"503":{"description":"Mailboxes or OTP extraction disabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailboxErrorResponse"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"mailboxId","in":"path"},{"schema":{"type":"string","format":"date-time"},"required":false,"name":"after","in":"query"},{"schema":{"type":"string"},"required":false,"name":"sender","in":"query"},{"schema":{"type":"integer","minimum":3,"maximum":12,"default":4},"required":false,"name":"minLength","in":"query"},{"schema":{"type":"integer","minimum":3,"maximum":12,"default":8},"required":false,"name":"maxLength","in":"query"}]}},"/mailboxes/{mailboxId}/messages":{"get":{"tags":["Mailbox Messages"],"summary":"List mailbox messages","operationId":"listMailboxMessages","description":"Lists mailbox messages with cursor pagination and optional time, sender, and OTP filters.","responses":{"200":{"description":"Messages retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailboxMessageList"}}}},"400":{"description":"The mailbox backend rejected the request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailboxErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"409":{"description":"Gmail connection is pending, expired, removed, or the message is too large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailboxErrorBody"}}}},"429":{"description":"Mailbox backend rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailboxErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"502":{"description":"Mailbox backend unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailboxErrorResponse"}}}},"503":{"description":"Mailboxes disabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailboxErrorBody"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"mailboxId","in":"path"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string"},"required":false,"name":"cursor","in":"query"},{"schema":{"type":"string","format":"date-time"},"required":false,"name":"after","in":"query"},{"schema":{"type":"string"},"required":false,"name":"sender","in":"query"},{"schema":{"type":"string","enum":["true","false"]},"required":false,"name":"hasOtp","in":"query"}]}},"/mailboxes/{mailboxId}/messages/{messageId}":{"get":{"tags":["Mailbox Messages"],"summary":"Get a mailbox message","operationId":"getMailboxMessage","responses":{"200":{"description":"Message retrieved","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/MailboxMessage"}},"required":["data"]}}}},"400":{"description":"The mailbox backend rejected the request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailboxErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"409":{"description":"Gmail connection is pending, expired, removed, or the message is too large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailboxErrorBody"}}}},"429":{"description":"Mailbox backend rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailboxErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}}},"502":{"description":"Mailbox backend unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailboxErrorResponse"}}}},"503":{"description":"Mailboxes disabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MailboxErrorBody"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"mailboxId","in":"path"},{"schema":{"type":"string","minLength":1},"required":true,"name":"messageId","in":"path"},{"schema":{"type":"string","enum":["true","false"],"description":"Return the raw HTML part as htmlBody (untrusted; render isolated)."},"required":false,"description":"Return the raw HTML part as htmlBody (untrusted; render isolated).","name":"includeHtml","in":"query"}]}},"/models":{"get":{"operationId":"listPublicModels","summary":"List available LLM models","description":"Returns the available LLM models with their identifiers, providers, and optional display metadata. Requires only your normal API authentication. Token prices are not included.","responses":{"200":{"description":"The public model list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelListResponse"}}}},"503":{"description":"The model catalog is temporarily unavailable (catalog_unavailable)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"Opaque","description":"Bearer token via Authorization header"}},"schemas":{"CancelEvent":{"properties":{"reason":{"type":"string","title":"Reason"}},"type":"object","required":["reason"],"title":"CancelEvent"},"CreatedEvent":{"properties":{"id":{"type":"string","title":"Id"},"streamUrl":{"type":"string","title":"Streamurl"}},"type":"object","required":["id","streamUrl"],"title":"CreatedEvent"},"ErrorResponse":{"properties":{"title":{"type":"string","title":"Title","description":"The title of the error"},"status":{"type":"integer","title":"Status","description":"The status code of the error"},"detail":{"type":"string","title":"Detail","description":"The detail of the error"},"errors":{"items":{},"type":"array","title":"Errors","description":"The errors"}},"type":"object","required":["title","status","detail","errors"],"title":"ErrorResponse"},"ExceptionEvent":{"properties":{"exception":{"type":"string","title":"Exception"}},"type":"object","required":["exception"],"title":"ExceptionEvent"},"ExecutorActionEvent":{"properties":{"action_json":{"title":"Action Json","type":"string"},"thought":{"title":"Thought","type":"string"},"description":{"title":"Description","type":"string"},"full_response":{"default":"","title":"Full Response","type":"string"}},"required":["action_json","thought","description"],"title":"ExecutorActionEvent","type":"object"},"ExecutorActionResultEvent":{"properties":{"action":{"additionalProperties":true,"title":"Action","type":"object"},"success":{"title":"Success","type":"boolean"},"error":{"title":"Error","type":"string"},"summary":{"title":"Summary","type":"string"},"thought":{"default":"","title":"Thought","type":"string"},"full_response":{"default":"","title":"Full Response","type":"string"}},"required":["action","success","error","summary"],"title":"ExecutorActionResultEvent","type":"object"},"ExecutorContextEvent":{"properties":{"subgoal":{"title":"Subgoal","type":"string"}},"required":["subgoal"],"title":"ExecutorContextEvent","type":"object"},"ExecutorInputEvent":{"properties":{"current_subgoal":{"title":"Current Subgoal","type":"string"}},"required":["current_subgoal"],"title":"ExecutorInputEvent","type":"object"},"ExecutorResponseEvent":{"properties":{"response":{"title":"Response","type":"string"},"usage":{"anyOf":[{"$ref":"#/components/schemas/UsageResult"},{"type":"null"}],"default":null}},"required":["response"],"title":"ExecutorResponseEvent","type":"object"},"ExecutorResultEvent":{"properties":{"action":{"additionalProperties":true,"title":"Action","type":"object"},"outcome":{"title":"Outcome","type":"boolean"},"error":{"title":"Error","type":"string"},"summary":{"title":"Summary","type":"string"}},"required":["action","outcome","error","summary"],"title":"ExecutorResultEvent","type":"object"},"FastAgentEndEvent":{"properties":{"success":{"title":"Success","type":"boolean"},"reason":{"title":"Reason","type":"string"},"tool_call_count":{"default":0,"title":"Tool Call Count","type":"integer"}},"required":["success","reason"],"title":"FastAgentEndEvent","type":"object"},"FastAgentExecuteEvent":{"properties":{"instruction":{"title":"Instruction","type":"string"}},"required":["instruction"],"title":"FastAgentExecuteEvent","type":"object"},"FastAgentInputEvent":{"properties":{},"title":"FastAgentInputEvent","type":"object"},"FastAgentOutputEvent":{"properties":{"output":{"title":"Output","type":"string"}},"required":["output"],"title":"FastAgentOutputEvent","type":"object"},"FastAgentResponseEvent":{"properties":{"thought":{"title":"Thought","type":"string"},"code":{"anyOf":[{"type":"string"},{"type":"null"}],"default":null,"title":"Code"},"usage":{"anyOf":[{"$ref":"#/components/schemas/UsageResult"},{"type":"null"}],"default":null},"tool_call_status":{"$ref":"#/components/schemas/ToolCallParseStatus","default":"no_markup"}},"required":["thought"],"title":"FastAgentResponseEvent","type":"object"},"FastAgentResultEvent":{"properties":{"success":{"title":"Success","type":"boolean"},"reason":{"title":"Reason","type":"string"},"instruction":{"title":"Instruction","type":"string"}},"required":["success","reason","instruction"],"title":"FastAgentResultEvent","type":"object"},"FastAgentToolCallEvent":{"properties":{"tool_calls_repr":{"title":"Tool Calls Repr","type":"string"}},"required":["tool_calls_repr"],"title":"FastAgentToolCallEvent","type":"object"},"FinalizeEvent":{"properties":{"success":{"title":"Success","type":"boolean"},"reason":{"title":"Reason","type":"string"}},"required":["success","reason"],"title":"FinalizeEvent","type":"object"},"ManagerContextEvent":{"properties":{},"title":"ManagerContextEvent","type":"object"},"ManagerInputEvent":{"properties":{},"title":"ManagerInputEvent","type":"object"},"ManagerPlanDetailsEvent":{"properties":{"plan":{"title":"Plan","type":"string"},"subgoal":{"title":"Subgoal","type":"string"},"thought":{"title":"Thought","type":"string"},"answer":{"default":"","title":"Answer","type":"string"},"memory_update":{"default":"","title":"Memory Update","type":"string"},"progress_summary":{"default":"","title":"Progress Summary","type":"string"},"success":{"anyOf":[{"type":"boolean"},{"type":"null"}],"default":null,"title":"Success"},"full_response":{"default":"","title":"Full Response","type":"string"}},"required":["plan","subgoal","thought"],"title":"ManagerPlanDetailsEvent","type":"object"},"ManagerPlanEvent":{"properties":{"plan":{"title":"Plan","type":"string"},"current_subgoal":{"title":"Current Subgoal","type":"string"},"thought":{"title":"Thought","type":"string"},"answer":{"default":"","title":"Answer","type":"string"},"success":{"anyOf":[{"type":"boolean"},{"type":"null"}],"default":null,"title":"Success"}},"required":["plan","current_subgoal","thought"],"title":"ManagerPlanEvent","type":"object"},"ManagerResponseEvent":{"properties":{"response":{"title":"Response","type":"string"},"usage":{"anyOf":[{"$ref":"#/components/schemas/UsageResult"},{"type":"null"}],"default":null}},"required":["response"],"title":"ManagerResponseEvent","type":"object"},"MediaListResponse":{"properties":{"urls":{"items":{"type":"string"},"type":"array","title":"Urls","description":"The list of media URLs"}},"type":"object","required":["urls"],"title":"MediaListResponse"},"MediaResponse":{"properties":{"url":{"type":"string","title":"Url","description":"The URL of the media"}},"type":"object","required":["url"],"title":"MediaResponse"},"PackageCredentials":{"properties":{"packageName":{"type":"string","title":"Packagename"},"credentialNames":{"items":{"type":"string"},"type":"array","title":"Credentialnames"}},"type":"object","required":["packageName","credentialNames"],"title":"PackageCredentials"},"PaginatedResult_TaskListItem_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/TaskListItem"},"type":"array","title":"Items","description":"The paginated items"},"pagination":{"$ref":"#/components/schemas/PaginationMeta","description":"Pagination metadata"}},"type":"object","required":["items","pagination"],"title":"PaginatedResult[TaskListItem]"},"PaginationMeta":{"properties":{"page":{"type":"integer","title":"Page","description":"Current page number (1-based)"},"pageSize":{"type":"integer","title":"Pagesize","description":"Number of items per page"},"total":{"type":"integer","title":"Total","description":"Total number of items"},"pages":{"type":"integer","title":"Pages","description":"Total number of pages"},"hasNext":{"type":"boolean","title":"Hasnext","description":"Whether there is a next page"},"hasPrev":{"type":"boolean","title":"Hasprev","description":"Whether there is a previous page"}},"type":"object","required":["page","pageSize","total","pages","hasNext","hasPrev"],"title":"PaginationMeta","description":"Pagination metadata."},"QueuedEvent":{"properties":{"id":{"type":"string","title":"Id"},"status":{"type":"string","title":"Status","default":"queued"}},"type":"object","required":["id"],"title":"QueuedEvent","description":"Emitted to SSE clients when the task is waiting in the device queue."},"RecordUIStateEvent":{"properties":{"url":{"type":"string","title":"Url"},"index":{"type":"integer","title":"Index"}},"type":"object","required":["url","index"],"title":"RecordUIStateEvent"},"ScreenshotEvent":{"properties":{"url":{"type":"string","title":"Url"},"index":{"type":"integer","title":"Index"}},"type":"object","required":["url","index"],"title":"ScreenshotEvent"},"StartEvent":{"properties":{},"title":"StartEvent","type":"object"},"StopEvent":{"properties":{},"title":"StopEvent","type":"object"},"TaskAPIResultEvent":{"properties":{"success":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Success"},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message"},"structured_output":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Structured Output"},"steps":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Steps"}},"type":"object","title":"TaskAPIResultEvent","description":"Final result event of a task."},"TaskCancelResponse":{"properties":{"cancelled":{"type":"boolean","title":"Cancelled","description":"Whether the task was cancelled"}},"type":"object","required":["cancelled"],"title":"TaskCancelResponse"},"TaskCreate":{"properties":{"llmModel":{"type":"string","title":"Llmmodel","description":"The LLM model identifier to use for the task (e.g. 'mobilerun/mobile-agent-fast'). When omitted with reasoning=false, the fast-mode default model is used.","default":"mobilerun/mobile-agent-fast"},"task":{"type":"string","minLength":1,"title":"Task"},"maxSteps":{"type":"integer","title":"Maxsteps","default":100},"temperature":{"type":"number","title":"Temperature","description":"Deprecated and ignored. Sampling behavior is controlled by the model provider.","default":0.5,"deprecated":true},"reasoning":{"type":"boolean","title":"Reasoning","default":true},"accessibility":{"type":"boolean","title":"Accessibility","default":true},"vision":{"type":"boolean","title":"Vision","default":false},"executionTimeout":{"type":"integer","maximum":2700,"minimum":1,"title":"Executiontimeout","description":"Maximum agent execution time in seconds (1–2700).","default":1000},"credentials":{"items":{"$ref":"#/components/schemas/PackageCredentials"},"type":"array","title":"Credentials"},"apps":{"items":{"type":"string"},"type":"array","title":"Apps"},"files":{"items":{"type":"string"},"type":"array","title":"Files"},"outputSchema":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Outputschema"},"vpnCountry":{"anyOf":[{"$ref":"#/components/schemas/VPNCountry"},{"type":"null"}]},"subagentModel":{"type":"string","title":"Subagentmodel","description":"LLM model used by sub-agent roles: executor, app_opener, structured_output","default":"mobilerun/mobile-agent-fast"},"stealth":{"type":"boolean","title":"Stealth","description":"Deprecated: use humanize. Both names must agree when supplied together.","default":false,"deprecated":true},"continueOnFailure":{"type":"boolean","title":"Continueonfailure","default":false},"recordingEnabled":{"type":"boolean","title":"Recordingenabled","description":"Record device video for the whole task and persist a retrievable reference","default":false},"deviceId":{"type":"string","format":"uuid","title":"Deviceid","description":"The ID of the device to run the task on."},"displayId":{"type":"integer","title":"Displayid","description":"The display ID of the device to run the task on.","default":0},"systemPrompt":{"anyOf":[{"type":"string","maxLength":32000},{"type":"null"}],"title":"Systemprompt","description":"Optional custom behavioral overlay applied on top of the agent's default system prompts. Never echoed back in responses or errors."},"humanize":{"type":"boolean","title":"Humanize","description":"Request human-like input where supported by the device. Replaces the deprecated stealth field; both must agree when supplied together.","default":false}},"type":"object","required":["task","deviceId"],"title":"TaskCreate"},"TaskCreatedResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id","description":"The ID of the task"},"status":{"$ref":"#/components/schemas/TaskStatus","description":"The status of the task (queued or created)"},"streamUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Streamurl","description":"The URL of the stream (null when queued)"}},"type":"object","required":["id","status"],"title":"TaskCreatedResponse"},"TaskExecution":{"properties":{"terminationReason":{"$ref":"#/components/schemas/TaskTerminationReason"},"retrySafety":{"$ref":"#/components/schemas/TaskRetrySafety","default":"unknown"},"checkpoint":{"$ref":"#/components/schemas/TaskExecutionCheckpoint"}},"type":"object","required":["terminationReason","checkpoint"],"title":"TaskExecution"},"TaskExecutionCheckpoint":{"properties":{"steps":{"type":"integer","minimum":0,"title":"Steps","default":0},"plan":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Plan"},"currentSubgoal":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Currentsubgoal"},"progressSummary":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Progresssummary"}},"type":"object","title":"TaskExecutionCheckpoint"},"TaskListItem":{"properties":{"createdAt":{"type":"string","format":"date-time","title":"Createdat"},"updatedAt":{"type":"string","format":"date-time","title":"Updatedat"},"llmModel":{"type":"string","title":"Llmmodel","description":"The LLM model identifier to use for the task (e.g. 'gemini/gemini-2.5-flash')"},"task":{"type":"string","minLength":1,"title":"Task"},"maxSteps":{"type":"integer","title":"Maxsteps","default":100},"temperature":{"type":"number","title":"Temperature","description":"Deprecated and ignored. Sampling behavior is controlled by the model provider.","default":0.5,"deprecated":true},"reasoning":{"type":"boolean","title":"Reasoning","default":true},"accessibility":{"type":"boolean","title":"Accessibility","default":true},"vision":{"type":"boolean","title":"Vision","default":false},"executionTimeout":{"type":"integer","title":"Executiontimeout","default":1000},"credentials":{"items":{"$ref":"#/components/schemas/PackageCredentials"},"type":"array","title":"Credentials"},"apps":{"items":{"type":"string"},"type":"array","title":"Apps"},"files":{"items":{"type":"string"},"type":"array","title":"Files"},"outputSchema":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Outputschema"},"vpnCountry":{"anyOf":[{"$ref":"#/components/schemas/VPNCountry"},{"type":"null"}]},"subagentModel":{"type":"string","title":"Subagentmodel","description":"LLM model used by sub-agent roles: executor, app_opener, structured_output","default":"mobilerun/mobile-agent-fast"},"stealth":{"type":"boolean","title":"Stealth","description":"Deprecated: use humanize. Both names must agree when supplied together.","default":false,"deprecated":true},"continueOnFailure":{"type":"boolean","title":"Continueonfailure","default":false},"recordingEnabled":{"type":"boolean","title":"Recordingenabled","description":"Record device video for the whole task and persist a retrievable reference","default":false},"id":{"type":"string","format":"uuid","title":"Id"},"status":{"$ref":"#/components/schemas/TaskStatus"},"deviceId":{"type":"string","format":"uuid","title":"Deviceid"},"displayId":{"type":"integer","title":"Displayid"},"tmpDevice":{"type":"boolean","title":"Tmpdevice"},"dispatchedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Dispatchedat"},"claimedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Claimedat"},"cancelRequestedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Cancelrequestedat"},"streamUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Streamurl"},"succeeded":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Succeeded"},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message"},"output":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Output"},"steps":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Steps"},"finishedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Finishedat"},"creditsUsed":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Creditsused"},"recordingId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Recordingid"},"recordingDeviceId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Recordingdeviceid"},"source":{"type":"string","enum":["api","agent"],"title":"Source","description":"Where the task came from: 'api' for tasks created via POST /tasks, 'agent' for tasks spawned by an agent step. Agent tasks are readable (status, trajectory, media) but not controllable via this API.","default":"api"},"userId":{"type":"string","title":"Userid","description":"Deprecated: use ownerId (tenancy) / createdBy (actor).","deprecated":true},"ownerId":{"type":"string","title":"Ownerid"},"createdBy":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Createdby"},"humanize":{"type":"boolean","title":"Humanize","description":"Whether human-like input was requested. Always equal to the deprecated stealth field.","default":false}},"type":"object","required":["llmModel","task","id","status","deviceId","displayId","tmpDevice","userId","ownerId"],"title":"TaskListItem","description":"Task representation for list endpoints — omits the large trajectory field."},"TaskMessageCreate":{"properties":{"message":{"type":"string","maxLength":4000000,"minLength":1,"title":"Message","description":"Message to send to the running agent"}},"type":"object","required":["message"],"title":"TaskMessageCreate"},"TaskMessageResponse":{"properties":{"sent":{"type":"boolean","title":"Sent","description":"Whether the message was queued for delivery"}},"type":"object","required":["sent"],"title":"TaskMessageResponse"},"TaskResponse":{"properties":{"task":{"$ref":"#/components/schemas/TaskListItem","description":"The task"}},"type":"object","required":["task"],"title":"TaskResponse"},"TaskRetrySafety":{"type":"string","enum":["unknown"],"title":"TaskRetrySafety"},"TaskStatus":{"type":"string","enum":["prepared","queued","created","running","cancelling","completed","failed","cancelled"],"title":"TaskStatus"},"TaskStatusResponse":{"properties":{"status":{"$ref":"#/components/schemas/TaskStatus","description":"The status of the task"},"succeeded":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Succeeded","description":"Whether the task succeeded"},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message","description":"The agent's final answer or failure reason"},"output":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Output","description":"Structured output if outputSchema was set"},"steps":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Steps","description":"Number of steps taken"},"execution":{"anyOf":[{"$ref":"#/components/schemas/TaskExecution"},{"type":"null"}],"description":"Execution metadata for abnormal terminal outcomes"},"lastResponse":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Lastresponse","description":"The last agent response (FastAgentResponseEvent or ManagerPlanEvent)"},"recordingId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Recordingid","description":"ID of the task's whole-task video recording, if recordingEnabled was set"},"recordingDeviceId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Recordingdeviceid","description":"Device ID associated with recordingId"}},"type":"object","required":["status"],"title":"TaskStatusResponse"},"TaskTerminationReason":{"type":"string","enum":["execution_timeout","worker_lost","cancelled","agent_failed"],"title":"TaskTerminationReason"},"TaskTrajectoryResponse":{"properties":{"trajectory":{"items":{"anyOf":[{"$ref":"#/components/schemas/TrajectoryQueuedEvent"},{"$ref":"#/components/schemas/TrajectoryCreatedEvent"},{"$ref":"#/components/schemas/TrajectoryExceptionEvent"},{"$ref":"#/components/schemas/TrajectoryCancelEvent"},{"$ref":"#/components/schemas/TrajectoryScreenshotEvent"},{"$ref":"#/components/schemas/TrajectoryStartEvent"},{"$ref":"#/components/schemas/TrajectoryFinalizeEvent"},{"$ref":"#/components/schemas/TrajectoryStopEvent"},{"$ref":"#/components/schemas/TrajectoryResultEvent"},{"$ref":"#/components/schemas/TrajectoryManagerInputEvent"},{"$ref":"#/components/schemas/TrajectoryManagerPlanEvent"},{"$ref":"#/components/schemas/TrajectoryExecutorInputEvent"},{"$ref":"#/components/schemas/TrajectoryExecutorResultEvent"},{"$ref":"#/components/schemas/TrajectoryFastAgentInputEvent"},{"$ref":"#/components/schemas/TrajectoryFastAgentResponseEvent"},{"$ref":"#/components/schemas/TrajectoryFastAgentToolCallEvent"},{"$ref":"#/components/schemas/TrajectoryFastAgentOutputEvent"},{"$ref":"#/components/schemas/TrajectoryFastAgentEndEvent"},{"$ref":"#/components/schemas/TrajectoryFastAgentExecuteEvent"},{"$ref":"#/components/schemas/TrajectoryFastAgentResultEvent"},{"$ref":"#/components/schemas/TrajectoryToolExecutionEvent"},{"$ref":"#/components/schemas/TrajectoryRecordUIStateEvent"},{"$ref":"#/components/schemas/TrajectoryManagerContextEvent"},{"$ref":"#/components/schemas/TrajectoryManagerResponseEvent"},{"$ref":"#/components/schemas/TrajectoryManagerPlanDetailsEvent"},{"$ref":"#/components/schemas/TrajectoryExecutorContextEvent"},{"$ref":"#/components/schemas/TrajectoryExecutorResponseEvent"},{"$ref":"#/components/schemas/TrajectoryExecutorActionEvent"},{"$ref":"#/components/schemas/TrajectoryExecutorActionResultEvent"},{"$ref":"#/components/schemas/TrajectoryUserMessageEvent"},{"$ref":"#/components/schemas/TrajectoryUnknownEvent"}]},"type":"array","title":"Trajectory","description":"The trajectory of the task"}},"type":"object","required":["trajectory"],"title":"TaskTrajectoryResponse"},"ToolCallParseStatus":{"type":"string","enum":["valid","no_markup","malformed"],"title":"ToolCallParseStatus","description":"Classification of tool-call markup in an LLM response."},"ToolExecutionEvent":{"properties":{"tool_name":{"title":"Tool Name","type":"string"},"tool_args":{"additionalProperties":true,"title":"Tool Args","type":"object"},"success":{"title":"Success","type":"boolean"},"summary":{"title":"Summary","type":"string"}},"required":["tool_name","tool_args","success","summary"],"title":"ToolExecutionEvent","type":"object"},"TrajectoryCancelEvent":{"properties":{"event":{"type":"string","const":"CancelEvent","title":"Event"},"data":{"$ref":"#/components/schemas/CancelEvent"}},"type":"object","required":["event","data"],"title":"TrajectoryCancelEvent"},"TrajectoryCreatedEvent":{"properties":{"event":{"type":"string","const":"CreatedEvent","title":"Event"},"data":{"$ref":"#/components/schemas/CreatedEvent"}},"type":"object","required":["event","data"],"title":"TrajectoryCreatedEvent"},"TrajectoryExceptionEvent":{"properties":{"event":{"type":"string","const":"ExceptionEvent","title":"Event"},"data":{"$ref":"#/components/schemas/ExceptionEvent"}},"type":"object","required":["event","data"],"title":"TrajectoryExceptionEvent"},"TrajectoryExecutorActionEvent":{"properties":{"event":{"type":"string","const":"ExecutorActionEvent","title":"Event"},"data":{"$ref":"#/components/schemas/ExecutorActionEvent"}},"type":"object","required":["event","data"],"title":"TrajectoryExecutorActionEvent"},"TrajectoryExecutorActionResultEvent":{"properties":{"event":{"type":"string","const":"ExecutorActionResultEvent","title":"Event"},"data":{"$ref":"#/components/schemas/ExecutorActionResultEvent"}},"type":"object","required":["event","data"],"title":"TrajectoryExecutorActionResultEvent"},"TrajectoryExecutorContextEvent":{"properties":{"event":{"type":"string","const":"ExecutorContextEvent","title":"Event"},"data":{"$ref":"#/components/schemas/ExecutorContextEvent"}},"type":"object","required":["event","data"],"title":"TrajectoryExecutorContextEvent"},"TrajectoryExecutorInputEvent":{"properties":{"event":{"type":"string","const":"ExecutorInputEvent","title":"Event"},"data":{"$ref":"#/components/schemas/ExecutorInputEvent"}},"type":"object","required":["event","data"],"title":"TrajectoryExecutorInputEvent"},"TrajectoryExecutorResponseEvent":{"properties":{"event":{"type":"string","const":"ExecutorResponseEvent","title":"Event"},"data":{"$ref":"#/components/schemas/ExecutorResponseEvent"}},"type":"object","required":["event","data"],"title":"TrajectoryExecutorResponseEvent"},"TrajectoryExecutorResultEvent":{"properties":{"event":{"type":"string","const":"ExecutorResultEvent","title":"Event"},"data":{"$ref":"#/components/schemas/ExecutorResultEvent"}},"type":"object","required":["event","data"],"title":"TrajectoryExecutorResultEvent"},"TrajectoryFastAgentEndEvent":{"properties":{"event":{"type":"string","const":"FastAgentEndEvent","title":"Event"},"data":{"$ref":"#/components/schemas/FastAgentEndEvent"}},"type":"object","required":["event","data"],"title":"TrajectoryFastAgentEndEvent"},"TrajectoryFastAgentExecuteEvent":{"properties":{"event":{"type":"string","const":"FastAgentExecuteEvent","title":"Event"},"data":{"$ref":"#/components/schemas/FastAgentExecuteEvent"}},"type":"object","required":["event","data"],"title":"TrajectoryFastAgentExecuteEvent"},"TrajectoryFastAgentInputEvent":{"properties":{"event":{"type":"string","const":"FastAgentInputEvent","title":"Event"},"data":{"$ref":"#/components/schemas/FastAgentInputEvent"}},"type":"object","required":["event","data"],"title":"TrajectoryFastAgentInputEvent"},"TrajectoryFastAgentOutputEvent":{"properties":{"event":{"type":"string","const":"FastAgentOutputEvent","title":"Event"},"data":{"$ref":"#/components/schemas/FastAgentOutputEvent"}},"type":"object","required":["event","data"],"title":"TrajectoryFastAgentOutputEvent"},"TrajectoryFastAgentResponseEvent":{"properties":{"event":{"type":"string","const":"FastAgentResponseEvent","title":"Event"},"data":{"$ref":"#/components/schemas/FastAgentResponseEvent"}},"type":"object","required":["event","data"],"title":"TrajectoryFastAgentResponseEvent"},"TrajectoryFastAgentResultEvent":{"properties":{"event":{"type":"string","const":"FastAgentResultEvent","title":"Event"},"data":{"$ref":"#/components/schemas/FastAgentResultEvent"}},"type":"object","required":["event","data"],"title":"TrajectoryFastAgentResultEvent"},"TrajectoryFastAgentToolCallEvent":{"properties":{"event":{"type":"string","const":"FastAgentToolCallEvent","title":"Event"},"data":{"$ref":"#/components/schemas/FastAgentToolCallEvent"}},"type":"object","required":["event","data"],"title":"TrajectoryFastAgentToolCallEvent"},"TrajectoryFinalizeEvent":{"properties":{"event":{"type":"string","const":"FinalizeEvent","title":"Event"},"data":{"$ref":"#/components/schemas/FinalizeEvent"}},"type":"object","required":["event","data"],"title":"TrajectoryFinalizeEvent"},"TrajectoryManagerContextEvent":{"properties":{"event":{"type":"string","const":"ManagerContextEvent","title":"Event"},"data":{"$ref":"#/components/schemas/ManagerContextEvent"}},"type":"object","required":["event","data"],"title":"TrajectoryManagerContextEvent"},"TrajectoryManagerInputEvent":{"properties":{"event":{"type":"string","const":"ManagerInputEvent","title":"Event"},"data":{"$ref":"#/components/schemas/ManagerInputEvent"}},"type":"object","required":["event","data"],"title":"TrajectoryManagerInputEvent"},"TrajectoryManagerPlanDetailsEvent":{"properties":{"event":{"type":"string","const":"ManagerPlanDetailsEvent","title":"Event"},"data":{"$ref":"#/components/schemas/ManagerPlanDetailsEvent"}},"type":"object","required":["event","data"],"title":"TrajectoryManagerPlanDetailsEvent"},"TrajectoryManagerPlanEvent":{"properties":{"event":{"type":"string","const":"ManagerPlanEvent","title":"Event"},"data":{"$ref":"#/components/schemas/ManagerPlanEvent"}},"type":"object","required":["event","data"],"title":"TrajectoryManagerPlanEvent"},"TrajectoryManagerResponseEvent":{"properties":{"event":{"type":"string","const":"ManagerResponseEvent","title":"Event"},"data":{"$ref":"#/components/schemas/ManagerResponseEvent"}},"type":"object","required":["event","data"],"title":"TrajectoryManagerResponseEvent"},"TrajectoryQueuedEvent":{"properties":{"event":{"type":"string","const":"QueuedEvent","title":"Event"},"data":{"$ref":"#/components/schemas/QueuedEvent"}},"type":"object","required":["event","data"],"title":"TrajectoryQueuedEvent"},"TrajectoryRecordUIStateEvent":{"properties":{"event":{"type":"string","const":"RecordUIStateEvent","title":"Event"},"data":{"$ref":"#/components/schemas/RecordUIStateEvent"}},"type":"object","required":["event","data"],"title":"TrajectoryRecordUIStateEvent"},"TrajectoryResultEvent":{"properties":{"event":{"type":"string","const":"ResultEvent","title":"Event"},"data":{"$ref":"#/components/schemas/TaskAPIResultEvent"}},"type":"object","required":["event","data"],"title":"TrajectoryResultEvent"},"TrajectoryScreenshotEvent":{"properties":{"event":{"type":"string","const":"ScreenshotEvent","title":"Event"},"data":{"$ref":"#/components/schemas/ScreenshotEvent"}},"type":"object","required":["event","data"],"title":"TrajectoryScreenshotEvent"},"TrajectoryStartEvent":{"properties":{"event":{"type":"string","const":"StartEvent","title":"Event"},"data":{"$ref":"#/components/schemas/StartEvent"}},"type":"object","required":["event","data"],"title":"TrajectoryStartEvent"},"TrajectoryStopEvent":{"properties":{"event":{"type":"string","const":"StopEvent","title":"Event"},"data":{"$ref":"#/components/schemas/StopEvent"}},"type":"object","required":["event","data"],"title":"TrajectoryStopEvent"},"TrajectoryToolExecutionEvent":{"properties":{"event":{"type":"string","const":"ToolExecutionEvent","title":"Event"},"data":{"$ref":"#/components/schemas/ToolExecutionEvent"}},"type":"object","required":["event","data"],"title":"TrajectoryToolExecutionEvent"},"TrajectoryUnknownEvent":{"properties":{"event":{"type":"string","title":"Event"},"data":{"additionalProperties":true,"type":"object","title":"Data","default":{}}},"type":"object","required":["event"],"title":"TrajectoryUnknownEvent"},"TrajectoryUserMessageEvent":{"properties":{"event":{"type":"string","const":"UserMessageEvent","title":"Event"},"data":{"$ref":"#/components/schemas/UserMessageEvent"}},"type":"object","required":["event","data"],"title":"TrajectoryUserMessageEvent"},"UnauthorizedResponse":{"properties":{"title":{"type":"string","title":"Title","description":"The title of the error","default":"Unauthorized"},"status":{"type":"integer","title":"Status","description":"The status code of the error","default":401},"detail":{"type":"string","title":"Detail","description":"The detail of the error","default":"You are not authorized to access this resource"},"errors":{"items":{},"type":"array","title":"Errors","description":"The errors","default":[]}},"type":"object","title":"UnauthorizedResponse"},"UsageResult":{"properties":{"request_tokens":{"type":"integer","title":"Request Tokens"},"response_tokens":{"type":"integer","title":"Response Tokens"},"total_tokens":{"type":"integer","title":"Total Tokens"},"requests":{"type":"integer","title":"Requests"}},"type":"object","required":["request_tokens","response_tokens","total_tokens","requests"],"title":"UsageResult"},"UserMessageEvent":{"properties":{"action":{"type":"string","title":"Action"},"message_ids":{"items":{"type":"string"},"type":"array","title":"Message Ids"},"consumer":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Consumer"},"reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reason"},"step_number":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Step Number"}},"type":"object","required":["action","message_ids"],"title":"UserMessageEvent","description":"Tracks the lifecycle of an external user message: queued → applied | dropped."},"VPNCountry":{"type":"string","enum":["US","BR","FR","DE","IN","JP","KR","ZA"],"title":"VPNCountry"},"OnePasswordConnection":{"type":"object","properties":{"connected":{"type":"boolean"},"connectedBy":{"type":"string"},"connectedAt":{"type":"string"},"vaults":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"}},"required":["id","title"]}}},"required":["connected"]},"CredentialErrorResponse":{"type":"object","properties":{"code":{"$ref":"#/components/schemas/CredentialErrorCode"},"message":{"type":"string"}},"required":["code","message"]},"CredentialErrorCode":{"type":"string","enum":["credential_read_only","credential_source_unavailable","credential_source_rate_limited","onepassword_not_connected","onepassword_token_invalid","onepassword_no_vaults","onepassword_reference_invalid","invalid_request","package_exists","credential_not_found","proxy_not_found","create_failed","update_failed","protocol_change_not_allowed"]},"ApiErrorEnvelope":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{},"traceId":{"type":"string"},"retryAfterSeconds":{"type":"number"}},"required":["code","message"]},"InternalServerError":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"traceId":{"type":"string"}},"required":["code","message"]},"OnePasswordItem":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"category":{"type":"string"},"websites":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string"},"label":{"type":"string"}},"required":["url","label"]}}},"required":["id","title","category","websites"]},"OnePasswordField":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"fieldType":{"type":"string"},"sectionId":{"type":"string"}},"required":["id","title","fieldType"]},"Credential":{"type":"object","properties":{"ownerId":{"type":"string"},"createdBy":{"type":["string","null"]},"userId":{"type":["string","null"],"deprecated":true,"description":"Deprecated: use createdBy (same value — the creating actor). Null for credentials created before rollout."},"packageName":{"type":"string"},"secretPath":{"type":"string"},"credentialName":{"type":"string"},"fields":{"type":"array","items":{"type":"object","properties":{"fieldType":{"type":"string","enum":["email","username","password","api_token","phone_number","two_factor_secret","backup_codes"]},"value":{"type":"string","minLength":1}},"required":["fieldType","value"]}},"source":{"type":"string","enum":["mobilerun","onepassword"]},"link":{"type":"object","properties":{"provider":{"type":"string","enum":["onepassword"]},"vaultId":{"type":"string","minLength":1},"vaultName":{"type":"string"},"itemId":{"type":"string","minLength":1},"itemTitle":{"type":"string"},"fieldMap":{"type":"array","items":{"type":"object","properties":{"fieldType":{"type":"string","enum":["email","username","password","api_token","phone_number","two_factor_secret","backup_codes"]},"fieldId":{"type":"string","minLength":1}},"required":["fieldType","fieldId"]},"minItems":1}},"required":["provider","vaultId","vaultName","itemId","itemTitle","fieldMap"]}},"required":["ownerId","createdBy","userId","packageName","secretPath","credentialName","fields"]},"CredentialList":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Credential"}},"pagination":{"$ref":"#/components/schemas/Pagination"}},"required":["items","pagination"]},"Pagination":{"type":"object","properties":{"hasNext":{"type":"boolean"},"hasPrev":{"type":"boolean"},"page":{"type":"integer","minimum":1},"pageSize":{"type":"integer","minimum":1},"pages":{"type":"integer","minimum":0},"total":{"type":"integer","minimum":0}},"required":["hasNext","hasPrev","page","pageSize","pages","total"]},"PackageSchema":{"type":"object","properties":{"packageName":{"type":"string","minLength":1,"maxLength":200}},"required":["packageName"]},"UpdateCredentialFieldBody":{"type":"object","properties":{"value":{"type":"string","minLength":1}},"required":["value"]},"CreateCredentialFieldBody":{"type":"object","properties":{"fieldType":{"type":"string","enum":["email","username","password","api_token","phone_number","two_factor_secret","backup_codes"]},"value":{"type":"string","minLength":1}},"required":["fieldType","value"]},"ProxyConfig":{"oneOf":[{"$ref":"#/components/schemas/Socks5ProxyConfig"},{"$ref":"#/components/schemas/WireguardProxyConfig"}],"discriminator":{"propertyName":"protocol","mapping":{"socks5":"#/components/schemas/Socks5ProxyConfig","wireguard":"#/components/schemas/WireguardProxyConfig"}}},"Socks5ProxyConfig":{"type":"object","properties":{"name":{"type":"string","minLength":3,"maxLength":50},"protocol":{"type":"string","enum":["socks5"]},"host":{"type":"string","minLength":1},"port":{"type":"integer","minimum":1,"maximum":65535},"user":{"type":"string","minLength":1},"password":{"type":"string","minLength":1},"proxyId":{"type":"string","format":"uuid"}},"required":["name","protocol","host","port","user","password","proxyId"]},"WireguardProxyConfig":{"type":"object","properties":{"name":{"type":"string","minLength":3,"maxLength":50},"protocol":{"type":"string","enum":["wireguard"]},"config":{"type":"string","minLength":1,"maxLength":10000},"proxyId":{"type":"string","format":"uuid"}},"required":["name","protocol","config","proxyId"]},"CreateProxyBody":{"oneOf":[{"$ref":"#/components/schemas/CreateSocks5Proxy"},{"$ref":"#/components/schemas/CreateWireguardProxy"}],"discriminator":{"propertyName":"protocol","mapping":{"socks5":"#/components/schemas/CreateSocks5Proxy","wireguard":"#/components/schemas/CreateWireguardProxy"}}},"CreateSocks5Proxy":{"type":"object","properties":{"name":{"type":"string","minLength":3,"maxLength":50},"protocol":{"type":"string","enum":["socks5"]},"host":{"type":"string","minLength":1},"port":{"type":"integer","minimum":1,"maximum":65535},"user":{"type":"string","minLength":1},"password":{"type":"string","minLength":1}},"required":["name","protocol","host","port","user","password"]},"CreateWireguardProxy":{"type":"object","properties":{"name":{"type":"string","minLength":3,"maxLength":50},"protocol":{"type":"string","enum":["wireguard"]},"config":{"type":"string","minLength":1,"maxLength":10000}},"required":["name","protocol","config"]},"UpdateProxyBody":{"oneOf":[{"$ref":"#/components/schemas/UpdateSocks5Proxy"},{"$ref":"#/components/schemas/UpdateWireguardProxy"}],"discriminator":{"propertyName":"protocol","mapping":{"socks5":"#/components/schemas/UpdateSocks5Proxy","wireguard":"#/components/schemas/UpdateWireguardProxy"}}},"UpdateSocks5Proxy":{"type":"object","properties":{"name":{"type":"string","minLength":3,"maxLength":50},"protocol":{"type":"string","enum":["socks5"]},"host":{"type":"string","minLength":1},"port":{"type":"integer","minimum":1,"maximum":65535},"user":{"type":"string","minLength":1},"password":{"type":"string","minLength":1}},"required":["name","protocol","host","port","user","password"]},"UpdateWireguardProxy":{"type":"object","properties":{"name":{"type":"string","minLength":3,"maxLength":50},"protocol":{"type":"string","enum":["wireguard"]},"config":{"type":"string","minLength":1,"maxLength":10000}},"required":["name","protocol","config"]},"AppsApiErrorResponse":{"type":"object","properties":{"code":{"$ref":"#/components/schemas/AppsErrorCode"},"message":{"type":"string"}},"required":["code","message"]},"AppsErrorCode":{"type":"string","enum":["bad_request","not_found","conflict","rate_limited","temporarily_unavailable","internal_error"]},"AppsLegacyUnauthorizedError":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]},"AppsInternalServerError":{"type":"object","properties":{"code":{"type":"string","enum":["internal_error"]},"message":{"type":"string"},"traceId":{"type":"string"}},"required":["code","message"]},"PublicAppWithVersion":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"bundleId":{"type":"string"},"platform":{"type":"string","enum":["android","ios"]},"displayName":{"type":"string"},"description":{"type":["string","null"]},"iconURL":{"type":"string"},"developerName":{"type":["string","null"]},"createdAt":{"type":["string","null"],"format":"date-time"},"updatedAt":{"type":["string","null"],"format":"date-time"},"version":{"$ref":"#/components/schemas/PublicAppVersion"}},"required":["id","bundleId","platform","displayName","description","iconURL","developerName","createdAt","updatedAt","version"]},"PublicAppVersion":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"appId":{"type":"string","format":"uuid"},"versionCode":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"versionName":{"type":"string"},"country":{"type":"string","enum":["AF","AL","DZ","AS","AD","AO","AI","AQ","AG","AR","AM","AW","AP","AU","AT","AZ","BS","BH","BD","BB","BY","BE","BZ","BJ","BM","BT","BO","BQ","BA","BW","BV","BR","IO","BN","BG","BF","BI","KH","CM","CA","CV","KY","CF","TD","CL","CN","CX","CC","CO","KM","CG","CD","CK","CR","HR","CU","CW","CY","CZ","CI","DK","DJ","DM","DO","EC","EG","SV","GQ","ER","EE","ET","FK","FO","FJ","FI","FR","GF","PF","TF","GA","GM","GE","DE","GH","GI","GR","GL","GD","GP","GU","GT","GG","GN","GW","GY","HT","HM","VA","HN","HK","HU","IS","IN","ID","IR","IQ","IE","IM","IL","IT","JM","JP","JE","JO","KZ","KE","KI","KR","KW","KG","LA","LV","LB","LS","LR","LY","LI","LT","LU","MO","MG","MW","MY","MV","ML","MT","MH","MQ","MR","MU","YT","MX","FM","MD","MC","MN","ME","MS","MA","MZ","MM","NA","NR","NP","NL","AN","NC","NZ","NI","NE","NG","NU","NF","KP","MK","MP","NO","OM","PK","PW","PS","PA","PG","PY","PE","PH","PN","PL","PT","PR","QA","RE","RO","RU","RW","BL","SH","KN","LC","MF","PM","VC","WS","SM","ST","SA","SN","RS","CS","SC","SL","SG","SX","SK","SI","SB","SO","ZA","GS","SS","ES","LK","SD","SR","SJ","SZ","SE","CH","SY","TW","TJ","TZ","TH","TL","TG","TK","TO","TT","TN","TR","TM","TC","TV","UG","UA","AE","GB","US","UM","UY","UZ","VU","VE","VN","VG","VI","WF","EH","YE","ZM","ZW","AX"]},"status":{"type":"string","enum":["queued","available","failed","pruned"]},"source":{"type":"string","enum":["user","system","portal","store"]},"userId":{"type":["string","null"],"deprecated":true,"description":"Deprecated: use ownerId (tenancy) / createdBy (actor)."},"ownerId":{"type":["string","null"]},"createdBy":{"type":["string","null"]},"targetSdk":{"type":["integer","null"],"minimum":-9007199254740991,"maximum":9007199254740991},"sizeBytes":{"type":["integer","null"],"minimum":-9007199254740991,"maximum":9007199254740991},"queuedAt":{"type":["string","null"],"format":"date-time"},"createdAt":{"type":["string","null"],"format":"date-time"},"updatedAt":{"type":["string","null"],"format":"date-time"}},"required":["id","appId","versionCode","versionName","country","status","source","userId","ownerId","createdBy","targetSdk","sizeBytes","queuedAt","createdAt","updatedAt"]},"ConfirmUploadBadRequest":{"anyOf":[{"$ref":"#/components/schemas/ApiErrorEnvelope"},{"$ref":"#/components/schemas/AppsApiErrorResponse"}]},"StorageLimitReachedErrorEnvelope":{"type":"object","properties":{"code":{"type":"string","enum":["storage_limit_reached"]},"message":{"type":"string"},"details":{"$ref":"#/components/schemas/StorageLimitReachedDetails"},"traceId":{"type":"string"}},"required":["code","message","details"]},"StorageLimitReachedDetails":{"type":"object","properties":{"reason":{"type":"string","enum":["storage_limit"]},"usedBytes":{"type":"number"},"quotaBytes":{"type":["number","null"]},"requiredBytes":{"type":"number"}},"required":["reason"]},"StorageCheckUnavailableErrorEnvelope":{"type":"object","properties":{"code":{"type":"string","enum":["storage_check_unavailable"]},"message":{"type":"string"},"traceId":{"type":"string"},"retryAfterSeconds":{"type":"number","enum":[30]}},"required":["code","message"]},"StorageUsage":{"type":"object","properties":{"usedBytes":{"type":"number","description":"Bytes currently used (the sum of the user’s app versions when storage billing is off)"},"includedBytes":{"type":["number","null"],"description":"Bytes included in the plan. Null when unlimited, unknown, or storage billing is off."},"maxBytes":{"type":["number","null"],"description":"Hard admission bound in bytes: included + max purchasable overage, or included when overage is not allowed. Null = unlimited, unknown, or storage billing is off."},"overageAllowed":{"type":"boolean","description":"True when usage above includedBytes is billed as overage instead of blocked"}},"required":["usedBytes","includedBytes","maxBytes","overageAllowed"]},"App":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"bundleId":{"type":"string"},"platform":{"type":"string","enum":["android","ios"]},"displayName":{"type":"string"},"description":{"type":["string","null"]},"iconURL":{"type":"string"},"developerName":{"type":["string","null"]},"createdAt":{"type":["string","null"],"format":"date-time"},"updatedAt":{"type":["string","null"],"format":"date-time"}},"required":["id","bundleId","platform","displayName","description","iconURL","developerName","createdAt","updatedAt"]},"A11YBounds":{"additionalProperties":false,"properties":{"bottom":{"format":"int64","type":"integer"},"left":{"format":"int64","type":"integer"},"right":{"format":"int64","type":"integer"},"top":{"format":"int64","type":"integer"}},"required":["left","top","right","bottom"],"type":"object"},"A11YNode":{"additionalProperties":false,"properties":{"boundsInScreen":{"$ref":"#/components/schemas/A11YBounds"},"children":{"items":{"$ref":"#/components/schemas/A11YNode"},"type":["array","null"]},"className":{"type":"string"},"contentDescription":{"type":"string"},"hint":{"type":"string"},"isCheckable":{"type":"boolean"},"isChecked":{"type":"boolean"},"isClickable":{"type":"boolean"},"isEnabled":{"type":"boolean"},"isFocusable":{"type":"boolean"},"isFocused":{"type":"boolean"},"isLongClickable":{"type":"boolean"},"isPassword":{"type":"boolean"},"isScrollable":{"type":"boolean"},"isSelected":{"type":"boolean"},"isVisibleToUser":{"type":"boolean"},"packageName":{"type":"string"},"resourceId":{"type":"string"},"text":{"type":"string"}},"required":["boundsInScreen","className","resourceId","text","contentDescription","packageName","isCheckable","isChecked","isClickable","isEnabled","isFocusable","isFocused","isScrollable","isLongClickable","isPassword","isSelected","children"],"type":"object"},"AndroidState":{"additionalProperties":false,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["https://example.com/schemas/AndroidState.json"],"format":"uri","readOnly":true,"type":"string"},"a11y_tree":{"$ref":"#/components/schemas/A11YNode"},"device_context":{"$ref":"#/components/schemas/DeviceContext"},"ime_tree":{"$ref":"#/components/schemas/A11YNode"},"phone_state":{"$ref":"#/components/schemas/PhoneState"}},"required":["a11y_tree","ime_tree","phone_state","device_context"],"type":"object"},"AppInfo":{"additionalProperties":false,"properties":{"availableUpdate":{"$ref":"#/components/schemas/AppUpdate"},"isSystemApp":{"type":"boolean"},"label":{"type":"string"},"packageName":{"type":"string"},"versionCode":{"format":"int64","type":"integer"},"versionName":{"type":"string"}},"required":["packageName","label","versionName","versionCode","isSystemApp"],"type":"object"},"AppInstallStatus":{"additionalProperties":false,"properties":{"appId":{"description":"Android package name or iOS bundle id","type":"string"},"errorClass":{"description":"Only present when status is failed.","enum":["download_failed","adb_install_failed","panic","timeout","failed"],"type":"string"},"platform":{"description":"android or ios","type":"string"},"startedAt":{"format":"date-time","type":"string"},"status":{"description":"On iOS MDM devices, succeeded means the install command was accepted by the device's MDM channel, not that the install finished on-device.","enum":["running","succeeded","failed"],"type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["platform","appId","status","startedAt","updatedAt"],"type":"object"},"AppUpdate":{"additionalProperties":false,"properties":{"country":{"type":"string"},"versionCode":{"format":"int64","type":"integer"},"versionName":{"type":"string"}},"required":["versionCode","versionName","country"],"type":"object"},"ApplyProfileInputBody":{"additionalProperties":false,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["https://example.com/schemas/ApplyProfileInputBody.json"],"format":"uri","readOnly":true,"type":"string"},"profileId":{"description":"ID of the profile to apply","type":"string"}},"required":["profileId"],"type":"object"},"Capabilities":{"additionalProperties":false,"properties":{"accessibility":{"type":"boolean"},"agent":{"type":"boolean"},"apps":{"type":"boolean"},"browser":{"type":"boolean"},"cameraInjection":{"type":"boolean"},"clipboard":{"type":"boolean"},"esim":{"type":"boolean"},"factoryReset":{"type":"boolean"},"files":{"type":"boolean"},"fingerprint":{"type":"boolean"},"frida":{"type":"boolean"},"geo":{"type":"boolean"},"humanTouch":{"type":"boolean"},"identityReset":{"type":"boolean"},"language":{"type":"boolean"},"logcat":{"type":"boolean"},"mediaInjectionTransport":{"enum":["direct"],"type":"string"},"microphoneInjection":{"type":"boolean"},"proxy":{"type":"boolean"},"reboot":{"type":"boolean"},"recording":{"type":"boolean"},"reset":{"type":"boolean"},"shell":{"type":"boolean"},"spoofing":{"type":"boolean"},"stop":{"type":"boolean"},"stream":{"type":"boolean"},"time":{"type":"boolean"},"trafficInspection":{"type":"boolean"}},"required":["agent","accessibility","apps","files","proxy","geo","time","language","stream","fingerprint","spoofing","esim","logcat","humanTouch","reset","factoryReset","identityReset","reboot","shell","browser","microphoneInjection","cameraInjection","frida","stop","clipboard","trafficInspection","recording"],"type":"object"},"CapabilityInfo":{"additionalProperties":false,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["https://example.com/schemas/CapabilityInfo.json"],"format":"uri","readOnly":true,"type":"string"},"capabilities":{"$ref":"#/components/schemas/Capabilities"},"deviceType":{"type":"string"}},"required":["deviceType","capabilities"],"type":"object"},"ClipboardBody":{"additionalProperties":false,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["https://example.com/schemas/ClipboardBody.json"],"format":"uri","readOnly":true,"type":"string"},"text":{"type":"string"}},"required":["text"],"type":"object"},"ConfigureESimBody":{"additionalProperties":false,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["https://example.com/schemas/ConfigureESimBody.json"],"format":"uri","readOnly":true,"type":"string"},"confirmationCode":{"description":"Optional carrier-issued confirmation code (the 4th LPA segment). Required only for plans whose SM-DP+ challenges the device for one. Requires matchingId — the LPA spec only interprets segment 4 when segment 3 is present.","type":"string"},"enable":{"type":"boolean"},"matchingId":{"type":"string"},"smDpAddr":{"type":"string"}},"required":["smDpAddr","enable"],"type":"object"},"ConnectProxyBody":{"additionalProperties":false,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["https://example.com/schemas/ConnectProxyBody.json"],"format":"uri","readOnly":true,"type":"string"},"connect":{"$ref":"#/components/schemas/Ref","description":"Mobilerun Connect proxy — pass exactly one of id (use an existing proxy's credentials) or country (provision or reuse a rotating residential proxy for the device)."},"host":{"deprecated":true,"format":"hostname","maxLength":255,"type":"string"},"name":{"description":"Proxy name","maxLength":255,"type":"string"},"password":{"deprecated":true,"maxLength":255,"type":"string","writeOnly":true},"port":{"deprecated":true,"format":"int64","maximum":65535,"minimum":1,"type":"integer"},"smartIp":{"type":"boolean"},"socks5":{"$ref":"#/components/schemas/ConnectSOCKS5Config","description":"SOCKS5 proxy configuration (required for socks5)."},"user":{"deprecated":true,"maxLength":255,"type":"string"}},"type":"object"},"ConnectSOCKS5Config":{"additionalProperties":false,"properties":{"host":{"format":"hostname","maxLength":255,"type":"string"},"password":{"maxLength":255,"type":"string","writeOnly":true},"port":{"format":"int64","maximum":65535,"minimum":1,"type":"integer"},"user":{"maxLength":255,"type":"string"}},"required":["host","port"],"type":"object"},"CreateSessionBody":{"additionalProperties":false,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["https://example.com/schemas/CreateSessionBody.json"],"format":"uri","readOnly":true,"type":"string"},"expiresInSeconds":{"default":3600,"format":"int64","maximum":14400,"minimum":60,"type":"integer"},"maxBodyBytes":{"default":1048576,"format":"int64","maximum":10485760,"minimum":0,"type":"integer"}},"type":"object"},"DeviceCarrier":{"additionalProperties":false,"properties":{"GsmOperatorAlpha":{"type":"string"},"GsmOperatorNumeric":{"format":"int64","type":"integer"},"GsmSimOperatorAlpha":{"type":"string"},"GsmSimOperatorIsoCountry":{"type":"string"},"GsmSimOperatorNumeric":{"format":"int64","type":"integer"},"PersistSysTimezone":{"type":"string"}},"required":["GsmOperatorAlpha","GsmOperatorNumeric","GsmSimOperatorAlpha","GsmSimOperatorNumeric","GsmSimOperatorIsoCountry","PersistSysTimezone"],"type":"object"},"DeviceContext":{"additionalProperties":false,"properties":{"display_metrics":{"$ref":"#/components/schemas/DisplayMetrics"},"filtering_params":{"$ref":"#/components/schemas/FilteringParams"},"screen_bounds":{"$ref":"#/components/schemas/Rect"}},"required":["screen_bounds","filtering_params","display_metrics"],"type":"object"},"DeviceIdentifiers":{"additionalProperties":false,"properties":{"BootloaderSerialNumber":{"type":"string"},"IdentifierAndroidID":{"type":"string"},"IdentifierAppSetID":{"type":"string"},"IdentifierBluetoothMAC":{"type":"string"},"IdentifierGAID":{"type":"string"},"IdentifierGSFID":{"type":"string"},"IdentifierICCID":{"type":"string"},"IdentifierIMEI":{"type":"string"},"IdentifierIMSI":{"type":"string"},"IdentifierMEID":{"type":"string"},"IdentifierMediaDRMID":{"type":"string"},"IdentifierPhoneNumber":{"type":"string"},"IdentifierSerial":{"type":"string"},"IdentifierWifiMAC":{"type":"string"},"SerialNumber":{"type":"string"}},"required":["IdentifierSerial","IdentifierAndroidID","IdentifierIMEI","IdentifierMEID","IdentifierIMSI","IdentifierICCID","IdentifierPhoneNumber","IdentifierGAID","IdentifierGSFID","IdentifierAppSetID","IdentifierMediaDRMID","IdentifierWifiMAC","IdentifierBluetoothMAC","SerialNumber","BootloaderSerialNumber"],"type":"object"},"DeviceInfo":{"additionalProperties":false,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["https://example.com/schemas/DeviceInfo.json"],"format":"uri","readOnly":true,"type":"string"},"activeTaskId":{"type":"string"},"assignedAt":{"format":"date-time","type":["string","null"]},"billingStrategy":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"createdBy":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"},"ownerId":{"type":"string"},"platform":{"description":"Operating system the device runs.","enum":["android","ios"],"type":"string"},"providerId":{"type":"string"},"state":{"type":"string"},"stateMessage":{"type":"string"},"streamToken":{"type":"string"},"streamUrl":{"type":"string"},"taskCount":{"format":"int64","type":"integer"},"terminatesAt":{"format":"date-time","type":["string","null"]},"type":{"type":"string"},"updatedAt":{"format":"date-time","type":"string"},"userId":{"deprecated":true,"description":"Deprecated: use ownerId/createdBy.","type":"string"}},"required":["id","name","state","stateMessage","streamUrl","type","platform","createdAt","updatedAt","assignedAt","terminatesAt","taskCount","activeTaskId"],"type":"object"},"DeviceProxyConfig":{"additionalProperties":false,"properties":{"connect":{"$ref":"#/components/schemas/Ref"},"name":{"type":"string"},"smartIp":{"type":"boolean"},"socks5":{"$ref":"#/components/schemas/SOCKS5"}},"type":"object"},"DeviceScreenshot":{"additionalProperties":false,"properties":{"capturedAt":{"format":"date-time","type":"string"},"deviceId":{"type":"string"},"expiresAt":{"format":"date-time","type":"string"},"id":{"type":"string"},"recordingId":{"type":["string","null"]},"sizeBytes":{"format":"int64","type":"integer"}},"required":["id","deviceId","recordingId","sizeBytes","capturedAt","expiresAt"],"type":"object"},"DeviceScreenshotList":{"additionalProperties":false,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["https://example.com/schemas/DeviceScreenshotList.json"],"format":"uri","readOnly":true,"type":"string"},"items":{"items":{"$ref":"#/components/schemas/DeviceScreenshot"},"type":["array","null"]},"nextCursor":{"type":"string"}},"required":["items","nextCursor"],"type":"object"},"DeviceSpec":{"additionalProperties":false,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["https://example.com/schemas/DeviceSpec.json"],"format":"uri","readOnly":true,"type":"string"},"androidVersion":{"format":"int64","type":"integer"},"apps":{"items":{"type":"string"},"type":["array","null"]},"carrier":{"$ref":"#/components/schemas/DeviceCarrier"},"country":{"type":"string"},"files":{"items":{"type":"string"},"type":["array","null"]},"identifiers":{"$ref":"#/components/schemas/DeviceIdentifiers"},"locale":{"type":"string"},"location":{"$ref":"#/components/schemas/Location"},"name":{"type":"string"},"proxy":{"$ref":"#/components/schemas/DeviceProxyConfig"},"timezone":{"type":"string"}},"type":"object"},"DisplayInfo":{"additionalProperties":false,"properties":{"height":{"format":"int64","type":"integer"},"rotation":{"format":"int64","type":"integer"},"width":{"format":"int64","type":"integer"}},"required":["width","height","rotation"],"type":"object"},"DisplayMetrics":{"additionalProperties":false,"properties":{"density":{"format":"double","type":"number"},"densityDpi":{"format":"int64","type":"integer"},"heightPixels":{"format":"int64","type":"integer"},"scaledDensity":{"format":"double","type":"number"},"widthPixels":{"format":"int64","type":"integer"}},"required":["density","densityDpi","scaledDensity","widthPixels","heightPixels"],"type":"object"},"DomainError":{"additionalProperties":false,"properties":{"code":{"type":"string"},"details":{"additionalProperties":{},"type":"object"},"message":{"type":"string"}},"required":["code","message"],"type":"object"},"ESimAPN":{"additionalProperties":false,"properties":{"apn":{"type":"string"},"id":{"format":"int64","type":"integer"},"isPreferred":{"type":"boolean"},"mcc":{"type":"string"},"mnc":{"type":"string"},"name":{"type":"string"},"protocol":{"type":"string"},"roamingProtocol":{"type":"string"},"subId":{"format":"int64","type":"integer"},"type":{"type":"string"}},"required":["id","name","apn","mcc","mnc","type","protocol","roamingProtocol","subId","isPreferred"],"type":"object"},"ESimStatus":{"additionalProperties":false,"properties":{"carrier":{"type":"string"},"dataRoamingEnabled":{"type":"boolean"},"dataState":{"type":"string"},"isRoaming":{"type":"boolean"},"mobileDataEnabled":{"type":"boolean"},"networkType":{"type":"string"},"operator":{"type":"string"},"phoneType":{"type":"string"},"simState":{"type":"string"},"subId":{"format":"int64","type":"integer"}},"required":["subId","carrier","dataState","networkType","isRoaming","dataRoamingEnabled","mobileDataEnabled","operator","simState","phoneType"],"type":"object"},"ESimSubscription":{"additionalProperties":false,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["https://example.com/schemas/ESimSubscription.json"],"format":"uri","readOnly":true,"type":"string"},"carrier":{"type":"string"},"displayName":{"type":"string"},"iccid":{"type":"string"},"isEmbedded":{"type":"boolean"},"slot":{"format":"int64","type":"integer"},"subId":{"format":"int64","type":"integer"},"type":{"type":"string"}},"required":["subId","iccid","carrier","displayName","slot","type","isEmbedded"],"type":"object"},"EnableESimBody":{"additionalProperties":false,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["https://example.com/schemas/EnableESimBody.json"],"format":"uri","readOnly":true,"type":"string"},"subId":{"format":"int64","type":"integer"}},"required":["subId"],"type":"object"},"EnableKioskArgs":{"additionalProperties":false,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["https://example.com/schemas/EnableKioskArgs.json"],"format":"uri","readOnly":true,"type":"string"},"packageName":{"description":"Package to lock the device to (Android lock-task mode).","minLength":1,"type":"string"}},"required":["packageName"],"type":"object"},"ErrorDetail":{"additionalProperties":false,"properties":{"location":{"description":"Where the error occurred, e.g. 'body.items[3].tags' or 'path.thing-id'","type":"string"},"message":{"description":"Error message text","type":"string"},"value":{"description":"The value at the given location"}},"type":"object"},"ErrorModel":{"additionalProperties":false,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["https://example.com/schemas/ErrorModel.json"],"format":"uri","readOnly":true,"type":"string"},"detail":{"description":"A human-readable explanation specific to this occurrence of the problem.","examples":["Property foo is required but is missing."],"type":"string"},"errors":{"description":"Optional list of individual error details","items":{"$ref":"#/components/schemas/ErrorDetail"},"type":["array","null"]},"instance":{"description":"A URI reference that identifies the specific occurrence of the problem.","examples":["https://example.com/error-log/abc123"],"format":"uri","type":"string"},"status":{"description":"HTTP status code","examples":[400],"format":"int64","type":"integer"},"title":{"description":"A short, human-readable summary of the problem type. This value should not change between occurrences of the error.","examples":["Bad Request"],"type":"string"},"type":{"default":"about:blank","description":"A URI reference to human-readable documentation for the error.","examples":["https://example.com/errors/example"],"format":"uri","type":"string"}},"type":"object"},"ExecuteScriptArgs":{"additionalProperties":false,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["https://example.com/schemas/ExecuteScriptArgs.json"],"format":"uri","readOnly":true,"type":"string"},"script":{"description":"JavaScript expression to evaluate in the device's foreground Chrome tab (CDP Runtime.evaluate). It is an expression, not a function body — the expression's value is returned (no top-level 'return'). Must evaluate to a JSON-serializable value; wrap multi-statement logic in an IIFE, e.g. (() => { ... ; return x })().","type":"string"}},"required":["script"],"type":"object"},"ExecuteScriptOutputBody":{"additionalProperties":false,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["https://example.com/schemas/ExecuteScriptOutputBody.json"],"format":"uri","readOnly":true,"type":"string"},"result":{"description":"JSON-serialized return value of the script (null if it returned undefined). Non-JSON-serializable numbers (Infinity, NaN, -0) are returned as their string representation."}},"required":["result"],"type":"object"},"FileInfo":{"additionalProperties":false,"properties":{"extendedAttributes":{"type":"boolean"},"group":{"type":"string"},"hardLinks":{"format":"int64","type":"integer"},"modifiedAt":{"format":"date-time","type":"string"},"name":{"type":"string"},"owner":{"type":"string"},"permissions":{"$ref":"#/components/schemas/FilePermissions"},"size":{"format":"int64","type":"integer"},"symlinkTarget":{"type":"string"},"type":{"type":"string"}},"required":["name","owner","group","size","type","permissions","hardLinks","modifiedAt","extendedAttributes"],"type":"object"},"FileListBody":{"additionalProperties":false,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["https://example.com/schemas/FileListBody.json"],"format":"uri","readOnly":true,"type":"string"},"files":{"items":{"$ref":"#/components/schemas/FileInfo"},"type":["array","null"]},"path":{"type":"string"},"total":{"format":"int64","type":"integer"}},"required":["path","total","files"],"type":"object"},"FilePermissions":{"additionalProperties":false,"properties":{"group":{"$ref":"#/components/schemas/PermissionSet"},"others":{"$ref":"#/components/schemas/PermissionSet"},"owner":{"$ref":"#/components/schemas/PermissionSet"},"special":{"$ref":"#/components/schemas/SpecialPermissions"}},"required":["owner","group","others","special"],"type":"object"},"FilteringParams":{"additionalProperties":false,"properties":{"min_element_size":{"format":"int64","type":"integer"},"overlay_offset":{"format":"int64","type":"integer"}},"required":["min_element_size","overlay_offset"],"type":"object"},"FingerprintDisplay":{"additionalProperties":false,"properties":{"densityDpi":{"format":"int64","type":"integer"},"height":{"format":"int64","type":"integer"},"width":{"format":"int64","type":"integer"}},"type":"object"},"FingerprintModel":{"additionalProperties":false,"properties":{"aospVersion":{"type":"string"},"brand":{"type":"string"},"device":{"type":"string"},"hardware":{"type":"string"},"manufacturer":{"type":"string"},"model":{"type":"string"}},"type":"object"},"FingerprintResult":{"additionalProperties":false,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["https://example.com/schemas/FingerprintResult.json"],"format":"uri","readOnly":true,"type":"string"},"carrier":{"$ref":"#/components/schemas/DeviceCarrier"},"display":{"$ref":"#/components/schemas/FingerprintDisplay"},"identifiers":{"$ref":"#/components/schemas/DeviceIdentifiers"},"model":{"$ref":"#/components/schemas/FingerprintModel"}},"required":["model","display","identifiers","carrier"],"type":"object"},"GetProxyInfo":{"additionalProperties":false,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["https://example.com/schemas/GetProxyInfo.json"],"format":"uri","readOnly":true,"type":"string"},"connected":{"type":"boolean"},"name":{"description":"Active proxy name","type":["string","null"]},"protocol":{"description":"Active proxy protocol (socks5).","type":["string","null"]}},"required":["connected","protocol","name"],"type":"object"},"GlobalArgs":{"additionalProperties":false,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["https://example.com/schemas/GlobalArgs.json"],"format":"uri","readOnly":true,"type":"string"},"action":{"format":"int64","type":"integer"}},"required":["action"],"type":"object"},"Item":{"additionalProperties":false,"properties":{"capturedAt":{"format":"date-time","type":"string"},"id":{"type":"string"},"sizeBytes":{"format":"int64","type":"integer"},"url":{"description":"Presigned download URL, valid for 15 minutes.","type":"string"}},"required":["id","capturedAt","sizeBytes","url"],"type":"object"},"KeyboardInputArgs":{"additionalProperties":false,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["https://example.com/schemas/KeyboardInputArgs.json"],"format":"uri","readOnly":true,"type":"string"},"clear":{"default":false,"type":"boolean"},"completionMode":{"default":"accepted","description":"Completion guarantee. accepted returns after the input provider accepts the operation; committed additionally waits for the focused UI state to contain the complete text or become quiescent.","enum":["accepted","committed"],"type":"string"},"errorRate":{"default":-1,"description":"Per-character mistake rate for humantouch typing. -1 uses server default.","format":"double","type":"number"},"humanize":{"description":"Request human-like input where supported by the device. Defaults to false.","type":"boolean"},"stealth":{"deprecated":true,"description":"Deprecated: use humanize. Both names must agree when supplied together.","type":"boolean"},"text":{"type":"string"},"wpm":{"default":0,"description":"Words per minute for humanized typing. 0 uses the device default.","format":"int64","type":"integer"}},"required":["text"],"type":"object"},"KeyboardKeyArgs":{"additionalProperties":false,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["https://example.com/schemas/KeyboardKeyArgs.json"],"format":"uri","readOnly":true,"type":"string"},"key":{"format":"int64","type":"integer"}},"required":["key"],"type":"object"},"LanguageBody":{"additionalProperties":false,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["https://example.com/schemas/LanguageBody.json"],"format":"uri","readOnly":true,"type":"string"},"locale":{"type":"string"}},"required":["locale"],"type":"object"},"ListAppInstallsOutputBody":{"additionalProperties":false,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["https://example.com/schemas/ListAppInstallsOutputBody.json"],"format":"uri","readOnly":true,"type":"string"},"installs":{"items":{"$ref":"#/components/schemas/AppInstallStatus"},"type":["array","null"]}},"required":["installs"],"type":"object"},"Location":{"additionalProperties":false,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["https://example.com/schemas/Location.json"],"format":"uri","readOnly":true,"type":"string"},"latitude":{"format":"double","type":"number"},"longitude":{"format":"double","type":"number"}},"required":["latitude","longitude"],"type":"object"},"Meta":{"additionalProperties":false,"properties":{"hasNext":{"type":"boolean"},"hasPrev":{"type":"boolean"},"page":{"format":"int64","type":"integer"},"pageSize":{"format":"int64","type":"integer"},"pages":{"format":"int64","type":"integer"},"total":{"format":"int64","type":"integer"}},"required":["hasNext","hasPrev","page","pageSize","total","pages"],"type":"object"},"None":{"additionalProperties":false,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["https://example.com/schemas/None.json"],"format":"uri","readOnly":true,"type":"string"}},"type":"object"},"OpenDeepLinkArgs":{"additionalProperties":false,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["https://example.com/schemas/OpenDeepLinkArgs.json"],"format":"uri","readOnly":true,"type":"string"},"action":{"description":"Android only: intent action to dispatch. Defaults to android.intent.action.VIEW.","type":"string"},"bundleId":{"description":"Reserved for targeting a specific iOS app; currently rejected as unsupported.","type":"string"},"deepLink":{"description":"Deep link to open (e.g. myapp://path or https://example.com/path)","minLength":1,"type":"string"},"packageName":{"description":"Android only: package to receive the intent (e.g. com.example.app). Omit to let the system pick the handler.","type":"string"}},"required":["deepLink"],"type":"object"},"OverlayVisibleBody":{"additionalProperties":false,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["https://example.com/schemas/OverlayVisibleBody.json"],"format":"uri","readOnly":true,"type":"string"},"visible":{"type":"boolean"}},"required":["visible"],"type":"object"},"PermissionSet":{"additionalProperties":false,"properties":{"execute":{"type":"boolean"},"read":{"type":"boolean"},"write":{"type":"boolean"}},"required":["read","write","execute"],"type":"object"},"PhoneState":{"additionalProperties":false,"properties":{"activityName":{"type":"string"},"currentApp":{"type":"string"},"focusedElement":{"$ref":"#/components/schemas/PhoneStateFocusedElementStruct"},"isEditable":{"type":"boolean"},"keyboardVisible":{"type":"boolean"},"packageName":{"type":"string"}},"required":["keyboardVisible","isEditable"],"type":"object"},"PhoneStateFocusedElementStruct":{"additionalProperties":false,"properties":{"className":{"type":"string"},"resourceId":{"type":"string"},"text":{"type":"string"}},"type":"object"},"RecordingInfo":{"additionalProperties":false,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["https://example.com/schemas/RecordingInfo.json"],"format":"uri","readOnly":true,"type":"string"},"actions":{"format":"int64","type":"integer"},"deviceId":{"type":"string"},"display":{"$ref":"#/components/schemas/DisplayInfo"},"endedAt":{"format":"date-time","type":"string"},"error":{"type":"string"},"expiresAt":{"format":"date-time","type":"string"},"id":{"type":"string"},"name":{"type":"string"},"startedAt":{"format":"date-time","type":"string"},"status":{"type":"string"},"types":{"items":{"type":"string"},"type":["array","null"]},"video":{"$ref":"#/components/schemas/VideoInfo"}},"required":["id","deviceId","name","types","status","startedAt","expiresAt","display","actions"],"type":"object"},"Rect":{"additionalProperties":false,"properties":{"height":{"format":"int64","type":"integer"},"width":{"format":"int64","type":"integer"}},"required":["width","height"],"type":"object"},"Ref":{"additionalProperties":false,"properties":{"country":{"description":"ISO 3166-1 alpha-2 country code; provisions (or reuses) a rotating residential Mobilerun Connect proxy for the device.","pattern":"^[a-zA-Z]{2}$","type":"string"},"id":{"description":"Existing Mobilerun Connect proxy id; its credentials are fetched server-side.","format":"uuid","type":"string"}},"type":"object"},"ResetRequest":{"additionalProperties":false,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["https://example.com/schemas/ResetRequest.json"],"format":"uri","readOnly":true,"type":"string"},"mode":{"description":"What to erase. full: factory reset — erases the user data (apps, accounts, storage) and gives the device a new identity. identity: new device fingerprint, apps and data are kept. When omitted: full, or identity on devices whose capabilities report factoryReset=false.","enum":["full","identity"],"type":"string"}},"type":"object"},"ResponseDeviceInfo":{"additionalProperties":false,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["https://example.com/schemas/ResponseDeviceInfo.json"],"format":"uri","readOnly":true,"type":"string"},"items":{"items":{"$ref":"#/components/schemas/DeviceInfo"},"type":["array","null"]},"pagination":{"$ref":"#/components/schemas/Meta"}},"required":["items","pagination"],"type":"object"},"ResponseSession":{"additionalProperties":false,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["https://example.com/schemas/ResponseSession.json"],"format":"uri","readOnly":true,"type":"string"},"items":{"items":{"$ref":"#/components/schemas/Session"},"type":["array","null"]},"pagination":{"$ref":"#/components/schemas/Meta"}},"required":["items","pagination"],"type":"object"},"ResponseTask":{"additionalProperties":false,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["https://example.com/schemas/ResponseTask.json"],"format":"uri","readOnly":true,"type":"string"},"items":{"items":{"$ref":"#/components/schemas/Task"},"type":["array","null"]},"pagination":{"$ref":"#/components/schemas/Meta"}},"required":["items","pagination"],"type":"object"},"SOCKS5":{"additionalProperties":false,"properties":{"host":{"type":"string"},"password":{"type":"string"},"port":{"format":"int64","type":"integer"},"user":{"type":"string"}},"required":["host","port","user","password"],"type":"object"},"SelectAPNBody":{"additionalProperties":false,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["https://example.com/schemas/SelectAPNBody.json"],"format":"uri","readOnly":true,"type":"string"},"apnId":{"format":"int64","type":"integer"},"subId":{"format":"int64","type":"integer"}},"required":["apnId","subId"],"type":"object"},"Session":{"additionalProperties":false,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["https://example.com/schemas/Session.json"],"format":"uri","readOnly":true,"type":"string"},"createdAt":{"format":"date-time","type":"string"},"deviceId":{"type":"string"},"error":{"$ref":"#/components/schemas/SessionError"},"expiresAt":{"format":"date-time","type":"string"},"id":{"type":"string"},"maxBodyBytes":{"format":"int64","type":"integer"},"retention":{"enum":["none"],"type":"string"},"startedAt":{"format":"date-time","type":"string"},"state":{"enum":["starting","active","stopping","stopped","failed","expired"],"type":"string"},"stoppedAt":{"format":"date-time","type":"string"},"stream":{"$ref":"#/components/schemas/StreamCredentials"}},"required":["id","deviceId","state","createdAt","expiresAt","maxBodyBytes","retention"],"type":"object"},"SessionError":{"additionalProperties":false,"properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"type":"object"},"SetAPNBody":{"additionalProperties":false,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["https://example.com/schemas/SetAPNBody.json"],"format":"uri","readOnly":true,"type":"string"},"apn":{"type":"string"},"mcc":{"type":"string"},"mnc":{"type":"string"},"name":{"type":"string"},"protocol":{"type":"string"},"roamingProtocol":{"type":"string"},"subId":{"format":"int64","type":"integer"},"type":{"type":"string"}},"required":["name","apn","mcc","mnc","type","protocol","roamingProtocol","subId"],"type":"object"},"SetClipboardArgs":{"additionalProperties":false,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["https://example.com/schemas/SetClipboardArgs.json"],"format":"uri","readOnly":true,"type":"string"},"text":{"type":"string"}},"required":["text"],"type":"object"},"SetLanguageArgs":{"additionalProperties":false,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["https://example.com/schemas/SetLanguageArgs.json"],"format":"uri","readOnly":true,"type":"string"},"locale":{"description":"BCP-47 locale: a 2–3 letter language tag, optionally followed by a 4-letter script and/or a 2-letter region (e.g. en-US, de-DE, ja-JP, zh-Hans-CN).","pattern":"^[a-z]{2,3}(-[A-Z][a-z]{3})?(-[A-Z]{2})?$","type":"string"},"restart":{"description":"Restart zygote so the locale change takes full effect immediately. Without it, the locale is written but won't fully apply until the next reboot.","type":"boolean"}},"required":["locale"],"type":"object"},"SetOverlayVisibleArgs":{"additionalProperties":false,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["https://example.com/schemas/SetOverlayVisibleArgs.json"],"format":"uri","readOnly":true,"type":"string"},"visible":{"type":"boolean"}},"required":["visible"],"type":"object"},"SetRoamingBody":{"additionalProperties":false,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["https://example.com/schemas/SetRoamingBody.json"],"format":"uri","readOnly":true,"type":"string"},"enabled":{"type":"boolean"}},"required":["enabled"],"type":"object"},"SetTimeZoneArgs":{"additionalProperties":false,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["https://example.com/schemas/SetTimeZoneArgs.json"],"format":"uri","readOnly":true,"type":"string"},"timezone":{"type":"string"}},"required":["timezone"],"type":"object"},"SpecialPermissions":{"additionalProperties":false,"properties":{"setGid":{"type":"boolean"},"setUid":{"type":"boolean"},"sticky":{"type":"boolean"}},"required":["setUid","setGid","sticky"],"type":"object"},"StartAppArgs":{"additionalProperties":false,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["https://example.com/schemas/StartAppArgs.json"],"format":"uri","readOnly":true,"type":"string"},"activity":{"type":"string"}},"type":"object"},"StartInputBody":{"additionalProperties":false,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["https://example.com/schemas/StartInputBody.json"],"format":"uri","readOnly":true,"type":"string"},"name":{"pattern":"^[A-Za-z0-9_.-]{1,64}$","type":"string"},"quality":{"description":"Capture quality from 1 (lowest) to 10 (full stream quality). Defaults to the device's full quality. Honored only by devices that support adjustable capture quality.","format":"int64","maximum":10,"minimum":1,"type":"integer"},"retentionDays":{"format":"int64","maximum":90,"minimum":1,"type":"integer"},"types":{"description":"Artifacts to capture: trajectory (input actions; on some devices only when the device announces trajectory capture), video, and audio (captured into the video artifact, so it requires video; honored only by devices that support audio capture). Defaults to trajectory and video, narrowed to what the device produces.","items":{"type":"string"},"type":["array","null"]}},"type":"object"},"StopAppArgs":{"additionalProperties":false,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["https://example.com/schemas/StopAppArgs.json"],"format":"uri","readOnly":true,"type":"string"},"clearData":{"description":"If true, clears all app data (pm clear) in addition to stopping the app.","type":"boolean"}},"type":"object"},"StreamCredentials":{"additionalProperties":false,"properties":{"protocol":{"type":"string"},"token":{"type":"string"},"url":{"type":"string"}},"required":["url","token","protocol"],"type":"object"},"SummaryOutputBody":{"additionalProperties":false,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["https://example.com/schemas/SummaryOutputBody.json"],"format":"uri","readOnly":true,"type":"string"},"byState":{"additionalProperties":{"format":"int64","type":"integer"},"type":"object"},"byType":{"additionalProperties":{"format":"int64","type":"integer"},"type":"object"},"total":{"format":"int64","type":"integer"}},"required":["total","byState","byType"],"type":"object"},"SwipeArgs":{"additionalProperties":false,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["https://example.com/schemas/SwipeArgs.json"],"format":"uri","readOnly":true,"type":"string"},"duration":{"description":"Swipe duration in milliseconds","format":"int64","minimum":10,"type":"integer"},"endX":{"format":"int64","type":"integer"},"endY":{"format":"int64","type":"integer"},"holdMs":{"default":0,"description":"Keep the finger at the end point for holdMs and suppress fling before lifting, so content moves by about the finger travel. Supported on Android cloud phones.","format":"int64","maximum":5000,"minimum":0,"type":"integer"},"humanize":{"description":"Request human-like input where supported by the device. Defaults to false.","type":"boolean"},"startX":{"format":"int64","type":"integer"},"startY":{"format":"int64","type":"integer"},"stealth":{"deprecated":true,"description":"Deprecated: use humanize. Both names must agree when supplied together.","type":"boolean"}},"required":["startX","startY","endX","endY","duration"],"type":"object"},"TapByCoordinatesArgs":{"additionalProperties":false,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["https://example.com/schemas/TapByCoordinatesArgs.json"],"format":"uri","readOnly":true,"type":"string"},"humanize":{"description":"Request human-like input where supported by the device. Defaults to false.","type":"boolean"},"stealth":{"deprecated":true,"description":"Deprecated: use humanize. Both names must agree when supplied together.","type":"boolean"},"x":{"format":"int64","type":"integer"},"y":{"format":"int64","type":"integer"}},"required":["x","y"],"type":"object"},"Task":{"additionalProperties":false,"properties":{"createdAt":{"format":"date-time","type":"string"},"taskId":{"type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["taskId","createdAt","updatedAt"],"type":"object"},"TerminateInputBody":{"additionalProperties":false,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["https://example.com/schemas/TerminateInputBody.json"],"format":"uri","readOnly":true,"type":"string"},"previousDeviceId":{"type":"string"},"terminateAt":{"format":"date-time","type":"string"}},"type":"object"},"TimeZoneBody":{"additionalProperties":false,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["https://example.com/schemas/TimeZoneBody.json"],"format":"uri","readOnly":true,"type":"string"},"timezone":{"type":["string","null"]}},"required":["timezone"],"type":"object"},"UpdateNameInputBody":{"additionalProperties":false,"properties":{"$schema":{"description":"A URL to the JSON Schema for this object.","examples":["https://example.com/schemas/UpdateNameInputBody.json"],"format":"uri","readOnly":true,"type":"string"},"name":{"maxLength":255,"minLength":1,"type":"string"}},"required":["name"],"type":"object"},"VideoInfo":{"additionalProperties":false,"properties":{"durationMs":{"format":"int64","type":"integer"},"format":{"type":"string"},"limitReason":{"type":"string"},"limited":{"type":"boolean"},"sizeBytes":{"format":"int64","type":"integer"}},"required":["durationMs","sizeBytes","format"],"type":"object"},"Trigger":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid","deprecated":true,"description":"Deprecated: use ownerId (tenancy) / createdBy (actor)."},"ownerId":{"type":"string","format":"uuid"},"createdBy":{"type":["string","null"],"format":"uuid"},"name":{"type":"string"},"description":{"type":["string","null"]},"activation":{"type":"string","enum":["event","schedule","custom"]},"scheduleRule":{"$ref":"#/components/schemas/ScheduleRule"},"timezone":{"type":["string","null"]},"nextFireTime":{"type":["string","null"]},"eventType":{"type":["string","null"]},"conditions":{},"customPayloadSchema":{"type":["object","null"],"additionalProperties":{}},"createdAt":{"type":["string","null"],"format":"date-time"},"updatedAt":{"type":["string","null"],"format":"date-time"}},"required":["id","userId","ownerId","createdBy","name","description","activation","scheduleRule","timezone","eventType","customPayloadSchema","createdAt","updatedAt"]},"ScheduleRule":{"type":"object","properties":{"type":{"type":"string","enum":["once","cron","recurring"]},"dateTime":{"type":"string","description":"ISO 8601 datetime (for type=once)"},"expression":{"type":"string","description":"Cron expression (for type=cron)"},"rrule":{"type":"string","description":"RRULE string (for type=recurring)"},"jitter":{"type":"object","description":"Optional per-occurrence random window around the nominal schedule time","properties":{"beforeMinutes":{"type":"integer","minimum":0,"maximum":1440,"default":0},"afterMinutes":{"type":"integer","minimum":0,"maximum":1440,"default":0}}}},"required":["type"]},"CreateTriggerBody":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":256},"description":{"type":"string","maxLength":2048},"activation":{"type":"string","enum":["event","schedule","custom"]},"eventType":{"type":"string","maxLength":256},"conditions":{"type":"object","properties":{"all":{"type":"array","items":{"type":"object"}},"any":{"type":"array","items":{"type":"object"}}}},"scheduleRule":{"type":"object","properties":{"type":{"type":"string","enum":["once","cron","recurring"]},"dateTime":{"type":"string","description":"ISO 8601 datetime (for type=once)"},"expression":{"type":"string","description":"Cron expression (for type=cron)"},"rrule":{"type":"string","description":"RRULE string (for type=recurring)"},"jitter":{"type":"object","description":"Optional per-occurrence random window around the nominal schedule time","properties":{"beforeMinutes":{"type":"integer","minimum":0,"maximum":1440,"default":0},"afterMinutes":{"type":"integer","minimum":0,"maximum":1440,"default":0}}}},"required":["type"]},"timezone":{"type":"string"},"customPayloadSchema":{"$ref":"#/components/schemas/CustomPayloadSchema"}},"required":["name","activation"]},"CustomPayloadSchema":{"type":"object","description":"Optional JSON Schema for validating payloads sent to this custom trigger","additionalProperties":true},"UpdateTriggerBody":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":256},"description":{"type":"string","maxLength":2048},"activation":{"type":"string","enum":["event","schedule","custom"]},"eventType":{"type":"string","maxLength":256},"conditions":{"type":["object","null"],"properties":{"all":{"type":"array","items":{"type":"object"}},"any":{"type":"array","items":{"type":"object"}}}},"scheduleRule":{"type":["object","null"],"properties":{"type":{"type":"string","enum":["once","cron","recurring"]},"dateTime":{"type":"string","description":"ISO 8601 datetime (for type=once)"},"expression":{"type":"string","description":"Cron expression (for type=cron)"},"rrule":{"type":"string","description":"RRULE string (for type=recurring)"},"jitter":{"type":"object","description":"Optional per-occurrence random window around the nominal schedule time","properties":{"beforeMinutes":{"type":"integer","minimum":0,"maximum":1440,"default":0},"afterMinutes":{"type":"integer","minimum":0,"maximum":1440,"default":0}}}},"required":["type"]},"timezone":{"type":["string","null"]},"customPayloadSchema":{"type":["object","null"],"description":"Optional JSON Schema for validating payloads sent to this custom trigger","additionalProperties":true}}},"TriggerNotFireableError":{"type":"object","properties":{"code":{"type":"string","enum":["trigger_not_fireable"]},"message":{"type":"string"},"details":{"type":"object","properties":{"activation":{"type":"string"}},"required":["activation"]}},"required":["code","message","details"]},"PayloadValidationError":{"type":"object","properties":{"code":{"type":"string","enum":["validation_error"]},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}}},"required":["code","message","details"]},"FireCustomTriggerBody":{"type":"object","properties":{"payload":{"type":"object","description":"Arbitrary JSON object forwarded to every flow attached to this trigger. Validated against the trigger's customPayloadSchema when one is configured; otherwise only \"must be a JSON object\" is enforced.","additionalProperties":true}},"required":["payload"]},"ActionCatalogEntry":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":["string","null"]},"service":{"type":"string","enum":["tasks_api","devices_api","agents_api","webhooks","integrations_api"]},"method":{"type":"string"},"provider":{"type":"string","enum":["mobilerun","oneDrive","googleDrive"]},"paramsSchema":{},"outputSchema":{},"createdAt":{"type":["string","null"],"format":"date-time"},"updatedAt":{"type":["string","null"],"format":"date-time"}},"required":["id","name","description","service","method","provider","createdAt","updatedAt"]},"Action":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid","deprecated":true,"description":"Deprecated: use ownerId (tenancy) / createdBy (actor)."},"ownerId":{"type":"string","format":"uuid"},"createdBy":{"type":["string","null"],"format":"uuid"},"catalogEntryId":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":["string","null"]},"service":{"type":"string","enum":["tasks_api","devices_api","agents_api","webhooks","integrations_api"]},"method":{"type":"string"},"params":{},"paramsSchema":{},"createdAt":{"type":["string","null"],"format":"date-time"},"updatedAt":{"type":["string","null"],"format":"date-time"}},"required":["id","userId","ownerId","createdBy","catalogEntryId","name","description","service","method","createdAt","updatedAt"]},"CreateActionBody":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":256},"description":{"type":"string","maxLength":2048},"catalogEntryId":{"type":"string","format":"uuid"},"params":{"type":"object","additionalProperties":{}}},"required":["name","catalogEntryId"]},"UpdateActionBody":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":256},"description":{"type":"string","maxLength":2048},"params":{"type":"object","additionalProperties":{}}}},"ServiceMethod":{"type":"object","properties":{"method":{"type":"string"},"params":{"type":"array","items":{"$ref":"#/components/schemas/ParamDef"}}},"required":["method","params"]},"ParamDef":{"type":"object","properties":{"name":{"type":"string"},"type":{"type":"string","enum":["string","number","boolean","object","array"]},"required":{"type":"boolean"},"description":{"type":"string"},"default":{},"example":{}},"required":["name","type","required","description"]},"FlowTemplateContext":{"type":"object","properties":{"templateResolutionVersion":{"type":"integer"},"grammar":{"type":"string"},"roots":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"shape":{}},"required":["name","description"]}},"stepReference":{"type":"object","properties":{"pattern":{"type":"string"},"slugRule":{"type":"string"},"keyRule":{"type":"string"},"note":{"type":"string"}},"required":["pattern","note"]},"payloadAliases":{"type":"array","items":{"type":"string"}},"loop":{"type":"object","properties":{"name":{"type":"string"},"itemVariableDefault":{"type":"string"},"context":{"type":"array","items":{"type":"string"}}},"required":["name","itemVariableDefault","context"]}},"required":["templateResolutionVersion","grammar","roots","stepReference","payloadAliases","loop"]},"FlowValidateResponse":{"type":"object","properties":{"valid":{"type":"boolean"},"errors":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string"},"field":{"type":"string"},"message":{"type":"string"},"reference":{"type":"string"},"knownSteps":{"type":"array","items":{"type":"string"}}},"required":["code","field","message"]}},"warnings":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"destination":{"type":"string"},"connectKey":{"type":"string"}},"required":["code","message"]}}},"required":["valid","errors","warnings"]},"RecordingPolicyMode":{"type":"string","enum":["off","flow","selected_steps"]},"FlowActionInput":{"type":"object","properties":{"actionId":{"type":"string","format":"uuid"},"position":{"type":"integer","minimum":0},"continueOnError":{"type":"boolean","default":false},"nameOverride":{"type":"string","minLength":1,"maxLength":256},"key":{"type":"string","pattern":"^[a-z_][a-z0-9_-]{0,63}$","description":"Stable identifier used by template resolution v2+ to address this step as {{key.field}}. Omitted keys are derived from the step name whenever a flow is created. For template resolution v3, replacing an existing flow's full action tree requires every step to carry an explicit key — a missing key is rejected there, not derived, so a name change can never silently move a step's key."},"overrides":{"$ref":"#/components/schemas/FlowActionOverrides"},"recordingEnabled":{"type":"boolean","default":false},"children":{"type":"array","items":{"$ref":"#/components/schemas/FlowChildActionInput"}}},"required":["actionId","position"],"additionalProperties":false},"FlowActionOverrides":{"type":["object","null"],"properties":{"params":{"type":"object","additionalProperties":{}}},"additionalProperties":false},"FlowChildActionInput":{"type":"object","properties":{"actionId":{"type":"string","format":"uuid"},"position":{"type":"integer","minimum":0},"continueOnError":{"type":"boolean","default":false},"nameOverride":{"type":"string","minLength":1,"maxLength":256},"key":{"type":"string","pattern":"^[a-z_][a-z0-9_-]{0,63}$","description":"Stable identifier used by template resolution v2+ to address this step as {{key.field}}. Omitted keys are derived from the step name whenever a flow is created. For template resolution v3, replacing an existing flow's full action tree requires every step to carry an explicit key — a missing key is rejected there, not derived, so a name change can never silently move a step's key."},"overrides":{"$ref":"#/components/schemas/FlowActionOverrides"},"recordingEnabled":{"type":"boolean","default":false}},"required":["actionId","position"],"additionalProperties":false},"FlowDraftActionInput":{"type":"object","properties":{"draft":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":256},"service":{"type":"string","minLength":1},"method":{"type":"string","minLength":1},"params":{"type":"object","additionalProperties":{},"default":{}}},"required":["name","service","method"],"additionalProperties":false},"position":{"type":"integer","minimum":0},"continueOnError":{"type":"boolean","default":false},"nameOverride":{"type":"string","minLength":1,"maxLength":256},"key":{"type":"string","pattern":"^[a-z_][a-z0-9_-]{0,63}$","description":"Stable identifier used by template resolution v2+ to address this step as {{key.field}}. Omitted keys are derived from the step name whenever a flow is created. For template resolution v3, replacing an existing flow's full action tree requires every step to carry an explicit key — a missing key is rejected there, not derived, so a name change can never silently move a step's key."},"overrides":{"$ref":"#/components/schemas/FlowActionOverrides"},"recordingEnabled":{"type":"boolean","default":false}},"required":["draft","position"],"additionalProperties":false},"Flow":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid","deprecated":true,"description":"Deprecated: use ownerId (tenancy) / createdBy (actor)."},"ownerId":{"type":"string","format":"uuid"},"agentId":{"type":["string","null"],"format":"uuid"},"createdBy":{"type":["string","null"],"format":"uuid"},"name":{"type":"string"},"description":{"type":["string","null"]},"triggerId":{"type":"string","format":"uuid"},"enabled":{"type":"boolean","description":"Compatibility projection of lifecycleStatus; true only when lifecycleStatus is enabled."},"lifecycleStatus":{"$ref":"#/components/schemas/AgentLifecycleStatus"},"archivedAt":{"type":["string","null"],"format":"date-time"},"deviceIds":{"type":"array","items":{"type":"string","format":"uuid"}},"cooldownSeconds":{"type":["integer","null"]},"cooldownScope":{"type":"string","enum":["flow","device"]},"notifyWebhookId":{"type":["string","null"],"format":"uuid"},"notifyOnSuccess":{"type":"boolean"},"notifyOnFailure":{"type":"boolean"},"lastTriggeredAt":{"type":["string","null"],"format":"date-time"},"status":{"$ref":"#/components/schemas/FlowStatus"},"templateResolutionVersion":{"type":"integer","minimum":1,"maximum":3,"description":"Template-resolver semantics this flow runs under. 1 = legacy (missing/forbidden/null all resolve to ''). 2 = typed (missing/forbidden throw, a whole-token null stays JSON null). 3 = typed, key-based (steps are addressed as {{steps.<key>...}} instead of by name; trigger.payload is not available). Existing flows stay 1; new flows default to the current version."},"consecutiveFailures":{"type":"integer","minimum":0},"lastFailureCode":{"$ref":"#/components/schemas/FlowFailureCode"},"lastFailureAt":{"type":["string","null"],"format":"date-time"},"blockedAt":{"type":["string","null"],"format":"date-time"},"healthMonitoringEnabled":{"type":"boolean"},"selfHealingEnabled":{"type":"boolean"},"selfHealingMaxAttempts":{"type":"integer","minimum":1,"maximum":5},"recordingEnabled":{"type":"boolean","deprecated":true,"description":"Deprecated: use recordingPolicy.mode (\"flow\" = recordingEnabled=true, \"off\" = recordingEnabled=false)."},"recordingPolicy":{"$ref":"#/components/schemas/RecordingPolicy"},"delivery":{"type":["object","null"],"properties":{"destination":{"type":"string","enum":["mobilerun","one_drive","google_drive"]},"folder":{"type":"string","minLength":1,"maxLength":1024,"description":"not allowed when destination is mobilerun"},"recording":{"type":"object","properties":{"filename":{"type":"string","minLength":1,"maxLength":255}},"required":["filename"],"additionalProperties":false},"screenshots":{"type":"object","properties":{},"additionalProperties":false}},"required":["destination"],"additionalProperties":false},"createdAt":{"type":["string","null"],"format":"date-time"},"updatedAt":{"type":["string","null"],"format":"date-time"}},"required":["id","userId","ownerId","agentId","createdBy","name","description","triggerId","enabled","lifecycleStatus","archivedAt","deviceIds","cooldownSeconds","cooldownScope","notifyWebhookId","notifyOnSuccess","notifyOnFailure","lastTriggeredAt","status","templateResolutionVersion","consecutiveFailures","lastFailureCode","lastFailureAt","blockedAt","healthMonitoringEnabled","selfHealingEnabled","selfHealingMaxAttempts","recordingEnabled","recordingPolicy","delivery","createdAt","updatedAt"]},"AgentLifecycleStatus":{"type":"string","enum":["enabled","disabled","archived"]},"FlowStatus":{"type":"string","enum":["healthy","failing","blocked"]},"FlowFailureCode":{"type":["string","null"],"enum":["device_not_found","permission_denied","client_error","transient","logic","invalid_config",null]},"RecordingPolicy":{"type":"object","properties":{"mode":{"$ref":"#/components/schemas/RecordingPolicyMode"}},"required":["mode"]},"FlowTemplateReferenceInvalidError":{"type":"object","properties":{"code":{"type":"string","enum":["template_reference_invalid"]},"message":{"type":"string","enum":["Template reference validation failed"]},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"},"reference":{"type":"string"},"knownSteps":{"type":"array","items":{"type":"string"},"maxItems":30}},"required":["field","message"]}}},"required":["code","message","details"]},"FlowNotFoundError":{"type":"object","properties":{"code":{"type":"string","enum":["flow_not_found"]},"message":{"type":"string"}},"required":["code","message"]},"FlowRoutineLimitError":{"type":"object","properties":{"code":{"type":"string","enum":["routine_limit_reached"]},"message":{"type":"string"},"details":{"type":"object","properties":{"limit":{"type":"integer","minimum":1},"used":{"type":"integer","minimum":0},"agentId":{"type":["string","null"],"format":"uuid"}},"required":["limit","used","agentId"]}},"required":["code","message","details"]},"CreateFlowBody":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":256},"description":{"type":"string","maxLength":2048},"triggerId":{"type":"string","format":"uuid"},"enabled":{"type":"boolean","default":true},"deviceIds":{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":256,"default":[]},"cooldownSeconds":{"type":["integer","null"],"minimum":0},"cooldownScope":{"type":"string","enum":["flow","device"],"default":"flow"},"notifyWebhookId":{"type":["string","null"],"format":"uuid"},"notifyOnSuccess":{"type":"boolean","default":false},"notifyOnFailure":{"type":"boolean","default":false},"healthMonitoringEnabled":{"type":"boolean","default":true},"selfHealingEnabled":{"type":"boolean"},"selfHealingMaxAttempts":{"type":"integer","minimum":1,"maximum":5,"default":2},"recordingEnabled":{"type":"boolean"},"recordingPolicy":{"type":"object","properties":{"mode":{"$ref":"#/components/schemas/RecordingPolicyMode"}},"required":["mode"],"additionalProperties":false},"delivery":{"type":"object","properties":{"destination":{"type":"string","enum":["mobilerun","one_drive","google_drive"]},"folder":{"type":"string","minLength":1,"maxLength":1024,"description":"not allowed when destination is mobilerun"},"recording":{"type":"object","properties":{"filename":{"type":"string","minLength":1,"maxLength":255}},"required":["filename"],"additionalProperties":false},"screenshots":{"type":"object","properties":{},"additionalProperties":false}},"required":["destination"],"additionalProperties":false},"actions":{"type":"array","items":{"$ref":"#/components/schemas/FlowActionInput"},"minItems":1}},"required":["name","triggerId","actions"],"additionalProperties":false},"FlowCapacity":{"type":"object","properties":{"included":{"type":"integer","minimum":0},"remaining":{"type":"integer","minimum":0},"status":{"$ref":"#/components/schemas/FlowCapacityStatus"}},"required":["included","remaining","status"],"additionalProperties":false},"FlowCapacityStatus":{"type":"string","enum":["available","exhausted"]},"UpdateFlowBody":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":256},"description":{"type":"string","maxLength":2048},"triggerId":{"type":"string","format":"uuid"},"enabled":{"type":"boolean"},"lifecycleStatus":{"type":"string","enum":["enabled","disabled"],"description":"Set the visible agent lifecycle. Archive remains available only through DELETE."},"deviceIds":{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":256},"cooldownSeconds":{"type":["integer","null"],"minimum":0},"cooldownScope":{"$ref":"#/components/schemas/CooldownScope"},"notifyWebhookId":{"type":["string","null"],"format":"uuid"},"notifyOnSuccess":{"type":"boolean"},"notifyOnFailure":{"type":"boolean"},"healthMonitoringEnabled":{"type":"boolean"},"selfHealingEnabled":{"type":"boolean"},"selfHealingMaxAttempts":{"type":"integer","minimum":1,"maximum":5},"recordingEnabled":{"type":"boolean","deprecated":true,"description":"Deprecated compatibility field. true maps to recordingPolicy.mode=\"flow\"; false maps to \"off\"."},"recordingPolicy":{"type":"object","properties":{"mode":{"$ref":"#/components/schemas/RecordingPolicyMode"}},"required":["mode"],"additionalProperties":false},"delivery":{"type":["object","null"],"properties":{"destination":{"type":"string","enum":["mobilerun","one_drive","google_drive"]},"folder":{"type":"string","minLength":1,"maxLength":1024,"description":"not allowed when destination is mobilerun"},"recording":{"type":"object","properties":{"filename":{"type":"string","minLength":1,"maxLength":255}},"required":["filename"],"additionalProperties":false},"screenshots":{"type":"object","properties":{},"additionalProperties":false}},"required":["destination"],"additionalProperties":false}},"additionalProperties":false},"CooldownScope":{"type":"string","enum":["flow","device"]},"FlowVerificationError":{"type":"object","properties":{"code":{"$ref":"#/components/schemas/FlowVerificationErrorCode"},"message":{"type":"string"}},"required":["code","message"]},"FlowVerificationErrorCode":{"type":"string","enum":["verification_invalid","verification_stale"]},"ActivateFlowBody":{"type":"object","properties":{"verificationExecutionId":{"type":"string","format":"uuid"}},"required":["verificationExecutionId"],"additionalProperties":false},"CloneFlowBody":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":256},"deviceIds":{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":256}},"additionalProperties":false},"FlowDryRunResult":{"type":"object","properties":{"activation":{"type":"string","enum":["event","schedule","custom"]},"validation":{"$ref":"#/components/schemas/DryRunValidation"},"conditionsPassed":{"type":["boolean","null"]},"nextFireTime":{"type":["string","null"]},"rateLimited":{"type":"boolean"},"gates":{"$ref":"#/components/schemas/DryRunGates"},"wouldFire":{"type":"boolean"},"actions":{"type":"array","items":{"$ref":"#/components/schemas/ResolvedAction"}}},"required":["activation","validation","conditionsPassed","nextFireTime","rateLimited","gates","wouldFire","actions"]},"DryRunValidation":{"type":"object","properties":{"valid":{"type":"boolean"},"errors":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}}},"required":["valid"]},"DryRunGates":{"type":"object","properties":{"enabled":{"type":"boolean"},"deviceAttached":{"type":"boolean"},"deviceIds":{"type":"array","items":{"type":"string","format":"uuid"}},"blocked":{"type":"boolean"},"cooldownActive":{"type":["boolean","null"]}},"required":["enabled","deviceAttached","deviceIds","blocked","cooldownActive"]},"ResolvedAction":{"type":"object","properties":{"key":{"type":"string"},"name":{"type":"string"},"service":{"type":"string","enum":["tasks_api","devices_api","agents_api","webhooks","integrations_api"]},"method":{"type":"string"},"params":{"type":"object","additionalProperties":{}},"continueOnError":{"type":"boolean"},"flowActionId":{"type":"string","format":"uuid"},"recordingEnabled":{"type":"boolean"},"children":{"type":"array","items":{},"description":"Nested child actions (loop/branch bodies), each the same shape as a ResolvedAction."}},"required":["key","name","service","method","continueOnError","flowActionId","recordingEnabled"]},"DryRunFlowBody":{"type":"object","properties":{"payload":{"type":"object","additionalProperties":{},"default":{}}},"additionalProperties":false},"WorkflowRepairEpisode":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"flowId":{"type":"string","format":"uuid"},"sourceExecutionId":{"type":"string","format":"uuid"},"deviceId":{"type":["string","null"],"format":"uuid"},"episode":{"type":"integer","exclusiveMinimum":0},"failedStepIndex":{"type":"integer","minimum":0},"attempt":{"type":"integer","exclusiveMinimum":0},"maxAttempts":{"type":"integer","exclusiveMinimum":0},"status":{"type":"string","enum":["pending","running","canary","promoting","repaired","failed","escalated"]},"originalSlug":{"type":"string"},"candidateSlug":{"type":"string"},"agentRunId":{"type":["string","null"]},"chatSessionId":{"type":["string","null"],"format":"uuid"},"verdict":{"type":["object","null"],"properties":{"outcome":{"type":"string","enum":["ok","flaky","broken"]},"summary":{"type":"string"},"reason":{"type":"string"}},"required":["outcome","summary"]},"error":{"type":["string","null"]},"startedAt":{"type":["string","null"],"format":"date-time"},"finishedAt":{"type":["string","null"],"format":"date-time"},"createdAt":{"type":["string","null"],"format":"date-time"},"updatedAt":{"type":["string","null"],"format":"date-time"}},"required":["id","flowId","sourceExecutionId","deviceId","episode","failedStepIndex","attempt","maxAttempts","status","originalSlug","candidateSlug","agentRunId","chatSessionId","verdict","error","startedAt","finishedAt","createdAt","updatedAt"]},"FlowAction":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"flowId":{"type":"string","format":"uuid"},"actionId":{"type":"string","format":"uuid"},"parentFlowActionId":{"type":["string","null"],"format":"uuid"},"position":{"type":"integer"},"continueOnError":{"type":"boolean"},"nameOverride":{"type":["string","null"]},"key":{"type":"string"},"overrides":{"type":["object","null"],"properties":{"params":{"type":"object","additionalProperties":{}}}},"recordingEnabled":{"type":"boolean","description":"Selected for per-step recording under the flow's \"selected_steps\" recording policy."},"createdAt":{"type":["string","null"],"format":"date-time"}},"required":["id","flowId","actionId","parentFlowActionId","position","continueOnError","nameOverride","key","overrides","recordingEnabled","createdAt"]},"FlowDeliveryOptions":{"type":"object","properties":{"recordingMode":{"$ref":"#/components/schemas/RecordingPolicyMode"},"canDeliverRecording":{"type":"boolean"},"hasFilesUpload":{"type":"boolean"},"directUploadStep":{"type":["object","null"],"properties":{"flowActionId":{"type":"string","format":"uuid"},"name":{"type":"string"}},"required":["flowActionId","name"]},"destinations":{"type":"array","items":{"$ref":"#/components/schemas/FlowDeliveryDestinationOption"},"description":"Delivery destinations in their canonical order."}},"required":["recordingMode","canDeliverRecording","hasFilesUpload","directUploadStep","destinations"]},"FlowDeliveryDestinationOption":{"type":"object","properties":{"key":{"type":"string","enum":["mobilerun","one_drive","google_drive"]},"label":{"type":"string"},"connectKey":{"type":"string"},"connection":{"$ref":"#/components/schemas/DeliveryDestinationConnectionStatus"},"iconUrl":{"type":["string","null"],"format":"uri"}},"required":["key","label","connectKey","connection","iconUrl"]},"DeliveryDestinationConnectionStatus":{"type":"string","enum":["connected","not_connected","expired","unknown"]},"SetFlowActionsBody":{"type":"object","properties":{"actions":{"type":"array","items":{"$ref":"#/components/schemas/FlowActionInput"},"minItems":1}},"required":["actions"],"additionalProperties":false},"AddFlowActionBody":{"type":"object","properties":{"actionId":{"type":"string","format":"uuid"},"position":{"type":"integer","minimum":0},"continueOnError":{"type":"boolean","default":false},"nameOverride":{"type":"string","minLength":1,"maxLength":256},"key":{"type":"string","pattern":"^[a-z_][a-z0-9_-]{0,63}$","description":"Stable identifier used by template resolution v2+ to address this step as {{key.field}}. Omitted keys are derived from the step name whenever a flow is created. For template resolution v3, replacing an existing flow's full action tree requires every step to carry an explicit key — a missing key is rejected there, not derived, so a name change can never silently move a step's key."},"overrides":{"$ref":"#/components/schemas/FlowActionOverrides"},"recordingEnabled":{"type":"boolean","default":false},"parentFlowActionId":{"type":["string","null"],"format":"uuid"},"children":{"type":"array","items":{"$ref":"#/components/schemas/FlowChildActionInput"}}},"required":["actionId","position"],"additionalProperties":false},"FlowActionNotFoundError":{"type":"object","properties":{"code":{"type":"string","enum":["flow_action_not_found"]},"message":{"type":"string"}},"required":["code","message"]},"FlowStillBrokenError":{"type":"object","properties":{"code":{"type":"string","enum":["still_broken"]},"message":{"type":"string"},"details":{"type":"object","properties":{"code":{"$ref":"#/components/schemas/FlowFailureCode"},"reason":{"type":"string"}},"required":["code","reason"]}},"required":["code","message","details"]},"VerifyFlowResult":{"type":"object","properties":{"executionId":{"type":"string","format":"uuid"},"invocationId":{"type":"string","format":"uuid"},"flowId":{"type":"string","format":"uuid"},"triggerId":{"type":"string","format":"uuid"},"deviceId":{"type":["string","null"],"format":"uuid","description":"Device the verification runs on; null for a device-free verification (a 0-device flow whose actions are all device-free allowlisted)."},"kind":{"type":"string","enum":["verification"]},"status":{"type":"string","enum":["pending","running","success","failed","cancelled","skipped","invalid"]},"deduplicated":{"type":"boolean","description":"True when this run already existed for the (flow, invocationId) key (HTTP 200); false for a newly enqueued run (HTTP 202)."}},"required":["executionId","invocationId","flowId","triggerId","deviceId","kind","status","deduplicated"]},"FlowConditionsNotMetError":{"type":"object","properties":{"code":{"type":"string","enum":["conditions_not_met"]},"message":{"type":"string"},"details":{"$ref":"#/components/schemas/FlowDryRunResult"}},"required":["code","message","details"]},"FlowDeviceSelectionError":{"type":"object","properties":{"code":{"$ref":"#/components/schemas/FlowDeviceSelectionErrorCode"},"message":{"type":"string"}},"required":["code","message"]},"FlowDeviceSelectionErrorCode":{"type":"string","enum":["device_required","device_not_bound"]},"VerifyFlowBody":{"type":"object","properties":{"invocationId":{"type":"string","format":"uuid","description":"Client-supplied idempotency key. A repeat request for the same (flow, invocationId) returns the existing verification run (`deduplicated: true`, HTTP 200) instead of enqueuing another."},"deviceId":{"type":"string","format":"uuid","description":"Device to run the verification on. Must be one the flow is bound to. Optional only when the flow is bound to exactly one device (that device is used); otherwise required."},"payload":{"type":"object","additionalProperties":{},"default":{}}},"required":["invocationId"],"additionalProperties":false},"FlowBlockedError":{"type":"object","properties":{"code":{"type":"string","enum":["flow_blocked"]},"message":{"type":"string"}},"required":["code","message"]},"RunFlowBody":{"type":"object","properties":{"payload":{"type":"object","additionalProperties":{},"default":{}},"captureScreenshots":{"type":"boolean","description":"Record and keep this run's scripts.run screenshots (device.screenshot(save=True)) even without flow delivery. Used for a one-off proof run."}},"additionalProperties":false},"DryRunResult":{"type":"object","properties":{"validation":{"$ref":"#/components/schemas/DryRunValidation"},"matchedFlows":{"type":"array","items":{"$ref":"#/components/schemas/DryRunMatchedFlow"}}},"required":["validation","matchedFlows"]},"DryRunMatchedFlow":{"type":"object","properties":{"flow":{"$ref":"#/components/schemas/Flow"},"trigger":{"$ref":"#/components/schemas/Trigger"},"actions":{"type":"array","items":{"$ref":"#/components/schemas/ResolvedAction"}},"gates":{"$ref":"#/components/schemas/DryRunGates"},"wouldFire":{"type":"boolean"}},"required":["flow","trigger","actions","gates","wouldFire"]},"IngestEventBody":{"type":"object","properties":{"eventType":{"type":"string","minLength":1,"maxLength":256},"deviceId":{"type":"string","format":"uuid"},"payload":{"type":"object","additionalProperties":{},"default":{}}},"required":["eventType"]},"FlowExecutionListItem":{"allOf":[{"$ref":"#/components/schemas/FlowExecution"},{"type":"object","properties":{"createdBy":{"type":["string","null"],"format":"uuid"},"recordings":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"flowActionId":{"type":["string","null"],"format":"uuid"},"stepIndex":{"type":"integer"},"parentIndex":{"type":"integer"},"iterationIndex":{"type":"integer"},"childIndex":{"type":"integer"},"attempt":{"type":"integer","minimum":0},"scope":{"type":"string","enum":["flow","step"]},"status":{"type":"string","enum":["starting","recording","stopping","stopped","failed"]},"recordingId":{"type":["string","null"],"format":"uuid"},"recordingDeviceId":{"type":["string","null"],"format":"uuid"},"startedAt":{"type":["string","null"],"format":"date-time"},"stoppedAt":{"type":["string","null"],"format":"date-time"},"lastError":{"type":["string","null"]}},"required":["id","flowActionId","stepIndex","parentIndex","iterationIndex","childIndex","attempt","scope","status","recordingId","recordingDeviceId","startedAt","stoppedAt","lastError"]},"description":"Durable recording segments ordered by step/loop coordinate and retry attempt. Whole-flow recordings use -1 for every coordinate."}},"required":["createdBy","recordings"]}]},"FlowExecution":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"flowId":{"type":"string","format":"uuid"},"triggerId":{"type":"string","format":"uuid"},"eventId":{"type":["string","null"],"format":"uuid"},"invocationId":{"type":["string","null"],"format":"uuid","description":"Client/verify invocation key this row belongs to. Set on live custom fires (one row per device fan-out) and on verification runs; null for event/schedule live rows."},"deviceId":{"type":["string","null"],"format":"uuid","description":"Device this execution targets (the job's deviceId). Null for device-less (event-only) runs."},"flowName":{"type":["string","null"]},"triggerName":{"type":["string","null"]},"status":{"type":["string","null"],"enum":["pending","running","success","failed","cancelled","skipped","invalid",null]},"kind":{"type":"string","enum":["live","dry_run","verification"]},"result":{"description":"Opaque per-step result blob ({ steps: [...] }). Each step additionally carries a `verdict` field ({ outcome, summary, reason? } | null) when it is an agent.run step that opted into a verdict — null otherwise. Steps of current executions also carry a `status` string (e.g. success/failed/stopped); it is optional and absent on older executions, so clients must not assume its presence."},"error":{"type":["string","null"]},"recordingId":{"type":["string","null"],"format":"uuid","description":"Device recording id for this execution, set once recording starts. Null when the flow has recording disabled, no device is bound, or the recording failed to start."},"recordingDeviceId":{"type":["string","null"],"format":"uuid"},"startedAt":{"type":["string","null"],"format":"date-time"},"finishedAt":{"type":["string","null"],"format":"date-time"}},"required":["id","flowId","triggerId","eventId","invocationId","deviceId","flowName","triggerName","status","kind","error","recordingId","recordingDeviceId","startedAt","finishedAt"]},"ExecutionMetrics":{"type":"object","properties":{"total":{"type":"integer"},"byStatus":{"type":"object","properties":{"pending":{"type":"integer"},"running":{"type":"integer"},"success":{"type":"integer"},"failed":{"type":"integer"},"cancelled":{"type":"integer"},"skipped":{"type":"integer"},"invalid":{"type":"integer"}},"required":["pending","running","success","failed","cancelled","skipped","invalid"]},"avgDurationMs":{"type":["number","null"]},"lastExecutionAt":{"type":["string","null"],"format":"date-time"}},"required":["total","byStatus","avgDurationMs","lastExecutionAt"]},"FlowExecutionDetail":{"allOf":[{"$ref":"#/components/schemas/FlowExecution"},{"type":"object","properties":{"createdBy":{"type":["string","null"],"format":"uuid"},"agentId":{"type":["string","null"],"format":"uuid","description":"Current agent assignment of the owner-scoped parent flow; null when unassigned."},"recordings":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"flowActionId":{"type":["string","null"],"format":"uuid"},"stepIndex":{"type":"integer"},"parentIndex":{"type":"integer"},"iterationIndex":{"type":"integer"},"childIndex":{"type":"integer"},"attempt":{"type":"integer","minimum":0},"scope":{"type":"string","enum":["flow","step"]},"status":{"type":"string","enum":["starting","recording","stopping","stopped","failed"]},"recordingId":{"type":["string","null"],"format":"uuid"},"recordingDeviceId":{"type":["string","null"],"format":"uuid"},"startedAt":{"type":["string","null"],"format":"date-time"},"stoppedAt":{"type":["string","null"],"format":"date-time"},"lastError":{"type":["string","null"]}},"required":["id","flowActionId","stepIndex","parentIndex","iterationIndex","childIndex","attempt","scope","status","recordingId","recordingDeviceId","startedAt","stoppedAt","lastError"]},"description":"Durable recording segments ordered by step/loop coordinate and retry attempt. Whole-flow recordings use -1 for every coordinate."},"files":{"type":"array","items":{"$ref":"#/components/schemas/ExecutionFile"},"description":"Files produced by files.upload steps, plus files an agent.run step reported on its terminal response (agent-created output or a workflow upload minted during the turn); derived server-side at read time."},"progress":{"type":["object","null"],"properties":{"total":{"type":"integer"},"currentIndex":{"type":["integer","null"]},"steps":{"type":"array","items":{"type":"object","properties":{"index":{"type":"integer"},"name":{"type":"string"},"service":{"type":"string"},"method":{"type":"string"},"status":{"type":"string","enum":["pending","running","success","failed","skipped","cancelled"]},"attempt":{"type":"integer","minimum":0,"description":"Zero-based retry attempt of the execution job during which this step last ran (0 = initial attempt). Not a per-step retry counter; may undercount after crash recovery."},"startedAt":{"type":["string","null"],"format":"date-time"},"finishedAt":{"type":["string","null"],"format":"date-time"},"sessionId":{"type":["string","null"]}},"required":["index","name","service","method","status","startedAt","finishedAt","sessionId"]}}},"required":["total","currentIndex","steps"],"description":"Live progress; null for runs started before this feature."},"deliveries":{"type":"array","items":{"type":"object","properties":{"artifact":{"type":"string","enum":["recording","file","screenshot"]},"stepIndex":{"type":["integer","null"]},"destination":{"type":"string","enum":["mobilerun","one_drive","google_drive"]},"folder":{"type":["string","null"]},"filename":{"type":"string"},"status":{"type":"string","enum":["waiting","uploading","succeeded","failed","unknown","cancelled"]},"errorCode":{"type":["string","null"]},"webUrl":{"type":["string","null"]},"startedAt":{"type":["string","null"],"format":"date-time"},"finishedAt":{"type":["string","null"],"format":"date-time"}},"required":["artifact","stepIndex","destination","folder","filename","status","errorCode","webUrl","startedAt","finishedAt"]},"description":"OneDrive/Google Drive delivery lifecycle for this run's recording, file, and screenshot uploads, ordered by startedAt. Empty when the flow has no delivery configured."},"screenshots":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"source":{"type":"string","enum":["task","agent","recording"]},"stepName":{"type":"string"},"stepIndex":{"type":"integer"},"iterationIndex":{"type":"integer"},"seq":{"type":"integer"},"capturedAt":{"type":["string","null"],"format":"date-time"},"mimeType":{"type":"string"}},"required":["id","source","stepName","stepIndex","iterationIndex","seq","capturedAt","mimeType"]},"description":"Screenshots captured by tasks.run/agent.run steps and saved by scripts into the flow screenshots recording (source recording), ordered by seq. Image bytes are never returned here — fetch a fresh signed URL via GET /executions/{id}/screenshots/{screenshotId}."}},"required":["createdBy","agentId","recordings","files","progress","deliveries","screenshots"]}]},"ExecutionFile":{"type":"object","properties":{"fileId":{"type":"string","format":"uuid"},"filename":{"type":"string"},"mimeType":{"type":"string"},"sizeBytes":{"type":"integer","minimum":0}},"required":["fileId","filename","mimeType","sizeBytes"]},"TimezonesResponse":{"type":"object","properties":{"data":{"type":"array","items":{"type":"string"}}},"required":["data"]},"ChatInsufficientCreditsError":{"type":"object","properties":{"code":{"type":"string","enum":["insufficient_credits"]},"message":{"type":"string"},"errorText":{"type":"string"},"remaining":{"type":"number"}},"required":["code","message","errorText","remaining"]},"ChatBillingUnavailableError":{"type":"object","properties":{"code":{"type":"string","enum":["billing_unavailable"]},"message":{"type":"string"},"errorText":{"type":"string"}},"required":["code","message","errorText"]},"ChatUpstreamUnavailableError":{"type":"object","properties":{"code":{"type":"string","enum":["upstream_unavailable"]},"message":{"type":"string"}},"required":["code","message"]},"ConnectErrorDetail":{"description":"A single error, locating an offending input where applicable.","properties":{"location":{"description":"Path to the offending input, e.g. \"body.proxyId\".","type":"string"},"message":{"description":"Human-readable description of this error.","type":"string"},"value":{"description":"The offending value, when available."}},"required":["location","message"],"type":"object"},"ConnectErrorResponse":{"description":"A Problem Details (RFC 7807-style) error response.","properties":{"detail":{"description":"Human-readable explanation of this occurrence.","type":"string"},"errors":{"description":"Per-input errors, when applicable.","items":{"$ref":"#/components/schemas/ConnectErrorDetail"},"type":"array"},"status":{"description":"HTTP status code.","type":"integer"},"title":{"description":"Short, human-readable summary of the error type.","type":"string"}},"required":["title","status","detail","errors"],"type":"object"},"ConnectPaginationMeta":{"description":"Pagination metadata for a list response.","properties":{"hasNext":{"description":"Whether a next page exists.","type":"boolean"},"hasPrev":{"description":"Whether a previous page exists.","type":"boolean"},"page":{"description":"Current page number (1-based).","type":"integer"},"pageSize":{"description":"Number of items per page.","type":"integer"},"pages":{"description":"Total number of pages.","type":"integer"},"total":{"description":"Total number of items across all pages.","type":"integer"}},"required":["page","pageSize","total","pages","hasNext","hasPrev"],"type":"object"},"Connection":{"description":"A single proxy connection, aggregated across its lifetime. Byte counts are totals for the whole connection.","properties":{"bytesIn":{"description":"Total bytes received from upstream over the connection's lifetime.","format":"int64","type":"integer"},"bytesOut":{"description":"Total bytes sent to upstream over the connection's lifetime.","format":"int64","type":"integer"},"closeReason":{"description":"Why the connection closed; null while still active.","nullable":true,"type":"string"},"country":{"description":"Upstream country code (ISO 3166-1 alpha-2), or empty if unknown.","type":"string"},"dstHost":{"description":"Destination host the client connected to.","type":"string"},"dstPort":{"description":"Destination port the client connected to.","type":"integer"},"durationMs":{"description":"Elapsed time between startedAt and endedAt, in milliseconds.","format":"int64","type":"integer"},"endedAt":{"description":"Time of the connection's last recorded activity (close time once closed).","format":"date-time","type":"string"},"protocol":{"$ref":"#/components/schemas/ConnectionProtocol"},"provider":{"description":"Identifier of the upstream provider that served the connection.","type":"string"},"proxyId":{"description":"The proxy the connection was routed through. All-zero when the upstream was unresolved at capture time.","format":"uuid","type":"string"},"sessionId":{"description":"Unique id of this connection.","format":"uuid","type":"string"},"srcIp":{"description":"Client source IP address.","type":"string"},"startedAt":{"description":"When the connection started.","format":"date-time","type":"string"},"status":{"$ref":"#/components/schemas/ConnectionStatus"},"totalBytes":{"description":"bytesIn + bytesOut.","format":"int64","type":"integer"},"userId":{"description":"The user that made the connection.","format":"uuid","type":"string"}},"required":["sessionId","userId","proxyId","srcIp","dstHost","dstPort","protocol","provider","country","bytesIn","bytesOut","totalBytes","startedAt","endedAt","durationMs","status"],"type":"object"},"ConnectionList":{"description":"A page of connections.","properties":{"items":{"items":{"$ref":"#/components/schemas/Connection"},"type":"array"},"pagination":{"$ref":"#/components/schemas/ConnectPaginationMeta"}},"required":["items","pagination"],"type":"object"},"ConnectionProtocol":{"description":"Transport protocol of a connection.","enum":["tcp","udp","unknown"],"type":"string"},"ConnectionStatus":{"description":"`active` while the connection is still open (no terminal record yet); `closed` once it has ended.","enum":["active","closed"],"type":"string"},"Country":{"properties":{"code":{"description":"ISO 3166-1 alpha-2 country code (lowercase).","example":"us","type":"string"},"name":{"example":"United States","type":"string"},"proxyTypes":{"description":"Proxy types available to provision in this country.","items":{"$ref":"#/components/schemas/ProxyType"},"minItems":1,"type":"array"}},"required":["code","name","proxyTypes"],"type":"object"},"CountryList":{"description":"A page of countries.","properties":{"items":{"items":{"$ref":"#/components/schemas/Country"},"type":"array"},"pagination":{"$ref":"#/components/schemas/ConnectPaginationMeta"}},"required":["items","pagination"],"type":"object"},"CreateProxyRequest":{"properties":{"country":{"description":"ISO 3166-1 alpha-2 country code to provision the proxy in.","format":"country-code","type":"string"},"name":{"description":"Display name for the proxy, up to 64 characters excluding surrounding whitespace, and containing no NUL. Omit it (or send only whitespace) to get a generated label built from the country, type, and id.","type":"string"},"type":{"$ref":"#/components/schemas/ProxyType"}},"required":["country","type"],"type":"object"},"CreateUserRequest":{"properties":{"password":{"description":"Desired SOCKS5 password, 1-255 bytes (RFC 1929). Generated when omitted.","maxLength":255,"minLength":1,"type":"string"},"proxyId":{"description":"Proxy to bind the user to for dedicated routing.","format":"uuid","type":"string"},"username":{"description":"Desired SOCKS5 username, 1-255 bytes (RFC 1929). Generated when omitted.","maxLength":255,"minLength":1,"type":"string"}},"type":"object"},"LatencySample":{"description":"An aggregated latency measurement taken through the proxy.","properties":{"avgMs":{"description":"Mean round-trip time over successful probes, in milliseconds.","type":"integer"},"jitterMs":{"description":"Round-trip time spread (max - min) over successful probes, in milliseconds.","type":"integer"},"maxMs":{"description":"Maximum round-trip time over successful probes, in milliseconds.","type":"integer"},"measuredAt":{"description":"When this measurement was taken.","format":"date-time","type":"string"},"minMs":{"description":"Minimum round-trip time over successful probes, in milliseconds.","type":"integer"},"packetLoss":{"description":"Fraction of probes that failed, 0..1 (1 means the proxy was unreachable; rtt fields are 0).","type":"number"},"samples":{"description":"Number of probes taken in this measurement.","type":"integer"},"target":{"description":"The host:port the latency was measured against, through the proxy.","type":"string"}},"required":["target","samples","minMs","avgMs","maxMs","jitterMs","packetLoss","measuredAt"],"type":"object"},"Proxy":{"description":"A provisioned proxy without its credentials.","properties":{"billingMode":{"$ref":"#/components/schemas/ProxyBillingMode"},"country":{"description":"ISO 3166-1 alpha-2 country code (lowercase).","type":"string"},"createdAt":{"format":"date-time","type":"string"},"host":{"type":"string"},"id":{"format":"uuid","type":"string"},"name":{"description":"Display name for the proxy. Set it on create or change it with PATCH; when no name has been set, a label generated from the proxy's country, type, and id is returned instead — so this is never empty.","example":"🇩🇪 Germany · Dedicated residential · 769fc289","type":"string"},"port":{"format":"int32","type":"integer"},"status":{"$ref":"#/components/schemas/ProxyStatus"},"type":{"$ref":"#/components/schemas/ProxyType"},"username":{"type":"string"}},"required":["id","name","country","type","status","host","port","username","createdAt"],"type":"object"},"ProxyBillingMode":{"enum":["included","standalone_paid"],"type":"string"},"ProxyCheckout":{"properties":{"paymentUrl":{"description":"Payable checkout URL; omitted after payment.","nullable":true,"type":"string"},"status":{"$ref":"#/components/schemas/ProxyStatus"}},"required":["status"],"type":"object"},"ProxyCheckoutConflict":{"allOf":[{"$ref":"#/components/schemas/ConnectErrorResponse"},{"properties":{"code":{"enum":["checkout_expired","not_pending"],"type":"string"}},"required":["code"],"type":"object"}]},"ProxyHealth":{"description":"The outcome of an ensure-healthy check.","properties":{"proxyId":{"format":"uuid","type":"string"},"status":{"description":"`healthy`: the upstream accepted the current session. `rotated`: the session was refused and the proxy now uses a fresh, checked session; retry through the proxy. `refused`: the session was refused and could not be replaced. `unreachable`: the upstream could not be reached; the session was left unchanged.","enum":["healthy","rotated","refused","unreachable"],"type":"string"}},"required":["proxyId","status"],"type":"object"},"ProxyLatency":{"description":"The latest cached latency reading for a proxy.","properties":{"latency":{"allOf":[{"$ref":"#/components/schemas/LatencySample"}],"description":"The latest reading, or null if none has been taken yet.","nullable":true},"proxyId":{"format":"uuid","type":"string"}},"required":["proxyId","latency"],"type":"object"},"ProxyList":{"description":"A page of proxies.","properties":{"items":{"items":{"$ref":"#/components/schemas/Proxy"},"type":"array"},"pagination":{"$ref":"#/components/schemas/ConnectPaginationMeta"}},"required":["items","pagination"],"type":"object"},"ProxyStatus":{"description":"Lifecycle of a proxy. A freshly created proxy is `checking` while its billing identity is being resolved — clients should poll until a `paymentUrl` or a later status appears — then `provisioning` — or `pending_payment` until the customer completes checkout — and becomes `active` once its upstream is assigned. `cancelling` retains full access through the paid period; when the subscription expires the proxy is `ended`. `error` marks a failed provisioning attempt.","enum":["checking","pending_payment","provisioning","active","cancelling","ended","error"],"type":"string"},"ProxyType":{"enum":["dedicated_residential","residential","mobile"],"type":"string"},"ProxyWithSecret":{"allOf":[{"$ref":"#/components/schemas/Proxy"},{"properties":{"password":{"type":"string"},"paymentUrl":{"description":"Checkout URL to complete payment while status is `pending_payment`. Null once paid or when no payment was required.","nullable":true,"type":"string"}},"required":["password"],"type":"object"}],"description":"A proxy including its password. Returned only on create and single-proxy reads."},"UpdateProxyRequest":{"properties":{"name":{"description":"New display name, up to 64 characters excluding surrounding whitespace, and containing no NUL. Send null (or an empty/whitespace-only string) to drop a custom name and go back to the generated label. Omit to leave the name unchanged.","nullable":true,"type":"string","x-go-type":"nullable.Nullable[string]","x-go-type-import":{"path":"github.com/oapi-codegen/nullable"},"x-go-type-skip-optional-pointer":true}},"type":"object"},"UpdateUserRequest":{"properties":{"proxyId":{"description":"Proxy to rebind to, or null to detach. Omit to leave the user's current binding unchanged — only an explicit null detaches.","format":"uuid","nullable":true,"type":"string","x-go-type":"nullable.Nullable[openapi_types.UUID]","x-go-type-import":{"path":"github.com/oapi-codegen/nullable"},"x-go-type-skip-optional-pointer":true}},"type":"object"},"User":{"description":"A SOCKS5 credential without its password.","properties":{"createdAt":{"format":"date-time","type":"string"},"id":{"format":"uuid","type":"string"},"proxyId":{"description":"The proxy this user routes to (dedicated routing), or null if unbound.","format":"uuid","nullable":true,"type":"string"},"username":{"type":"string"}},"required":["id","username","createdAt"],"type":"object"},"UserList":{"description":"A page of SOCKS5 users.","properties":{"items":{"items":{"$ref":"#/components/schemas/User"},"type":"array"},"pagination":{"$ref":"#/components/schemas/ConnectPaginationMeta"}},"required":["items","pagination"],"type":"object"},"UserWithSecret":{"allOf":[{"$ref":"#/components/schemas/User"},{"properties":{"password":{"type":"string"}},"required":["password"],"type":"object"}],"description":"A SOCKS5 user including its password. Returned only on create and single-user reads."},"WebhookInternalServerError":{"type":"object","properties":{"code":{"$ref":"#/components/schemas/WebhookHttpErrorCode"},"message":{"type":"string"},"details":{},"traceId":{"type":"string"}},"required":["code","message"]},"WebhookHttpErrorCode":{"type":"string","enum":["bad_request","not_found","conflict","service_unavailable","internal_error"]},"WebhookHttpError":{"type":"object","properties":{"code":{"$ref":"#/components/schemas/WebhookHttpErrorCode"},"message":{"type":"string","example":"webhook not found"},"details":{},"traceId":{"type":"string"}},"required":["code","message"]},"LineCapabilities":{"type":"object","properties":{"sms":{"$ref":"#/components/schemas/ChannelCapabilities"}},"required":["sms"],"description":"What this line supports in principle, per channel. Use `actions` for what you can do right now."},"ChannelCapabilities":{"type":"object","properties":{"inbound":{"type":"boolean","description":"This line can receive on this channel."},"outbound":{"type":"boolean","description":"This line can send on this channel."}},"required":["inbound","outbound"]},"PublicMessageListResponse":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/PublicMessageRow"}},"pagination":{"$ref":"#/components/schemas/Pagination"}},"required":["items","pagination"]},"PublicMessageRow":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"esimId":{"type":["string","null"],"format":"uuid"},"direction":{"type":"string","enum":["inbound","outbound"]},"status":{"type":"string","enum":["received","queued","claimed","sending","sent","sent_unconfirmed","delivered","failed"],"description":"Message status. Outbound messages move queued → sending → sent, or end at failed. `sent` means the mobile network accepted the message and is the final success status. `delivered` and `sent_unconfirmed` are kept for compatibility; current lines return no carrier delivery report, so neither is emitted."},"peerNumber":{"type":["string","null"]},"peerKey":{"type":["string","null"]},"body":{"type":["string","null"]},"deliveryStatus":{"type":["string","null"]},"detectedSender":{"type":["string","null"]},"providerCode":{"type":["string","null"]},"classification":{"$ref":"#/components/schemas/MessageClassification"},"occurredAt":{"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","esimId","direction","status","peerNumber","peerKey","body","deliveryStatus","detectedSender","providerCode","classification","occurredAt","createdAt"]},"MessageClassification":{"type":["object","null"],"properties":{"spam":{"type":"boolean"}},"required":["spam"]},"MessageErrorResponse":{"type":"object","properties":{"code":{"$ref":"#/components/schemas/MessageErrorReason"},"message":{"type":"string"}},"required":["code","message"],"description":"Messaging error envelope. `code` is the canonical discriminator (see `MessageErrorReason` for the code set)."},"MessageErrorReason":{"type":"string","enum":["not_installed","missing_device","missing_subscription","idempotency_key_reused","send_disabled","daily_cap_exceeded","rate_limited","capability_unavailable","invalid_recipient","unsupported_destination","body_too_long","daily_limit_reached","number_rate_limited","product_disabled"],"description":"Stable machine-readable messaging error code. Unknown future values should be handled as a generic error with the same HTTP status."},"ListConversationsResponse":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/ConversationRow"}},"nextCursor":{"$ref":"#/components/schemas/ConversationCursor"}},"required":["items","nextCursor"]},"ConversationRow":{"type":"object","properties":{"peerKey":{"type":"string"},"lastMessage":{"$ref":"#/components/schemas/ConversationLastMessage"},"unreadCount":{"type":"integer","minimum":0},"esimIds":{"type":"array","items":{"type":"string","format":"uuid"}}},"required":["peerKey","lastMessage","unreadCount","esimIds"]},"ConversationLastMessage":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"direction":{"type":"string","enum":["inbound","outbound"]},"status":{"type":"string","enum":["received","queued","claimed","sending","sent","sent_unconfirmed","delivered","failed"],"description":"Message status. Outbound messages move queued → sending → sent, or end at failed. `sent` means the mobile network accepted the message and is the final success status. `delivered` and `sent_unconfirmed` are kept for compatibility; current lines return no carrier delivery report, so neither is emitted."},"body":{"type":["string","null"]},"occurredAt":{"type":"string","format":"date-time"}},"required":["id","direction","status","body","occurredAt"]},"ConversationCursor":{"type":["object","null"],"properties":{"lastOccurredAt":{"type":"string","format":"date-time"},"lastMessageId":{"type":"string","format":"uuid"}},"required":["lastOccurredAt","lastMessageId"]},"MarkConversationReadResponse":{"type":"object","properties":{"updated":{"type":"integer","minimum":0}},"required":["updated"]},"MarkConversationReadInput":{"type":"object","properties":{"peerKey":{"type":"string","minLength":1,"maxLength":128,"description":"The thread's canonical peer key (see GET .../conversations)"},"upToOccurredAt":{"type":"string","format":"date-time","description":"Mark inbound messages read up to (and including) this occurredAt/upToMessageId cursor"},"upToMessageId":{"type":"string","format":"uuid"}},"required":["peerKey","upToOccurredAt","upToMessageId"]},"PurchaseAcceptedResponse":{"type":"object","properties":{"numberId":{"type":"string","format":"uuid"},"state":{"type":"string","enum":["awaiting_payment","provisioning"]},"checkoutUrl":{"type":["string","null"]}},"required":["numberId","state","checkoutUrl"]},"PublicPhonePurchaseError":{"type":"object","properties":{"code":{"type":"string","enum":["purchase_in_progress","included_capacity_unavailable","out_of_stock","unsupported_country","idempotency_key_reused","unavailable"]},"message":{"type":"string"}},"required":["code","message"]},"NumberErrorResponse":{"type":"object","properties":{"code":{"$ref":"#/components/schemas/NumberErrorReason"},"message":{"type":"string"},"details":{"type":"object","properties":{"esimId":{"type":"string","format":"uuid"}},"required":["esimId"]}},"required":["code","message"],"description":"Phone-number error envelope. `code` is the canonical discriminator (see `NumberErrorReason` for the code set)."},"NumberErrorReason":{"type":"string","enum":["product_disabled","not_cancellable","capability_unavailable"],"description":"Stable machine-readable phone-number error code. Unknown future values should be handled as a generic error with the same HTTP status."},"PublicPhonePurchaseInput":{"type":"object","properties":{"country":{"type":"string","minLength":2,"maxLength":2,"pattern":"^[a-z]{2}$","example":"de","description":"Optional ISO 3166-1 alpha-2 country code from GET /numbers/phones/countries."},"billingPreference":{"type":"string","enum":["included","included_only","rent"],"description":"Use included capacity when available, require included capacity without paid fallback (included_only), or start a paid checkout (rent)."},"label":{"type":["string","null"],"example":"Support line","description":"User-defined display label — NFC-normalized, up to 100 GRAPHEMES (not UTF-16 code units; an emoji/flag may span several). Display-only, never used for routing."}},"additionalProperties":false},"PhoneCapacityResponse":{"type":"object","properties":{"included":{"type":"integer","minimum":0},"remaining":{"type":"integer","minimum":0},"status":{"type":"string","enum":["available","exhausted","not_included"]},"includedRemaining":{"type":"integer","minimum":0,"deprecated":true,"description":"Deprecated — always equal to `remaining`. Migrate to `remaining`; this field will be removed in a future revision."}},"required":["included","remaining","status","includedRemaining"]},"PhoneCapacityError":{"type":"object","properties":{"code":{"type":"string","enum":["unsupported_country"]},"message":{"type":"string"}},"required":["code","message"]},"PhoneCapacityUpstreamError":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]},"ListDedicatedCountriesResponse":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/DedicatedCountry"}}},"required":["items"]},"DedicatedCountry":{"type":"object","properties":{"country":{"type":"string"},"name":{"type":"string"},"inStock":{"type":"boolean"},"planId":{"type":"string"}},"required":["country","name","inStock","planId"]},"PublicListNumbersResponse":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/PublicNumber"}},"pagination":{"$ref":"#/components/schemas/Pagination"}},"required":["items","pagination"]},"PublicNumber":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"phoneNumber":{"type":["string","null"]},"label":{"type":["string","null"]},"state":{"type":"string","enum":["awaiting_payment","provisioning","active","cancel_scheduled","expired","failed"]},"failureReason":{"type":["string","null"],"enum":["out_of_stock","unknown",null],"description":"Why setup failed. Null unless state is failed, and null when the failure has no classified reason. out_of_stock: no number is currently available for the requested country."},"countryCode":{"type":["string","null"]},"lineCapabilities":{"$ref":"#/components/schemas/LineCapabilities"},"currentPeriodEnd":{"type":["string","null"],"format":"date-time"},"cancelAtPeriodEnd":{"type":"boolean"},"actions":{"$ref":"#/components/schemas/PublicNumberActions"},"createdAt":{"type":["string","null"],"format":"date-time"},"updatedAt":{"type":["string","null"],"format":"date-time"},"capabilities":{"type":["array","null"],"items":{"type":"string","enum":["sms","voice"]},"deprecated":true,"description":"Deprecated: use `lineCapabilities`"},"canSend":{"type":"boolean","deprecated":true,"description":"Deprecated: use `actions.send`"},"purpose":{"type":["string","null"]},"checkoutUrl":{"type":["string","null"]},"cancellable":{"type":"boolean","deprecated":true,"description":"Deprecated: use `actions.cancel`"}},"required":["id","phoneNumber","label","state","failureReason","countryCode","lineCapabilities","currentPeriodEnd","cancelAtPeriodEnd","actions","createdAt","updatedAt","capabilities","canSend","purpose","checkoutUrl","cancellable"]},"PublicNumberActions":{"type":"object","properties":{"send":{"type":"boolean","description":"True when this number passes the send gate of POST /numbers/phones/{id}/messages: self-service sending is switched on and the number is active and able to send SMS. Daily and burst limits and recipient/body checks still apply; the send endpoint stays the final judge."},"cancel":{"type":"boolean","description":"True when DELETE /numbers/phones/{id} would currently succeed."}},"required":["send","cancel"],"description":"Actions currently available for this phone number."},"PublicPhoneMessageListResponse":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"esimId":{"type":["string","null"],"format":"uuid"},"direction":{"type":"string","enum":["inbound","outbound"]},"status":{"type":"string","enum":["received","queued","claimed","sending","sent","sent_unconfirmed","delivered","failed"],"description":"Message status. Outbound messages move queued → sending → sent, or end at failed. `sent` means the mobile network accepted the message and is the final success status. `delivered` and `sent_unconfirmed` are kept for compatibility; current lines return no carrier delivery report, so neither is emitted."},"peerNumber":{"type":["string","null"]},"peerKey":{"type":["string","null"]},"body":{"type":["string","null"]},"deliveryStatus":{"type":["string","null"]},"detectedSender":{"type":["string","null"]},"classification":{"$ref":"#/components/schemas/MessageClassification"},"occurredAt":{"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","esimId","direction","status","peerNumber","peerKey","body","deliveryStatus","detectedSender","classification","occurredAt","createdAt"]}},"pagination":{"$ref":"#/components/schemas/Pagination"}},"required":["items","pagination"]},"SendPhoneMessageInput":{"type":"object","properties":{"to":{"type":"string","minLength":1,"maxLength":32,"example":"+15551230001","description":"Recipient phone number, as E.164 or a US 10/11-digit number. Destinations the number cannot send to are rejected with 422 unsupported_destination, non-numbers with 422 invalid_recipient."},"body":{"type":"string","minLength":1,"maxLength":1600,"description":"SMS body text, up to 1600 characters (longer bodies are rejected with 400). A number's own limit may be lower and is answered 422 body_too_long."},"deliveryReport":{"type":"boolean","default":false,"deprecated":true,"description":"Deprecated: best effort and ignored on most lines. Hosted SIM numbers return no carrier delivery report, so their messages end at `sent` and no `sms.send.delivered` event follows. Defaults to false."}},"required":["to","body"]},"PatchPhoneInput":{"type":"object","properties":{"label":{"type":["string","null"],"example":"Support line","description":"User-defined display label — NFC-normalized, up to 100 GRAPHEMES (not UTF-16 code units; an emoji/flag may span several). Display-only, never used for routing."}}},"MailboxConnection":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"mailboxId":{"type":"string","format":"uuid"},"redirectUrl":{"type":["string","null"]},"status":{"$ref":"#/components/schemas/MailboxConnectionStatus"},"address":{"type":["string","null"]}},"required":["connectionId","mailboxId","redirectUrl","status","address"]},"MailboxConnectionStatus":{"type":"string","enum":["pending","active","expired","removed"]},"MailboxErrorResponse":{"anyOf":[{"$ref":"#/components/schemas/MailboxErrorBody"},{"$ref":"#/components/schemas/MailboxApiErrorEnvelope"}]},"MailboxErrorBody":{"type":"object","properties":{"code":{"$ref":"#/components/schemas/MailboxErrorReason"},"message":{"type":"string"}},"required":["code","message"]},"MailboxErrorReason":{"type":"string","enum":["mailboxes_disabled","otp_extraction_disabled","idempotency_conflict","invalid_idempotency_key","idempotency_key_required","idempotency_key_reused","invalid_local_part","local_part_reserved","local_part_taken","mailbox_vanity_disabled","allocated_mailbox_limit_reached","awaiting_payment_limit_reached","vanity_awaiting_payment_limit_reached","daily_allocation_limit_reached","billing_not_configured","included_capacity_unavailable","mailbox_not_active","uncancel_not_allowed","backend_rate_limited","backend_rejected","backend_unavailable","integration_forbidden","provider_error","assistant_checkout_return_unavailable","custom_domains_disabled","domain_not_disableable","invalid_domain","domain_reserved","domain_unavailable","domain_not_active","domain_limit_reached","domain_verification_expired","domain_claim_superseded","dns_check_rate_limited","gmail_already_connected","connection_pending","connection_expired","connection_removed","message_too_large","external_cancel_not_allowed"],"description":"Stable, machine-readable error reason. Values are frozen and never renamed; new values may be added, so treat unknown values as a generic failure of the same HTTP status."},"MailboxApiErrorEnvelope":{"type":"object","properties":{"code":{"$ref":"#/components/schemas/MailboxErrorReason"},"message":{"type":"string"},"traceId":{"type":"string"},"retryAfterSeconds":{"type":"number"}},"required":["code","message"]},"CreateMailboxConnectionRequest":{"type":"object","properties":{"provider":{"type":"string","enum":["gmail"]},"label":{"type":"string","maxLength":100},"bindingHash":{"type":"string","pattern":"^[0-9a-f]{64}$","description":"sha256 hex of the browser-held connect binding secret."}},"required":["provider"]},"Mailbox":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"provider":{"$ref":"#/components/schemas/MailboxProvider"},"domainId":{"type":["string","null"],"format":"uuid"},"address":{"type":["string","null"],"example":"mx_7k3q9p2m4v8d@inbox.example"},"label":{"type":["string","null"],"maxLength":100},"status":{"$ref":"#/components/schemas/MailboxStatus"},"billingMode":{"$ref":"#/components/schemas/MailboxBillingMode"},"cancelAtPeriodEnd":{"type":"boolean"},"checkoutUrl":{"type":["string","null"]},"checkoutExpiresAt":{"type":["string","null"],"format":"date-time"},"currentPeriodEnd":{"type":["string","null"],"format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"inboundMessages":{"$ref":"#/components/schemas/MailboxInboundMessagesUsage"}},"required":["id","provider","domainId","address","label","status","billingMode","cancelAtPeriodEnd","checkoutUrl","checkoutExpiresAt","currentPeriodEnd","createdAt","inboundMessages"]},"MailboxProvider":{"type":"string","enum":["matix","gmail"]},"MailboxStatus":{"type":"string","enum":["provisioning","awaiting_payment","active","cancel_scheduled","archived","billing_error","pending_connection","connection_expired","connection_removed"]},"MailboxBillingMode":{"type":"string","enum":["rent","included","domain","external"]},"MailboxInboundMessagesUsage":{"type":"object","properties":{"used":{"type":"integer","minimum":0},"included":{"type":"integer","minimum":0},"exhausted":{"type":"boolean"},"resetsAt":{"type":["string","null"],"format":"date-time"}},"required":["used","included","exhausted","resetsAt"]},"CreateMailboxRequest":{"type":"object","properties":{"label":{"type":"string","maxLength":100},"domainId":{"type":"string","format":"uuid","description":"Optional active custom mailbox domain owned by the caller. Omit to use the system domain."},"localPart":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9](?:[A-Za-z0-9._-]{0,62}[A-Za-z0-9])?$","description":"Optional mailbox name before the \"@\". Omit to generate a random address.","example":"jane-doe"},"billingPreference":{"$ref":"#/components/schemas/MailboxBillingPreference"}}},"MailboxBillingPreference":{"type":"string","enum":["included","included_only","rent"],"description":"included uses package capacity when available and otherwise starts paid checkout; included_only fails without creating a paid reservation when no included slot remains; rent always starts paid checkout."},"MailboxList":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Mailbox"}},"pagination":{"$ref":"#/components/schemas/Pagination"}},"required":["items","pagination"]},"MailboxCapacity":{"type":"object","properties":{"included":{"type":"integer","minimum":0},"remaining":{"type":"integer","minimum":0},"status":{"$ref":"#/components/schemas/MailboxCapacityStatus"},"includedRemaining":{"type":"integer","minimum":0}},"required":["included","remaining","status","includedRemaining"]},"MailboxCapacityStatus":{"type":"string","enum":["available","exhausted","not_included"]},"UpdateMailboxRequest":{"type":"object","properties":{"label":{"type":["string","null"],"maxLength":100}},"required":["label"]},"RestartMailboxRequest":{"type":"object","properties":{"billingPreference":{"$ref":"#/components/schemas/MailboxBillingPreference"}}},"MailboxOtp":{"type":"object","properties":{"code":{"type":"string","example":"042911","description":"OTP code as text to preserve leading zeros."},"confidence":{"$ref":"#/components/schemas/OtpConfidence"},"messageId":{"type":"string"},"sender":{"type":["string","null"]},"subject":{"type":["string","null"]},"receivedAt":{"type":"string","format":"date-time"}},"required":["code","confidence","messageId","sender","subject","receivedAt"]},"OtpConfidence":{"type":"string","enum":["high","medium","low"]},"MailboxMessageList":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/MailboxMessageSummary"}},"nextCursor":{"type":["string","null"]}},"required":["items","nextCursor"]},"MailboxMessageSummary":{"type":"object","properties":{"id":{"type":"string"},"mailboxId":{"type":"string","format":"uuid"},"fromAddress":{"type":["string","null"]},"subject":{"type":["string","null"]},"preview":{"type":["string","null"]},"hasOtp":{"type":"boolean"},"receivedAt":{"type":"string","format":"date-time"}},"required":["id","mailboxId","fromAddress","subject","preview","hasOtp","receivedAt"]},"MailboxMessage":{"type":"object","properties":{"id":{"type":"string"},"mailboxId":{"type":"string","format":"uuid"},"fromAddress":{"type":["string","null"]},"fromName":{"type":["string","null"]},"subject":{"type":["string","null"]},"textBody":{"type":["string","null"]},"htmlBody":{"type":["string","null"],"description":"Raw HTML part as received. Present only with includeHtml=true; null when the mail has no HTML part or it exceeds 1 MiB (UTF-8 bytes). Untrusted content: render only in an isolated sandboxed frame, never inline."},"hasOtp":{"type":"boolean"},"attachmentCount":{"type":"integer","minimum":0},"attachments":{"type":"array","items":{"$ref":"#/components/schemas/MailboxAttachmentMeta"}},"receivedAt":{"type":"string","format":"date-time"}},"required":["id","mailboxId","fromAddress","fromName","subject","textBody","hasOtp","attachmentCount","attachments","receivedAt"]},"MailboxAttachmentMeta":{"type":"object","properties":{"name":{"type":["string","null"]},"contentType":{"type":["string","null"]},"size":{"type":"integer","minimum":0}},"required":["name","contentType","size"]},"ModelListResponse":{"type":"object","required":["object","data"],"properties":{"object":{"type":"string","const":"list"},"data":{"type":"array","items":{"$ref":"#/components/schemas/ModelItem"}}}},"ModelItem":{"type":"object","required":["id","object","created","owned_by"],"properties":{"id":{"type":"string"},"object":{"type":"string","const":"model"},"created":{"type":"integer"},"owned_by":{"type":"string"},"label":{"type":"string"},"group":{"type":"string","enum":["recommended","fast","more"]},"order":{"type":"integer"},"surfaces":{"type":"array","items":{"type":"string","enum":["assistant","tasks"]},"description":"Model pickers in which this model is available. When omitted, the model is available in every picker."}}},"Error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","description":"Machine-readable error catalog code. This is a closed enum: every value the gateway can return is listed here (mirrored from auth.ErrorCodes in the Go source of truth). Switch on `code`, not on `message`; treat an unrecognized value as a generic error with the same HTTP status.","enum":["forbidden","invalid_owner_id","source_forbidden","owner_mismatch","invalid_request","invalid_request_id","invalid_credential_id","invalid_api_key","credential_rejected","credential_not_found","credential_exists","credential_state","byok_disabled","byok_credential_unproven","model_unavailable","routing_failed","no_model_groups","insufficient_credit","rate_limited","idempotency_key_reused","policy_version_conflict","not_found","team_binding_unavailable","request_state_failed","internal_error","gateway_draining","unexpected_response","upstream_unavailable","upstream_timeout","catalog_unavailable"]},"message":{"type":"string"}}}},"parameters":{"ConnCloseReason":{"description":"Filter to connections that closed with this reason (closed connections only).","in":"query","name":"closeReason","schema":{"type":"string"}},"ConnCountry":{"description":"Filter to connections served from this upstream country (ISO 3166-1 alpha-2).","in":"query","name":"country","schema":{"type":"string"}},"ConnDstHost":{"description":"Filter to connections to this destination host (exact match).","in":"query","name":"dstHost","schema":{"type":"string"}},"ConnDstPort":{"description":"Filter to connections to this destination port.","in":"query","name":"dstPort","schema":{"maximum":65535,"minimum":0,"type":"integer"}},"ConnEndedAfter":{"description":"Filter to connections whose last activity was at or after this time (inclusive).","in":"query","name":"endedAfter","schema":{"format":"date-time","type":"string"}},"ConnEndedBefore":{"description":"Filter to connections whose last activity was at or before this time (inclusive).","in":"query","name":"endedBefore","schema":{"format":"date-time","type":"string"}},"ConnMaxBytesIn":{"description":"Filter to connections with at most this many bytes received from upstream.","in":"query","name":"maxBytesIn","schema":{"format":"int64","minimum":0,"type":"integer"}},"ConnMaxBytesOut":{"description":"Filter to connections with at most this many bytes sent to upstream.","in":"query","name":"maxBytesOut","schema":{"format":"int64","minimum":0,"type":"integer"}},"ConnMaxDurationMs":{"description":"Filter to connections lasting at most this many milliseconds.","in":"query","name":"maxDurationMs","schema":{"format":"int64","minimum":0,"type":"integer"}},"ConnMaxTotalBytes":{"description":"Filter to connections with at most this much total traffic (bytesIn + bytesOut).","in":"query","name":"maxTotalBytes","schema":{"format":"int64","minimum":0,"type":"integer"}},"ConnMinBytesIn":{"description":"Filter to connections with at least this many bytes received from upstream.","in":"query","name":"minBytesIn","schema":{"format":"int64","minimum":0,"type":"integer"}},"ConnMinBytesOut":{"description":"Filter to connections with at least this many bytes sent to upstream.","in":"query","name":"minBytesOut","schema":{"format":"int64","minimum":0,"type":"integer"}},"ConnMinDurationMs":{"description":"Filter to connections lasting at least this many milliseconds.","in":"query","name":"minDurationMs","schema":{"format":"int64","minimum":0,"type":"integer"}},"ConnMinTotalBytes":{"description":"Filter to connections with at least this much total traffic (bytesIn + bytesOut).","in":"query","name":"minTotalBytes","schema":{"format":"int64","minimum":0,"type":"integer"}},"ConnOrder":{"description":"Sort direction.","in":"query","name":"order","schema":{"default":"desc","enum":["asc","desc"],"type":"string"}},"ConnOrderBy":{"description":"Property to order the results by.","in":"query","name":"orderBy","schema":{"default":"startedAt","enum":["startedAt","endedAt","bytesIn","bytesOut","totalBytes","durationMs"],"type":"string"}},"ConnProtocol":{"description":"Filter to connections of this transport protocol.","in":"query","name":"protocol","schema":{"$ref":"#/components/schemas/ConnectionProtocol"}},"ConnProvider":{"description":"Filter to connections served by this upstream provider identifier.","in":"query","name":"provider","schema":{"type":"string"}},"ConnProxyId":{"description":"Filter to connections routed through this proxy.","in":"query","name":"proxyId","schema":{"format":"uuid","type":"string"}},"ConnSessionId":{"description":"Filter to a single connection by its session id.","in":"query","name":"sessionId","schema":{"format":"uuid","type":"string"}},"ConnStartedAfter":{"description":"Filter to connections that started at or after this time (inclusive).","in":"query","name":"startedAfter","schema":{"format":"date-time","type":"string"}},"ConnStartedBefore":{"description":"Filter to connections that started at or before this time (inclusive).","in":"query","name":"startedBefore","schema":{"format":"date-time","type":"string"}},"ConnStatus":{"description":"Filter by connection status.","in":"query","name":"status","schema":{"$ref":"#/components/schemas/ConnectionStatus"}},"ConnUserId":{"description":"Filter to connections made by this user.","in":"query","name":"userId","schema":{"format":"uuid","type":"string"}},"Page":{"description":"Page number (1-based).","in":"query","name":"page","schema":{"default":1,"minimum":1,"type":"integer"}},"PageSize":{"description":"Number of items per page.","in":"query","name":"pageSize","schema":{"default":20,"maximum":100,"minimum":1,"type":"integer"}},"ProxyID":{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}},"UserID":{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}},"responses":{"BadRequest":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ConnectErrorResponse"}}},"description":"The request was invalid."},"Conflict":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ConnectErrorResponse"}}},"description":"The request cannot be fulfilled in the current state (e.g. no capacity is available for the requested country/type)."},"NotFound":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ConnectErrorResponse"}}},"description":"The resource was not found."},"ServiceUnavailable":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ConnectErrorResponse"}}},"description":"Connection history is temporarily unavailable."},"Unauthorized":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ConnectErrorResponse"}}},"description":"Missing or invalid credentials."}}}}