Skip to main content

AndroidNexus API

The AndroidNexus API provides programmatic access to manage your Android device fleet. Use it to automate device management, integrate with your existing tools, and build custom solutions.

Base URL​

https://api.androidnexus.ai/api/v1

Build your integration against staging first. It carries its own enterprises and devices and behaves exactly like production:

https://staging-api.androidnexus.ai/api/v1

Building a customer-facing UI on this API? Start with Build your own frontend, which covers holding the key server-side, enrollment, embedded remote control and webhooks.

Authentication​

Create an API key in the AndroidNexus console and send it as a bearer token on every request:

curl https://api.androidnexus.ai/api/v1/devices \
-H "Authorization: Bearer nxk_..."

Organization owners and admins create and revoke API keys under Settings. Store a key in a secret manager and rotate it by creating a new key and deleting the old one.

An API key is an administrator credential

Every API key carries full administrator authority over your enterprise, whoever created it. It can read and change every device, policy and private app, start remote control, and factory reset hardware, and the scopes shown when a key is created do not narrow what it can reach.

Keep it on a server you control. Never ship it to a browser or a mobile app. See Roles and Permissions.

note

Every endpoint in this reference accepts an API key. API keys, users and team members are managed in the console by a signed-in person; those endpoints refuse an API key with 403 unauthorized_principal_kind.

Response Format​

Every response shares one envelope.

Success Response​

{
"status": "success",
"data": {},
"metadata": {
"timestamp": "2026-01-01T00:00:00Z",
"request_id": "..."
}
}

Error Response​

{
"status": "error",
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid request format",
"details": {}
},
"metadata": {
"timestamp": "2026-01-01T00:00:00Z",
"request_id": "..."
}
}

Include the request_id when you contact support about a failed request.

Rate limits​

Requests are bounded in two places, and a refusal from either is an HTTP 429 carrying Retry-After in whole seconds. Honour that header and back off; retrying sooner is refused again.

BoundApplies toBudget
Per API keyevery authenticated request your key makes1000 a minute
Per organizationstarting remote-control sessions, across every key and every console operator120 a minute
Per addresssign-in and token routes, at our network edge100 a minute
Per addressthe rest of the API, at our network edge3000 a minute

The first two belong to your credential and follow it whatever address you call from. The last two belong to the address you call from, so every integration sharing one egress address shares them.

The two kinds of refusal do not look alike, and your client has to handle both. A limit we apply answers with the ordinary error envelope:

HTTP/1.1 429 Too Many Requests
Content-Type: application/json
Retry-After: 37

{
"status": "error",
"error": {
"code": "api_key_rate_limited",
"message": "API key request budget exceeded"
},
"metadata": { "timestamp": "...", "request_id": "..." }
}

error.code is api_key_rate_limited or remote_control_rate_limited depending on which budget you spent.

A limit applied at the edge never reaches our API, so it carries no envelope, no request_id and no error.code. It is plain text:

HTTP/2 429
Content-Type: text/plain; charset=UTF-8
Retry-After: 51
Server: cloudflare

error code: 1015

So read the status code and Retry-After first, and only then try to parse the body. A client that assumes every response is JSON throws on this one. Server: cloudflare and the absence of status in the body are what tell the two apart if you need to.

Device agent traffic (heartbeats, telemetry, pending-command polls, compliance reports and bug-report uploads) is not bounded by the per-address limits, so a large fleet behind one corporate address is not throttled by its own size.

Pagination​

List endpoints accept these parameters:

ParameterDefaultDescription
page1Page number (starts at 1)
per_pagevariesItems per page (max 100)

Paginated responses report page, per_page, total and total_pages.

Quick Start Examples​

List Devices​

curl "https://api.androidnexus.ai/api/v1/devices?page=1&per_page=20" \
-H "Authorization: Bearer $ANDROIDNEXUS_API_KEY"

Get Device Details​

curl "https://api.androidnexus.ai/api/v1/devices/$DEVICE_ID" \
-H "Authorization: Bearer $ANDROIDNEXUS_API_KEY"

Send a Lock Command​

curl -X POST "https://api.androidnexus.ai/api/v1/devices/$DEVICE_ID/commands" \
-H "Authorization: Bearer $ANDROIDNEXUS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"command_type": "lock_device"}'

SDK Examples​

Python​

import os
import requests

BASE_URL = "https://api.androidnexus.ai/api/v1"
session = requests.Session()
session.headers["Authorization"] = f"Bearer {os.environ['ANDROIDNEXUS_API_KEY']}"

devices = session.get(f"{BASE_URL}/devices").json()

session.post(
f"{BASE_URL}/devices/{device_id}/commands",
json={"command_type": "lock_device"},
)

JavaScript​

const BASE_URL = 'https://api.androidnexus.ai/api/v1';
const headers = {
Authorization: `Bearer ${process.env.ANDROIDNEXUS_API_KEY}`,
'Content-Type': 'application/json',
};

async function listDevices() {
const response = await fetch(`${BASE_URL}/devices`, { headers });
return response.json();
}

async function sendCommand(deviceId, commandType) {
const response = await fetch(`${BASE_URL}/devices/${deviceId}/commands`, {
method: 'POST',
headers,
body: JSON.stringify({ command_type: commandType }),
});
return response.json();
}

Command Types​

POST /devices/{deviceId}/commands runs the quick actions the console offers on a device:

command_typePayloadEffect
lock_devicenoneLock the device screen
restart_devicenoneRestart the device
factory_resetnoneFactory reset the device and remove it from management
remove_work_profilenoneRemove the work profile (work profile and COPE devices)
amapi_issue_command{"type": "RESET_PASSWORD", "newPassword": "...", "resetPasswordFlags": [...]}Reset the device password; both fields are optional
amapi_issue_command{"type": "CLEAR_APP_DATA", "clearAppsDataParams": {"packageNames": ["..."]}}Clear the named apps' data
amapi_issue_command{"type": "START_LOST_MODE", "startLostModeParams": {...}}Start lost mode with the message, phone number, email and address to show
amapi_issue_command{"type": "STOP_LOST_MODE"}Stop lost mode

An optional priority (low, normal, high, urgent) can accompany any command.

Need Help?​

  • API Reference: Browse the complete API documentation in this section
  • Support: Contact [email protected]