# Mobile Next > Tools for AI agents and developers to control mobile devices. ## docs Mobile Next lets AI agents and developers control real iOS and Android devices through one MCP server, a CLI, and a cloud device farm. - [The mobile automation layer for AI agents and developers](https://mobilenext.ai/docs/index.md): Mobile Next lets AI agents and developers control real iOS and Android devices through one MCP server, a CLI, and a cloud device farm. ### api - [Account](https://mobilenext.ai/docs/api/account.md): Account API - [API Keys](https://mobilenext.ai/docs/api/api-keys.md): API Keys API - [Apps](https://mobilenext.ai/docs/api/apps.md): Apps API - [Billing](https://mobilenext.ai/docs/api/billing.md): Billing API - [Chats](https://mobilenext.ai/docs/api/chats.md): Chats API - [Devices](https://mobilenext.ai/docs/api/devices.md): Devices API - [Files](https://mobilenext.ai/docs/api/files.md): Files API - [Instances](https://mobilenext.ai/docs/api/instances.md): Instances API - [Mobile Next Cloud API](https://mobilenext.ai/docs/api/intro.md): REST API for Mobile Next Cloud. - [Invitations](https://mobilenext.ai/docs/api/invitations.md): Invitations API - [Organizations](https://mobilenext.ai/docs/api/organizations.md): Organizations API - [Sessions](https://mobilenext.ai/docs/api/sessions.md): Sessions API - [Test Results](https://mobilenext.ai/docs/api/test-results.md): Test Results API ### architecture How Mobile Next products fit together. - [Architecture](https://mobilenext.ai/docs/architecture.md): How Mobile Next products fit together. ### cloud - [Apps](https://mobilenext.ai/docs/cloud/apps.md): Upload an APK or IPA once, then start real devices with it or install it on a running device. - [Available Devices](https://mobilenext.ai/docs/cloud/devices.md): The iOS and Android devices you can allocate on Mobile Next Cloud. - [ChatGPT (Web & Desktop App)](https://mobilenext.ai/docs/cloud/installation/chatgpt-web-desktop.md): Install Mobile Next Cloud MCP server with ChatGPT Web and Desktop App. - [Claude Code](https://mobilenext.ai/docs/cloud/installation/claude-code.md): Install Mobile Next Cloud MCP server with Claude Code. - [Claude (Web & Desktop App)](https://mobilenext.ai/docs/cloud/installation/claude-web-desktop.md): Install Mobile Next Cloud MCP server with Claude Web and Desktop App. - [Codex](https://mobilenext.ai/docs/cloud/installation/codex.md): Install Mobile Next Cloud MCP server with Codex. - [Cursor](https://mobilenext.ai/docs/cloud/installation/cursor.md): Install Mobile Next Cloud MCP server with Cursor. - [Gemini CLI](https://mobilenext.ai/docs/cloud/installation/gemini-cli.md): Install Mobile Next Cloud MCP server with Gemini CLI. - [Introduction](https://mobilenext.ai/docs/cloud/introduction.md): Learn how to get started with Mobile Next Cloud MCP Server. - [Overview](https://mobilenext.ai/docs/cloud/overview.md): What is Mobile Next Cloud and how it helps manage your device infrastructure. - [Tools & Prompts](https://mobilenext.ai/docs/cloud/tools-and-prompts.md): Available tools and prompts for Mobile Next Cloud MCP Server. - [Using Mobile Next Cloud MCP](https://mobilenext.ai/docs/cloud/using-mobilenext-mcp.md): How to use the mobilenext server to interact with Mobile Next Cloud. ### guides - [Give Claude Code a Real Phone](https://mobilenext.ai/docs/guides/claude-code-real-phone.md): Connect Claude Code to a local iOS or Android device using Mobile MCP. - [Run Mobile Tests in CI](https://mobilenext.ai/docs/guides/mobile-tests-in-ci.md): Run Mobilewright tests in a CI pipeline using GitHub Actions. - [Test an iOS App with Mobilewright](https://mobilenext.ai/docs/guides/test-ios-app-with-mobilewright.md): End-to-end guide: write and run your first Mobilewright test on iOS. ### mobilewright - [Mobilewright](https://mobilenext.ai/docs/mobilewright/overview.md): Using Mobilewright with Mobile Next Cloud. ## Optional - [OpenAPI spec](https://mobilenext.ai/docs/openapi.json): OpenAPI 3 definition of the Mobile Next Cloud API --- # Full Documentation Content # Account ## Get current user[​](#get-me "Direct link to Get current user") GET/api/v1/me Returns The authenticated user. To learn which organizations the caller belongs to (and their role in each), call GET /api/v1/organizations. `id`string · uuidrequired The user's own id `name`string `email`string · emailrequired Request ``` curl https://app.mobilenext.ai/api/v1/me \ -X GET \ -H 'Authorization: Bearer mob_...' ``` Response 200401 Current user info ``` { "id": "string", "name": "string", "email": "string" } ``` ## Delete your account[​](#delete-me "Direct link to Delete your account") DELETE/api/v1/me Deletes the caller's account and their Personal organization. Every session, API key and CLI login stops working, and the same login can sign up again later as a new account. Refused while the caller still belongs to any other organization: leave or delete those first. Not available to API keys. Request ``` curl https://app.mobilenext.ai/api/v1/me \ -X DELETE \ -H 'Authorization: Bearer mob_...' ``` Response 204401403409 Account deleted ``` // No response body ``` --- # API Keys ## List API keys[​](#list-api-keys "Direct link to List API keys") GET/api/v1/keys Lists all API keys in the selected organization, visible to every member of it. Secrets are never returned; only a short suffix is shown to help identify each key. Requires an interactive (JWT) session: an API key cannot list keys. Use the X-Organization-Id header to choose the organization; otherwise the caller's default organization is used. Header parameters `X-Organization-Id`string Selects which of the caller's organizations the request acts on. When omitted, the caller's default organization is used. Returns `object`stringrequired `data`arrayrequired Show child attributes `id`string · uuidrequired `apiKeySuffix`stringrequired Last few characters of the secret, to help identify the key `name`stringnullable Human-readable label for the key `createdAt`string · date-timerequired `lastUsedAt`string · date-timenullable When the key was last used; null if never used Request ``` curl https://app.mobilenext.ai/api/v1/keys \ -X GET \ -H 'Authorization: Bearer mob_...' ``` Response 200401403 All API keys in the selected organization ``` { "object": "list", "data": [ { "id": "string", "apiKeySuffix": "a1b", "name": "string", "createdAt": "2026-01-01T00:00:00Z", "lastUsedAt": "2026-01-01T00:00:00Z" } ] } ``` ## Create an API key[​](#create-api-key "Direct link to Create an API key") POST/api/v1/keys Creates a new API key in the selected organization and returns its secret. The full secret is shown only once, in this response; it is never retrievable again. Requires an interactive (JWT) session: an API key cannot create another API key. Use the X-Organization-Id header to choose which organization the new key belongs to. Header parameters `X-Organization-Id`string Selects which of the caller's organizations the request acts on. When omitted, the caller's default organization is used. Body parameters `name`stringrequired Human-readable label for the key Returns A newly created API key. apiKey is the full secret and is returned only here, only once. `id`string · uuidrequired `apiKey`stringrequired The full secret, starting with mob\_. Shown once; store it now. `name`stringrequired `createdAt`string · date-timerequired Request ``` curl https://app.mobilenext.ai/api/v1/keys \ -X POST \ -H 'Authorization: Bearer mob_...' \ -H 'Content-Type: application/json' \ -d '{"name":"CI pipeline"}' ``` Response 201400401403 API key created; the full secret is returned once in apiKey ``` { "id": "string", "apiKey": "mob_a1b2c3...", "name": "string", "createdAt": "2026-01-01T00:00:00Z" } ``` ## Delete an API key[​](#delete-api-key "Direct link to Delete an API key") DELETE/api/v1/keys/{id} Permanently deletes an API key in the organization. Any key in the organization can be deleted (not only the caller's own). Requires an interactive (JWT) session: an API key cannot delete keys. Requires a read/write or admin role; read-only members cannot delete keys. Use the X-Organization-Id header to choose the organization; otherwise the caller's default organization is used. Path parameters `id`string · uuidrequired API key id Header parameters `X-Organization-Id`string Selects which of the caller's organizations the request acts on. When omitted, the caller's default organization is used. Request ``` curl https://app.mobilenext.ai/api/v1/keys/{id} \ -X DELETE \ -H 'Authorization: Bearer mob_...' ``` Response 204401403404 API key deleted ``` // No response body ``` --- # Apps ## List apps[​](#list-apps "Direct link to List apps") GET/api/v1/apps Apps with at least one ready, unexpired file, newest first. Any role. Query parameters `platform`string Only files for this platform. `q`string Case-insensitive substring of the name, filename or bundle id. `limit`integer Page size, 1 to 100. Default 25. `cursor`string \`nextCursor\` from the previous page. Opaque. Header parameters `X-Organization-Id`string Selects which of the caller's organizations the request acts on. When omitted, the caller's default organization is used. Returns `object`stringrequired `data`arrayrequired Show child attributes `id`string · uuidrequired `platform`stringrequired `bundleId`stringrequired `name`stringrequirednullable Label of the latest file that had one. `iconUrl`stringrequirednullable Relative URL of the icon (getAppIcon); null when no icon could be extracted. `fileCount`integerrequired Ready, unexpired files. `latestFile`objectrequirednullable Newest ready file, whoever uploaded it and whatever its branch. Null only when every file has expired. Show child attributes `id`string · uuidrequired `name`stringrequired `version`stringrequirednullable `buildNumber`stringrequirednullable `createdAt`string · date-timerequired `expiresAt`string · date-timerequired `createdAt`string · date-timerequired `updatedAt`string · date-timerequired `nextCursor`string Pass as \`cursor\` for the next page. Absent on the last page. Request ``` curl https://app.mobilenext.ai/api/v1/apps \ -X GET \ -H 'Authorization: Bearer mob_...' ``` Response 200400401 A page of apps ``` { "object": "list", "data": [ { "id": "string", "platform": "android", "bundleId": "com.acme.shop", "name": "Acme Shop", "iconUrl": "/api/v1/apps/7d2a90c1-5b0e-4f7a-8c11-2e9f0a4b6d33/icon", "fileCount": 0, "latestFile": { "id": "string", "name": "string", "version": "4.2.0", "buildNumber": "4201", "createdAt": "2026-01-01T00:00:00Z", "expiresAt": "2026-01-01T00:00:00Z" }, "createdAt": "2026-01-01T00:00:00Z", "updatedAt": "2026-01-01T00:00:00Z" } ], "nextCursor": "string" } ``` ## Get an app[​](#get-app "Direct link to Get an app") GET/api/v1/apps/{appId} Any role. An app whose files have all expired is still returned, with `fileCount: 0` and `latestFile: null`. Path parameters `appId`string · uuidrequired App UUID Header parameters `X-Organization-Id`string Selects which of the caller's organizations the request acts on. When omitted, the caller's default organization is used. Returns `id`string · uuidrequired `platform`stringrequired `bundleId`stringrequired `name`stringrequirednullable Label of the latest file that had one. `iconUrl`stringrequirednullable Relative URL of the icon (getAppIcon); null when no icon could be extracted. `fileCount`integerrequired Ready, unexpired files. `latestFile`objectrequirednullable Newest ready file, whoever uploaded it and whatever its branch. Null only when every file has expired. Show child attributes `id`string · uuidrequired `name`stringrequired `version`stringrequirednullable `buildNumber`stringrequirednullable `createdAt`string · date-timerequired `expiresAt`string · date-timerequired `createdAt`string · date-timerequired `updatedAt`string · date-timerequired Request ``` curl https://app.mobilenext.ai/api/v1/apps/{appId} \ -X GET \ -H 'Authorization: Bearer mob_...' ``` Response 200401404 The app ``` { "id": "string", "platform": "android", "bundleId": "com.acme.shop", "name": "Acme Shop", "iconUrl": "/api/v1/apps/7d2a90c1-5b0e-4f7a-8c11-2e9f0a4b6d33/icon", "fileCount": 0, "latestFile": { "id": "string", "name": "string", "version": "4.2.0", "buildNumber": "4201", "createdAt": "2026-01-01T00:00:00Z", "expiresAt": "2026-01-01T00:00:00Z" }, "createdAt": "2026-01-01T00:00:00Z", "updatedAt": "2026-01-01T00:00:00Z" } ``` ## List an app's files[​](#list-app-files "Direct link to List an app's files") GET/api/v1/apps/{appId}/files Same as listFiles, restricted to this app. For a branch's newest build: `?branch=main&limit=1`. Path parameters `appId`string · uuidrequired App UUID Query parameters `sha256`string Only the file with this lowercase hex SHA-256. `platform`string Only files for this platform. `bundleId`string Only files with this bundle id. `branch`string Only files whose build.branch equals this. `commit`string Only files whose build.commit equals this. `status`string Only files in this status. Without it, ready and processing files are listed; pendingUpload and failed are for debugging. `q`string Case-insensitive substring of the name, filename or bundle id. `limit`integer Page size, 1 to 100. Default 25. `cursor`string \`nextCursor\` from the previous page. Opaque. Header parameters `X-Organization-Id`string Selects which of the caller's organizations the request acts on. When omitted, the caller's default organization is used. Returns `object`stringrequired `data`arrayrequired Show child attributes `id`string · uuidrequired `status`stringrequired pendingUpload: bytes not verified yet. processing: verification running (seen only by a concurrent caller). ready: installable. failed: see failureReason; creating the same sha256 again resets it. `app`string · uuidrequirednullable The app this file belongs to, once metadata is extracted. `platform`stringrequirednullable Known once metadata is extracted. `filename`stringrequired `filesize`integer · int64required `sha256`stringrequired `name`stringrequired Display name. Defaults to the filename until metadata is extracted. `bundleId`stringrequirednullable Android package name or iOS bundle identifier. `version`stringrequirednullable Version name (Android) or CFBundleShortVersionString (iOS). `buildNumber`stringrequirednullable Version code (Android) or CFBundleVersion (iOS). `minOsVersion`stringrequirednullable Minimum OS version the build supports. `isSimulator`booleanrequired True for an iOS simulator build. `build`objectrequirednullable Show child attributes `branch`string `commit`string `ciRunUrl`string · uri https only. Stored and displayed, never fetched. `source`stringrequired How the file was created, derived from the credential. `organization`stringrequired Organization that owns the file. `user`stringrequirednullable Uploader; null if the user was deleted. `failureReason`stringrequirednullable Why the file failed; null otherwise. `createdAt`string · date-timerequired `lastUsedAt`string · date-timerequirednullable Last dedup hit or install. `expiresAt`string · date-timerequired The file and its bytes are deleted after this. `nextCursor`string Pass as \`cursor\` for the next page. Absent on the last page. Request ``` curl https://app.mobilenext.ai/api/v1/apps/{appId}/files \ -X GET \ -H 'Authorization: Bearer mob_...' ``` Response 200400401404 A page of the app's files ``` { "object": "list", "data": [ { "id": "string", "status": "pendingUpload", "app": "string", "platform": "android", "filename": "app-release.apk", "filesize": 48211033, "sha256": "string", "name": "Checkout fix", "bundleId": "com.acme.shop", "version": "4.2.0", "buildNumber": "4201", "minOsVersion": "8.0", "isSimulator": false, "build": { "branch": "fix/checkout", "commit": "3dbd301", "ciRunUrl": "https://github.com/acme/shop/actions/runs/991" }, "source": "api", "organization": "string", "user": "string", "failureReason": "checksum_mismatch", "createdAt": "2026-01-01T00:00:00Z", "lastUsedAt": "2026-01-01T00:00:00Z", "expiresAt": "2026-01-01T00:00:00Z" } ], "nextCursor": "string" } ``` ## Get an app's icon[​](#get-app-icon "Direct link to Get an app's icon") GET/api/v1/apps/{appId}/icon The icon as PNG (at most 512×512). Supports `If-None-Match` with the returned `ETag`. Any role. Path parameters `appId`string · uuidrequired App UUID Header parameters `If-None-Match`string `X-Organization-Id`string Selects which of the caller's organizations the request acts on. When omitted, the caller's default organization is used. Request ``` curl https://app.mobilenext.ai/api/v1/apps/{appId}/icon \ -X GET \ -H 'Authorization: Bearer mob_...' ``` Response 200304401404 PNG icon ``` // No response body ``` --- # Billing ## Get plan and remaining usage[​](#get-billing-balance "Direct link to Get plan and remaining usage") GET/api/v1/billing/balance Returns the selected organization's plan, its overage cap, its Stripe subscription state (null on the free hobby plan), and the remaining seconds for each metered resource. Usage is metered in seconds, not money: a plan grants a number of seconds per period and sessions debit them. On a paid plan secondsRemaining may be negative, which is overage billed at the end of the period up to overageCapUsd. Visible to every member of the organization. Header parameters `X-Organization-Id`string Selects which of the caller's organizations the request acts on. When omitted, the caller's default organization is used. Returns `accountType`stringrequired The organization's plan. `overageCapUsd`numberrequired Dollars of overage allowed past the plan's included seconds in one period, at $0.15 per minute. 0 means the organization hard-stops when it runs out. `subscription`objectrequirednullable The Stripe subscription backing a paid plan, or null on the free hobby plan. Show child attributes `status`stringrequired Stripe subscription status. active, trialing, and past\_due all keep the plan's entitlements; the plan ends only when the subscription is deleted. `currentPeriodEnd`string · date-timerequired When the current billing period ends, and the included seconds are granted again. `cancelAtPeriodEnd`booleanrequired True when the subscription is set to end at currentPeriodEnd rather than renew. `resources`arrayrequired Remaining usage per metered resource. Today only mobile is metered; more resources are added as array entries, so read the entry whose resource you want rather than the first one. Show child attributes `resource`stringrequired A metered resource. Only "mobile" exists today; more are added over time, so treat an unrecognised value as a resource you do not handle rather than an error. `secondsRemaining`integerrequired Seconds left in the current period. Negative on a paid plan means overage already used, billed on the next invoice up to overageCapUsd. `periodStart`string · date-timerequirednullable Start of the period this balance belongs to, or null when the organization has never been granted any. `periodEnd`string · date-timerequirednullable End of the period this balance belongs to, or null when the organization has never been granted any. Request ``` curl https://app.mobilenext.ai/api/v1/billing/balance \ -X GET \ -H 'Authorization: Bearer mob_...' ``` Response 200401403 Current plan, subscription, and usage balances ``` { "accountType": "starter", "overageCapUsd": 25, "subscription": { "status": "active", "currentPeriodEnd": "2026-01-01T00:00:00Z", "cancelAtPeriodEnd": true }, "resources": [ { "resource": "mobile", "secondsRemaining": 11400, "periodStart": "2026-01-01T00:00:00Z", "periodEnd": "2026-01-01T00:00:00Z" } ] } ``` --- # Chats ## List chats in a session[​](#list-chats "Direct link to List chats in a session") GET/api/v1/sessions/{sessionId}/chats Chats belonging to the session, oldest first. A chat exists only inside a session; there is no way to address one without it. Visible to every member of the organization that owns the session. Path parameters `sessionId`string · uuidrequired Session UUID Header parameters `X-Organization-Id`string Selects which of the caller's organizations the request acts on. When omitted, the caller's default organization is used. Returns `object`stringrequired `data`arrayrequired Show child attributes `id`stringrequired The chat's own id `session`string · uuidrequired Reference to the session the chat belongs to `title`stringnullable `organization`stringrequired Reference to the owning organization `user`stringrequired Reference to the user who created the chat `metadata`object Client-supplied metadata. deviceId binds the chat to an allocated device. Show child attributes `deviceId`string · uuid `createdAt`string · date-timerequired `updatedAt`string · date-timerequired Request ``` curl https://app.mobilenext.ai/api/v1/sessions/{sessionId}/chats \ -X GET \ -H 'Authorization: Bearer mob_...' ``` Response 200401403404 Chats in the session ``` { "object": "list", "data": [ { "id": "chat_2f1c8e4a-1f2b-4a1e-9a2c-0b7f5d3e6a11", "session": "string", "title": "string", "organization": "string", "user": "string", "metadata": { "deviceId": "string" }, "createdAt": "2026-01-01T00:00:00Z", "updatedAt": "2026-01-01T00:00:00Z" } ] } ``` ## Create a chat[​](#create-chat "Direct link to Create a chat") POST/api/v1/sessions/{sessionId}/chats Creates a chat in the session. Bind the chat to an allocated device by setting metadata.deviceId; the assistant's device tools then act on that device. Every action is still authorized against the caller, never against the bound device. Path parameters `sessionId`string · uuidrequired Session UUID Header parameters `X-Organization-Id`string Selects which of the caller's organizations the request acts on. When omitted, the caller's default organization is used. Body parameters `title`string Human-readable title `metadata`object Client-supplied metadata. Set deviceId to bind the chat to a device allocated in this session. Show child attributes `deviceId`string · uuid Returns A conversation with the assistant, inside a session. `id`stringrequired The chat's own id `session`string · uuidrequired Reference to the session the chat belongs to `title`stringnullable `organization`stringrequired Reference to the owning organization `user`stringrequired Reference to the user who created the chat `metadata`object Client-supplied metadata. deviceId binds the chat to an allocated device. Show child attributes `deviceId`string · uuid `createdAt`string · date-timerequired `updatedAt`string · date-timerequired Request ``` curl https://app.mobilenext.ai/api/v1/sessions/{sessionId}/chats \ -X POST \ -H 'Authorization: Bearer mob_...' \ -H 'Content-Type: application/json' \ -d '{"title":"string","metadata":{"deviceId":"string"}}' ``` Response 201400401403404 Chat created ``` { "id": "chat_2f1c8e4a-1f2b-4a1e-9a2c-0b7f5d3e6a11", "session": "string", "title": "string", "organization": "string", "user": "string", "metadata": { "deviceId": "string" }, "createdAt": "2026-01-01T00:00:00Z", "updatedAt": "2026-01-01T00:00:00Z" } ``` ## Get a chat[​](#get-chat "Direct link to Get a chat") GET/api/v1/sessions/{sessionId}/chats/{chatId} Returns a chat in the session. A chat id that belongs to a different session is not found, even within the same organization. Path parameters `sessionId`string · uuidrequired Session UUID `chatId`stringrequired Chat id, e.g. chat\_2f1c…. Resolved within its session; a chat id from another session is not found. Header parameters `X-Organization-Id`string Selects which of the caller's organizations the request acts on. When omitted, the caller's default organization is used. Returns A conversation with the assistant, inside a session. `id`stringrequired The chat's own id `session`string · uuidrequired Reference to the session the chat belongs to `title`stringnullable `organization`stringrequired Reference to the owning organization `user`stringrequired Reference to the user who created the chat `metadata`object Client-supplied metadata. deviceId binds the chat to an allocated device. Show child attributes `deviceId`string · uuid `createdAt`string · date-timerequired `updatedAt`string · date-timerequired Request ``` curl https://app.mobilenext.ai/api/v1/sessions/{sessionId}/chats/{chatId} \ -X GET \ -H 'Authorization: Bearer mob_...' ``` Response 200401404 Chat detail ``` { "id": "chat_2f1c8e4a-1f2b-4a1e-9a2c-0b7f5d3e6a11", "session": "string", "title": "string", "organization": "string", "user": "string", "metadata": { "deviceId": "string" }, "createdAt": "2026-01-01T00:00:00Z", "updatedAt": "2026-01-01T00:00:00Z" } ``` ## List messages in a chat[​](#list-chat-messages "Direct link to List messages in a chat") GET/api/v1/sessions/{sessionId}/chats/{chatId}/messages The most recent messages of the chat, returned oldest first, with cursor pagination backwards into older history. Each assistant message includes the tool calls it made, so a client can rebuild the conversation — text and tool calls — after a page reload. Follow nextCursor with ?before= to load older messages. Path parameters `sessionId`string · uuidrequired Session UUID `chatId`stringrequired Chat id, e.g. chat\_2f1c…. Resolved within its session; a chat id from another session is not found. Query parameters `limit`integer Maximum messages to return (default 100, max 500) `before`string · date-time Cursor: return the messages created strictly before this RFC3339 timestamp. Pass the nextCursor of a previous page to walk further back through the conversation. Header parameters `X-Organization-Id`string Selects which of the caller's organizations the request acts on. When omitted, the caller's default organization is used. Returns `object`stringrequired `data`arrayrequired Show child attributes `id`stringrequired `chat`stringrequired Reference to the chat `role`stringrequired `status`stringrequired For an assistant message this is its execution's status. `content`arrayrequired Show child attributes `type`stringrequired `text`stringrequired `execution`object The work behind an assistant message. Synthesized from the message; not a separate resource. Show child attributes `id`stringrequired `status`stringrequired `triggerMessage`stringrequired Reference to the user message that started this execution `responseMessage`stringrequired Reference to the assistant message this execution produces `eventsUrl`stringrequired SSE stream of this execution's events `toolCallsUrl`stringrequired `cancelUrl`stringrequired `startedAt`string · date-timenullable `completedAt`string · date-timenullable `toolCalls`array Tool calls made while producing this message. Absent when there were none. Show child attributes `id`stringrequired `execution`stringrequired `message`stringrequired `tool`stringrequired `status`stringrequired `input`object Tool arguments, shape depends on the tool `output`object Tool result, shape depends on the tool `error`stringnullable `createdAt`string · date-timerequired `completedAt`string · date-timenullable `createdAt`string · date-timerequired `completedAt`string · date-timenullable `nextCursor`stringnullable Cursor for the next page; absent when there are no more results Request ``` curl https://app.mobilenext.ai/api/v1/sessions/{sessionId}/chats/{chatId}/messages \ -X GET \ -H 'Authorization: Bearer mob_...' ``` Response 200400401404 Paginated list of messages, oldest first ``` { "object": "list", "data": [ { "id": "msg_9a3b…", "chat": "string", "role": "user", "status": "running", "content": [ { "type": "text", "text": "string" } ], "execution": { "id": "exec_7d2a…", "status": "running", "triggerMessage": "string", "responseMessage": "string", "eventsUrl": "string", "toolCallsUrl": "string", "cancelUrl": "string", "startedAt": "2026-01-01T00:00:00Z", "completedAt": "2026-01-01T00:00:00Z" }, "toolCalls": [ { "id": "toolcall_1b9e…", "execution": "string", "message": "string", "tool": "instance_bash", "status": "running", "input": {}, "output": {}, "error": "string", "createdAt": "2026-01-01T00:00:00Z", "completedAt": "2026-01-01T00:00:00Z" } ], "createdAt": "2026-01-01T00:00:00Z", "completedAt": "2026-01-01T00:00:00Z" } ], "nextCursor": "string" } ``` ## Post a message and run the assistant[​](#create-chat-message "Direct link to Post a message and run the assistant") POST/api/v1/sessions/{sessionId}/chats/{chatId}/messages Appends a user message and runs the assistant. Three modes: * default (async): responds 202 with the assistant message in status "running". Follow execution.eventsUrl to stream it. * mode=sync: runs inline and responds 201 with the completed assistant message and its tool calls. * stream=true: responds with a text/event-stream of execution and assistant.message events. Set execute=false to store the user message without running the assistant. Path parameters `sessionId`string · uuidrequired Session UUID `chatId`stringrequired Chat id, e.g. chat\_2f1c…. Resolved within its session; a chat id from another session is not found. Header parameters `X-Organization-Id`string Selects which of the caller's organizations the request acts on. When omitted, the caller's default organization is used. Body parameters `role`stringrequired `content`arrayrequired Show child attributes `type`stringrequired `text`stringrequired `execute`boolean false stores the user message without running the assistant `mode`string sync runs the assistant inline and returns the completed message `stream`boolean true responds with a text/event-stream instead of JSON `model`string Overrides the assistant's default model for this turn `metadata`object Request ``` curl https://app.mobilenext.ai/api/v1/sessions/{sessionId}/chats/{chatId}/messages \ -X POST \ -H 'Authorization: Bearer mob_...' \ -H 'Content-Type: application/json' \ -d '{"role":"user","content":[{"type":"text","text":"string"}],"execute":true,"mode":"async","stream":false,"model":"string","metadata":{}}' ``` Response 200201202400401403404 stream=true: a text/event-stream of execution.\* and assistant.message.\* events ``` // No response body ``` ## Get a message[​](#get-chat-message "Direct link to Get a message") GET/api/v1/sessions/{sessionId}/chats/{chatId}/messages/{messageId} Path parameters `sessionId`string · uuidrequired Session UUID `chatId`stringrequired Chat id, e.g. chat\_2f1c…. Resolved within its session; a chat id from another session is not found. `messageId`stringrequired Message id, e.g. msg\_9a3b… Header parameters `X-Organization-Id`string Selects which of the caller's organizations the request acts on. When omitted, the caller's default organization is used. Returns `id`stringrequired `chat`stringrequired Reference to the chat `role`stringrequired `status`stringrequired For an assistant message this is its execution's status. `content`arrayrequired Show child attributes `type`stringrequired `text`stringrequired `execution`object The work behind an assistant message. Synthesized from the message; not a separate resource. Show child attributes `id`stringrequired `status`stringrequired `triggerMessage`stringrequired Reference to the user message that started this execution `responseMessage`stringrequired Reference to the assistant message this execution produces `eventsUrl`stringrequired SSE stream of this execution's events `toolCallsUrl`stringrequired `cancelUrl`stringrequired `startedAt`string · date-timenullable `completedAt`string · date-timenullable `toolCalls`array Tool calls made while producing this message. Absent when there were none. Show child attributes `id`stringrequired `execution`stringrequired `message`stringrequired `tool`stringrequired `status`stringrequired `input`object Tool arguments, shape depends on the tool `output`object Tool result, shape depends on the tool `error`stringnullable `createdAt`string · date-timerequired `completedAt`string · date-timenullable `createdAt`string · date-timerequired `completedAt`string · date-timenullable Request ``` curl https://app.mobilenext.ai/api/v1/sessions/{sessionId}/chats/{chatId}/messages/{messageId} \ -X GET \ -H 'Authorization: Bearer mob_...' ``` Response 200401404 Message detail, including its tool calls ``` { "id": "msg_9a3b…", "chat": "string", "role": "user", "status": "running", "content": [ { "type": "text", "text": "string" } ], "execution": { "id": "exec_7d2a…", "status": "running", "triggerMessage": "string", "responseMessage": "string", "eventsUrl": "string", "toolCallsUrl": "string", "cancelUrl": "string", "startedAt": "2026-01-01T00:00:00Z", "completedAt": "2026-01-01T00:00:00Z" }, "toolCalls": [ { "id": "toolcall_1b9e…", "execution": "string", "message": "string", "tool": "instance_bash", "status": "running", "input": {}, "output": {}, "error": "string", "createdAt": "2026-01-01T00:00:00Z", "completedAt": "2026-01-01T00:00:00Z" } ], "createdAt": "2026-01-01T00:00:00Z", "completedAt": "2026-01-01T00:00:00Z" } ``` ## Stream a message's execution events[​](#stream-chat-message-events "Direct link to Stream a message's execution events") GET/api/v1/sessions/{sessionId}/chats/{chatId}/messages/{messageId}/events Server-Sent Events for one assistant message: execution.started, assistant.message.started, assistant.message.delta, tool\_call.created, tool\_call.completed, assistant.message.completed, execution.completed|failed. Safe to call after a disconnect: a still-running execution replays its events from the start, and a finished one replays its stored final state — the stored replay emits the message text as a single delta and no tool\_call events. Clients must therefore not render the message's persisted text and also reattach here, or the text appears twice. Path parameters `sessionId`string · uuidrequired Session UUID `chatId`stringrequired Chat id, e.g. chat\_2f1c…. Resolved within its session; a chat id from another session is not found. `messageId`stringrequired Message id, e.g. msg\_9a3b… Header parameters `X-Organization-Id`string Selects which of the caller's organizations the request acts on. When omitted, the caller's default organization is used. Request ``` curl https://app.mobilenext.ai/api/v1/sessions/{sessionId}/chats/{chatId}/messages/{messageId}/events \ -X GET \ -H 'Authorization: Bearer mob_...' ``` Response 200401404 An event stream for the message's execution ``` // No response body ``` ## List a message's tool calls[​](#list-chat-message-tool-calls "Direct link to List a message's tool calls") GET/api/v1/sessions/{sessionId}/chats/{chatId}/messages/{messageId}/tool-calls Path parameters `sessionId`string · uuidrequired Session UUID `chatId`stringrequired Chat id, e.g. chat\_2f1c…. Resolved within its session; a chat id from another session is not found. `messageId`stringrequired Message id, e.g. msg\_9a3b… Header parameters `X-Organization-Id`string Selects which of the caller's organizations the request acts on. When omitted, the caller's default organization is used. Returns `object`stringrequired `data`arrayrequired Show child attributes `id`stringrequired `execution`stringrequired `message`stringrequired `tool`stringrequired `status`stringrequired `input`object Tool arguments, shape depends on the tool `output`object Tool result, shape depends on the tool `error`stringnullable `createdAt`string · date-timerequired `completedAt`string · date-timenullable Request ``` curl https://app.mobilenext.ai/api/v1/sessions/{sessionId}/chats/{chatId}/messages/{messageId}/tool-calls \ -X GET \ -H 'Authorization: Bearer mob_...' ``` Response 200401404 Tool calls made while producing the message ``` { "object": "list", "data": [ { "id": "toolcall_1b9e…", "execution": "string", "message": "string", "tool": "instance_bash", "status": "running", "input": {}, "output": {}, "error": "string", "createdAt": "2026-01-01T00:00:00Z", "completedAt": "2026-01-01T00:00:00Z" } ] } ``` ## Cancel a running message[​](#cancel-chat-message "Direct link to Cancel a running message") POST/api/v1/sessions/{sessionId}/chats/{chatId}/messages/{messageId}/cancel Requests cancellation of a message whose execution is still running. Requires a read/write or admin role. Path parameters `sessionId`string · uuidrequired Session UUID `chatId`stringrequired Chat id, e.g. chat\_2f1c…. Resolved within its session; a chat id from another session is not found. `messageId`stringrequired Message id, e.g. msg\_9a3b… Header parameters `X-Organization-Id`string Selects which of the caller's organizations the request acts on. When omitted, the caller's default organization is used. Returns `id`stringrequired `chat`stringrequired Reference to the chat `role`stringrequired `status`stringrequired For an assistant message this is its execution's status. `content`arrayrequired Show child attributes `type`stringrequired `text`stringrequired `execution`object The work behind an assistant message. Synthesized from the message; not a separate resource. Show child attributes `id`stringrequired `status`stringrequired `triggerMessage`stringrequired Reference to the user message that started this execution `responseMessage`stringrequired Reference to the assistant message this execution produces `eventsUrl`stringrequired SSE stream of this execution's events `toolCallsUrl`stringrequired `cancelUrl`stringrequired `startedAt`string · date-timenullable `completedAt`string · date-timenullable `toolCalls`array Tool calls made while producing this message. Absent when there were none. Show child attributes `id`stringrequired `execution`stringrequired `message`stringrequired `tool`stringrequired `status`stringrequired `input`object Tool arguments, shape depends on the tool `output`object Tool result, shape depends on the tool `error`stringnullable `createdAt`string · date-timerequired `completedAt`string · date-timenullable `createdAt`string · date-timerequired `completedAt`string · date-timenullable Request ``` curl https://app.mobilenext.ai/api/v1/sessions/{sessionId}/chats/{chatId}/messages/{messageId}/cancel \ -X POST \ -H 'Authorization: Bearer mob_...' ``` Response 200401403404 The message with its updated status ``` { "id": "msg_9a3b…", "chat": "string", "role": "user", "status": "running", "content": [ { "type": "text", "text": "string" } ], "execution": { "id": "exec_7d2a…", "status": "running", "triggerMessage": "string", "responseMessage": "string", "eventsUrl": "string", "toolCallsUrl": "string", "cancelUrl": "string", "startedAt": "2026-01-01T00:00:00Z", "completedAt": "2026-01-01T00:00:00Z" }, "toolCalls": [ { "id": "toolcall_1b9e…", "execution": "string", "message": "string", "tool": "instance_bash", "status": "running", "input": {}, "output": {}, "error": "string", "createdAt": "2026-01-01T00:00:00Z", "completedAt": "2026-01-01T00:00:00Z" } ], "createdAt": "2026-01-01T00:00:00Z", "completedAt": "2026-01-01T00:00:00Z" } ``` --- # Devices ## List devices in a session[​](#list-devices "Direct link to List devices in a session") GET/api/v1/sessions/{sessionId}/devices Devices attached to the session, newest first. Visible to every member of the organization that owns the session. Path parameters `sessionId`string · uuidrequired Session UUID Header parameters `X-Organization-Id`string Selects which of the caller's organizations the request acts on. When omitted, the caller's default organization is used. Returns `object`stringrequired `data`arrayrequired Show child attributes `id`string · uuidrequired Allocation id. Stable and always present, including while the device is still provisioning and no physical device exists yet. This is not the device's own id — see info.serial. `status`stringrequired Device lifecycle status. \`provisioning\` means a device is being booted and has no info.serial yet; \`in\_use\` means it is allocated and driveable; \`released\` means it has been returned to the pool. More values will be added. `info`objectrequired Descriptive attributes of the device. Show child attributes `platform`stringrequired `type`string `name`stringrequired `osVersion`stringrequired `serial`string The physical device's own id — a UDID on iOS, a serial on Android. Absent while the device is provisioning. This is the id accepted by the device endpoints and tools. `createdAt`string · date-timerequired When the device was added to the session `releasedAt`string · date-timenullable When the device was released (billing end) `nextCursor`stringnullable Cursor for the next page; absent when there are no more results Request ``` curl https://app.mobilenext.ai/api/v1/sessions/{sessionId}/devices \ -X GET \ -H 'Authorization: Bearer mob_...' ``` Response 200401403404 Devices attached to the session ``` { "object": "list", "data": [ { "id": "string", "status": "provisioning", "info": { "platform": "ios", "type": "real", "name": "string", "osVersion": "string", "serial": "00008150-001C30842678401C" }, "createdAt": "2026-01-01T00:00:00Z", "releasedAt": "2026-01-01T00:00:00Z" } ], "nextCursor": "string" } ``` ## Allocate a device[​](#allocate-device "Direct link to Allocate a device") POST/api/v1/sessions/{sessionId}/devices Allocates a device matching the given filters and attaches it to the session. Uses the same filter DSL as the fleet.allocate RPC. Allocation is asynchronous: the device is returned immediately with status "provisioning" or "queued" and becomes usable once its status is "ready". Poll GET /sessions/{sessionId}/devices/{deviceId} to observe readiness. Path parameters `sessionId`string · uuidrequired Session UUID Header parameters `X-Organization-Id`string Selects which of the caller's organizations the request acts on. When omitted, the caller's default organization is used. Body parameters `filters`arrayrequired Show child attributes `attribute`stringrequired `operator`stringrequired Allowed operators depend on the attribute: platform and type accept only EQUALS; name accepts EQUALS, STARTS\_WITH, CONTAINS; version accepts EQUALS and the comparison operators. `value`stringrequired Must be non-empty. For platform: 'ios' or 'android'. For type: 'real'. `file`string · uuid A ready file from app storage to install on the device. Its platform must match the platform filter. On iOS the app is installed while the device is provisioned, so a new device is always started. `launchAfterInstall`boolean Launch the app from \`file\` once it is installed and the device is ready. A failed launch does not fail the allocation. Returns `id`string · uuidrequired Allocation id. Stable and always present, including while the device is still provisioning and no physical device exists yet. This is not the device's own id — see info.serial. `status`stringrequired Device lifecycle status. \`provisioning\` means a device is being booted and has no info.serial yet; \`in\_use\` means it is allocated and driveable; \`released\` means it has been returned to the pool. More values will be added. `info`objectrequired Descriptive attributes of the device. Show child attributes `platform`stringrequired `type`string `name`stringrequired `osVersion`stringrequired `serial`string The physical device's own id — a UDID on iOS, a serial on Android. Absent while the device is provisioning. This is the id accepted by the device endpoints and tools. `createdAt`string · date-timerequired When the device was added to the session `releasedAt`string · date-timenullable When the device was released (billing end) Request ``` curl https://app.mobilenext.ai/api/v1/sessions/{sessionId}/devices \ -X POST \ -H 'Authorization: Bearer mob_...' \ -H 'Content-Type: application/json' \ -d '{"filters":[{"attribute":"platform","operator":"EQUALS","value":"ios"}],"file":"string","launchAfterInstall":false}' ``` Response 201400401403404409 Device allocated; provisioning has started ``` { "id": "string", "status": "provisioning", "info": { "platform": "ios", "type": "real", "name": "string", "osVersion": "string", "serial": "00008150-001C30842678401C" }, "createdAt": "2026-01-01T00:00:00Z", "releasedAt": "2026-01-01T00:00:00Z" } ``` ## Get a device[​](#get-device "Direct link to Get a device") GET/api/v1/sessions/{sessionId}/devices/{deviceId} Returns a device attached to the session. Visible to every member of the organization that owns the session. Path parameters `sessionId`string · uuidrequired Session UUID `deviceId`stringrequired The physical device's own id, as returned in SessionDevice.info.serial — a UDID on iOS, a serial on Android. Not the allocation id (SessionDevice.id). Header parameters `X-Organization-Id`string Selects which of the caller's organizations the request acts on. When omitted, the caller's default organization is used. Returns `id`string · uuidrequired Allocation id. Stable and always present, including while the device is still provisioning and no physical device exists yet. This is not the device's own id — see info.serial. `status`stringrequired Device lifecycle status. \`provisioning\` means a device is being booted and has no info.serial yet; \`in\_use\` means it is allocated and driveable; \`released\` means it has been returned to the pool. More values will be added. `info`objectrequired Descriptive attributes of the device. Show child attributes `platform`stringrequired `type`string `name`stringrequired `osVersion`stringrequired `serial`string The physical device's own id — a UDID on iOS, a serial on Android. Absent while the device is provisioning. This is the id accepted by the device endpoints and tools. `createdAt`string · date-timerequired When the device was added to the session `releasedAt`string · date-timenullable When the device was released (billing end) Request ``` curl https://app.mobilenext.ai/api/v1/sessions/{sessionId}/devices/{deviceId} \ -X GET \ -H 'Authorization: Bearer mob_...' ``` Response 200401403404 Device detail ``` { "id": "string", "status": "provisioning", "info": { "platform": "ios", "type": "real", "name": "string", "osVersion": "string", "serial": "00008150-001C30842678401C" }, "createdAt": "2026-01-01T00:00:00Z", "releasedAt": "2026-01-01T00:00:00Z" } ``` ## Release a device[​](#release-device "Direct link to Release a device") POST/api/v1/sessions/{sessionId}/devices/{deviceId}/release Releases a device, stopping billing and returning it to the fleet. Returns the device with its updated status. Idempotent: releasing an already-released device is a no-op. Path parameters `sessionId`string · uuidrequired Session UUID `deviceId`stringrequired The physical device's own id, as returned in SessionDevice.info.serial — a UDID on iOS, a serial on Android. Not the allocation id (SessionDevice.id). Header parameters `X-Organization-Id`string Selects which of the caller's organizations the request acts on. When omitted, the caller's default organization is used. Returns `id`string · uuidrequired Allocation id. Stable and always present, including while the device is still provisioning and no physical device exists yet. This is not the device's own id — see info.serial. `status`stringrequired Device lifecycle status. \`provisioning\` means a device is being booted and has no info.serial yet; \`in\_use\` means it is allocated and driveable; \`released\` means it has been returned to the pool. More values will be added. `info`objectrequired Descriptive attributes of the device. Show child attributes `platform`stringrequired `type`string `name`stringrequired `osVersion`stringrequired `serial`string The physical device's own id — a UDID on iOS, a serial on Android. Absent while the device is provisioning. This is the id accepted by the device endpoints and tools. `createdAt`string · date-timerequired When the device was added to the session `releasedAt`string · date-timenullable When the device was released (billing end) Request ``` curl https://app.mobilenext.ai/api/v1/sessions/{sessionId}/devices/{deviceId}/release \ -X POST \ -H 'Authorization: Bearer mob_...' ``` Response 202401403404 Release accepted; teardown proceeds asynchronously ``` { "id": "string", "status": "provisioning", "info": { "platform": "ios", "type": "real", "name": "string", "osVersion": "string", "serial": "00008150-001C30842678401C" }, "createdAt": "2026-01-01T00:00:00Z", "releasedAt": "2026-01-01T00:00:00Z" } ``` ## Install a stored file on a device[​](#install-file "Direct link to Install a stored file on a device") POST/api/v1/sessions/{sessionId}/devices/{deviceId}/install Installs a ready file from app storage on a device of this session, without uploading it again. Synchronous: a large app can take minutes. Path parameters `sessionId`string · uuidrequired Session UUID `deviceId`stringrequired The physical device's own id, as returned in SessionDevice.info.serial — a UDID on iOS, a serial on Android. Not the allocation id (SessionDevice.id). Header parameters `X-Organization-Id`string Selects which of the caller's organizations the request acts on. When omitted, the caller's default organization is used. Body parameters `file`string · uuidrequired A ready file of the organization (see Files). `launchAfterInstall`boolean Launch the app once it is installed. A failed launch does not fail the install; see \`launched\`. Returns `file`string · uuidrequired `status`stringrequired `bundleId`stringrequired `launched`booleanrequired True when launchAfterInstall was set and the launch succeeded. Request ``` curl https://app.mobilenext.ai/api/v1/sessions/{sessionId}/devices/{deviceId}/install \ -X POST \ -H 'Authorization: Bearer mob_...' \ -H 'Content-Type: application/json' \ -d '{"file":"string","launchAfterInstall":false}' ``` Response 200400401403404409422502 Installed ``` { "file": "string", "status": "installed", "bundleId": "com.acme.shop", "launched": true } ``` --- # Files ## List files[​](#list-files "Direct link to List files") GET/api/v1/files The organization's unexpired files, newest first. Any role. Query parameters `sha256`string Only the file with this lowercase hex SHA-256. `app`string · uuid Only files of this app. `platform`string Only files for this platform. `bundleId`string Only files with this bundle id. `branch`string Only files whose build.branch equals this. `commit`string Only files whose build.commit equals this. `status`string Only files in this status. Without it, ready and processing files are listed; pendingUpload and failed are for debugging. `q`string Case-insensitive substring of the name, filename or bundle id. `limit`integer Page size, 1 to 100. Default 25. `cursor`string \`nextCursor\` from the previous page. Opaque. Header parameters `X-Organization-Id`string Selects which of the caller's organizations the request acts on. When omitted, the caller's default organization is used. Returns `object`stringrequired `data`arrayrequired Show child attributes `id`string · uuidrequired `status`stringrequired pendingUpload: bytes not verified yet. processing: verification running (seen only by a concurrent caller). ready: installable. failed: see failureReason; creating the same sha256 again resets it. `app`string · uuidrequirednullable The app this file belongs to, once metadata is extracted. `platform`stringrequirednullable Known once metadata is extracted. `filename`stringrequired `filesize`integer · int64required `sha256`stringrequired `name`stringrequired Display name. Defaults to the filename until metadata is extracted. `bundleId`stringrequirednullable Android package name or iOS bundle identifier. `version`stringrequirednullable Version name (Android) or CFBundleShortVersionString (iOS). `buildNumber`stringrequirednullable Version code (Android) or CFBundleVersion (iOS). `minOsVersion`stringrequirednullable Minimum OS version the build supports. `isSimulator`booleanrequired True for an iOS simulator build. `build`objectrequirednullable Show child attributes `branch`string `commit`string `ciRunUrl`string · uri https only. Stored and displayed, never fetched. `source`stringrequired How the file was created, derived from the credential. `organization`stringrequired Organization that owns the file. `user`stringrequirednullable Uploader; null if the user was deleted. `failureReason`stringrequirednullable Why the file failed; null otherwise. `createdAt`string · date-timerequired `lastUsedAt`string · date-timerequirednullable Last dedup hit or install. `expiresAt`string · date-timerequired The file and its bytes are deleted after this. `nextCursor`string Pass as \`cursor\` for the next page. Absent on the last page. Request ``` curl https://app.mobilenext.ai/api/v1/files \ -X GET \ -H 'Authorization: Bearer mob_...' ``` Response 200400401 A page of files ``` { "object": "list", "data": [ { "id": "string", "status": "pendingUpload", "app": "string", "platform": "android", "filename": "app-release.apk", "filesize": 48211033, "sha256": "string", "name": "Checkout fix", "bundleId": "com.acme.shop", "version": "4.2.0", "buildNumber": "4201", "minOsVersion": "8.0", "isSimulator": false, "build": { "branch": "fix/checkout", "commit": "3dbd301", "ciRunUrl": "https://github.com/acme/shop/actions/runs/991" }, "source": "api", "organization": "string", "user": "string", "failureReason": "checksum_mismatch", "createdAt": "2026-01-01T00:00:00Z", "lastUsedAt": "2026-01-01T00:00:00Z", "expiresAt": "2026-01-01T00:00:00Z" } ], "nextCursor": "string" } ``` ## Create a file[​](#create-file "Direct link to Create a file") POST/api/v1/files Declares a file by its SHA-256. If the organization already stores that hash, the stored file is returned instead of a new one. **PUT the bytes if and only if the response contains `upload`.** Do not branch on the status code. Then call `completeFile` unless the file is already `ready`. | Stored file with this sha256 | Response | `upload` | | ---------------------------- | ---------------------------------------- | -------------- | | none | `201`, `pendingUpload` | yes | | `pendingUpload` or `failed` | `200`, same id, reset to `pendingUpload` | yes, fresh URL | | `processing` | `200` | no | | `ready` | `200`, expiry extended, `lastUsedAt` set | no | A dedup hit keeps the first create's `filename`, `name`, `build` and `user`, and never shortens the expiry. Rate limited to 100 creates per 15 minutes per organization. Header parameters `X-Organization-Id`string Selects which of the caller's organizations the request acts on. When omitted, the caller's default organization is used. Body parameters `filename`stringrequired Must end in .apk or .ipa. `filesize`integer · int64required Bytes. At most the plan's per-file cap: hobby 250 MB, starter 1 GB, team and enterprise 2 GB. `sha256`stringrequired Lowercase hex SHA-256 of the file. `expiresIn`integer · int64 Seconds until the file expires: 10 minutes to 90 days, default 30 days. A dedup hit only ever extends the expiry. `name`string Display name. Kept from the first create on a dedup hit. `build`object Where the build came from. Every field is optional; CI clients fill it from their environment. Show child attributes `branch`string `commit`string `ciRunUrl`string · uri https only. Stored and displayed, never fetched. Returns `id`string · uuidrequired `status`stringrequired pendingUpload: bytes not verified yet. processing: verification running (seen only by a concurrent caller). ready: installable. failed: see failureReason; creating the same sha256 again resets it. `app`string · uuidrequirednullable The app this file belongs to, once metadata is extracted. `platform`stringrequirednullable Known once metadata is extracted. `filename`stringrequired `filesize`integer · int64required `sha256`stringrequired `name`stringrequired Display name. Defaults to the filename until metadata is extracted. `bundleId`stringrequirednullable Android package name or iOS bundle identifier. `version`stringrequirednullable Version name (Android) or CFBundleShortVersionString (iOS). `buildNumber`stringrequirednullable Version code (Android) or CFBundleVersion (iOS). `minOsVersion`stringrequirednullable Minimum OS version the build supports. `isSimulator`booleanrequired True for an iOS simulator build. `build`objectrequirednullable Show child attributes `branch`string `commit`string `ciRunUrl`string · uri https only. Stored and displayed, never fetched. `source`stringrequired How the file was created, derived from the credential. `organization`stringrequired Organization that owns the file. `user`stringrequirednullable Uploader; null if the user was deleted. `failureReason`stringrequirednullable Why the file failed; null otherwise. `createdAt`string · date-timerequired `lastUsedAt`string · date-timerequirednullable Last dedup hit or install. `expiresAt`string · date-timerequired The file and its bytes are deleted after this. `upload`object Present only while the caller is expected to upload the bytes. Send exactly these headers; the URL is signed for the declared size and SHA-256, so any other bytes are rejected by storage. Show child attributes `method`stringrequired `url`string · urirequired `headers`objectrequired `expiresAt`string · date-timerequired When the URL stops working. Calling create again returns a fresh one. Request ``` curl https://app.mobilenext.ai/api/v1/files \ -X POST \ -H 'Authorization: Bearer mob_...' \ -H 'Content-Type: application/json' \ -d '{"filename":"app-release.apk","filesize":48211033,"sha256":"string","expiresIn":2592000,"name":"string","build":{"branch":"fix/checkout","commit":"3dbd301","ciRunUrl":"https://github.com/acme/shop/actions/runs/991"}}' ``` Response 200201400401403409413422429 The organization already stores this sha256; \`upload\` is present only when the bytes are still needed ``` { "id": "string", "status": "pendingUpload", "app": "string", "platform": "android", "filename": "app-release.apk", "filesize": 48211033, "sha256": "string", "name": "Checkout fix", "bundleId": "com.acme.shop", "version": "4.2.0", "buildNumber": "4201", "minOsVersion": "8.0", "isSimulator": false, "build": { "branch": "fix/checkout", "commit": "3dbd301", "ciRunUrl": "https://github.com/acme/shop/actions/runs/991" }, "source": "api", "organization": "string", "user": "string", "failureReason": "checksum_mismatch", "createdAt": "2026-01-01T00:00:00Z", "lastUsedAt": "2026-01-01T00:00:00Z", "expiresAt": "2026-01-01T00:00:00Z", "upload": { "method": "PUT", "url": "string", "headers": { "X-Amz-Checksum-Sha256": "WJG1tSLV3whtD/CxEPvZ0hu0/HFjrzTQgoai6Eb2vgM=", "Content-Length": "48211033" }, "expiresAt": "2026-01-01T00:00:00Z" } } ``` ## Get file storage usage[​](#get-file-usage "Direct link to Get file storage usage") GET/api/v1/files/usage Stored bytes against the plan's quota, for display. The quota is not enforced yet; the only enforced limit is a safety ceiling (`403 storage_quota_exceeded` on create). Header parameters `X-Organization-Id`string Selects which of the caller's organizations the request acts on. When omitted, the caller's default organization is used. Returns `usedBytes`integer · int64required Sum of the organization's stored files, failed files excluded. `quotaBytes`integer · int64requirednullable The plan's storage quota; null when unlimited. Shown, not enforced yet. Request ``` curl https://app.mobilenext.ai/api/v1/files/usage \ -X GET \ -H 'Authorization: Bearer mob_...' ``` Response 200401 Usage ``` { "usedBytes": 0, "quotaBytes": 0 } ``` ## Get a file[​](#get-file "Direct link to Get a file") GET/api/v1/files/{fileId} Returns a file in any status. A missing, expired or other organization's file is 404. Path parameters `fileId`string · uuidrequired File UUID Header parameters `X-Organization-Id`string Selects which of the caller's organizations the request acts on. When omitted, the caller's default organization is used. Returns One stored app binary. Immutable bytes, unique per organization by SHA-256. `id`string · uuidrequired `status`stringrequired pendingUpload: bytes not verified yet. processing: verification running (seen only by a concurrent caller). ready: installable. failed: see failureReason; creating the same sha256 again resets it. `app`string · uuidrequirednullable The app this file belongs to, once metadata is extracted. `platform`stringrequirednullable Known once metadata is extracted. `filename`stringrequired `filesize`integer · int64required `sha256`stringrequired `name`stringrequired Display name. Defaults to the filename until metadata is extracted. `bundleId`stringrequirednullable Android package name or iOS bundle identifier. `version`stringrequirednullable Version name (Android) or CFBundleShortVersionString (iOS). `buildNumber`stringrequirednullable Version code (Android) or CFBundleVersion (iOS). `minOsVersion`stringrequirednullable Minimum OS version the build supports. `isSimulator`booleanrequired True for an iOS simulator build. `build`objectrequirednullable Show child attributes `branch`string `commit`string `ciRunUrl`string · uri https only. Stored and displayed, never fetched. `source`stringrequired How the file was created, derived from the credential. `organization`stringrequired Organization that owns the file. `user`stringrequirednullable Uploader; null if the user was deleted. `failureReason`stringrequirednullable Why the file failed; null otherwise. `createdAt`string · date-timerequired `lastUsedAt`string · date-timerequirednullable Last dedup hit or install. `expiresAt`string · date-timerequired The file and its bytes are deleted after this. Request ``` curl https://app.mobilenext.ai/api/v1/files/{fileId} \ -X GET \ -H 'Authorization: Bearer mob_...' ``` Response 200401404 The file ``` { "id": "string", "status": "pendingUpload", "app": "string", "platform": "android", "filename": "app-release.apk", "filesize": 48211033, "sha256": "string", "name": "Checkout fix", "bundleId": "com.acme.shop", "version": "4.2.0", "buildNumber": "4201", "minOsVersion": "8.0", "isSimulator": false, "build": { "branch": "fix/checkout", "commit": "3dbd301", "ciRunUrl": "https://github.com/acme/shop/actions/runs/991" }, "source": "api", "organization": "string", "user": "string", "failureReason": "checksum_mismatch", "createdAt": "2026-01-01T00:00:00Z", "lastUsedAt": "2026-01-01T00:00:00Z", "expiresAt": "2026-01-01T00:00:00Z" } ``` ## Update a file[​](#update-file "Direct link to Update a file") PATCH/api/v1/files/{fileId} Changes a file's expiry or display name. The bytes are immutable. Path parameters `fileId`string · uuidrequired File UUID Header parameters `X-Organization-Id`string Selects which of the caller's organizations the request acts on. When omitted, the caller's default organization is used. Body parameters `expiresIn`integer · int64 Seconds from now: 10 minutes to 90 days. Restarts the clock and may shorten the expiry (a create never does). `name`string Display name. An empty string clears it, so the file shows its filename again. Returns One stored app binary. Immutable bytes, unique per organization by SHA-256. `id`string · uuidrequired `status`stringrequired pendingUpload: bytes not verified yet. processing: verification running (seen only by a concurrent caller). ready: installable. failed: see failureReason; creating the same sha256 again resets it. `app`string · uuidrequirednullable The app this file belongs to, once metadata is extracted. `platform`stringrequirednullable Known once metadata is extracted. `filename`stringrequired `filesize`integer · int64required `sha256`stringrequired `name`stringrequired Display name. Defaults to the filename until metadata is extracted. `bundleId`stringrequirednullable Android package name or iOS bundle identifier. `version`stringrequirednullable Version name (Android) or CFBundleShortVersionString (iOS). `buildNumber`stringrequirednullable Version code (Android) or CFBundleVersion (iOS). `minOsVersion`stringrequirednullable Minimum OS version the build supports. `isSimulator`booleanrequired True for an iOS simulator build. `build`objectrequirednullable Show child attributes `branch`string `commit`string `ciRunUrl`string · uri https only. Stored and displayed, never fetched. `source`stringrequired How the file was created, derived from the credential. `organization`stringrequired Organization that owns the file. `user`stringrequirednullable Uploader; null if the user was deleted. `failureReason`stringrequirednullable Why the file failed; null otherwise. `createdAt`string · date-timerequired `lastUsedAt`string · date-timerequirednullable Last dedup hit or install. `expiresAt`string · date-timerequired The file and its bytes are deleted after this. Request ``` curl https://app.mobilenext.ai/api/v1/files/{fileId} \ -X PATCH \ -H 'Authorization: Bearer mob_...' \ -H 'Content-Type: application/json' \ -d '{"expiresIn":0,"name":"string"}' ``` Response 200400401403404422 The updated file ``` { "id": "string", "status": "pendingUpload", "app": "string", "platform": "android", "filename": "app-release.apk", "filesize": 48211033, "sha256": "string", "name": "Checkout fix", "bundleId": "com.acme.shop", "version": "4.2.0", "buildNumber": "4201", "minOsVersion": "8.0", "isSimulator": false, "build": { "branch": "fix/checkout", "commit": "3dbd301", "ciRunUrl": "https://github.com/acme/shop/actions/runs/991" }, "source": "api", "organization": "string", "user": "string", "failureReason": "checksum_mismatch", "createdAt": "2026-01-01T00:00:00Z", "lastUsedAt": "2026-01-01T00:00:00Z", "expiresAt": "2026-01-01T00:00:00Z" } ``` ## Delete a file[​](#delete-file "Direct link to Delete a file") DELETE/api/v1/files/{fileId} Deletes the file immediately: it no longer appears in lists, cannot be fetched or downloaded, and stops counting as usage. Download URLs already issued keep working until they expire. Path parameters `fileId`string · uuidrequired File UUID Header parameters `X-Organization-Id`string Selects which of the caller's organizations the request acts on. When omitted, the caller's default organization is used. Request ``` curl https://app.mobilenext.ai/api/v1/files/{fileId} \ -X DELETE \ -H 'Authorization: Bearer mob_...' ``` Response 204401403404 Deleted ``` // No response body ``` ## Complete a file upload[​](#complete-file "Direct link to Complete a file upload") POST/api/v1/files/{fileId}/complete Call after the PUT. Verifies the stored bytes against the declared size and SHA-256 and returns the file as `ready` or `failed`. Synchronous; there is nothing to poll. Idempotent: a `ready` or `failed` file is returned unchanged. Path parameters `fileId`string · uuidrequired File UUID Header parameters `X-Organization-Id`string Selects which of the caller's organizations the request acts on. When omitted, the caller's default organization is used. Returns One stored app binary. Immutable bytes, unique per organization by SHA-256. `id`string · uuidrequired `status`stringrequired pendingUpload: bytes not verified yet. processing: verification running (seen only by a concurrent caller). ready: installable. failed: see failureReason; creating the same sha256 again resets it. `app`string · uuidrequirednullable The app this file belongs to, once metadata is extracted. `platform`stringrequirednullable Known once metadata is extracted. `filename`stringrequired `filesize`integer · int64required `sha256`stringrequired `name`stringrequired Display name. Defaults to the filename until metadata is extracted. `bundleId`stringrequirednullable Android package name or iOS bundle identifier. `version`stringrequirednullable Version name (Android) or CFBundleShortVersionString (iOS). `buildNumber`stringrequirednullable Version code (Android) or CFBundleVersion (iOS). `minOsVersion`stringrequirednullable Minimum OS version the build supports. `isSimulator`booleanrequired True for an iOS simulator build. `build`objectrequirednullable Show child attributes `branch`string `commit`string `ciRunUrl`string · uri https only. Stored and displayed, never fetched. `source`stringrequired How the file was created, derived from the credential. `organization`stringrequired Organization that owns the file. `user`stringrequirednullable Uploader; null if the user was deleted. `failureReason`stringrequirednullable Why the file failed; null otherwise. `createdAt`string · date-timerequired `lastUsedAt`string · date-timerequirednullable Last dedup hit or install. `expiresAt`string · date-timerequired The file and its bytes are deleted after this. Request ``` curl https://app.mobilenext.ai/api/v1/files/{fileId}/complete \ -X POST \ -H 'Authorization: Bearer mob_...' ``` Response 200401403404409 The file, \`ready\` or \`failed\` ``` { "id": "string", "status": "pendingUpload", "app": "string", "platform": "android", "filename": "app-release.apk", "filesize": 48211033, "sha256": "string", "name": "Checkout fix", "bundleId": "com.acme.shop", "version": "4.2.0", "buildNumber": "4201", "minOsVersion": "8.0", "isSimulator": false, "build": { "branch": "fix/checkout", "commit": "3dbd301", "ciRunUrl": "https://github.com/acme/shop/actions/runs/991" }, "source": "api", "organization": "string", "user": "string", "failureReason": "checksum_mismatch", "createdAt": "2026-01-01T00:00:00Z", "lastUsedAt": "2026-01-01T00:00:00Z", "expiresAt": "2026-01-01T00:00:00Z" } ``` ## Download a file[​](#download-file "Direct link to Download a file") GET/api/v1/files/{fileId}/download Returns a presigned download URL valid for 5 minutes; it saves under the file's original filename. Any role. Does not change `lastUsedAt`. Returns JSON rather than redirecting, so the route itself cannot be shared as a download link. Path parameters `fileId`string · uuidrequired File UUID Header parameters `X-Organization-Id`string Selects which of the caller's organizations the request acts on. When omitted, the caller's default organization is used. Returns `url`string · urirequired Presigned download URL; the browser saves it under the file's original filename. `expiresAt`string · date-timerequired When the URL stops working (5 minutes). Request ``` curl https://app.mobilenext.ai/api/v1/files/{fileId}/download \ -X GET \ -H 'Authorization: Bearer mob_...' ``` Response 200401404409 A short-lived download URL ``` { "url": "string", "expiresAt": "2026-01-01T00:00:00Z" } ``` --- # Instances ## List instances in a session[​](#list-instances "Direct link to List instances in a session") GET/api/v1/sessions/{sessionId}/instances Instances attached to the session, newest first. Visible to every member of the organization that owns the session. Path parameters `sessionId`string · uuidrequired Session UUID Header parameters `X-Organization-Id`string Selects which of the caller's organizations the request acts on. When omitted, the caller's default organization is used. Returns `object`stringrequired `data`arrayrequired Show child attributes `id`string · uuidrequired The instance's own id `status`stringrequired Lifecycle: provisioning -> ready, then released, or failed if provisioning could not complete `os`stringrequired Instance operating system. Only macos is supported today. `image`stringrequired Server-assigned base image the instance booted from `machine`objectrequired The compute backing an instance. Show child attributes `arch`stringrequired CPU architecture. Only arm64 is supported today. `cpuCores`integerrequired `memoryMb`integerrequired `diskMb`integerrequired `createdAt`string · date-timerequired When the instance was allocated (billing start) `readyAt`string · date-timenullable When the instance finished provisioning; null while provisioning `releasedAt`string · date-timenullable When the instance was released (billing end); null while active `nextCursor`stringnullable Cursor for the next page; absent when there are no more results Request ``` curl https://app.mobilenext.ai/api/v1/sessions/{sessionId}/instances \ -X GET \ -H 'Authorization: Bearer mob_...' ``` Response 200401403404 Instances attached to the session ``` { "object": "list", "data": [ { "id": "string", "status": "provisioning", "os": "macos", "image": "macos-15-xcode-16", "machine": { "arch": "arm64", "cpuCores": 8, "memoryMb": 16384, "diskMb": 262144 }, "createdAt": "2026-01-01T00:00:00Z", "readyAt": "2026-01-01T00:00:00Z", "releasedAt": "2026-01-01T00:00:00Z" } ], "nextCursor": "string" } ``` ## Allocate an instance[​](#create-instance "Direct link to Allocate an instance") POST/api/v1/sessions/{sessionId}/instances Allocates a new instance (a build/automation machine) attached to the session. Provisioning is asynchronous: the instance is returned immediately with status "provisioning" and becomes usable once its status is "ready". Poll GET /sessions/{sessionId}/instances/{instanceId} to observe readiness. Path parameters `sessionId`string · uuidrequired Session UUID Header parameters `X-Organization-Id`string Selects which of the caller's organizations the request acts on. When omitted, the caller's default organization is used. Body parameters `os`stringrequired Instance operating system. Only macos is supported today. Returns A build/automation machine allocated to a session. `id`string · uuidrequired The instance's own id `status`stringrequired Lifecycle: provisioning -> ready, then released, or failed if provisioning could not complete `os`stringrequired Instance operating system. Only macos is supported today. `image`stringrequired Server-assigned base image the instance booted from `machine`objectrequired The compute backing an instance. Show child attributes `arch`stringrequired CPU architecture. Only arm64 is supported today. `cpuCores`integerrequired `memoryMb`integerrequired `diskMb`integerrequired `createdAt`string · date-timerequired When the instance was allocated (billing start) `readyAt`string · date-timenullable When the instance finished provisioning; null while provisioning `releasedAt`string · date-timenullable When the instance was released (billing end); null while active Request ``` curl https://app.mobilenext.ai/api/v1/sessions/{sessionId}/instances \ -X POST \ -H 'Authorization: Bearer mob_...' \ -H 'Content-Type: application/json' \ -d '{"os":"macos"}' ``` Response 201400401403404409 Instance allocated; provisioning has started ``` { "id": "string", "status": "provisioning", "os": "macos", "image": "macos-15-xcode-16", "machine": { "arch": "arm64", "cpuCores": 8, "memoryMb": 16384, "diskMb": 262144 }, "createdAt": "2026-01-01T00:00:00Z", "readyAt": "2026-01-01T00:00:00Z", "releasedAt": "2026-01-01T00:00:00Z" } ``` ## Get an instance[​](#get-instance "Direct link to Get an instance") GET/api/v1/sessions/{sessionId}/instances/{instanceId} Returns an instance attached to the session. Visible to every member of the organization that owns the session. Path parameters `sessionId`string · uuidrequired Session UUID `instanceId`string · uuidrequired Instance UUID Header parameters `X-Organization-Id`string Selects which of the caller's organizations the request acts on. When omitted, the caller's default organization is used. Returns A build/automation machine allocated to a session. `id`string · uuidrequired The instance's own id `status`stringrequired Lifecycle: provisioning -> ready, then released, or failed if provisioning could not complete `os`stringrequired Instance operating system. Only macos is supported today. `image`stringrequired Server-assigned base image the instance booted from `machine`objectrequired The compute backing an instance. Show child attributes `arch`stringrequired CPU architecture. Only arm64 is supported today. `cpuCores`integerrequired `memoryMb`integerrequired `diskMb`integerrequired `createdAt`string · date-timerequired When the instance was allocated (billing start) `readyAt`string · date-timenullable When the instance finished provisioning; null while provisioning `releasedAt`string · date-timenullable When the instance was released (billing end); null while active Request ``` curl https://app.mobilenext.ai/api/v1/sessions/{sessionId}/instances/{instanceId} \ -X GET \ -H 'Authorization: Bearer mob_...' ``` Response 200401403404 Instance detail ``` { "id": "string", "status": "provisioning", "os": "macos", "image": "macos-15-xcode-16", "machine": { "arch": "arm64", "cpuCores": 8, "memoryMb": 16384, "diskMb": 262144 }, "createdAt": "2026-01-01T00:00:00Z", "readyAt": "2026-01-01T00:00:00Z", "releasedAt": "2026-01-01T00:00:00Z" } ``` ## Release an instance[​](#release-instance "Direct link to Release an instance") POST/api/v1/sessions/{sessionId}/instances/{instanceId}/release Releases an instance, stopping billing and tearing it down. Returns the instance with its updated status. Idempotent: releasing an already-released instance is a no-op. Path parameters `sessionId`string · uuidrequired Session UUID `instanceId`string · uuidrequired Instance UUID Header parameters `X-Organization-Id`string Selects which of the caller's organizations the request acts on. When omitted, the caller's default organization is used. Returns A build/automation machine allocated to a session. `id`string · uuidrequired The instance's own id `status`stringrequired Lifecycle: provisioning -> ready, then released, or failed if provisioning could not complete `os`stringrequired Instance operating system. Only macos is supported today. `image`stringrequired Server-assigned base image the instance booted from `machine`objectrequired The compute backing an instance. Show child attributes `arch`stringrequired CPU architecture. Only arm64 is supported today. `cpuCores`integerrequired `memoryMb`integerrequired `diskMb`integerrequired `createdAt`string · date-timerequired When the instance was allocated (billing start) `readyAt`string · date-timenullable When the instance finished provisioning; null while provisioning `releasedAt`string · date-timenullable When the instance was released (billing end); null while active Request ``` curl https://app.mobilenext.ai/api/v1/sessions/{sessionId}/instances/{instanceId}/release \ -X POST \ -H 'Authorization: Bearer mob_...' ``` Response 202401403404 Release accepted; teardown proceeds asynchronously ``` { "id": "string", "status": "provisioning", "os": "macos", "image": "macos-15-xcode-16", "machine": { "arch": "arm64", "cpuCores": 8, "memoryMb": 16384, "diskMb": 262144 }, "createdAt": "2026-01-01T00:00:00Z", "readyAt": "2026-01-01T00:00:00Z", "releasedAt": "2026-01-01T00:00:00Z" } ``` --- # Mobile Next Cloud API REST API for Mobile Next Cloud. ## Base URL[​](#base-url "Direct link to Base URL") ``` https://app.mobilenext.ai ``` ## Authentication[​](#authentication "Direct link to Authentication") All endpoints require a Bearer token that starts with `mob_`: ``` Authorization: Bearer mob_... ``` All API keys in an organization are service keys: they belong to the organization, not to a user. Using a specific API key binds the request to that organization's scope. --- # Invitations ## List invitations addressed to the caller[​](#list-incoming-invitations "Direct link to List invitations addressed to the caller") GET/api/v1/invitations Pending, unexpired invitations addressed to the caller's email across all organizations. Interactive (JWT) sessions only. Returns `object`stringrequired `data`arrayrequired Show child attributes `id`string · uuidrequired `organization`objectrequired Reference to the inviting organization Show child attributes `id`stringrequired Inviting organization id `name`stringnullable Inviting organization name `role`stringrequired Organization role. admin: manage members and billing, plus everything readwrite can do. readwrite: start sessions, create API keys, delete sessions. readonly: view sessions, API keys, and test results only. `inviterEmail`stringnullable Email of the inviter `createdAt`string · date-timerequired `expiresAt`string · date-timenullable Request ``` curl https://app.mobilenext.ai/api/v1/invitations \ -X GET \ -H 'Authorization: Bearer mob_...' ``` Response 200401403500 Pending invitations addressed to the caller ``` { "object": "list", "data": [ { "id": "string", "organization": { "id": "string", "name": "string" }, "role": "admin", "inviterEmail": "string", "createdAt": "2026-01-01T00:00:00Z", "expiresAt": "2026-01-01T00:00:00Z" } ] } ``` ## Accept an invitation[​](#accept-invitation "Direct link to Accept an invitation") POST/api/v1/invitations/{invitationId}/accept Accepts an invitation addressed to the caller, joining the organization with the invited role. Interactive (JWT) sessions only. Path parameters `invitationId`string · uuidrequired Invitation UUID Request ``` curl https://app.mobilenext.ai/api/v1/invitations/{invitationId}/accept \ -X POST \ -H 'Authorization: Bearer mob_...' ``` Response 204401403404 Invitation accepted; the caller is now a member of the organization ``` // No response body ``` ## Reject an invitation[​](#reject-invitation "Direct link to Reject an invitation") POST/api/v1/invitations/{invitationId}/reject Rejects (declines) an invitation addressed to the caller. Interactive (JWT) sessions only. Path parameters `invitationId`string · uuidrequired Invitation UUID Request ``` curl https://app.mobilenext.ai/api/v1/invitations/{invitationId}/reject \ -X POST \ -H 'Authorization: Bearer mob_...' ``` Response 204401403404 Invitation rejected ``` // No response body ``` ## List pending invitations for the organization[​](#list-organization-invitations "Direct link to List pending invitations for the organization") GET/api/v1/organizations/{id}/invitations Returns the pending invitations for the organization. Admin only. Path parameters `id`stringrequired Organization id Returns `object`stringrequired `data`arrayrequired Pending invitations only Show child attributes `id`string · uuidrequired `email`string · emailrequired `role`stringrequired Organization role. admin: manage members and billing, plus everything readwrite can do. readwrite: start sessions, create API keys, delete sessions. readonly: view sessions, API keys, and test results only. `status`stringrequired `inviter`string · uuidnullable Reference to the inviting user `createdAt`string · date-timerequired `expiresAt`string · date-timenullable Request ``` curl https://app.mobilenext.ai/api/v1/organizations/{id}/invitations \ -X GET \ -H 'Authorization: Bearer mob_...' ``` Response 200401403404 Pending invitations for the organization ``` { "object": "list", "data": [ { "id": "string", "email": "string", "role": "admin", "status": "pending", "inviter": "string", "createdAt": "2026-01-01T00:00:00Z", "expiresAt": "2026-01-01T00:00:00Z" } ] } ``` ## Invite a new member to the organization[​](#invite-organization-member "Direct link to Invite a new member to the organization") POST/api/v1/organizations/{id}/invitations Creates a pending invitation for an email with the given role. Admin only. Fails if the email already belongs to a member or already has a pending invitation. Path parameters `id`stringrequired Organization id Body parameters `email`string · emailrequired `role`stringrequired Organization role. admin: manage members and billing, plus everything readwrite can do. readwrite: start sessions, create API keys, delete sessions. readonly: view sessions, API keys, and test results only. Returns `id`string · uuidrequired `email`string · emailrequired `role`stringrequired Organization role. admin: manage members and billing, plus everything readwrite can do. readwrite: start sessions, create API keys, delete sessions. readonly: view sessions, API keys, and test results only. `status`stringrequired `inviter`string · uuidnullable Reference to the inviting user `createdAt`string · date-timerequired `expiresAt`string · date-timenullable Request ``` curl https://app.mobilenext.ai/api/v1/organizations/{id}/invitations \ -X POST \ -H 'Authorization: Bearer mob_...' \ -H 'Content-Type: application/json' \ -d '{"email":"string","role":"admin"}' ``` Response 201400401403404409 Invitation created ``` { "id": "string", "email": "string", "role": "admin", "status": "pending", "inviter": "string", "createdAt": "2026-01-01T00:00:00Z", "expiresAt": "2026-01-01T00:00:00Z" } ``` ## Revoke a pending invitation[​](#revoke-organization-invitation "Direct link to Revoke a pending invitation") DELETE/api/v1/organizations/{id}/invitations/{invitationId} Revokes a pending invitation in the organization. Admin only. Path parameters `id`stringrequired Organization id `invitationId`string · uuidrequired Invitation UUID Request ``` curl https://app.mobilenext.ai/api/v1/organizations/{id}/invitations/{invitationId} \ -X DELETE \ -H 'Authorization: Bearer mob_...' ``` Response 204401403404 Invitation revoked ``` // No response body ``` --- # Organizations ## List organizations the caller belongs to[​](#list-organizations "Direct link to List organizations the caller belongs to") GET/api/v1/organizations Returns `object`stringrequired `data`arrayrequired Show child attributes `id`stringrequired The organization's own id `name`stringnullable Organization name; null for the Personal organization `type`stringrequired `role`stringrequired Organization role. admin: manage members and billing, plus everything readwrite can do. readwrite: start sessions, create API keys, delete sessions. readonly: view sessions, API keys, and test results only. `createdAt`string · date-timerequired Request ``` curl https://app.mobilenext.ai/api/v1/organizations \ -X GET \ -H 'Authorization: Bearer mob_...' ``` Response 200401403500 Organizations the caller is a member of, with their role in each ``` { "object": "list", "data": [ { "id": "string", "name": "string", "type": "hobby", "role": "admin", "createdAt": "2026-01-01T00:00:00Z" } ] } ``` ## Create a new organization[​](#create-organization "Direct link to Create a new organization") POST/api/v1/organizations Creates an organization owned by the caller (who becomes its admin). The name is required, cannot be "Personal", and cannot duplicate the name of an organization the caller already belongs to. Body parameters `name`stringrequired Organization name; required, not "Personal", unique among the caller's organizations Returns `id`stringrequired The organization's own id `name`stringnullable Organization name; null for the Personal organization `type`stringrequired `role`stringrequired Organization role. admin: manage members and billing, plus everything readwrite can do. readwrite: start sessions, create API keys, delete sessions. readonly: view sessions, API keys, and test results only. `createdAt`string · date-timerequired Request ``` curl https://app.mobilenext.ai/api/v1/organizations \ -X POST \ -H 'Authorization: Bearer mob_...' \ -H 'Content-Type: application/json' \ -d '{"name":"string"}' ``` Response 201400401409 Organization created ``` { "id": "string", "name": "string", "type": "hobby", "role": "admin", "createdAt": "2026-01-01T00:00:00Z" } ``` ## List organization members[​](#list-organization-members "Direct link to List organization members") GET/api/v1/organizations/{id}/members Returns the active members of the organization. The caller must be a member of the organization. Path parameters `id`stringrequired Organization id Returns `object`stringrequired `data`arrayrequired Show child attributes `user`string · uuidrequired Reference to the user `email`string · emailrequired `name`stringnullable `role`stringrequired Organization role. admin: manage members and billing, plus everything readwrite can do. readwrite: start sessions, create API keys, delete sessions. readonly: view sessions, API keys, and test results only. `joinedAt`string · date-timerequired Request ``` curl https://app.mobilenext.ai/api/v1/organizations/{id}/members \ -X GET \ -H 'Authorization: Bearer mob_...' ``` Response 200401403404500 Active members of the organization ``` { "object": "list", "data": [ { "user": "string", "email": "string", "name": "string", "role": "admin", "joinedAt": "2026-01-01T00:00:00Z" } ] } ``` ## Rename an organization[​](#rename-organization "Direct link to Rename an organization") PATCH/api/v1/organizations/{id} Renames the organization. Admin only. Not available for the Personal organization, nor to API keys. The name cannot be blank, cannot be "Personal", and cannot be the name of another organization the caller belongs to. Path parameters `id`stringrequired Organization id Body parameters `name`stringrequired New name. Same rules as create: not blank, not "Personal", not the name of another organization the caller belongs to. Returns `id`stringrequired The organization's own id `name`stringnullable Organization name; null for the Personal organization `type`stringrequired `role`stringrequired Organization role. admin: manage members and billing, plus everything readwrite can do. readwrite: start sessions, create API keys, delete sessions. readonly: view sessions, API keys, and test results only. `createdAt`string · date-timerequired Request ``` curl https://app.mobilenext.ai/api/v1/organizations/{id} \ -X PATCH \ -H 'Authorization: Bearer mob_...' \ -H 'Content-Type: application/json' \ -d '{"name":"string"}' ``` Response 200400401403409 Organization renamed ``` { "id": "string", "name": "string", "type": "hobby", "role": "admin", "createdAt": "2026-01-01T00:00:00Z" } ``` ## Delete an organization[​](#delete-organization "Direct link to Delete an organization") DELETE/api/v1/organizations/{id} Deletes the organization. Its members and API keys can no longer use it. Admin only, and only once the caller is its sole member; refused while a plan still renews (a plan already set to cancel at period end does not block) or a device is still allocated. Not available for the Personal organization, nor to API keys. Path parameters `id`stringrequired Organization id Request ``` curl https://app.mobilenext.ai/api/v1/organizations/{id} \ -X DELETE \ -H 'Authorization: Bearer mob_...' ``` Response 204401403409 Organization deleted ``` // No response body ``` ## Change a member's role[​](#change-organization-member-role "Direct link to Change a member's role") PATCH/api/v1/organizations/{id}/members/{userId} Sets another member's role. Admin only. A caller can never change their own role: every change is made by an admin who stays an admin, so an organization cannot lose its last admin. Applies on the member's next request. Path parameters `id`stringrequired Organization id `userId`stringrequired The member's \`user\` id as returned by the members list (URL-encoded), or the literal \`me\` for the caller. Body parameters `role`stringrequired Organization role. admin: manage members and billing, plus everything readwrite can do. readwrite: start sessions, create API keys, delete sessions. readonly: view sessions, API keys, and test results only. Returns `user`string · uuidrequired Reference to the user `email`string · emailrequired `name`stringnullable `role`stringrequired Organization role. admin: manage members and billing, plus everything readwrite can do. readwrite: start sessions, create API keys, delete sessions. readonly: view sessions, API keys, and test results only. `joinedAt`string · date-timerequired Request ``` curl https://app.mobilenext.ai/api/v1/organizations/{id}/members/{userId} \ -X PATCH \ -H 'Authorization: Bearer mob_...' \ -H 'Content-Type: application/json' \ -d '{"role":"admin"}' ``` Response 200400401403404 Role changed ``` { "user": "string", "email": "string", "name": "string", "role": "admin", "joinedAt": "2026-01-01T00:00:00Z" } ``` ## Remove a member, or leave[​](#remove-organization-member "Direct link to Remove a member, or leave") DELETE/api/v1/organizations/{id}/members/{userId} Removes a member from the organization. When `userId` is the caller (or `me`) this is a leave, allowed to any member; otherwise the caller must be an admin. The last admin cannot leave: make another member an admin first, or delete the organization. The removed member's API keys for this organization stop working. Path parameters `id`stringrequired Organization id `userId`stringrequired The member's \`user\` id as returned by the members list (URL-encoded), or the literal \`me\` for the caller. Request ``` curl https://app.mobilenext.ai/api/v1/organizations/{id}/members/{userId} \ -X DELETE \ -H 'Authorization: Bearer mob_...' ``` Response 204401403404409 Member removed ``` // No response body ``` --- # Sessions ## List sessions[​](#list-sessions "Direct link to List sessions") GET/api/v1/sessions Sessions in the selected organization, visible to every member of it, newest first, with cursor pagination. The organization is chosen by the X-Organization-Id header, or the organization the API key is bound to, otherwise the caller's default organization. Query parameters `limit`integer Maximum sessions to return (default 100, max 500) `before`string · date-time Cursor: return sessions created strictly before this RFC3339 timestamp `days`integer Only sessions created in the last N days (1-90). Combines with before. Header parameters `X-Organization-Id`string Selects which of the caller's organizations the request acts on. When omitted, the caller's default organization is used. Returns `object`stringrequired `data`arrayrequired Show child attributes `id`string · uuidrequired The session's own id `title`stringnullable Human-readable title; may be null `user`stringrequired User who created this session `userName`stringnullable Display name of the user who created this session. Only on the organization listing. `userEmail`string Email of the user who created this session. Only on the organization listing. `devices`arrayrequired Device allocations linked to this session, ordered by createdAt ascending Show child attributes `id`string · uuidrequired Allocation id. Stable and always present, including while the device is still provisioning and no physical device exists yet. This is not the device's own id — see info.serial. `status`stringrequired Device lifecycle status. \`provisioning\` means a device is being booted and has no info.serial yet; \`in\_use\` means it is allocated and driveable; \`released\` means it has been returned to the pool. More values will be added. `info`objectrequired Descriptive attributes of the device. Show child attributes `platform`stringrequired `type`string `name`stringrequired `osVersion`stringrequired `serial`string The physical device's own id — a UDID on iOS, a serial on Android. Absent while the device is provisioning. This is the id accepted by the device endpoints and tools. `createdAt`string · date-timerequired When the device was added to the session `releasedAt`string · date-timenullable When the device was released (billing end) `instances`array Instances linked to this session, ordered by createdAt ascending Show child attributes `id`string · uuidrequired The instance's own id `status`stringrequired Lifecycle: provisioning -> ready, then released, or failed if provisioning could not complete `os`stringrequired Instance operating system. Only macos is supported today. `image`stringrequired Server-assigned base image the instance booted from `machine`objectrequired The compute backing an instance. Show child attributes `arch`stringrequired CPU architecture. Only arm64 is supported today. `cpuCores`integerrequired `memoryMb`integerrequired `diskMb`integerrequired `createdAt`string · date-timerequired When the instance was allocated (billing start) `readyAt`string · date-timenullable When the instance finished provisioning; null while provisioning `releasedAt`string · date-timenullable When the instance was released (billing end); null while active `chats`array Chats in this session, oldest first. A client restoring a session's conversation reads the last one. Show child attributes `id`stringrequired Chat id `createdAt`string · date-timerequired `nextCursor`stringnullable Cursor for the next page; absent when there are no more results Request ``` curl https://app.mobilenext.ai/api/v1/sessions \ -X GET \ -H 'Authorization: Bearer mob_...' ``` Response 200400401403 Paginated list of sessions ``` { "object": "list", "data": [ { "id": "string", "title": "string", "user": "string", "userName": "string", "userEmail": "string", "devices": [ { "id": "string", "status": "provisioning", "info": { "platform": "ios", "type": "real", "name": "string", "osVersion": "string", "serial": "00008150-001C30842678401C" }, "createdAt": "2026-01-01T00:00:00Z", "releasedAt": "2026-01-01T00:00:00Z" } ], "instances": [ { "id": "string", "status": "provisioning", "os": "macos", "image": "macos-15-xcode-16", "machine": { "arch": "arm64", "cpuCores": 8, "memoryMb": 16384, "diskMb": 262144 }, "createdAt": "2026-01-01T00:00:00Z", "readyAt": "2026-01-01T00:00:00Z", "releasedAt": "2026-01-01T00:00:00Z" } ], "chats": [ { "id": "string" } ], "createdAt": "2026-01-01T00:00:00Z" } ], "nextCursor": "string" } ``` ## Create a session[​](#create-session "Direct link to Create a session") POST/api/v1/sessions Creates an empty session container. Attach resources to it separately: use fleet.allocate with sessionId to link a device, or allocate an instance with sessionId. Header parameters `X-Organization-Id`string Selects which of the caller's organizations the request acts on. When omitted, the caller's default organization is used. Returns `id`string · uuidrequired The session's own id `title`stringnullable Human-readable title; may be null `user`stringrequired User who created this session `userName`stringnullable Display name of the user who created this session. Only on the organization listing. `userEmail`string Email of the user who created this session. Only on the organization listing. `devices`arrayrequired Device allocations linked to this session, ordered by createdAt ascending Show child attributes `id`string · uuidrequired Allocation id. Stable and always present, including while the device is still provisioning and no physical device exists yet. This is not the device's own id — see info.serial. `status`stringrequired Device lifecycle status. \`provisioning\` means a device is being booted and has no info.serial yet; \`in\_use\` means it is allocated and driveable; \`released\` means it has been returned to the pool. More values will be added. `info`objectrequired Descriptive attributes of the device. Show child attributes `platform`stringrequired `type`string `name`stringrequired `osVersion`stringrequired `serial`string The physical device's own id — a UDID on iOS, a serial on Android. Absent while the device is provisioning. This is the id accepted by the device endpoints and tools. `createdAt`string · date-timerequired When the device was added to the session `releasedAt`string · date-timenullable When the device was released (billing end) `instances`array Instances linked to this session, ordered by createdAt ascending Show child attributes `id`string · uuidrequired The instance's own id `status`stringrequired Lifecycle: provisioning -> ready, then released, or failed if provisioning could not complete `os`stringrequired Instance operating system. Only macos is supported today. `image`stringrequired Server-assigned base image the instance booted from `machine`objectrequired The compute backing an instance. Show child attributes `arch`stringrequired CPU architecture. Only arm64 is supported today. `cpuCores`integerrequired `memoryMb`integerrequired `diskMb`integerrequired `createdAt`string · date-timerequired When the instance was allocated (billing start) `readyAt`string · date-timenullable When the instance finished provisioning; null while provisioning `releasedAt`string · date-timenullable When the instance was released (billing end); null while active `chats`array Chats in this session, oldest first. A client restoring a session's conversation reads the last one. Show child attributes `id`stringrequired Chat id `createdAt`string · date-timerequired Request ``` curl https://app.mobilenext.ai/api/v1/sessions \ -X POST \ -H 'Authorization: Bearer mob_...' ``` Response 201401403 Session created ``` { "id": "string", "title": "string", "user": "string", "userName": "string", "userEmail": "string", "devices": [ { "id": "string", "status": "provisioning", "info": { "platform": "ios", "type": "real", "name": "string", "osVersion": "string", "serial": "00008150-001C30842678401C" }, "createdAt": "2026-01-01T00:00:00Z", "releasedAt": "2026-01-01T00:00:00Z" } ], "instances": [ { "id": "string", "status": "provisioning", "os": "macos", "image": "macos-15-xcode-16", "machine": { "arch": "arm64", "cpuCores": 8, "memoryMb": 16384, "diskMb": 262144 }, "createdAt": "2026-01-01T00:00:00Z", "readyAt": "2026-01-01T00:00:00Z", "releasedAt": "2026-01-01T00:00:00Z" } ], "chats": [ { "id": "string" } ], "createdAt": "2026-01-01T00:00:00Z" } ``` ## Get a session[​](#get-session "Direct link to Get a session") GET/api/v1/sessions/{sessionId} Returns a session in the selected organization, visible to every member of it. The organization is chosen by the X-Organization-Id header, or the organization the API key is bound to, otherwise the caller's default organization. Path parameters `sessionId`string · uuidrequired Session UUID Header parameters `X-Organization-Id`string Selects which of the caller's organizations the request acts on. When omitted, the caller's default organization is used. Returns `id`string · uuidrequired The session's own id `title`stringnullable Human-readable title; may be null `user`stringrequired User who created this session `userName`stringnullable Display name of the user who created this session. Only on the organization listing. `userEmail`string Email of the user who created this session. Only on the organization listing. `devices`arrayrequired Device allocations linked to this session, ordered by createdAt ascending Show child attributes `id`string · uuidrequired Allocation id. Stable and always present, including while the device is still provisioning and no physical device exists yet. This is not the device's own id — see info.serial. `status`stringrequired Device lifecycle status. \`provisioning\` means a device is being booted and has no info.serial yet; \`in\_use\` means it is allocated and driveable; \`released\` means it has been returned to the pool. More values will be added. `info`objectrequired Descriptive attributes of the device. Show child attributes `platform`stringrequired `type`string `name`stringrequired `osVersion`stringrequired `serial`string The physical device's own id — a UDID on iOS, a serial on Android. Absent while the device is provisioning. This is the id accepted by the device endpoints and tools. `createdAt`string · date-timerequired When the device was added to the session `releasedAt`string · date-timenullable When the device was released (billing end) `instances`array Instances linked to this session, ordered by createdAt ascending Show child attributes `id`string · uuidrequired The instance's own id `status`stringrequired Lifecycle: provisioning -> ready, then released, or failed if provisioning could not complete `os`stringrequired Instance operating system. Only macos is supported today. `image`stringrequired Server-assigned base image the instance booted from `machine`objectrequired The compute backing an instance. Show child attributes `arch`stringrequired CPU architecture. Only arm64 is supported today. `cpuCores`integerrequired `memoryMb`integerrequired `diskMb`integerrequired `createdAt`string · date-timerequired When the instance was allocated (billing start) `readyAt`string · date-timenullable When the instance finished provisioning; null while provisioning `releasedAt`string · date-timenullable When the instance was released (billing end); null while active `chats`array Chats in this session, oldest first. A client restoring a session's conversation reads the last one. Show child attributes `id`stringrequired Chat id `createdAt`string · date-timerequired Request ``` curl https://app.mobilenext.ai/api/v1/sessions/{sessionId} \ -X GET \ -H 'Authorization: Bearer mob_...' ``` Response 200401403404 Session detail ``` { "id": "string", "title": "string", "user": "string", "userName": "string", "userEmail": "string", "devices": [ { "id": "string", "status": "provisioning", "info": { "platform": "ios", "type": "real", "name": "string", "osVersion": "string", "serial": "00008150-001C30842678401C" }, "createdAt": "2026-01-01T00:00:00Z", "releasedAt": "2026-01-01T00:00:00Z" } ], "instances": [ { "id": "string", "status": "provisioning", "os": "macos", "image": "macos-15-xcode-16", "machine": { "arch": "arm64", "cpuCores": 8, "memoryMb": 16384, "diskMb": 262144 }, "createdAt": "2026-01-01T00:00:00Z", "readyAt": "2026-01-01T00:00:00Z", "releasedAt": "2026-01-01T00:00:00Z" } ], "chats": [ { "id": "string" } ], "createdAt": "2026-01-01T00:00:00Z" } ``` --- # Test Results ## List test results[​](#list-test-results "Direct link to List test results") GET/api/v1/test-results Test results in the selected organization, visible to every member of it. The organization is chosen by the X-Organization-Id header, or the organization the API key is bound to, otherwise the caller's default organization. Header parameters `X-Organization-Id`string Selects which of the caller's organizations the request acts on. When omitted, the caller's default organization is used. Returns `object`stringrequired `data`arrayrequired Show child attributes `id`string · uuidrequired `name`stringrequired `userAgent`stringrequired `createdAt`string · date-timerequired `status`stringrequired Run status. queued and running mark a run still in progress; errored means the run itself broke (infrastructure, crash) rather than a test; the rest are terminal test outcomes. Omit on create to derive it from stats: unexpected > 0 is failed, flaky > 0 is flaky, otherwise passed (also when stats are absent). Request ``` curl https://app.mobilenext.ai/api/v1/test-results \ -X GET \ -H 'Authorization: Bearer mob_...' ``` Response 200401 Paginated list of test results, newest first ``` { "object": "list", "data": [ { "id": "string", "name": "Smoke suite", "userAgent": "mobilewright/0.0.39", "createdAt": "2026-01-01T00:00:00Z", "status": "queued" } ] } ``` ## Create a test result[​](#create-test-result "Direct link to Create a test result") POST/api/v1/test-results Called by the mobilewright reporter once a test run completes. Returns the created record including its id, which is used for subsequent asset uploads. The result is filed under the organization the API key is bound to, or the X-Organization-Id header, otherwise the caller's default organization. Header parameters `X-Organization-Id`string Selects which of the caller's organizations the request acts on. When omitted, the caller's default organization is used. Body parameters `name`stringrequired Human-readable name for this test run `userAgent`stringrequired Reporter name and version `status`string Run status. queued and running mark a run still in progress; errored means the run itself broke (infrastructure, crash) rather than a test; the rest are terminal test outcomes. Omit on create to derive it from stats: unexpected > 0 is failed, flaky > 0 is flaky, otherwise passed (also when stats are absent). Returns `id`string · uuidrequired `name`stringrequired `userAgent`stringrequired `createdAt`string · date-timerequired `status`stringrequired Run status. queued and running mark a run still in progress; errored means the run itself broke (infrastructure, crash) rather than a test; the rest are terminal test outcomes. Omit on create to derive it from stats: unexpected > 0 is failed, flaky > 0 is flaky, otherwise passed (also when stats are absent). Request ``` curl https://app.mobilenext.ai/api/v1/test-results \ -X POST \ -H 'Authorization: Bearer mob_...' \ -H 'Content-Type: application/json' \ -d '{"name":"Smoke suite","userAgent":"mobilewright/0.0.39","status":"queued"}' ``` Response 201400401 Test result created ``` { "id": "string", "name": "Smoke suite", "userAgent": "mobilewright/0.0.39", "createdAt": "2026-01-01T00:00:00Z", "status": "queued" } ``` ## Get a test result[​](#get-test-result "Direct link to Get a test result") GET/api/v1/test-results/{testResultId} Path parameters `testResultId`string · uuidrequired Test result UUID Header parameters `X-Organization-Id`string Selects which of the caller's organizations the request acts on. When omitted, the caller's default organization is used. Returns `id`string · uuidrequired `name`stringrequired `userAgent`stringrequired `createdAt`string · date-timerequired `status`stringrequired Run status. queued and running mark a run still in progress; errored means the run itself broke (infrastructure, crash) rather than a test; the rest are terminal test outcomes. Omit on create to derive it from stats: unexpected > 0 is failed, flaky > 0 is flaky, otherwise passed (also when stats are absent). Request ``` curl https://app.mobilenext.ai/api/v1/test-results/{testResultId} \ -X GET \ -H 'Authorization: Bearer mob_...' ``` Response 200401404 Test result detail ``` { "id": "string", "name": "Smoke suite", "userAgent": "mobilewright/0.0.39", "createdAt": "2026-01-01T00:00:00Z", "status": "queued" } ``` ## Update a test result[​](#update-test-result "Direct link to Update a test result") PATCH/api/v1/test-results/{testResultId} Partial update, typically called by the reporter to finish a run that was created as queued or running. Only the fields present in the body change. Path parameters `testResultId`string · uuidrequired Test result UUID Header parameters `X-Organization-Id`string Selects which of the caller's organizations the request acts on. When omitted, the caller's default organization is used. Body parameters `status`string Run status. queued and running mark a run still in progress; errored means the run itself broke (infrastructure, crash) rather than a test; the rest are terminal test outcomes. Omit on create to derive it from stats: unexpected > 0 is failed, flaky > 0 is flaky, otherwise passed (also when stats are absent). `environment`string `stats`object Aggregate Playwright run stats Show child attributes `startTime`string · date-time `duration`number Total duration in milliseconds `expected`integer `unexpected`integer `skipped`integer `flaky`integer Returns `id`string · uuidrequired `name`stringrequired `userAgent`stringrequired `createdAt`string · date-timerequired `status`stringrequired Run status. queued and running mark a run still in progress; errored means the run itself broke (infrastructure, crash) rather than a test; the rest are terminal test outcomes. Omit on create to derive it from stats: unexpected > 0 is failed, flaky > 0 is flaky, otherwise passed (also when stats are absent). Request ``` curl https://app.mobilenext.ai/api/v1/test-results/{testResultId} \ -X PATCH \ -H 'Authorization: Bearer mob_...' \ -H 'Content-Type: application/json' \ -d '{"status":"queued","environment":"staging","stats":{"startTime":"2026-01-01T00:00:00Z","duration":0,"expected":0,"unexpected":0,"skipped":0,"flaky":0}}' ``` Response 200400401404 Updated test result ``` { "id": "string", "name": "Smoke suite", "userAgent": "mobilewright/0.0.39", "createdAt": "2026-01-01T00:00:00Z", "status": "queued" } ``` ## List assets for a test result[​](#list-test-result-assets "Direct link to List assets for a test result") GET/api/v1/test-results/{testResultId}/assets Returns all uploaded assets (e.g. trace.zip, screenshots.zip) for this test result. Path parameters `testResultId`string · uuidrequired Test result UUID Header parameters `X-Organization-Id`string Selects which of the caller's organizations the request acts on. When omitted, the caller's default organization is used. Returns `object`stringrequired `data`arrayrequired Show child attributes `id`string · uuidrequired `name`stringrequired `contentType`stringrequired `size`integerrequired File size in bytes `createdAt`string · date-timerequired Request ``` curl https://app.mobilenext.ai/api/v1/test-results/{testResultId}/assets \ -X GET \ -H 'Authorization: Bearer mob_...' ``` Response 200401404 List of assets ``` { "object": "list", "data": [ { "id": "string", "name": "trace.zip", "contentType": "application/zip", "size": 0, "createdAt": "2026-01-01T00:00:00Z" } ] } ``` ## Upload an asset[​](#upload-test-result-asset "Direct link to Upload an asset") POST/api/v1/test-results/{testResultId}/assets Uploads a binary asset attached to a test result. Use multipart/form-data with the file and its name. In future, a presignedUrl parameter may be added to return an S3 pre-signed URL instead of accepting the upload directly. Path parameters `testResultId`string · uuidrequired Test result UUID Header parameters `X-Organization-Id`string Selects which of the caller's organizations the request acts on. When omitted, the caller's default organization is used. Returns `id`string · uuidrequired `name`stringrequired `contentType`stringrequired `size`integerrequired File size in bytes `createdAt`string · date-timerequired Request ``` curl https://app.mobilenext.ai/api/v1/test-results/{testResultId}/assets \ -X POST \ -H 'Authorization: Bearer mob_...' ``` Response 201401404 Asset uploaded ``` { "id": "string", "name": "trace.zip", "contentType": "application/zip", "size": 0, "createdAt": "2026-01-01T00:00:00Z" } ``` ## Download an asset[​](#download-test-result-asset "Direct link to Download an asset") GET/api/v1/test-results/{testResultId}/assets/{assetId} Streams the raw binary content of a specific asset. Path parameters `testResultId`string · uuidrequired Test result UUID `assetId`string · uuidrequired Asset UUID Header parameters `X-Organization-Id`string Selects which of the caller's organizations the request acts on. When omitted, the caller's default organization is used. Request ``` curl https://app.mobilenext.ai/api/v1/test-results/{testResultId}/assets/{assetId} \ -X GET \ -H 'Authorization: Bearer mob_...' ``` Response 200401404 Raw asset content ``` // No response body ``` --- # Architecture **There is one runtime underneath everything.** MobileCLI is the single API that speaks to every device. Mobilewright and Mobile MCP are clients of it, CI and scripts call it directly, and Mobile Next Cloud is that same runtime — managed and scaled for you. So the stack is an hourglass: many ways in on top, one waist in the middle, every device on the bottom. The same MobileCLI runs in two places, unchanged — on your machine, or behind the cloud: Because local and cloud are the same stack, moving to the cloud is a connection-string change, not a rewrite. ## Which piece do I use?[​](#which-piece-do-i-use "Direct link to Which piece do I use?") | You are… | You use… | | ---------------------------------------------------------- | ---------------------------------------- | | A developer writing mobile tests or automating mobile apps | **Mobilewright** | | An AI agent (Claude Code, Cursor, Copilot…) | **Mobile MCP** | | Scripting or CI, want raw control | **mobilecli** directly (CLI or JSON-RPC) | | You need real devices at scale | **Mobile Next Cloud** | ## How a single action flows[​](#how-a-single-action-flows "Direct link to How a single action flows") When Mobile MCP receives *"tap the Login button"*, it calls MobileCLI, which asks DeviceKit (running on the device) for the accessibility tree, finds the element, and tells DeviceKit to inject the tap — then the result travels back up the same path. Every layer speaks JSON-RPC, so the identical call works whether the device is on your desk or in the cloud. ## Layers[​](#layers "Direct link to Layers") **DeviceKit** — Runs on the device (or simulator host). Exposes a JSON-RPC 2.0 API over WebSocket or HTTP. Handles screen capture, accessibility tree dumps, input injection, app lifecycle. Separate implementations for iOS ([devicekit-ios](https://github.com/mobile-next/devicekit-ios)) and Android ([devicekit-android](https://github.com/mobile-next/devicekit-android)). **MobileCLI** — A single Go binary that connects to DeviceKit and exposes a unified interface across iOS and Android. Serves three interfaces: CLI commands, JSON-RPC over WebSocket, JSON-RPC over HTTP POST. Mobilewright and Mobile MCP both talk to MobileCLI. **Mobilewright** — TypeScript/JS automation framework. Connects to MobileCLI via WebSocket. Provides the Playwright-style API (`getByRole`, `expect`, auto-waiting) on top of MobileCLI's raw JSON-RPC calls. **Mobile MCP** — MCP server that connects to MobileCLI. Makes mobile device control available to any MCP-compatible AI agent (Claude Code, Cursor, VS Code Copilot, etc.) as a set of structured tools. **Mobile Next Cloud** — Manages a fleet of MobileCLI instances running in the cloud (AWS Device Farm). Handles device allocation, session management, test result hosting, and permissions. Exposes a REST API for management, JSON-RPC for device interaction, and its own MCP server for remote access. --- # Apps Upload a build of your app once and Mobile Next Cloud keeps it for your organization. Start a real device with it, install it on a device you are already using, or point CI and agents at it by its file id. The same bytes uploaded twice are stored once. ## Upload a build[​](#upload-a-build "Direct link to Upload a build") In the web app, open **Apps** and choose **Upload app**. Pick an `.apk` or `.ipa`. * The file is checked in your browser first. If your organization already has these exact bytes, nothing is uploaded and you see **Already uploaded**. * Once uploaded, Mobile Next reads the app's name, package or bundle id, version, build number and icon. Builds of the same app are grouped under it. * iOS builds are re-signed for the device when they are installed, so an unsigned or ad hoc signed device `.ipa` works. Simulator builds are stored but do not install on real devices. For Android, upload an APK, not an App Bundle (`.aab`). **Apps** lists one row per app with its latest version. Open an app to see all its builds, or **All files** for every upload. From a file's menu you can rename it, change when it expires, download it, or delete it. ## Start a device with an app[​](#start-a-device-with-an-app "Direct link to Start a device with an app") Choose the play button on an app or a file row. **Start Session** opens with that app selected and lists only devices of its platform. Pick a device and start the session; you can also choose an app in the **Install an app** section when starting any session. * **Android:** the app is installed and launched before the device is handed to you. * **iOS:** a new device is always started, and the app is installed while it boots, so it takes a few minutes. ## Install on a running device[​](#install-on-a-running-device "Direct link to Install on a running device") On a running Android device, choose **Install App** in the device toolbar. Pick an app and a version (newest first, with the filename and upload date), or **Upload app** to add a new build first. The app is installed and launched. A running iPhone cannot take a new app. To use an iOS build, start a new session with it from **Apps**. ## Limits and expiry[​](#limits-and-expiry "Direct link to Limits and expiry") | Plan | Largest file | Storage | | ---------- | ------------ | ------- | | Hobby | 250 MB | 1 GB | | Starter | 1 GB | 2 GB | | Team | 2 GB | 10 GB | | Enterprise | 2 GB | — | A build expires 30 days after upload unless you choose otherwise (10 minutes to 90 days). Uploading the same file again extends it. Deleting a build removes it from your organization at once. ## Use it from CI[​](#use-it-from-ci "Direct link to Use it from CI") Upload the build from your pipeline and start a device with it, using an [API key](https://mobilenext.ai/docs/docs/api/api-keys.md). The flow is the same as the web app: hash, create, upload only if asked, then complete. ``` set -euo pipefail API=https://app.mobilenext.ai/api/v1 AUTH="Authorization: Bearer $MOBILENEXT_API_KEY" APP=app/build/outputs/apk/release/app-release.apk # 1. Create the file. A dedup hit returns the existing file with no `upload`. jq -n --arg name "$(basename "$APP")" --argjson size "$(stat -c%s "$APP")" \ --arg sha "$(sha256sum "$APP" | cut -d' ' -f1)" \ --arg branch "$GITHUB_REF_NAME" --arg commit "$GITHUB_SHA" \ --arg run "$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID" \ '{filename: $name, filesize: $size, sha256: $sha, build: {branch: $branch, commit: $commit, ciRunUrl: $run}}' > create.json curl -sf "$API/files" -H "$AUTH" -H 'Content-Type: application/json' -d @create.json > file.json FILE_ID=$(jq -r .id file.json) # 2. Upload the bytes only when asked, with the headers it returns. if [ "$(jq -r '.upload != null' file.json)" = true ]; then HEADERS=() while IFS= read -r header; do HEADERS+=(-H "$header"); done < <( jq -r '.upload.headers | to_entries[] | select(.key | ascii_downcase != "content-length") | "\(.key): \(.value)"' file.json) curl -sf -X PUT "${HEADERS[@]}" --upload-file "$APP" "$(jq -r .upload.url file.json)" fi # 3. Complete it; the file comes back `ready` or `failed` with a `failureReason`. if [ "$(jq -r .status file.json)" != ready ]; then curl -sf -X POST "$API/files/$FILE_ID/complete" -H "$AUTH" > file.json fi [ "$(jq -r .status file.json)" = ready ] || { jq . file.json; exit 1; } # 4. Start a device with the build and launch it. SESSION_ID=$(curl -sf -X POST "$API/sessions" -H "$AUTH" | jq -r .id) curl -sf "$API/sessions/$SESSION_ID/devices" -H "$AUTH" -H 'Content-Type: application/json' \ -d "{\"filters\": [{\"attribute\": \"platform\", \"operator\": \"EQUALS\", \"value\": \"android\"}], \"file\": \"$FILE_ID\", \"launchAfterInstall\": true}" ``` To install on a device that is already running instead, call `POST /api/v1/sessions/{sessionId}/devices/{deviceId}/install` with `{"file": "", "launchAfterInstall": true}` (Android only). See [Files](https://mobilenext.ai/docs/docs/api/files.md), [Apps](https://mobilenext.ai/docs/docs/api/apps.md) and [Devices](https://mobilenext.ai/docs/docs/api/devices.md) in the API reference. --- # Available Devices Mobile Next Cloud provisions real devices on demand. These are the models currently available, with the OS versions each one ships with. A device is requested by name, platform and OS version — see [Mobile Next Cloud overview](https://mobilenext.ai/docs/docs/cloud/overview.md). To start a device with your own build installed, see [Apps](https://mobilenext.ai/docs/docs/cloud/apps.md). 107 device configurations are available. ## iOS[​](#ios "Direct link to iOS") ### iPhone[​](#iphone "Direct link to iPhone") | Device | OS versions | Screen (pt) | | ----------------------- | ------------------ | ----------- | | Apple iPhone Air | 26.3.1 | 420 × 912 | | Apple iPhone 17 Pro Max | 26.3.1 | 440 × 956 | | Apple iPhone 17 Pro | 26.3.1 | 402 × 874 | | Apple iPhone 17 | 26.3.1 | 402 × 874 | | Apple iPhone 16 Pro | 26.0, 18.3.1 | 402 × 874 | | Apple iPhone 16 | 26.0, 18.6.2, 18.0 | 393 × 852 | | Apple iPhone 14 Pro Max | 26.5, 18.6 | 430 × 932 | | Apple iPhone 16 Pro Max | 18.3.1 | 440 × 956 | | Apple iPhone 16 Plus | 18.3.1 | 430 × 932 | | Apple iPhone 16e | 18.3.2 | 390 × 844 | | Apple iPhone 15 Pro Max | 17.3.1 | 430 × 932 | | Apple iPhone 15 Pro | 18.1, 17.3.1 | 393 × 852 | | Apple iPhone 15 Plus | 17.4.1 | 430 × 932 | | Apple iPhone 15 | 18.5, 18.0, 17.2.1 | 393 × 852 | | Apple iPhone 14 Pro | 17.3.1 | 393 × 852 | | Apple iPhone 14 | 18.6.2, 17.6.1 | 390 × 844 | | Apple iPhone 13 Pro Max | 17.3 | 428 × 926 | | Apple iPhone 13 | 18.5, 17.6.1 | 390 × 844 | | Apple iPhone 12 | 18.5, 17.5.1 | 390 × 844 | | Apple iPhone 11 | 18.6.2 | 414 × 896 | ### iPad[​](#ipad "Direct link to iPad") | Device | OS versions | Screen (pt) | | ------------------------ | ------------ | ----------- | | Apple iPad Air 11 (2024) | 26.1, 18.3.1 | 820 × 1180 | | Apple iPad mini (2024) | 18.6 | 744 × 1133 | | Apple iPad Air 13 (2025) | 18.4.1 | 1024 × 1366 | | Apple iPad Air 11 (2025) | 18.3.2 | 820 × 1180 | | Apple iPad (2025) | 18.3.2 | 820 × 1180 | | Apple iPad (2022) | 17.3.1 | 820 × 1180 | ## Android[​](#android "Direct link to Android") ### Phones[​](#phones "Direct link to Phones") | Device | OS versions | Screen (pt) | | ----------------------------- | ----------- | ----------- | | Google Pixel 10 Pro XL | 16 | 360 × 801 | | Google Pixel 10 Pro | 16 | 360 × 803 | | Google Pixel 10 | 16 | 360 × 808 | | Google Pixel 9 Pro XL | 17, 15 | 336 × 748 | | Google Pixel 9 Pro | 15 | 320 × 714 | | Google Pixel 9a | 15 | 360 × 808 | | Google Pixel 9 | 16, 15 | 360 × 808 | | Google Pixel 8 Pro | 15, 14 | 336 × 748 | | Google Pixel 8a | 15, 14 | 360 × 800 | | Google Pixel 8 | 15, 14 | 360 × 800 | | Google Pixel 7 Pro | 13 | 360 × 780 | | Google Pixel 7a | 13 | 360 × 800 | | Google Pixel 7 | 14, 13 | 360 × 800 | | Google Pixel 6 Pro (Unlocked) | 12 | 480 × 1040 | | Google Pixel 6 (Unlocked) | 13, 12 | 360 × 800 | | Google Pixel 5a 5G | 12 | 360 × 800 | | Google Pixel 5 (Unlocked) | 12 | 360 × 780 | | Google Pixel 4a | 12 | 360 × 780 | | Google Pixel 3a XL | 12 | 360 × 720 | | Samsung Galaxy S26 Ultra | 16 | 360 × 780 | | Samsung Galaxy S26+ | 16 | 360 × 780 | | Samsung Galaxy S26 | 16 | 360 × 780 | | Samsung Galaxy S25 Ultra | 15 | 480 × 1040 | | Samsung Galaxy S25+ | 15 | 480 × 1040 | | Samsung Galaxy S25 | 16, 15 | 360 × 780 | | Samsung Galaxy S24 Ultra | 14 | 480 × 1040 | | Samsung Galaxy S24+ | 14 | 480 × 1040 | | Samsung Galaxy S24 | 14 | 360 × 780 | | Samsung Galaxy S23 Ultra | 13 | 480 × 1029 | | Samsung Galaxy S23+ | 13 | 360 × 780 | | Samsung Galaxy S23 | 14, 13 | 360 × 780 | | Samsung Galaxy S22 Ultra 5G | 12 | 480 × 1029 | | Samsung Galaxy S22+ 5G | 12 | 360 × 780 | | Samsung Galaxy S22 5G | 13, 12 | 360 × 780 | | Samsung Galaxy S21 Ultra | 12 | 480 × 1067 | | Samsung Galaxy S21 | 12 | 360 × 800 | | Samsung Galaxy S20 (Unlocked) | 13 | 480 × 1067 | | Samsung Galaxy A73 5G | 12 | 360 × 800 | | Samsung Galaxy A56 | 15 | 360 × 780 | | Samsung Galaxy A55 | 14 | 360 × 780 | | Samsung Galaxy A54 | 13 | 360 × 780 | | Samsung Galaxy A53 5G | 12 | 360 × 800 | | Samsung Galaxy A36 | 15 | 360 × 780 | | Samsung Galaxy A35 | 14 | 360 × 780 | | Samsung Galaxy A34 | 13 | 360 × 780 | | Samsung Galaxy A26 | 15 | 360 × 780 | | Samsung Galaxy A25 | 14 | 360 × 780 | | Samsung Galaxy A24 4G | 14 | 360 × 780 | | Samsung Galaxy A16 | 14 | 360 × 780 | | Samsung Galaxy A15 | 14 | 360 × 780 | | Samsung Galaxy A14 5G | 13 | 360 × 803 | | Samsung A51 | 13 | 360 × 800 | ### Tablets[​](#tablets "Direct link to Tablets") | Device | OS versions | Screen (pt) | | -------------------------- | ----------- | ----------- | | Google Pixel Tablet | 16 | 800 × 1280 | | Samsung Galaxy Tab S11 | 16 | 800 × 1280 | | Samsung Galaxy Tab S9 | 13 | 800 × 1280 | | Samsung Galaxy Tab S8 | 12 | 800 × 1280 | | Samsung Galaxy Tab A9 | 13 | 400 × 670 | | Samsung Galaxy Tab A7 Lite | 13 | 400 × 670 | --- # ChatGPT (Web & Desktop App) Coming soon. --- # Claude Code ``` claude mcp add mobilenext --transport http https://app.mobilenext.ai/mcp ``` The first time Claude Code uses a Mobile Next tool, your browser opens to authorize your Mobile Next account. To authenticate ahead of time instead, run: ``` claude mcp login mobilenext ``` Once authenticated, you can start allocating cloud devices. ## Tutorial[​](#tutorial "Direct link to Tutorial") [Mobile Next Cloud MCP + Claude Code](https://www.youtube.com/embed/QbCimbdgHFk) --- # Claude (Web & Desktop App) Follow these instructions to connect Mobile Next Cloud MCP to your Claude Web and Claude Desktop. There is nothing to download. 1. In left sidebar, click **"Customize"** ![Step 1](/docs/assets/images/claude-web-1-e9bcdfce407968705fa1a5787a15e87f.png) 2. Select **"Connect your apps"** ![Step 2](/docs/assets/images/claude-web-2-8f4a2b3029245d6de0ead0c048cdcd1f.png) 3. Click on **"Manage connectors"** ![Step 3](/docs/assets/images/claude-web-3-2c139c3a1cd1c279afabc8714ab10c5a.png) 4. Click on **"Plus**" to add a new connector ![Step 4](/docs/assets/images/claude-web-4-6a199c89ed59970d352265a48c36c6ca.png) 5. Select **"Add custom connector"** ![Step 5](data:image/png;base64,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) 6. Type **"mobilenext"** in name field, and `https://app.mobilenext.ai/mcp` in url, click **"Add"** ![Step 6](/docs/assets/images/claude-web-6-c4ad1e288f5c4368164d5ebb7093ea04.png) 7. Lastly, click on **"Connect**" to start the authorization flow ![Step 7](/docs/assets/images/claude-web-7-c81bebde1852e1f9d12f29ba39f61007.png) 8. You have successfully connected Claude with Mobile Next Cloud ✅ ![Step 8](/docs/assets/images/claude-web-8-b2317b1d18e73040545757d10888843e.png) --- # Codex ``` codex mcp add mobilenext --url https://app.mobilenext.ai/mcp ``` Codex will immediately start the authorization flow, approving connection between Codex and Mobile Next. Once approved and done, you are ready to use Mobile Next Cloud. --- # Cursor #### Click the button to install:[​](#click-the-button-to-install "Direct link to Click the button to install:") [![Install in Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=mobilenext\&config=eyJ1cmwiOiJodHRwczovL2FwcC5tb2JpbGVuZXh0LmFpL21jcCJ9) #### Or install manually:[​](#or-install-manually "Direct link to Or install manually:") Go to `Cursor Settings` → `MCP` → `Add new MCP Server`. Name it `mobilenext`, choose the **URL** type, and set the URL to `https://app.mobilenext.ai/mcp`. Cursor will start the authorization flow in your browser. Once you approve, you are ready to use Mobile Next Cloud. --- # Gemini CLI ``` gemini mcp add --transport http --scope user mobilenext https://app.mobilenext.ai/mcp ``` The first time Gemini CLI connects, your browser opens to authorize your Mobile Next account. Once approved, you are ready to use Mobile Next Cloud. --- # Introduction `mobilenext` is a **remote MCP server** that gives your AI agent real iOS and Android devices in the cloud. There is nothing to download or run locally — you add one URL to your agent, log in through your browser, and your agent can allocate a device, install your app, and start tapping, typing, and taking screenshots. ![Architecture Diagram](data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxOTIwIiBoZWlnaHQ9IjUyNCIgdmlld0JveD0iMCAwIDE5MjAgNTI0IiByb2xlPSJpbWciIGFyaWEtbGFiZWxsZWRieT0idGl0bGUgZGVzYyIgc3R5bGU9ImJhY2tncm91bmQ6I2ZmZmZmZjtib3JkZXItcmFkaXVzOjhweCI+CiAgPHRpdGxlIGlkPSJ0aXRsZSI+U2ltcGxlIGFyY2hpdGVjdHVyZSBkaWFncmFtPC90aXRsZT4KICA8ZGVzYyBpZD0iZGVzYyI+QSBsZWZ0LXRvLXJpZ2h0IGFyY2hpdGVjdHVyZSBkaWFncmFtIHNob3dpbmcgVXNlciwgQWdlbnQgTExNLCBNb2JpbGUgTmV4dCBDbG91ZCwgQW5kcm9pZCBEZXZpY2UsIGFuZCBpT1MgRGV2aWNlLjwvZGVzYz4KCiAgPGRlZnM+CiAgICA8bGluZWFyR3JhZGllbnQgaWQ9ImJveEZpbGwiIHgxPSIwIiB5MT0iMCIgeDI9IjAiIHkyPSIxIj4KICAgICAgPHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2ZmZjViZiIvPgogICAgICA8c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiNmZmYwYTMiLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bWFya2VyIGlkPSJhcnJvdyIgdmlld0JveD0iMCAwIDEwIDEwIiByZWZYPSI5IiByZWZZPSI1IiBtYXJrZXJXaWR0aD0iOSIgbWFya2VySGVpZ2h0PSI5IiBvcmllbnQ9ImF1dG8tc3RhcnQtcmV2ZXJzZSI+CiAgICAgIDxwYXRoIGQ9Ik0gMCAwIEwgMTAgNSBMIDAgMTAgeiIgZmlsbD0iIzlhOWE5YSIvPgogICAgPC9tYXJrZXI+CiAgICA8c3R5bGU+CiAgICAgIHRleHQgewogICAgICAgIGZpbGw6ICMyMjI0Mjg7CiAgICAgICAgZm9udC1mYW1pbHk6IC1hcHBsZS1zeXN0ZW0sIEJsaW5rTWFjU3lzdGVtRm9udCwgIlNlZ29lIFVJIiwgUm9ib3RvLCBIZWx2ZXRpY2EsIEFyaWFsLCBzYW5zLXNlcmlmOwogICAgICAgIGZvbnQtc2l6ZTogMjdweDsKICAgICAgICBkb21pbmFudC1iYXNlbGluZTogbWlkZGxlOwogICAgICAgIHRleHQtYW5jaG9yOiBtaWRkbGU7CiAgICAgIH0KICAgICAgLmJveCB7CiAgICAgICAgZmlsbDogdXJsKCNib3hGaWxsKTsKICAgICAgICBzdHJva2U6ICNiMDgyMDA7CiAgICAgICAgc3Ryb2tlLXdpZHRoOiA0OwogICAgICB9CiAgICAgIC5saW5lIHsKICAgICAgICBmaWxsOiBub25lOwogICAgICAgIHN0cm9rZTogIzlhOWE5YTsKICAgICAgICBzdHJva2Utd2lkdGg6IDQ7CiAgICAgICAgc3Ryb2tlLWxpbmVjYXA6IHJvdW5kOwogICAgICAgIHN0cm9rZS1saW5lam9pbjogcm91bmQ7CiAgICAgICAgbWFya2VyLWVuZDogdXJsKCNhcnJvdyk7CiAgICAgIH0KICAgIDwvc3R5bGU+CiAgPC9kZWZzPgoKICA8cmVjdCB4PSI3NSIgeT0iMjE3IiB3aWR0aD0iMjc3IiBoZWlnaHQ9Ijk5IiByeD0iMTgiIGNsYXNzPSJib3giLz4KICA8dGV4dCB4PSIyMTQiIHk9IjI2NiI+VXNlciDwn5GkPC90ZXh0PgoKICA8cmVjdCB4PSI1NTkiIHk9IjIxNyIgd2lkdGg9IjI3NyIgaGVpZ2h0PSIxMTAiIHJ4PSIxOCIgY2xhc3M9ImJveCIvPgogIDx0ZXh0IHg9IjY5OCIgeT0iMjcyIj5BZ2VudCAoTExNKSDwn6SWPC90ZXh0PgoKICA8cmVjdCB4PSIxMDQwIiB5PSIyMTIiIHdpZHRoPSIyNzkiIGhlaWdodD0iMTE2IiByeD0iMTgiIGNsYXNzPSJib3giLz4KICA8dGV4dCB4PSIxMTc5IiB5PSIyNzAiPk1vYmlsZSBOZXh0IENsb3VkIOKYge+4jzwvdGV4dD4KCiAgPHJlY3QgeD0iMTQ5NSIgeT0iNzgiIHdpZHRoPSIzMTciIGhlaWdodD0iMTEyIiByeD0iMTgiIGNsYXNzPSJib3giLz4KICA8dGV4dCB4PSIxNjU0IiB5PSIxMzQiPkFuZHJvaWQgRGV2aWNlIPCfk7I8L3RleHQ+CgogIDxyZWN0IHg9IjE0OTUiIHk9IjM2NiIgd2lkdGg9IjMxNyIgaGVpZ2h0PSIxMDIiIHJ4PSIxOCIgY2xhc3M9ImJveCIvPgogIDx0ZXh0IHg9IjE2NTQiIHk9IjQxNyI+aU9TIERldmljZSDwn5OyPC90ZXh0PgoKICA8cGF0aCBkPSJNIDM1MiAyNjYgSCA1NTkiIGNsYXNzPSJsaW5lIi8+CiAgPHBhdGggZD0iTSA4MzYgMjcyIEggMTA0MCIgY2xhc3M9ImxpbmUiLz4KICA8cGF0aCBkPSJNIDEzMTkgMjcwIEggMTM2MSBWIDEzNCBIIDE0OTUiIGNsYXNzPSJsaW5lIi8+CiAgPHBhdGggZD0iTSAxMzE5IDI3MCBIIDEzNjEgViA0MTcgSCAxNDk1IiBjbGFzcz0ibGluZSIvPgo8L3N2Zz4K) ## Get started in two steps[​](#get-started-in-two-steps "Direct link to Get started in two steps") 1. **Add the server to your agent** — pick your client under [Installation](https://mobilenext.ai/docs/docs/cloud/installation/claude-code.md): ``` claude mcp add mobilenext --transport http https://app.mobilenext.ai/mcp ``` 2. **Ask your agent for a device.** The first tool call opens your browser to authorize your Mobile Next account, then the agent takes it from there: > Allocate an iOS device, install my app, and walk through the login flow. ## What your agent can do[​](#what-your-agent-can-do "Direct link to What your agent can do") * **Allocate and release** real iOS and Android devices on demand * **Install apps** — upload your own `.apk`/`.ipa` (unsigned iOS builds are re-signed automatically) * **Drive the UI** — tap, swipe, type, press buttons, read the accessibility tree * **See the screen** — screenshots, screen recordings, and a live interactive device view See [Tools & Prompts](https://mobilenext.ai/docs/docs/cloud/tools-and-prompts.md) for the full tool reference, including how device allocation and sessions work. ## Core Resources[​](#core-resources "Direct link to Core Resources") | Resource | Description | | -------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- | | [Installation](https://mobilenext.ai/docs/docs/cloud/installation/claude-code.md) | Set up the MCP server in Claude Code, Claude Web/Desktop, Codex, Cursor, or Gemini CLI | | [Using Mobile Next Cloud MCP](https://mobilenext.ai/docs/docs/cloud/using-mobilenext-mcp.md) | How the remote server and authorization work | | [Tools and Prompts](https://mobilenext.ai/docs/docs/cloud/tools-and-prompts.md) | Available tools and prompts for Mobile Next Cloud MCP | --- # Overview Mobile Next Cloud is a cloud device farm service that lets you programmatically allocate and release mobile devices on demand. You can perform operations such as installing apps, listing elements on screen, tapping, typing, and more — all without physically connecting a device to your computer. ![Mobile Next Cloud Architecture](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAyAAAAGQAQAAAAB+XjmZAAAAIGNIUk0AAHomAACAhAAA+gAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAACYktHRAAB3YoTpAAAAAd0SU1FB+oDEhEoJc0GxCoAAAAldEVYdGRhdGU6Y3JlYXRlADIwMjYtMDMtMThUMTc6NDA6MzcrMDA6MDAyA0MWAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDI2LTAzLTE4VDE3OjQwOjM3KzAwOjAwQ177qgAAACh0RVh0ZGF0ZTp0aW1lc3RhbXAAMjAyNi0wMy0xOFQxNzo0MDozNyswMDowMBRL2nUAAACkSURBVHja7c0xAQAADAIg+5fWDHt2QQHSB5FIJBKJRCKRSCQSiUQikUgkEolEIpFIJBKJRCKRSCQSiUQikUgkEolEIpFIJBKJRCKRSCQSiUQikUgkEolEIpFIJBKJRCKRSCQSiUQikUgkEolEIpFIJBKJRCKRSCQSiUQikUgkEolEIpFIJBKJRCKRSCQSiUQikUgkEolEIpFIJBKJRCKRSCSSuwFEH6zWB0bbYAAAAABJRU5ErkJggg==) --- # Tools & Prompts Available tools and prompts for Mobile Next Cloud MCP Server. ## Tools[​](#tools "Direct link to Tools") | Tool | Description | | ------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------- | | `mobilenext_list_available_devices` | List your allocated devices and devices available for allocation | | `mobilenext_allocate_device` | Reserve a device from the remote fleet for testing and development. Allocation is asynchronous — see [How allocation works](#how-allocation-works) | | `mobilenext_release_device` | Release a device back to the remote fleet | | `mobilenext_list_apps` | List all the installed apps on the device | | `mobilenext_launch_app` | Launch an app on mobile device | | `mobilenext_terminate_app` | Stop and terminate an app on mobile device | | `mobilenext_create_upload` | Create a presigned upload URL. `PUT` your `.apk`/`.ipa` file to the returned URL, then pass the `uploadId` to `mobilenext_install_app` | | `mobilenext_install_app` | Install an app on a device — pass an `uploadId` from `mobilenext_create_upload`, or a URL to a `.apk`/`.ipa` file hosted at `github.com/mobile-next` | | `mobilenext_get_screen_size` | Get the screen size of the mobile device in pixels | | `mobilenext_click_on_screen_at_coordinates` | Click on the screen at given x,y coordinates | | `mobilenext_double_tap_on_screen` | Double-tap on the screen at given x,y coordinates | | `mobilenext_long_press_on_screen_at_coordinates` | Long press on the screen at given x,y coordinates | | `mobilenext_list_elements_on_screen` | List elements on screen and their coordinates, with display text or accessibility label | | `mobilenext_press_button` | Press a device button: `HOME`, `BACK` (Android only), `VOLUME_UP`, `VOLUME_DOWN`, `ENTER`, or a D-pad button | | `mobilenext_open_url` | Open a URL in browser on device | | `mobilenext_swipe_on_screen` | Swipe on the screen | | `mobilenext_type_keys` | Type text into the focused element | | `mobilenext_take_screenshot` | Take a screenshot of the mobile device. | | `mobilenext_save_screenshot` | Take a screenshot of the mobile device and return a download URL | | `mobilenext_set_orientation` | Change the screen orientation of the device | | `mobilenext_get_orientation` | Get the current screen orientation of the device | | `mobilenext_start_screen_recording` | Start recording the screen of a mobile device | | `mobilenext_stop_screen_recording` | Stop an active screen recording on a mobile device | ## How allocation works[​](#how-allocation-works "Direct link to How allocation works") Device allocation is asynchronous. When `mobilenext_allocate_device` returns a device in the `allocating` state, provisioning is still in progress — Android devices are typically ready within a minute, while iOS devices can take a few minutes. Your agent can check progress by calling `mobilenext_list_available_devices` again; there is no need to re-allocate. Allocating a device creates a session (or joins the session ID you pass in). Keep the returned session ID — `mobilenext_release_device` needs it to release the device when you're done. ### Session duration[​](#session-duration "Direct link to Session duration") A device allocation can stay open for up to **120 minutes**. Allocations still open after that are released automatically. This is a safety net for sessions that were never released (for example, an agent that crashed or disconnected), not a budget to plan around — release devices explicitly with `mobilenext_release_device` as soon as you're done. ## Installing your own app[​](#installing-your-own-app "Direct link to Installing your own app") To test your own build, upload it first: call `mobilenext_create_upload`, `PUT` the file to the returned presigned URL, then call `mobilenext_install_app` with the `uploadId`. For iOS, IPA files may be **unsigned or ad hoc signed** — Mobile Next Cloud re-signs them automatically before installation, so you don't need a device-provisioned signing profile. Direct-URL installs are limited to `.apk`/`.ipa` files hosted at `github.com/mobile-next` (such as the Milliways sample app); use the upload flow for everything else. --- # Using Mobile Next Cloud MCP `mobilenext` is a remote MCP server that requires no downloads or local installation. It allows you to control your cloud devices directly through your AI agent — allocate devices, install apps, interact with UI elements, and more, all from your agent's conversation. When adding the MCP server, you will be redirected to authorize your Mobile Next account. --- # Give Claude Code a Real Phone ## Prerequisites[​](#prerequisites "Direct link to Prerequisites") A booted iOS simulator or Android emulator (or connected real device). Node.js v22+. * iOS: `xcrun simctl boot "iPhone 16"` to start a simulator * Android: start an emulator via Android Studio or `emulator -avd ` ## 1. Add Mobile MCP to Claude Code[​](#1-add-mobile-mcp-to-claude-code "Direct link to 1. Add Mobile MCP to Claude Code") ``` claude mcp add mobile-mcp -- npx -y @mobilenext/mobile-mcp@latest ``` ## 2. Verify the connection[​](#2-verify-the-connection "Direct link to 2. Verify the connection") In Claude Code, type `/mcp`. You should see `mobile-mcp` listed and connected. ## 3. Ask Claude to interact with your device[​](#3-ask-claude-to-interact-with-your-device "Direct link to 3. Ask Claude to interact with your device") Some example prompts: * "List the devices available and take a screenshot of the current screen" * "Open the Settings app and navigate to Wi-Fi settings" * "Launch com.example.myapp, sign in with email and password test123" * "Take a screenshot, describe what's on screen, then tap the first button you see" ## 4. Install and test an app[​](#4-install-and-test-an-app "Direct link to 4. Install and test an app") ``` Install the app at /path/to/MyApp.ipa, launch it, and tell me what you see on the home screen. ``` ## Troubleshooting[​](#troubleshooting "Direct link to Troubleshooting") * If no devices appear: confirm your simulator/emulator is booted (`xcrun simctl list` or `adb devices`) * If Mobile MCP disconnects: restart Claude Code and reconnect via `/mcp` ## Next steps[​](#next-steps "Direct link to Next steps") [Mobile MCP on GitHub](https://github.com/mobile-next/mobile-mcp) | [Mobile Next Cloud](https://mobilenext.ai/docs/docs/cloud/overview.md) (for cloud devices) --- # Run Mobile Tests in CI This guide shows how to run Mobilewright tests against an iOS simulator in GitHub Actions. Android CI setup follows the same pattern with Android-specific setup steps. **Prerequisites:** Mobilewright tests already running locally (see [Test an iOS App with Mobilewright](https://mobilenext.ai/docs/docs/guides/test-ios-app-with-mobilewright.md)). ## GitHub Actions workflow[​](#github-actions-workflow "Direct link to GitHub Actions workflow") Create `.github/workflows/mobile-tests.yml`: ``` name: Mobile Tests on: push: branches: [main] pull_request: jobs: test: runs-on: macos-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: '22' - name: Install dependencies run: npm ci - name: Boot simulator run: | xcrun simctl boot "iPhone 16" || true xcrun simctl bootstatus "iPhone 16" -b - name: Run Mobilewright tests run: npx mobilewright test --reporter list - name: Upload test report if: always() uses: actions/upload-artifact@v4 with: name: mobilewright-report path: mobilewright-report/ ``` ## Android CI[​](#android-ci "Direct link to Android CI") Swap the simulator setup step with: ``` - name: Start Android emulator uses: reactivecircus/android-emulator-runner@v2 with: api-level: 35 script: npx mobilewright test --reporter list ``` ## Cloud devices[​](#cloud-devices "Direct link to Cloud devices") Running on macOS GitHub Actions runners is slower and more expensive than running against cloud devices. With [Mobile Next Cloud](https://mobilenext.ai/docs/docs/cloud/overview.md), your tests run on managed real devices and your CI can use a standard `ubuntu-latest` runner. See [Mobile Next Cloud](https://mobilenext.ai/docs/docs/cloud/overview.md) for setup, and [Apps → Use it from CI](https://mobilenext.ai/docs/docs/cloud/apps.md#use-it-from-ci) to upload each build once and start a cloud device with it. --- # Test an iOS App with Mobilewright ## Prerequisites[​](#prerequisites "Direct link to Prerequisites") Node.js >= 18, Xcode with Command Line Tools, and a booted iPhone simulator or connected real device. ## 1. Install Mobilewright[​](#1-install-mobilewright "Direct link to 1. Install Mobilewright") ``` npm install mobilewright @mobilewright/test ``` ## 2. Verify your environment[​](#2-verify-your-environment "Direct link to 2. Verify your environment") ``` npx mobilewright doctor npx mobilewright devices # confirm your device appears ``` ## 3. Initialize project config[​](#3-initialize-project-config "Direct link to 3. Initialize project config") ``` npx mobilewright init ``` This creates `mobilewright.config.ts` and an example test file. ## 4. Edit `mobilewright.config.ts`[​](#4-edit-mobilewrightconfigts "Direct link to 4-edit-mobilewrightconfigts") Set your app's bundle ID: ``` import { defineConfig } from 'mobilewright'; export default defineConfig({ platform: 'ios', bundleId: 'com.example.myapp', timeout: 10_000, }); ``` ## 5. Write a test[​](#5-write-a-test "Direct link to 5. Write a test") In `example.test.ts`: ``` import { test, expect } from '@mobilewright/test'; test('can sign in', async ({ device, screen, bundleId }) => { await device.terminateApp(bundleId).catch(() => {}); await device.launchApp(bundleId); await screen.getByLabel('Email').fill('user@example.com'); await screen.getByLabel('Password').fill('password123'); await screen.getByRole('button', { name: 'Sign In' }).tap(); await expect(screen.getByText('Welcome back')).toBeVisible(); }); ``` ## 6. Run the tests[​](#6-run-the-tests "Direct link to 6. Run the tests") ``` npx mobilewright test ``` Optional flags: ``` npx mobilewright test --reporter html # generate HTML report npx mobilewright test --retries 2 # retry flaky tests npx mobilewright show-report # open HTML report ``` ## Test failures[​](#test-failures "Direct link to Test failures") When a test fails, Mobilewright automatically takes a screenshot at the point of failure and attaches it to the report. ## Next steps[​](#next-steps "Direct link to Next steps") [Mobilewright Overview](https://mobilenext.ai/docs/docs/mobilewright/overview.md) | [Mobile Next Cloud](https://mobilenext.ai/docs/docs/cloud/overview.md) --- # Mobilewright [Mobilewright](https://mobilewright.dev) is a TypeScript/JavaScript automation framework for iOS and Android, inspired by Playwright's architecture and API. Full documentation is at [mobilewright.dev/docs](https://mobilewright.dev/docs). This page covers how to connect Mobilewright to **Mobile Next Cloud** to run your scripts and tests against real cloud devices instead of local simulators. ## Connect to Mobile Next Cloud[​](#connect-to-mobile-next-cloud "Direct link to Connect to Mobile Next Cloud") Mobilewright uses a `driver` config option to target cloud devices. When `MOBILENEXT_API_KEY` is set, add a `driver` block to your `mobilewright.config.ts`: ``` import { defineConfig, type MobilewrightConfig } from 'mobilewright'; const config: MobilewrightConfig = { platform: 'ios', bundleId: 'com.example.myapp', // ...rest of your config }; if (process.env['MOBILENEXT_API_KEY']) { config.driver = { type: 'mobilenext', apiKey: process.env['MOBILENEXT_API_KEY'], }; } export default defineConfig(config); ``` When `MOBILENEXT_API_KEY` is not set, Mobilewright falls back to a local device via mobilecli. This lets you run the same config locally and in CI without any code changes. ## Test result metadata[​](#test-result-metadata "Direct link to Test result metadata") The driver config accepts an optional `testResult` block to label runs in the Mobile Next Cloud dashboard: ``` config.driver = { type: 'mobilenext', apiKey: process.env['MOBILENEXT_API_KEY'], testResult: { name: 'Smoke suite', tags: ['nightly'], environment: 'production', }, }; ``` ## Get an API key[​](#get-an-api-key "Direct link to Get an API key") Get your API key at [app.mobilenext.ai](https://app.mobilenext.ai). See [Mobile Next Cloud](https://mobilenext.ai/docs/docs/cloud/overview.md) for device allocation and account setup. --- # The mobile automation layer for AI agents and developers Control any iOS or Android device — real or virtual, local or cloud — from code, the CLI, or your AI agent. [Start with Mobile Next MCP](https://mobilenext.ai/docs/docs/cloud/introduction.md)[Browse the API](https://mobilenext.ai/docs/docs/api/intro.md) Open source · Works with Claude Code, Cursor, Codex, Gemini and others ## What do you want to do?[​](#what-do-you-want-to-do "Direct link to What do you want to do?") [⚡](https://mobilenext.ai/docs/docs/mobilewright/overview.md) [Automate & test apps](https://mobilenext.ai/docs/docs/mobilewright/overview.md) [Write end-to-end tests with **Mobilewright**, a Playwright-style automation framework for iOS and Android.](https://mobilenext.ai/docs/docs/mobilewright/overview.md) [→](https://mobilenext.ai/docs/docs/mobilewright/overview.md) [🤖](https://github.com/mobile-next/mobile-mcp) [Give my agent a device](https://github.com/mobile-next/mobile-mcp) [Hand a local device to any AI agent with **Mobile MCP** — open source, no cloud account needed.](https://github.com/mobile-next/mobile-mcp) [→](https://github.com/mobile-next/mobile-mcp) [⌨️](https://github.com/mobile-next/mobilecli) [Script devices from the terminal](https://github.com/mobile-next/mobilecli) [Use **MobileCLI**, one Go binary that replaces `simctl`, `adb`, and `go-ios`.](https://github.com/mobile-next/mobilecli) [→](https://github.com/mobile-next/mobilecli) [☁️](https://mobilenext.ai/docs/docs/cloud/overview.md) [Use cloud devices](https://mobilenext.ai/docs/docs/cloud/overview.md) [Allocate real iOS and Android devices on demand with **Mobile Next Cloud** — no hardware setup.](https://mobilenext.ai/docs/docs/cloud/overview.md) [→](https://mobilenext.ai/docs/docs/cloud/overview.md) ## The products[​](#the-products "Direct link to The products") **MobileCLI** — One Go binary that replaces `simctl`, `adb`, and `go-ios`. Supports CLI, JSON-RPC over WebSocket, and JSON-RPC over HTTP. [Get started](https://github.com/mobile-next/mobilecli) **Mobilewright** — TypeScript/JavaScript automation framework for iOS and Android, built upon Playwright. Auto-waiting, semantic locators, cross-platform. Works locally and with cloud devices. [Get started](https://mobilenext.ai/docs/docs/mobilewright/overview.md) **Mobile MCP** — Open-source MCP server that gives AI agents direct control of local iOS and Android devices. No cloud account needed. [Get started](https://github.com/mobile-next/mobile-mcp) **Mobile Next Cloud** — Cloud device farm. Allocate real iOS and Android devices on demand. No hardware setup. Accessible via MCP, REST API, or the web dashboard at app.mobilenext.ai. [Get started](https://mobilenext.ai/docs/docs/cloud/overview.md) For AI agents Use [llms.txt](https://mobilenext.ai/docs/docs/llms.txt) for the documentation index and [llms-full.txt](https://mobilenext.ai/docs/docs/llms-full.txt) for the full text in one file. Append `.md` to any page URL to get its raw markdown. ---