REST API¶
The customer REST API is served from the regional URL assigned to the rental. Examples use
https://uswest1.aimlib.com.
Authentication¶
Send the customer API key as a bearer token on every /v1 request:
API keys can carry these scopes:
| Scope | Allows |
|---|---|
proxies.read |
List leased devices, proxy endpoints, browser state, and footprints |
sessions.write |
Start and stop browsers, set footprints, rotate IPs, switch carriers, and poll those operations |
Ticket routes require an authenticated active customer but no additional scope. A missing, expired,
revoked, or malformed key returns 401 with {"error":"unauthorized"}. A missing scope returns
403 with {"error":"forbidden"}.
Common behavior¶
- Request and response bodies use JSON unless noted.
- Customer keys are limited to 6,000 requests per hour. A limit response is
429and can includeRetry-After. - UUID path values are strings.
- Timestamps are ISO 8601 UTC values.
- Unknown or cross-account resource identifiers return the resource's normal not-found response.
- Do not log bearer tokens, proxy URLs, or browser connection tokens.
GET /v1/devices¶
Lists devices in the caller's active rentals. Requires proxies.read.
Response: 200 OK.
[
{
"device_id": "550e8400-e29b-41d4-a716-446655440000",
"region": "uswest1",
"carrier": "tmobile",
"current_egress_ip": "203.0.113.45",
"lease": {
"id": "660e8400-e29b-41d4-a716-446655440000",
"ends_at": "2026-12-31T23:59:59Z"
},
"proxy": {
"id": "770e8400-e29b-41d4-a716-446655440000",
"protocols": ["http", "socks5"],
"http_url": "http://user:password@uswest1.aimlib.com:43117",
"socks5_url": "socks5://user:password@uswest1.aimlib.com:43117",
"socks5h_url": "socks5h://user:password@uswest1.aimlib.com:43117",
"status": "active"
},
"browser": {"available": true}
}
]
proxy.url and proxy.protocol can also appear for compatibility. New clients should use
http_url, socks5_url, or socks5h_url; all three identify the same listener and credentials.
proxy is absent while endpoint setup is incomplete. current_egress_ip is the latest public
address observed for the rental and can change.
POST /v1/devices/{id}/browser¶
Creates the remote-browser session for a leased device. Requires sessions.write. An empty JSON body
is valid.
| Field | Type | Behavior |
|---|---|---|
ttl |
integer seconds | Defaults to and is capped at 1,800 seconds; also capped by rental end |
idle_timeout |
integer seconds | Defaults to 120 seconds |
footprint |
string | Optional slug returned by the footprints endpoint |
Response: 201 Created.
{
"session_id": "880e8400-e29b-41d4-a716-446655440000",
"status": "provisioning",
"connect_url": "<authenticated-connection-url>",
"connect_token": "<session-secret>",
"region": "uswest1",
"ready_in_s": 30,
"egress_ip": null,
"expires_at": "2026-07-14T20:10:00Z",
"desired_footprint": "pixel-9",
"max_tabs": 5
}
Important errors:
| Status | Code | Meaning |
|---|---|---|
400 |
footprint_not_clean |
Footprint is not available for this device |
403 |
lease_inactive |
The active-rental requirement is not met |
409 |
browser_unavailable |
Remote browser is not currently available |
409 |
data_cap_exceeded |
The account's usage allowance is exhausted |
429 |
capacity_unavailable |
Device or account session capacity is in use |
503 |
browser_unavailable |
Browser is temporarily unreachable; retry shortly |
GET /v1/devices/{id}/browser¶
Returns the active remote-browser session for the caller's rented device. Requires proxies.read.
Poll until status is ready before connecting.
Response: 200 OK.
{
"session_id": "880e8400-e29b-41d4-a716-446655440000",
"status": "ready",
"connect_url": "<authenticated-connection-url>",
"egress_ip": "203.0.113.45",
"expires_at": "2026-07-14T20:10:00Z",
"started_at": "2026-07-14T20:00:22Z",
"desired_footprint": "pixel-9",
"applied_footprint": "pixel-9"
}
No active session returns 404 with {"error":"session_not_found"}. The connection token is
returned only by the create call.
DELETE /v1/devices/{id}/browser¶
Requests a stop for the active remote-browser session. Requires sessions.write.
Response: 200 OK.
No active session returns 404 with {"error":"session_not_found"}. Poll the browser endpoint until
it returns 404 when stop completion matters.
GET /v1/devices/{id}/footprints¶
Lists footprint choices available for the rented device. Requires proxies.read.
Response: 200 OK.
{
"device_id": "550e8400-e29b-41d4-a716-446655440000",
"footprints": [
{"slug":"pixel-9","name":"Google Pixel 9"}
]
}
No option is guaranteed across all devices. An inactive rental returns 403 with
{"error":"lease_inactive"}.
POST /v1/devices/{id}/footprint¶
Changes the desired footprint for the active browser session. Requires sessions.write.
Use an empty string to restore the device default. Response: 200 OK.
{
"session_id": "880e8400-e29b-41d4-a716-446655440000",
"desired_footprint": "pixel-9",
"applied_footprint": ""
}
Poll the browser endpoint until desired and applied values match. Without an active browser, the
response is 409 with {"error":"no_session"}. An unavailable option returns 400 with
{"error":"footprint_not_clean"}.
POST /v1/devices/{id}/rotate-ip¶
Requests a new public mobile IP. Requires sessions.write.
wait defaults to true. The accepted timeout range is normalized by the service. A completed
response is 200 OK:
{
"operation_id": "990e8400-e29b-41d4-a716-446655440000",
"type": "ip_rotation",
"status": "succeeded",
"new_ip": "203.0.113.86"
}
With wait:false, the response is 202 Accepted with operation_id and status:"queued". Poll the
operation endpoint. Network operations on one device must be at least 30 seconds apart; otherwise the
response is 429 with {"error":"rate_limited"}.
POST /v1/devices/{id}/carrier¶
Switches to a carrier available for the rental. Requires sessions.write.
Accepted identifiers are tmobile, att, and verizon. Device-specific availability still applies.
A successful 200 OK response can include carrier and new_ip. With wait:false, the response is
202 Accepted and can be polled. An invalid identifier returns 400 with {"error":"bad_carrier"}.
GET /v1/operations/{id}¶
Returns an IP-rotation or carrier-switch operation for a device in the caller's current active rental.
Requires sessions.write.
{
"operation_id": "990e8400-e29b-41d4-a716-446655440000",
"type": "carrier_switch",
"status": "running"
}
Statuses are queued, sent, running, succeeded, failed, or timeout. Successful responses can
include the allowlisted new_ip and carrier fields. Failed and timed-out responses include only a
stable public error and message. Invalid, unsupported, expired-rental, and cross-account IDs all return
404 with {"error":"operation_not_found"}.
POST /v1/tickets¶
Creates a support ticket. No extra scope is required.
Both fields are required. Response: 201 Created with the ticket and its first message.
GET /v1/tickets¶
Lists the caller's tickets without full message threads. No extra scope is required. Response:
200 OK with an array.
GET /v1/tickets/{id}¶
Returns one caller-owned ticket including messages. No extra scope is required. Missing and
cross-account IDs return 404 with {"error":"ticket_not_found"}.
POST /v1/tickets/{id}/messages¶
Adds a customer reply and reopens a closed ticket. No extra scope is required.
Response: 201 Created with the updated ticket and message thread.
POST /v1/tickets/{id}/close¶
Closes the ticket from the customer's side. No extra scope is required. Response: 200 OK. A ticket
is fully closed only after both the customer and aimlib support close it.
Error envelope¶
Request failures use a stable error code and can include a safe message:
Do not branch on human-readable messages. Use HTTP status plus error, and see
Limits and errors for retry guidance.