# Phones

> Allocate cloud Android phones over the API, start and stop them, and release them. Each is paid for monthly, or hourly billed per minute while it runs.

You allocate phones to your workspace, in the console or over the API, and keep them until you release them. Each is paid for from your balance, monthly, or hourly billed per minute while it runs; see [Billing](https://distilled.cx/docs/billing/). A phone that is running and `READY` takes actions and runs.

## Allocating phones

To allocate, pick a `profileId` from `GET /v1/catalog` and ask for 1 to 50 phones of it. You get all of them or none. `plan` is `monthly` or `payg`, and `payg` when left out. Your balance must cover the new phones, or the request answers `402 payment-required`.

```bash
curl https://api.distilled.cx/v1/phones \
  -H "Authorization: Bearer $DISTILLED_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: first-phones-0001" \
  -d "{ \"profileId\": \"$PROFILE_ID\", \"count\": 2, \"plan\": \"monthly\" }"
```

Phone:

```json
{
  "id": "phone-1",
  "status": "assigned",
  "plan": "monthly",
  "paidThrough": "2026-10-23T09:41:12.000Z",
  "profileId": "<a profileId from GET /v1/catalog>",
  "androidVersion": 16,
  "phase": "READY",
  "running": true,
  "stoppedForBalance": false,
  "region": "us",
  "exit": { "kind": "distilled", "country": "US" },
  "createdAt": "2026-09-23T09:41:12.000Z"
}
```

- `id` (string): Use this everywhere the API asks for a phone.
- `status` (string): `assigned`, or `stopped` when it has been switched off.
- `profileId` (string): The device the phone presents: maker, codename, Android version and build.
- `androidVersion` (integer): 13, 14, 15 or 16.
- `phase` (string | null): Where the phone is in starting up. `READY` means it can be used.
- `running` (boolean): Whether the phone is on right now.
- `stoppedForBalance` (boolean): Stopped because the balance ran out. It starts again once you top up.
- `region` (string | null): Where the phone runs.
- `exit` (object): Where its traffic leaves: `distilled` for our network, or `proxy` with the proxy's id. See [Proxies](https://distilled.cx/docs/proxies/).
- `createdAt` (string): When the phone was made, in ISO 8601.

## Endpoints

- `GET /v1/catalog` (scope `phones:read`): The devices you can allocate, the regions with free slots, and a phone's monthly price in US cents.
- `GET /v1/phones` (scope `phones:read`): Every phone in the workspace.
- `POST /v1/phones` (scope `phones:write`): Allocates `{ profileId, count, region? }` and answers 201 with `{ phones }`. Without `region`, any region with room. Send an `Idempotency-Key` to make a retry safe. Answers 503 when there are not that many free slots, and allocates none.
- `GET /v1/phones/{id}` (scope `phones:read`): One phone.
- `DELETE /v1/phones/{id}` (scope `phones:write`): Releases the phone: it is removed and its data wiped at once, and it stops costing.
- `POST /v1/phones/{id}/stop` (scope `phones:write`): Switches the phone off. Its apps and data are kept.
- `POST /v1/phones/{id}/start` (scope `phones:write`): Switches it on again. Answers 402 while the balance is used up.
- `POST /v1/phones/{id}/restart` (scope `phones:write`): Recreates the phone's container. Apps, data and identity stay.
- `POST /v1/phones/{id}/respoof` (scope `phones:write`): Gives the phone a new device identity. Send `{ "wipe": true }` to delete its apps and data as well.
- `GET /v1/phones/{id}/location` (scope `phones:read`): Where the phone's GPS says it is: the point it is asked to be at (`location`), whether that is still on its way (`pending`), the fix its Android last acknowledged (`applied`), and what last went wrong (`error`).
- `PUT /v1/phones/{id}/location` (scope `phones:write`): Puts the GPS back near the exit with `{ "mode": "exit" }`, or pins it to a point with `{ "mode": "manual", "latitude": 37.7749, "longitude": -122.4194 }`. Answers the location as it now stands.

Stopping, starting and restarting answer `409` while a run or a lease holds the phone. When your balance runs out, running phones stop and start again once you top up; a phone still stopped for balance after a week is removed with its data.

## Location

Each phone also has a place. Unless you set one, its GPS sits near wherever its traffic exits, and follows the exit when it moves or drifts. A manual point holds however its exits move, and survives restarts until it is put back on automatic. A fresh fix reaches the phone on its next sync, usually within about a minute, and apps still need the location permission they always did to read it.

Source: https://distilled.cx/docs/phones/
