# Quickstart

> From zero to your agent tapping on a real Android phone, in five calls with curl.

Source: https://fones.ai/docs/quickstart

Five calls: check the catalog, buy a phone, wait for it, look at the screen, tap. Then hand the phone to your agent over MCP.

## 1. Get a key

Sign in at [fones.ai/login](https://fones.ai/login) with your email, top up the balance (from $10) and create an API key under Developers. The key is shown once. Keep it in an environment variable:

```bash
export FONES_API_KEY=fones_...   # from Developers, API keys
export API=https://api.fones.ai/v1
```

New keys have every scope: `phones:read`, `phones:control` and `phones:buy`. Create a key without `phones:buy` for an agent that should never spend.

## 2. Check the catalog

```bash
curl $API/catalog -H "Authorization: Bearer $FONES_API_KEY"
```

The answer lists the tiers (`cloud`, `identity`), the models you can pick for a real phone identity, the prices in cents and your balance.

## 3. Buy a phone

```bash
curl -X POST $API/phones \
  -H "Authorization: Bearer $FONES_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: first-phone" \
  -d '{"tier":"cloud","number":true,"label":"first"}'
```

```json
{
  "id": "ph_7k2m9q",
  "label": "first",
  "tier": "cloud",
  "status": "provisioning",
  "number": null,
  "number_status": "provisioning",
  "ip": null,
  "proxy_status": null,
  "monthly_cents": 2800
}
```

The first month ($19 for the phone, $9 for the number) comes from the balance now. Send the same `Idempotency-Key` again and you get the same phone, never a second one. The phone starts as `provisioning`.

## 4. Wait until it is ready

```bash
curl $API/phones/ph_7k2m9q -H "Authorization: Bearer $FONES_API_KEY"
```

When `status` is `ready`, the phone has its number and, if you asked, its static IP (one that could not be set up is refunded instead, with `number.failed` or `proxy.failed`: the phone is ready all the same). With a [webhook](https://fones.ai/docs/webhooks) you get `phone.ready` instead of polling. If setup fails you get `phone.failed` and the charge back.

## 5. Look, then act

```bash
curl $API/phones/ph_7k2m9q/screenshot -H "Authorization: Bearer $FONES_API_KEY" -o screen.png
curl $API/phones/ph_7k2m9q/ui -H "Authorization: Bearer $FONES_API_KEY"
```

`ui` returns the screen as nodes: text, id, class, whether it is clickable, and its center on the 0 to 1000 grid. Tap one:

```bash
curl -X POST $API/phones/ph_7k2m9q/actions \
  -H "Authorization: Bearer $FONES_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"type":"tap","x":500,"y":418}'
```

That is the whole loop: look, act, look again. In code:

```ts
const api = (path: string, init: RequestInit = {}) =>
  fetch(`https://api.fones.ai/v1${path}`, {
    ...init,
    headers: { Authorization: `Bearer ${process.env.FONES_API_KEY}`, 'Content-Type': 'application/json' },
  }).then((r) => r.json());

const phone = 'ph_7k2m9q';
const { nodes } = await api(`/phones/${phone}/ui`);          // look
const button = nodes.find((n) => n.text === 'Send code');
await api(`/phones/${phone}/actions`, {                        // act
  method: 'POST',
  body: JSON.stringify({ type: 'tap', x: button.x, y: button.y }),
});
const sms = await api(`/phones/${phone}/sms`);                // look again
console.log(sms.data[0]?.code);
```

```python
import os, requests

api = "https://api.fones.ai/v1"
s = requests.Session()
s.headers["Authorization"] = f"Bearer {os.environ['FONES_API_KEY']}"

phone = "ph_7k2m9q"
nodes = s.get(f"{api}/phones/{phone}/ui").json()["nodes"]          # look
button = next(n for n in nodes if n["text"] == "Send code")
s.post(f"{api}/phones/{phone}/actions",                            # act
       json={"type": "tap", "x": button["x"], "y": button["y"]})
sms = s.get(f"{api}/phones/{phone}/sms").json()["data"]           # look again
print(sms[0]["code"] if sms else None)
```

## Next

- [Connect your agent](https://fones.ai/docs/connect) and let it drive the phone itself.
- [MCP tools](https://fones.ai/docs/mcp) and the [REST API](https://fones.ai/docs/api) for every action.
- When you are done, `DELETE /v1/phones/ph_7k2m9q` stops the renewal; the phone runs to the end of the paid 30 days.
