# Lusor > Run AI agents on real phones, or drive a phone directly, with the Lusor API. - [Introduction](https://docs.lusor.ai/index.md): Run AI agents on real phones, or drive a phone yourself, with the Lusor API. - [Quickstart](https://docs.lusor.ai/quickstart.md): From an API key to your first agent turn in a few minutes. - [Authentication](https://docs.lusor.ai/authentication.md): Authenticate every request with a workspace API key. - [Core concepts](https://docs.lusor.ai/concepts.md): The objects the Lusor API works with, and how they fit together. - [Create an agent](https://docs.lusor.ai/agents/create-an-agent.md): Create a persistent agent, give it a phone, and manage it over time. - [Send a turn](https://docs.lusor.ai/agents/send-a-turn.md): Send a task to an agent, retry safely, and start sessions without an agent. - [Follow a session](https://docs.lusor.ai/agents/follow-a-session.md): Track a session's status, read its events and artifacts, and list past sessions. - [Answer the agent](https://docs.lusor.ai/agents/answer-the-agent.md): Reply when the agent pauses to ask you a question. - [Follow-up messages](https://docs.lusor.ai/agents/follow-up-messages.md): Send a new message into an existing session, on the same conversation. - [Structured output](https://docs.lusor.ai/agents/structured-output.md): Get the session's result back as JSON in a shape you define. - [Choose a model](https://docs.lusor.ai/agents/choose-a-model.md): Pick the AI model an agent or a session uses. - [Recordings and replay](https://docs.lusor.ai/agents/recordings-and-replay.md): Watch a session back as video, or step through it action by action. - [Stop a session](https://docs.lusor.ai/agents/stop-a-session.md): Stop a session that has started, or withdraw a turn or message that is still waiting. - [Phones overview](https://docs.lusor.ai/phones/overview.md): The two kinds of phone in a workspace, how to list them, and how to see which agent is using one. - [Direct control](https://docs.lusor.ai/phones/direct-control.md): Drive a phone yourself: read the screen, tap, type, swipe, press keys and launch apps. - [Chains and capture](https://docs.lusor.ai/phones/chains-and-capture.md): Get the screen back with an action, and run up to 20 actions in one request. - [Live view](https://docs.lusor.ai/phones/live-view.md): Stream a phone's screen into your own app over WebRTC. - [Add and remove Lusor Phones](https://docs.lusor.ai/phones/add-and-remove.md): Add Lusor Phones to your Phone plan, or remove one, with a price preview first. - [Location and timezone](https://docs.lusor.ai/phones/location-and-timezone.md): Read and set the GPS location and timezone a Lusor Phone reports to apps. - [Language and identity](https://docs.lusor.ai/phones/language-and-identity.md): Change a Lusor Phone's system language, the device identity apps read, and its advertising ID. - [Internet and static IP](https://docs.lusor.ai/phones/internet-and-static-ip.md): See where a Lusor Phone's Internet traffic exits, and the state of its static IP. - [Shell](https://docs.lusor.ai/phones/shell.md): Run a restricted Android shell command on a Lusor Phone, as a last resort. - [Phone numbers and email](https://docs.lusor.ai/phones/phone-numbers-and-email.md): Read your workspace's phone numbers, the SMS they receive, and your Agent Mail inboxes. - [Credits and minutes](https://docs.lusor.ai/billing/credits-and-minutes.md): What uses credits, what uses Lusor Phone minutes, and what happens when either runs out. - [Errors](https://docs.lusor.ai/billing/errors.md): How Lusor reports errors, and what to do about the common ones. - [Rate limits](https://docs.lusor.ai/billing/rate-limits.md): How Lusor limits request rates, and how to handle a 429. - [Help Center](https://docs.lusor.ai/help/index.md): How to use the Lusor app: set up phones, run your first task, and manage your plan, team and account. - [Install the Mac app](https://docs.lusor.ai/help/install-the-mac-app.md): Download Lusor for Mac, sign in, and keep the app up to date. - [Your first task](https://docs.lusor.ai/help/your-first-task.md): Create an agent, give it a phone, and send it a task in the Lusor app. - [Connect your iPhone](https://docs.lusor.ai/help/connect-your-iphone.md): Set up your own iPhone with the Lusor Mac app, step by step, so agents can use it. - [Connect your Android phone](https://docs.lusor.ai/help/connect-your-android.md): Set up your own Android phone with the Lusor Launcher app, step by step, so agents can use it. - [Lusor Phones](https://docs.lusor.ai/help/lusor-phones.md): What a Lusor Phone is, how to add and remove one, wipe and reset it, and set its internet location. - [Plans and credits](https://docs.lusor.ai/help/plans-and-credits.md): What each Lusor plan includes, what credits pay for, Lusor Phone minutes, Lusor Internet, overages and credit packs. - [Recordings and history](https://docs.lusor.ai/help/recordings-and-history.md): What Lusor records while an agent works, how to watch it back, and how long your plan keeps it. - [Members and workspaces](https://docs.lusor.ai/help/members-and-workspaces.md): Invite teammates to your organization and control which workspaces they can use. - [API keys](https://docs.lusor.ai/help/api-keys.md): Create and revoke API keys so your own scripts and tools can use Lusor. - [Troubleshooting](https://docs.lusor.ai/help/troubleshooting.md): Fix common problems: a phone shows offline, an iPhone won't connect, a run failed or ran out of credits, or the agent is waiting on you. - [Connect an AI app](https://docs.lusor.ai/connect/index.md): Give Claude, ChatGPT, Grok, Hermes, Pi, Codex or Cursor your phones through the Lusor MCP server. - [Docs for AI agents](https://docs.lusor.ai/connect/for-agents.md): Point a coding agent or AI app at the Lusor docs and API spec in a form it can read. - [Claude](https://docs.lusor.ai/connect/claude.md): Add Lusor to Claude as a custom connector. - [ChatGPT](https://docs.lusor.ai/connect/chatgpt.md): Add Lusor to a ChatGPT Business, Enterprise or Edu workspace as a custom MCP server. - [Codex](https://docs.lusor.ai/connect/codex.md): Add Lusor to the Codex CLI as a remote MCP server. - [Cursor](https://docs.lusor.ai/connect/cursor.md): Add Lusor to Cursor as a remote MCP server. - [Grok](https://docs.lusor.ai/connect/grok.md): Add Lusor to Grok as a custom connector. - [Hermes](https://docs.lusor.ai/connect/hermes.md): Add Lusor to Hermes Agent as a remote MCP server. - [Pi](https://docs.lusor.ai/connect/pi.md): Add Lusor to the Pi coding agent as a remote MCP server. - [API reference](https://docs.lusor.ai/api-reference/introduction.md): Every Lusor API endpoint, with an interactive playground. - [Get session detail](https://docs.lusor.ai/api-reference/sessions/get-session-detail.md) - [Rename a session](https://docs.lusor.ai/api-reference/sessions/rename-a-session.md): Sets the session's display name. Send `name: null` to clear it, so the name is derived from the prompt again. Returns the updated session. - [Get session events](https://docs.lusor.ai/api-reference/sessions/get-session-events.md) - [Get the detailed step breakdown (session JSON)](https://docs.lusor.ai/api-reference/sessions/get-the-detailed-step-breakdown-session-json.md): The replay view's JSON breakdown: the session detail and its full event list as one `lusor.session.v1` document. Included only on App tiers with the detailed step breakdown (Hobby and above); other tiers get 403 `detailed_breakdown_not_in_plan` and no session data. The same retention window as `GET… - [List sessions for device](https://docs.lusor.ai/api-reference/sessions/list-sessions-for-device.md) - [Create a new session on this device](https://docs.lusor.ai/api-reference/sessions/create-a-new-session-on-this-device.md): Starts an agent run on this phone without a persistent agent. Returns `202 Accepted { id, status: "queued" }` immediately; poll `GET /v1/sessions/{id}/status` or `GET /v1/sessions/{id}/events` for progress. - [List sessions](https://docs.lusor.ai/api-reference/sessions/list-sessions.md): Server-side filtering over the workspace's session history, newest first. `deviceId` and `status` are exact single-value matches; the filter parameters (`statuses`, `statusMode`, `nameContains`, `deviceContains`, `createdBefore`, `createdAfter`) are applied server-side so the result stays correct ac… - [Get session status (lightweight)](https://docs.lusor.ai/api-reference/sessions/get-session-status-lightweight.md) - [Get session artifacts (screenshots + ui-states + output)](https://docs.lusor.ai/api-reference/sessions/get-session-artifacts-screenshots-+-ui-states-+-output.md) - [Cancel a running session](https://docs.lusor.ai/api-reference/sessions/cancel-a-running-session.md): Idempotent cancel. Repeated calls after a successful cancel return `status: "noop"`. - [Get one captured UI state of a session](https://docs.lusor.ai/api-reference/sessions/get-one-captured-ui-state-of-a-session.md): The UI tree the agent saw at one step of the run, as the JSON array of nodes it was captured as. `file` is the step index followed by `.json`, for example `0.json`. Content follows the workspace's history window: a state older than the window returns `404`. - [Cancel a queued follow-up or queued agent turn](https://docs.lusor.ai/api-reference/sessions/cancel-a-queued-follow-up-or-queued-agent-turn.md): Removes a turn that is waiting behind a running one, before it starts. `invocationId` is the `invocationId` of the `202` `{ queued: true }` response of `POST /v1/sessions/{id}/continue` or `POST /v1/agents/{id}/turns`. Idempotent: cancelling an already-cancelled entry returns `alreadyCancelled: true… - [Send a follow-up message to a session](https://docs.lusor.ai/api-reference/sessions/send-a-follow-up-message-to-a-session.md): Continues the session with a new prompt on the same transcript. The follow-up runs on the session's phone (for an agent's session, the phone the agent has now). If the session is still running, the follow-up is queued behind it (`queued: true`) and runs when the current run ends. Continuing a finish… - [Answer the agent's question (request_human)](https://docs.lusor.ai/api-reference/sessions/answer-the-agents-question-request_human.md): When the agent asks a question, the run pauses: the session's status becomes `awaiting_human` and its events include a `hitl_requested` event whose `data.correlation_id` identifies the question (`data.question`, and `data.options` when the agent offered answer labels). Post the answer here; the run… - [Get the session's video recording](https://docs.lusor.ai/api-reference/sessions/get-the-sessions-video-recording.md): Returns signed URLs for the recording's MP4 segments, in order. URLs expire at each segment's `expires_at` (Unix seconds); fetch this endpoint again for fresh ones. - [Get the session's step-by-step replay](https://docs.lusor.ai/api-reference/sessions/get-the-sessions-step-by-step-replay.md): Each completed action paired with the screenshot taken after it, in time order, with a signed `frame_url` that expires at `expires_at` (Unix seconds, about five minutes). Frames still uploading are left out until they are ready. Past the workspace's history window this returns `402` with `reason: "h… - [Download one replay frame (PNG)](https://docs.lusor.ai/api-reference/sessions/download-one-replay-frame-png.md): The bytes of one replay screenshot, served by the API instead of a signed URL. `index` selects into the list `GET /v1/sessions/{id}/replay` returns, counting from 0. - [List skills](https://docs.lusor.ai/api-reference/skills/list-skills.md) - [Create a skill](https://docs.lusor.ai/api-reference/skills/create-a-skill.md): Creates a private skill owned by the caller. The slug is derived from `title`; a title that slugs to the same value as another of your skills returns `409 skill_exists`. - [Get a skill](https://docs.lusor.ai/api-reference/skills/get-a-skill.md) - [Delete a skill](https://docs.lusor.ai/api-reference/skills/delete-a-skill.md) - [Update a skill](https://docs.lusor.ai/api-reference/skills/update-a-skill.md): Partial update. When `clientRevision` is supplied the update is applied only if it is newer than the stored revision — this orders concurrent PATCHes (e.g. an in-flight autosave racing the Skills panel's unload flush) so an older request landing last cannot revert newer values. A stale revision retu… - [List the secrets saved in a workspace](https://docs.lusor.ai/api-reference/secrets/list-the-secrets-saved-in-a-workspace.md): Lists the secrets saved in the workspace, names only. Reference them by `.` in a session's `secrets`. Secret values are never returned. With an API key, no field values are returned at all. Secrets are added, changed and deleted in the Lusor app's Vault, not with an API key. - [List workspace phone numbers](https://docs.lusor.ai/api-reference/phonenumbers/list-workspace-phone-numbers.md): Returns numbers shared within the authorized workspace, including country, paid coverage and lifecycle information. Numbers have no manual assignments or default agent/device/app bindings. - [Get one workspace phone number](https://docs.lusor.ai/api-reference/phonenumbers/get-one-workspace-phone-number.md): Returns workspace-owned number details without manual associations. Unknown or foreign numbers return an opaque 404. - [Page stored SMS messages for a workspace number](https://docs.lusor.ai/api-reference/phonenumbers/page-stored-sms-messages-for-a-workspace-number.md): Read-only human inbox. Returns raw stored text and codes, never parsed OTPs or inferred sender identities. Requires an API key bound to this exact workspace. Unknown, foreign, or malformed workspace/number IDs return opaque 404s. No provider polling, writes, or outbound SMS occurs. - [List the workspace's Agent Mail addresses](https://docs.lusor.ai/api-reference/emails/list-the-workspaces-agent-mail-addresses.md): Read-only Agent Mail identity list. Returns only addresses owned by the caller's workspace. - [Page stored inbound mail for a workspace address](https://docs.lusor.ai/api-reference/emails/page-stored-inbound-mail-for-a-workspace-address.md): Read-only human inbox. Returns stored sender fields, subject, and the raw plain-text body — never parsed codes, executed HTML, or remotely fetched assets. The address is resolved inside the caller's workspace: an absent, repeated, foreign, or malformed addressId returns the same opaque 404 and never… - [List devices in the key's workspace](https://docs.lusor.ai/api-reference/devices/list-devices-in-the-keys-workspace.md): Returns every phone in the API key's workspace, including offline ones. The same list as `GET /v1/workspaces/{workspaceId}/devices`, without needing the workspace id in the path. - [List devices in a workspace](https://docs.lusor.ai/api-reference/devices/list-devices-in-a-workspace.md) - [Preview deploying Lusor Phones](https://docs.lusor.ai/api-reference/devices/preview-deploying-lusor-phones.md): Quotes `quantity` more Lusor Phones (default 1) on the workspace's Phone plan, as one change: the prorated amount charged today for the rest of the current period, and the next full invoice. Nothing is charged. The quote expires after 10 minutes; confirm it with `POST /devices/deploy`. - [Deploy the quoted Lusor Phones](https://docs.lusor.ai/api-reference/devices/deploy-the-quoted-lusor-phones.md): Confirms a deploy quote: the Phone plan quantity rises by the quoted number of phones and the quoted amount is charged to the saved card now. If the payment does not go through, the quantity stays unchanged, `paymentPending` is true and no phone is deployed; complete the payment in billing managemen… - [Preview removing a Lusor Phone](https://docs.lusor.ai/api-reference/devices/preview-removing-a-lusor-phone.md): Quotes removing this Lusor Phone from the Phone plan: the plan quantity falls by one and the unused rest of the current period is credited to the account balance (applied to the next invoice). Nothing changes yet. The quote expires after 10 minutes; confirm it with `POST /devices/{deviceId}/remove`. - [Remove a Lusor Phone](https://docs.lusor.ai/api-reference/devices/remove-a-lusor-phone.md): Confirms a removal quote. This phone, and no other, stops accepting runs at once; the plan quantity falls by one, and the phone is then wiped and released. Its data cannot be recovered. A session started on it since the quote refuses the removal with 409 `device_busy`. - [Get a Lusor Phone's location and timezone](https://docs.lusor.ai/api-reference/devices/get-a-lusor-phones-location-and-timezone.md): The GPS location and timezone the phone reports to apps. In `auto` mode both follow the phone's Internet exit IP and are re-applied after every IP change. In `override` mode they are the values set with `PUT /geo`, and `apply.state` says whether the phone has them yet (`pending`, `applied`, `held` w… - [Set a Lusor Phone's location and timezone](https://docs.lusor.ai/api-reference/devices/set-a-lusor-phones-location-and-timezone.md): Sets the GPS location and timezone the phone reports, replacing the automatic match to its Internet exit IP. The setting persists across restarts and IP changes until it is cleared with `DELETE /geo`, or until the phone is wiped (Wipe & reset) or removed. It can disagree with the exit IP's country o… - [Restore a Lusor Phone's automatic location](https://docs.lusor.ai/api-reference/devices/restore-a-lusor-phones-automatic-location.md): Clears a location set with `PUT /geo`. The phone's GPS location and timezone follow its Internet exit IP again and are re-applied now. Clearing when nothing is set changes nothing. - [Get which agents are using, queued for, or attached to a phone](https://docs.lusor.ai/api-reference/devices/get-which-agents-are-using-queued-for-or-attached-to-a-phone.md): `active` is the run currently holding the phone (null when idle; `agentId` is null for a run started without an agent). `queue` lists agent turns waiting for the phone, oldest first. `assigned` lists the agents attached to the phone. - [List the countries a Lusor Phone's Internet can exit from](https://docs.lusor.ai/api-reference/devices/list-the-countries-a-lusor-phones-internet-can-exit-from.md): `rotating`: the countries a phone can be bought in or moved to on the residential route. `persistent`: the countries a static IP is sold in. ISO 3166-1 alpha-2 codes, lowercase. Any other country answers 400 `unsupported_country` at purchase and on a location change. - [Get a Lusor Phone's Internet exit country and route](https://docs.lusor.ai/api-reference/devices/get-a-lusor-phones-internet-exit-country-and-route.md): The country the phone's Internet traffic exits from, and whether the phone is on its static IP (`route: "static"`) or the shared residential route (`route: "residential"`). `applied` is `pending` until the phone's route is recorded. - [Get a Lusor Phone's static IP status](https://docs.lusor.ai/api-reference/devices/get-a-lusor-phones-static-ip-status.md): Without `operation`, returns the phone's static IP state. With the `operation` id returned when a static IP was requested, returns that operation's outcome: `200` once it settled, `202` while it is still in progress (poll again). - [Get a Lusor Phone's wipe-and-reset progress](https://docs.lusor.ai/api-reference/devices/get-a-lusor-phones-wipe-and-reset-progress.md): The state of the phone's most recent wipe and reset: `idle` (none has run), `running`, `succeeded`, `refused` (it did not start; see `reason`), or `failed`. - [Get device UI state](https://docs.lusor.ai/api-reference/devices/get-device-ui-state.md): Captures the current UI tree and screen dimensions. The `a11yTree` field carries the formatted element tree (with 1-based interactive indices) used by `POST /tap { index }`. - [Get fresh device screenshot (binary PNG)](https://docs.lusor.ai/api-reference/devices/get-fresh-device-screenshot-binary-png.md): Triggers a fresh screenshot on the device and returns the resulting PNG bytes. Response is binary `image/png`. - [Get a Lusor Phone's language](https://docs.lusor.ai/api-reference/devices/get-a-lusor-phones-language.md): The language last set through `PUT .../language` and how applying it ended. `null` fields mean none has been set. `inProgress` names a change that is still being applied. - [Set a Lusor Phone's language](https://docs.lusor.ai/api-reference/devices/set-a-lusor-phones-language.md): Sets the phone's system language (and optional region). Answers 202 at once with the change `pending`; read `GET .../language` until `state` is `applied` or `failed`. The phone may restart to apply it. Refused with 409 `phone_busy` while a session or live viewer holds the phone or another change is… - [Get a Lusor Phone's identity](https://docs.lusor.ai/api-reference/devices/get-a-lusor-phones-identity.md): The identity fields set so far (latest value of each) and how the last change ended. Fields never set keep the phone's own values and are absent here. - [Set a Lusor Phone's identity](https://docs.lusor.ai/api-reference/devices/set-a-lusor-phones-identity.md): Sets the device identity apps read: brand, manufacturer, model, device codename, product name, build fingerprint and Android ID. Only the fields sent change. Raw Android properties are refused (400 `identity_prop_refused`). Answers 202 with the change `pending`; once written (`state` `applied`, `res… - [Get a Lusor Phone's last advertising-ID reset](https://docs.lusor.ai/api-reference/devices/get-a-lusor-phones-last-advertising-id-reset.md): How the last advertising-ID reset ended. The ID itself is not returned. - [Reset a Lusor Phone's advertising ID](https://docs.lusor.ai/api-reference/devices/reset-a-lusor-phones-advertising-id.md): Gives the phone a new Google advertising ID. **Irreversible**: the previous ID cannot be restored. Answers 202 with the reset `pending`; read `GET .../advertising-id` until it is `applied` or `failed`. - [Trigger screenshot (capture-aware verb)](https://docs.lusor.ai/api-reference/deviceverbs/trigger-screenshot-capture-aware-verb.md): Triggers a fresh screenshot on the device and returns the standard verb envelope. Pass `capture: true` (or `capture: { screenshot: true, ui: true }`) to receive the formatted element tree + `screenshot_url` in the same response. - [Tap on device](https://docs.lusor.ai/api-reference/deviceverbs/tap-on-device.md): Tap an interactive element by `{ index }` (1-based, from `/state.a11yTree`) OR an explicit `{ x, y }` coordinate. Supplying both is accepted and `index` wins. At least one of the two forms is required: supplying neither is a 400, and `x` without `y` is also a 400 when no `index` is supplied (with `i… - [Swipe gesture on device](https://docs.lusor.ai/api-reference/deviceverbs/swipe-gesture-on-device.md): Optionally include `capture: true | CaptureOptions` to return a fresh element tree + screen dimensions in the same round trip. - [Type text into focused field](https://docs.lusor.ai/api-reference/deviceverbs/type-text-into-focused-field.md): Optionally include `capture: true | CaptureOptions` to return a fresh element tree + screen dimensions in the same round trip. - [Press a key on device](https://docs.lusor.ai/api-reference/deviceverbs/press-a-key-on-device.md): Send a single Android KeyEvent. Common codes: 66=Enter, 67=Del, 61=Tab, 111=Esc, 19/20/21/22=DPad. - [Clear focused field](https://docs.lusor.ai/api-reference/deviceverbs/clear-focused-field.md): Accepts an optional `capture` field identical in shape to the parameterised verbs. - [Press Back key](https://docs.lusor.ai/api-reference/deviceverbs/press-back-key.md): Accepts an optional `capture` field. - [Press Home key](https://docs.lusor.ai/api-reference/deviceverbs/press-home-key.md): Accepts an optional `capture` field. - [Press Recent Apps key](https://docs.lusor.ai/api-reference/deviceverbs/press-recent-apps-key.md): Accepts an optional `capture` field. - [Launch an app](https://docs.lusor.ai/api-reference/deviceverbs/launch-an-app.md): Launch an Android app by package name. The `package` and optional `activity` must be dotted identifiers (for example `com.android.settings`); anything else is a 400. - [Force-stop an app](https://docs.lusor.ai/api-reference/deviceverbs/force-stop-an-app.md): Force-stop an Android app by package name. The `package` is validated the same way as `apps/start`. - [Run a chain of actions](https://docs.lusor.ai/api-reference/deviceverbs/run-a-chain-of-actions.md): Execute a typed sequence of up to 20 deterministic actions in order, optionally collecting a UI capture per step. On a Lusor Phone, an API-key chain meters phone minutes before every step; a `402` or `503` stops the chain before that step reaches the phone. - [Run a restricted shell command](https://docs.lusor.ai/api-reference/shell/run-a-restricted-shell-command.md): Last-resort shell access. The command is checked against a server-side denylist (shell metacharacters such as `|`, `;`, `&` and backticks are refused anywhere in the string) and every attempt, allowed or denied, is audit-logged. The response reports whether the command ran; command output is not ret… - [Start a live view of the session's phone](https://docs.lusor.ai/api-reference/liveview/start-a-live-view-of-the-sessions-phone.md): Asks the phone to start a WebRTC stream for this session. Open `GET /v1/sessions/{id}/stream/events` first to receive the phone's offer. TURN servers are added automatically unless you pass `iceServers`. - [Re-arm a live view](https://docs.lusor.ai/api-reference/liveview/re-arm-a-live-view.md): Reconnects the WebRTC stream without starting over: the phone reuses its running screen capture when it can. Same body and response as `POST /v1/sessions/{id}/stream/start`. - [Extend a live view's liveness](https://docs.lusor.ai/api-reference/liveview/extend-a-live-views-liveness.md): Sends one extra keep-alive to the phone. The server already sends one every 25 seconds while a stream is active, so this is optional. - [Ask the phone for a fresh keyframe](https://docs.lusor.ai/api-reference/liveview/ask-the-phone-for-a-fresh-keyframe.md): Makes the phone's encoder send a keyframe, which recovers a frozen picture without reconnecting. - [Send a WebRTC answer or ICE candidate to the phone](https://docs.lusor.ai/api-reference/liveview/send-a-webrtc-answer-or-ice-candidate-to-the-phone.md): Relays the client's side of the WebRTC handshake to the phone. `message.type` must be `webrtc_answer` or `webrtc_ice`; the rest of `message` is passed to the phone unchanged. - [Stop a live view](https://docs.lusor.ai/api-reference/liveview/stop-a-live-view.md) - [Get the ICE servers for a live view](https://docs.lusor.ai/api-reference/liveview/get-the-ice-servers-for-a-live-view.md): The STUN/TURN configuration for the client's `RTCPeerConnection`. The phone gets the same TURN allocation, so pass these to the browser unchanged. `iceServers` is null when TURN is not available; fall back to STUN. Rotating the credential during a live view is not available through the API yet: afte… - [Receive the phone's WebRTC signaling (Server-Sent Events)](https://docs.lusor.ai/api-reference/liveview/receive-the-phones-webrtc-signaling-server-sent-events.md): A Server-Sent Events stream. Each event is named `signal` and its `data` is one JSON signaling message from the phone, identified by its `action` (for example `webrtc_offer`, `webrtc_ice`, `stream_ready`). A `keep-alive` comment arrives every 15 seconds. The stream stays open until the client discon… - [Promote one session run's list to a Dataset](https://docs.lusor.ai/api-reference/datasets/promote-one-session-runs-list-to-a-dataset.md): Resolves the specified run's terminal list and saves it as a Dataset. Promotion is idempotent on `(session_id, run_id)`: the first request creates the Dataset; re-promotion updates it without duplicating it. - [List Datasets visible to the caller](https://docs.lusor.ai/api-reference/datasets/list-datasets-visible-to-the-caller.md): Returns Datasets whose source sessions belong to workspaces the caller can access, newest first. - [Get a Dataset](https://docs.lusor.ai/api-reference/datasets/get-a-dataset.md) - [Delete a Dataset](https://docs.lusor.ai/api-reference/datasets/delete-a-dataset.md) - [Update a Dataset (rename and/or replace output)](https://docs.lusor.ai/api-reference/datasets/update-a-dataset-rename-andor-replace-output.md): Provide `name`, `output`, or both. `output` replaces the stored list (validated as `{ schema, rows }` with at least one row of plain objects); `row_count` is recomputed server-side from the accepted rows. Typed schema entries are validated strictly: an object entry whose `name` is missing/empty or w… - [List active agents](https://docs.lusor.ai/api-reference/agents/list-active-agents.md): Without `limit` or `cursor`, returns every active agent, newest created first; only the 50 agents with the newest sessions carry a latest-turn preview. With either parameter, returns one page ordered by `activityAt` (newest first), every row with its own preview, plus `nextCursor`/`hasMore`. `activi… - [Create an agent](https://docs.lusor.ai/api-reference/agents/create-an-agent.md) - [Get or create the workspace's primary agent](https://docs.lusor.ai/api-reference/agents/get-or-create-the-workspaces-primary-agent.md): Returns the workspace's primary agent, restoring it if it was archived or creating it if the workspace has none. Idempotent: repeated calls return the same agent. - [List agents recoverable within the 30-day restore window](https://docs.lusor.ai/api-reference/agents/list-agents-recoverable-within-the-30-day-restore-window.md): Lists archived agents in the authenticated tenant and selected workspace with a non-null `purgeAfter` strictly later than the query time. Expired and already-purged agents are excluded. This read does not purge rows. Ordered by `purgeAfter` ascending (nearest deadline first), then `id`. Each entry i… - [Get an agent, attachments, and the newest page of turns](https://docs.lusor.ai/api-reference/agents/get-an-agent-attachments-and-the-newest-page-of-turns.md): `turns` is the NEWEST page of history only (20 turns), oldest-first. Walk backwards with `GET /v1/agents/{id}/turns` using `turnsCursor`. - [Archive an agent for 30 days](https://docs.lusor.ai/api-reference/agents/archive-an-agent-for-30-days.md) - [Update an agent and atomically replace its attachment set](https://docs.lusor.ai/api-reference/agents/update-an-agent-and-atomically-replace-its-attachment-set.md) - [Restore an archived agent within its 30-day window](https://docs.lusor.ai/api-reference/agents/restore-an-archived-agent-within-its-30-day-window.md) - [Read one older page of an agent's turn history](https://docs.lusor.ai/api-reference/agents/read-one-older-page-of-an-agents-turn-history.md): Cursor (keyset) pagination over the stable `(created_at, id)` session ordering, walking BACKWARDS from newest to oldest. Offsets are not supported on purpose: a turn arriving mid-scroll shifts every offset by one, so consecutive offset pages both duplicate and drop rows. - [Submit a turn to an agent](https://docs.lusor.ai/api-reference/agents/submit-a-turn-to-an-agent.md): Starts a run on the agent's phone, or queues it if the phone is busy (`queued: true`). An agent with no phone gets a turn that waits for one (`needsDevice: true`). Track the run with the returned `sessionId` under `/v1/sessions/{id}`. - [Cancel a turn that is still waiting for its device](https://docs.lusor.ai/api-reference/agents/cancel-a-turn-that-is-still-waiting-for-its-device.md): Retracts a queued turn before it starts. Idempotent: a turn that has already finished answers `200` with `cancelled: false`. A turn that has started returns `400`; stop it with `POST /v1/sessions/{id}/stop` instead. `409` means the cancel's outcome is not known yet; retry it. - [Get a workspace](https://docs.lusor.ai/api-reference/workspaces/get-a-workspace.md): An API key can read only the workspace it is bound to; any other id returns an opaque `404`. - [List installable catalog apps](https://docs.lusor.ai/api-reference/catalog/list-installable-catalog-apps.md): Up to 500 apps, ordered by name. - [Get a catalog app's icon (binary image)](https://docs.lusor.ai/api-reference/catalog/get-a-catalog-apps-icon-binary-image.md): Returns the icon bytes, as `image/png`, `image/jpeg` or `image/webp`. - [Health check](https://docs.lusor.ai/api-reference/health/health-check.md): Unauthenticated health probe for uptime monitoring. - [Changelog](https://docs.lusor.ai/changelog.md): New features and changes in the Lusor app, the API, Lusor Phones and the Lusor Mac app. ## OpenAPI Specs - [openapi](/api-reference/openapi.yaml) This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.