DroidDesk · API & MCP
DroidDesk API & MCP
Operate the Android phones you rent on DroidDesk from your own code or AI assistant.
- REST API
https://api.mobirent.io/v1- MCP (AI assistants)
https://api.mobirent.io/mcp- OpenAPI
https://api.mobirent.io/v1/openapi.json
Use a DroidDesk API key to connect your assistant or application. The key controls which rented phones and actions are available. Phone access depends on the active rental and the permissions chosen when creating the key.
For AI assistants, connect the MCP endpoint. For direct integration, use the REST endpoints below. Read the current screen before acting and inspect the operation status after each action.
Documentation for people and AI agents
Choose a guide to get started or a machine-readable reference for your integration.
- Complete MCP guide →
Connect your assistant and explore practical workflows. Markdown, in English.
- MCP tool reference →
Tool descriptions and input schemas for AI agents and developers.
- AI documentation index →
A concise, machine-readable starting point with links to the documentation.
- REST API schema →
OpenAPI JSON for applications, code generators and AI tools.
Have an old link? The previous guide address remains available and contains the same English guide.
Quick start
- Sign in to your DroidDesk account. Rent a phone before running device actions.
- Open the cabinet → AI & Tasks → AI / MCP → create a key. Copy the key: it is shown once.
- Connect your AI assistant (below), or call the API from your code.
export DROIDDESK_API_KEY="dd_live_…"
curl -H "Authorization: Bearer $DROIDDESK_API_KEY" https://api.mobirent.io/v1/phonesConnect your AI
DroidDesk uses remote MCP over Streamable HTTP. Choose a client that supports a bearer authorization header. Tasks using screenshots also require a model and client that can process images. Tool access depends on account features, key permissions and device availability.
Complete MCP guide for people and AI agents (Markdown) → · Tool reference and schemas →
claude mcp add --transport http droiddesk https://api.mobirent.io/mcp \
--header "Authorization: Bearer dd_live_…"[mcp_servers.droiddesk]
url = "https://api.mobirent.io/mcp"
bearer_token_env_var = "DROIDDESK_API_KEY"{
"mcpServers": {
"droiddesk": {
"url": "https://api.mobirent.io/mcp",
"headers": {
"Authorization": "Bearer dd_live_…"
}
}
}
}ChatGPT custom MCP connections use OAuth rather than a manually supplied DroidDesk API key. Direct ChatGPT integration is not yet verified. OpenAI Responses API supports remote MCP, but its compatibility with this server has not been verified here.
Keep your key private and revoke it if exposed. See the complete MCP guide for connection examples, device access, uploads, scenarios, SMS and troubleshooting.
MCP capabilities
Ask your assistant to list available tools after connecting. Capabilities depend on account settings and key permissions. Paid rentals require separate permission and a per-order limit. SMS requires your own connected provider account. CAPTCHA support is limited to supported challenge types.
- Devices and rental:
list_phones, phone_status, phone_info, phone_capabilities, list_available_phones, rent_phone, get_rental_order - Screen and actions:
get_screen, screenshot, list_apps, tap, type_text, swipe, press_key, launch_app, open_url, wait_for, get_operation - Templates and scenarios:
list_templates, validate_template, save_template, run_template, get_template_run, stop_template_run, list_scenarios, run_scenario, get_scenario_run, continue_scenario_run, stop_scenario_run, run_automation_mode - Files, SMS and CAPTCHA:
prepare_file_upload, file_transfer_status, sms_offers, sms_order, sms_status, sms_cancel, solve_text_captcha, get_text_captcha, solve_click_captcha, get_image_captcha - Getting started:
get_started
Files are transferred through a prepared upload and tracked to completion. If a transfer, paid order, CAPTCHA task or run returns an unknown result, inspect its status before repeating it.
Driving a phone
- Read the screen.
GET /phones/2018/screenreturns numbered elements and asnapshot_id. - Act on an element with its number and that
snapshot_id, e.g. tap element 2. If the screen changed meanwhile, you getstale_snapshotand nothing is tapped. - Use the new screen that comes back with every finished action, and repeat.
For requests that support an Idempotency-Key, use a new key for a new action and reuse it only for the identical request. An unknown outcome may have happened: inspect the operation and phone before deciding whether to repeat it.
Check the returned operation status and use a fresh screen snapshot when making the next decision.
Account
/meThe key and its account
curl "https://api.mobirent.io/v1/me" \
-H "Authorization: Bearer $DROIDDESK_API_KEY"{
"user_id": 4356,
"key": {
"id": "key_Ab12Cd34Ef56Gh78Ij90",
"name": "Claude Code",
"prefix": "dd_live_AbCd",
"scope": "control",
"phones": "all",
"created_at": "2026-10-28T12:00:00Z",
"expires_at": null,
"last_used_at": "2026-10-28T15:20:00Z",
"grace_until": null
}
}- 401
invalid_key,key_expired,key_revoked - 403
feature_disabled,balance_frozen - 429
rate_limited
Phones
/phonesPhones this key can use
Your live rentals and phones shared with you, limited to the phones the key is bound to.
curl "https://api.mobirent.io/v1/phones" \
-H "Authorization: Bearer $DROIDDESK_API_KEY"{
"phones": [
{
"phone": "2018",
"name": "Galaxy S22 · Las Vegas, US · T-Mobile 5G",
"model": "Galaxy S22",
"country": "US",
"city": "Las Vegas",
"carrier": "T-Mobile",
"network": "mobile",
"rental_ends_at": "2026-11-23T20:57:56Z",
"shared": false
}
]
}- 401
invalid_key,key_expired,key_revoked - 403
feature_disabled,balance_frozen - 429
rate_limited
/phones/{phone}/statusOnline, ready to control, rental time left
| Parameter | In | Description |
|---|---|---|
phone* | path | Phone number from GET /phones, e.g. 2018. |
curl "https://api.mobirent.io/v1/phones/2018/status" \
-H "Authorization: Bearer $DROIDDESK_API_KEY"{
"phone": "2018",
"online": true,
"control_ready": true,
"preparing": false,
"controller": "none",
"rental_ends_at": "2026-11-23T20:57:56Z",
"seconds_left": 2280000
}- 401
invalid_key,key_expired,key_revoked - 403
feature_disabled,balance_frozen - 404
phone_not_found - 409
rental_ended - 429
rate_limited - 503
access_check_unavailable
/phones/{phone}/infoStored device, network and approximate location details
Returns details for an authorized active rental. IP and location are stored observations, may be stale, and are not GPS.
| Parameter | In | Description |
|---|---|---|
phone* | path | Phone number from GET /phones, e.g. 2018. |
curl "https://api.mobirent.io/v1/phones/2018/info" \
-H "Authorization: Bearer $DROIDDESK_API_KEY"- 401
invalid_key,key_expired,key_revoked - 403
feature_disabled,balance_frozen - 404
phone_not_found - 409
rental_ended - 429
rate_limited - 503
access_check_unavailable
/phones/{phone}/capabilitiesWhat the phone supports
| Parameter | In | Description |
|---|---|---|
phone* | path | Phone number from GET /phones, e.g. 2018. |
curl "https://api.mobirent.io/v1/phones/2018/capabilities" \
-H "Authorization: Bearer $DROIDDESK_API_KEY"- 401
invalid_key,key_expired,key_revoked - 403
feature_disabled,balance_frozen - 404
phone_not_found - 409
rental_ended - 429
rate_limited - 503
access_check_unavailable
/phones/{phone}/appsApps you can open with launch_app
Apps your plan shows on this phone. System settings, installers, calls and SMS are never listed.
| Parameter | In | Description |
|---|---|---|
phone* | path | Phone number from GET /phones, e.g. 2018. |
curl "https://api.mobirent.io/v1/phones/2018/apps" \
-H "Authorization: Bearer $DROIDDESK_API_KEY"{
"apps": [
{
"package": "com.android.chrome",
"label": "Chrome"
},
{
"package": "com.instagram.android",
"label": "Instagram"
}
]
}- 401
invalid_key,key_expired,key_revoked - 403
feature_disabled,balance_frozen - 404
phone_not_found - 409
rental_ended - 429
rate_limited - 503
access_check_unavailable;apps_unavailable
Screen
/phones/{phone}/screenCurrent screen as numbered elements
Elements are the visible texts, buttons, fields and lists. Coordinates are in the screen frame. Up to 300 elements; truncated is true when there were more. Limit: 4 per second per phone.
| Parameter | In | Description |
|---|---|---|
phone* | path | Phone number from GET /phones, e.g. 2018. |
curl "https://api.mobirent.io/v1/phones/2018/screen" \
-H "Authorization: Bearer $DROIDDESK_API_KEY"{
"snapshot_id": "snp_Q2xk8vT1aB3c",
"taken_at": "2026-10-28T15:22:31Z",
"frame": {
"width": 720,
"height": 1600
},
"app": {
"package": "com.android.chrome"
},
"keyboard": false,
"truncated": false,
"elements": [
{
"n": 1,
"role": "edit",
"text": "",
"desc": "Search",
"bounds": [
40,
300,
680,
380
],
"click": true,
"edit": true
},
{
"n": 2,
"role": "button",
"text": "Google Search",
"bounds": [
120,
460,
360,
540
],
"click": true
}
]
}- 401
invalid_key,key_expired,key_revoked - 403
feature_disabled,balance_frozen - 404
phone_not_found - 409
rental_ended;phone_offline - 429
rate_limited - 502
bridge_unavailable - 503
access_check_unavailable
/phones/{phone}/screenshotJPEG screenshot
Prefer screen (cheaper, exact). Use screenshots for games, canvas apps or when elements are missing. Limit: 20 per minute per phone.
| Parameter | In | Description |
|---|---|---|
phone* | path | Phone number from GET /phones, e.g. 2018. |
max | query | Longest side in px. Default 1024. |
quality | query | JPEG quality. Default 60. |
curl "https://api.mobirent.io/v1/phones/2018/screenshot" \
-H "Authorization: Bearer $DROIDDESK_API_KEY"{
"mime": "image/jpeg",
"data": "/9j/4AAQSkZJRgABAQ…",
"width": 461,
"height": 1024
}- 401
invalid_key,key_expired,key_revoked - 403
feature_disabled,balance_frozen - 404
phone_not_found - 409
rental_ended - 429
rate_limited - 502
screenshot_failed - 503
access_check_unavailable
Actions
/phones/{phone}/actionsTap, type, swipe, press a key, open an app or a link
Needs a control key. Send a new Idempotency-Key for every new action; repeating a request with the same key returns the same operation and never acts twice. Actions on one phone run one at a time, in order. The response waits up to wait seconds: 200 when the operation finished (with the new screen), 202 while it is still running — then poll GET /operations/{id}. Limit: 5 actions per second per phone.
| Parameter | In | Description |
|---|---|---|
phone* | path | Phone number from GET /phones, e.g. 2018. |
Idempotency-Key* | header | 1–64 printable characters, unique per action. |
wait | query | Seconds to wait for the result. Default 10. |
curl -X POST "https://api.mobirent.io/v1/phones/2018/actions" \
-H "Authorization: Bearer $DROIDDESK_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"type":"tap","element":2,"snapshot_id":"snp_Q2xk8vT1aB3c"}'Body examples
Tap element 2 of a screen
{"type":"tap","element":2,"snapshot_id":"snp_Q2xk8vT1aB3c"}Type into element 1 and press Enter
{"type":"type_text","element":1,"snapshot_id":"snp_Q2xk8vT1aB3c","text":"weather in Paris","submit":true}Scroll down
{"type":"swipe","direction":"down"}Open a link
{"type":"open_url","url":"https://example.com"}Open an app
{"type":"launch_app","package":"com.android.chrome"}Go home
{"type":"press_key","key":"home"}Wait until a text appears
{"type":"wait_for","text":"Welcome","timeout_s":15}{
"operation": {
"id": "op_7fKq2LxPz9",
"type": "tap",
"phone": "2018",
"status": "succeeded",
"created_at": "2026-10-28T15:22:40Z",
"started_at": "2026-10-28T15:22:40Z",
"finished_at": "2026-10-28T15:22:41Z",
"screen": {
"snapshot_id": "snp_Q2xk8vT1aB3c",
"taken_at": "2026-10-28T15:22:31Z",
"frame": {
"width": 720,
"height": 1600
},
"app": {
"package": "com.android.chrome"
},
"keyboard": false,
"truncated": false,
"elements": [
{
"n": 1,
"role": "edit",
"text": "",
"desc": "Search",
"bounds": [
40,
300,
680,
380
],
"click": true,
"edit": true
},
{
"n": 2,
"role": "button",
"text": "Google Search",
"bounds": [
120,
460,
360,
540
],
"click": true
}
]
}
}
}- 401
invalid_key,key_expired,key_revoked - 403
feature_disabled,balance_frozen;insufficient_scope,app_hidden,url_scheme_not_allowed - 404
phone_not_found - 409
rental_ended;phone_offline - 422
invalid_request,idempotency_mismatch - 429
rate_limited - 503
access_check_unavailable
/operations/{id}Status of an action
The new screen is included for 10 minutes after the operation finished.
| Parameter | In | Description |
|---|---|---|
id* | path |
curl "https://api.mobirent.io/v1/operations/op_7fKq2LxPz9" \
-H "Authorization: Bearer $DROIDDESK_API_KEY"- 401
invalid_key,key_expired,key_revoked - 403
feature_disabled,balance_frozen - 404
operation_not_found - 429
rate_limited
Templates
/templatesList my templates
curl "https://api.mobirent.io/v1/templates" \
-H "Authorization: Bearer $DROIDDESK_API_KEY"- 403Not enabled or control access required
- 409Version conflict or device unavailable
- 422Invalid schema or parameters
/templatesCreate or version a private template
curl -X POST "https://api.mobirent.io/v1/templates" \
-H "Authorization: Bearer $DROIDDESK_API_KEY"- 403Not enabled or control access required
- 409Version conflict or device unavailable
- 422Invalid schema or parameters
/templates/validateValidate schema without operating a phone
curl -X POST "https://api.mobirent.io/v1/templates/validate" \
-H "Authorization: Bearer $DROIDDESK_API_KEY"- 403Not enabled or control access required
- 409Version conflict or device unavailable
- 422Invalid schema or parameters
/template-runsList my recent template runs
curl "https://api.mobirent.io/v1/template-runs" \
-H "Authorization: Bearer $DROIDDESK_API_KEY"- 403Not enabled or control access required
- 409Version conflict or device unavailable
- 422Invalid schema or parameters
/template-runsStart without AI; values are not retained in history
| Parameter | In | Description |
|---|---|---|
Idempotency-Key* | header |
curl -X POST "https://api.mobirent.io/v1/template-runs" \
-H "Authorization: Bearer $DROIDDESK_API_KEY"- 403Not enabled or control access required
- 409Version conflict or device unavailable
- 422Invalid schema or parameters
/template-runs/{id}Read run and step events
| Parameter | In | Description |
|---|---|---|
id* | path |
curl "https://api.mobirent.io/v1/template-runs/op_7fKq2LxPz9" \
-H "Authorization: Bearer $DROIDDESK_API_KEY"- 403Not enabled or control access required
- 409Version conflict or device unavailable
- 422Invalid schema or parameters
/template-runs/{id}/stopStop before the next action; an in-flight action may finish
| Parameter | In | Description |
|---|---|---|
id* | path |
curl -X POST "https://api.mobirent.io/v1/template-runs/op_7fKq2LxPz9/stop" \
-H "Authorization: Bearer $DROIDDESK_API_KEY"- 403Not enabled or control access required
- 409Version conflict or device unavailable
- 422Invalid schema or parameters
Errors
Errors share one shape: {"error": {"code": "phone_not_found", "message": "…", "retryable": false}}. Check code, not the message.
| HTTP | code | Meaning |
|---|---|---|
| 401 | invalid_key, key_expired, key_revoked | The key is wrong, expired, revoked, or was replaced and its 24-hour grace period is over. |
| 403 | feature_disabled | AI access is not enabled for the account yet. |
| 403 | insufficient_scope | A view-only key tried to act. |
| 403 | balance_frozen | The account balance is frozen; contact support. |
| 403 | app_hidden, url_scheme_not_allowed | The app is not available on your plan; only http(s) links can be opened. |
| 404 | phone_not_found | Not one of your rentals for this key (the API does not reveal other phones). |
| 409 | rental_ended, phone_offline | The rental is over, or the phone is not connected right now. |
| 422 | invalid_request, idempotency_mismatch | Bad parameters, or an Idempotency-Key reused for a different action. |
| 429 | rate_limited | Too many requests; wait for the Retry-After seconds. |
| 503 | access_check_unavailable, bridge_unavailable | Temporary; retry shortly. |
Limits
Limits depend on the account and operation. If a request is rate limited, follow the response and retry guidance. Check available capabilities for the selected phone.
OpenAPI file
The machine-readable description (OpenAPI 3.1) for Postman, code generators and AI tools: https://api.mobirent.io/v1/openapi.json
Questions: [email protected]
