Concepts
Phones, sessions, statuses, parking, timers, billing and limits.
Phones
A phone is a persistent Android device in the cloud. Its ID starts with ph_, as in ph_7kx2m6q4v3ta. A phone keeps its installed apps, files and signed-in accounts for as long as it exists, whether it is running or parked. It is gone only when you delete it, or when it fails, because a failed phone can't be started again.
You can give a phone a name and up to 20 metadata pairs of your own, such as a customer ID, and find phones by them later. A phone can also ask for a country when you create it: where it appears to be, from the list that GET /v1/account returns.
Sessions
A session is one billed period on one phone, from the moment it starts until it parks. Its ID starts with ses_. Creating a phone opens its first session, and each start after a park opens a new one. While a session is open, the phone's session field shows when it started, its timers and when it will park. GET /v1/phones/{id}/sessions lists a phone's sessions with what each one cost.
Statuses
| Status | Meaning | Billed |
|---|---|---|
creating | The phone is being set up for the first time. This often takes about a minute. | Yes |
starting | The phone is resuming after a park, or restarting after a reboot. | Yes |
ready | The phone's screen and a screenshot have both answered, so you can use it. | Yes |
parking | A park was requested and the device is stopping. | No: billing stopped when the park was requested. |
parked | The phone is stopped. Its apps, files and sign-ins are kept. | No |
unavailable | The phone is under maintenance, or its state is unknown. Its session was closed, and you can start it again later. | No |
failed | Setting up the phone failed, or its device was lost. The phone's failure field says why. It can't be used again, so create a new phone, with a new idempotency key if you created this one with a key. | No |
deleted | You deleted the phone. This can't be undone. | No |
Only a ready phone accepts screen, action, app, file and device requests. Any other status answers with an error whose next field names the way forward, such as starting the phone.
Parking and timers
Parking stops a phone and its billing while keeping everything on it. Park a phone yourself whenever you're done with it. Phonebox also parks it for you:
- A phone parks when its
idle_timeouthas passed since itslast_active_at: the moment it became ready, or the last time a request addressed it since. The default is 300 seconds, and you can choose from 60 to 3600. - A phone parks when its session reaches its
max_duration, however busy it is. The default is up to 900 seconds, shortened automatically to available credit and the monthly spending limit, and you can choose from 60 to 10800, which is three hours.
Any API or MCP request that addresses a ready phone counts as activity, including reads, and so does a live view that is open on it. Three kinds of request don't count: a long poll that waits for the phone to park, a request refused with 401 or 403, and any request made with a key that is revoked or expired. last_active_at moves to the time of a request at most once every 15 seconds, so a phone can park up to about 15 seconds sooner than idle_timeout after your last request. The phone's session.parks_at field says when it will park, which is last_active_at plus idle_timeout or the session's deadline, whichever comes first, and park_reason says which rule will park it: idle or max_duration.
You set both timers when you create or start a phone. Starting a phone that is already running renews it: its deadline moves to max_duration from now. Phonebox also parks running phones when a project is frozen or during maintenance.
Billing
A phone costs $0.06 a minute, which is $0.001 a second, while it is creating, starting or ready. Billing is per second, with a 60-second minimum for each session. A parked phone costs nothing.
The clock starts when Phonebox accepts your create or start request. It stops when you ask to park, when Phonebox decides to park the phone, or when the phone becomes unavailable or fails. Any time the device takes to stop after that is not billed.
A session that ends before the phone was ever ready costs nothing, unless you parked or deleted the phone yourself. In that case it is billed like any other session.
Reservations
When a session starts, Phonebox reserves credit for its whole max_duration: $3.60 for the default hour. The session's reserved_usd field shows the amount. When the session ends, you're charged for the seconds it ran, never more than the reservation, and the rest is released. Renewing a running phone reserves only the extra time.
If your balance, minus what is already reserved, can't cover a new reservation, the request fails with 402 insufficient_credits. Its details.max_affordable_seconds says the longest max_duration you can afford right now. Because of the reservation, your balance can never go below zero.
Spending limit
Each project has a monthly spending limit, $100 by default, which you change in the console's Settings. A session whose reservation would take the month's spending past the limit fails with 402 spend_limit_reached. A limit of $0 stops all spending.
You buy credits in Billing, from $10 to $1,000 at a time. Credits don't expire, and there are no subscriptions or automatic top-ups. GET /v1/account shows your balance, what is reserved and what you spent this month:
{
"project": "Checkout QA",
"balance_usd": "21.400000",
"reserved_usd": "3.600000",
"spend_limit_usd": "100.000000",
"spent_this_month_usd": "4.120000",
"limits": { "phones": 10, "running": 2 },
"running": 1,
"phones": 3,
"price": { "per_minute_usd": "0.060000", "minimum_seconds": 60 },
"countries": [{ "code": "AR", "name": "Argentina" }, { "code": "US", "name": "United States" }]
}The API writes money as a decimal string of US dollars with six places, so that no amount is rounded.
Limits
| Limit | Default | When you exceed it |
|---|---|---|
| Phones in a project, not counting deleted or failed ones | 10 | 409 phone_limit_reached |
| Phones running at once | 2, which you can lower in Settings | 409 running_limit_reached |
| Requests | 600 a minute for each API key | 429 rate_limited with Retry-After |
| Creates, starts, parks and deletes | 60 a minute for each project | 429 rate_limited with Retry-After |
| Actions in one batch | 20, with at most 60 seconds of waiting | 400 validation_failed |
| File uploads and downloads | 4 MB | 413 payload_too_large |
| Live link lifetime | 60 seconds to 24 hours, 1 hour by default | 400 validation_failed |
| Monthly spending | $100 | 402 spend_limit_reached |
| Active API keys | 50 | The console refuses a new key. |
The running limit counts all of your projects together. To run more phones at once, email team@phonebox.dev. A failed phone holds no device, so it doesn't count toward the phone limit. When Phonebox as a whole has no phones free, a create or a start fails with 503 capacity_unavailable. Its retryable field says what that means. When it is true, nothing is lost: wait for Retry-After, about 30 seconds, and send the same request again, a few times at most. That covers a create that was refused, which made no phone, and a start whose phone parked again, which you start again with its apps and sign-ins. When it is false, a new phone could get no device and has failed, so its status is failed: create another phone with a new key. A phone is gone only when its status is failed or deleted, never because an error names it in details.phone.
One agent per phone
Phonebox doesn't lock a phone to one caller. If two agents act on the same phone at once, each acts on screens the other changed. Give each agent its own phone, and each end user their own phone too, so that their apps and sign-ins stay apart.