POST /sessions accepts a request and returns 202. Use GET /sessions/{sid} to follow it.
A session is a temporary Android phone (the default), your saved Android phone (profile_id, see Android), or your own iPhone (platform: "ios", see iPhone). Everything below applies to all of them.
After removal from the active runtime,
GET /sessions/{sid} returns 404. Use the durable create receipt or history to inspect the completed request. A 404 alone is not a cleanup receipt.
Three different clocks
timeout_seconds defaults to 300 seconds. Pass a positive integer to select a different finite duration. Extremely large durations that cannot form a supported timestamp are rejected. There is no unlimited mode or session-extension endpoint.
Use the returned expires_at Unix timestamp, in seconds, as the session’s deadline. Reloading the dashboard, polling the API, sending input, or requesting another viewer does not extend it. Current sessions with a selected deadline do not use a separate inactivity cutoff.
Readiness is not the first video frame
ready means API operations can attach to the phone. Opening the browser viewer also requires obtaining a viewer URL, establishing the connection, and displaying video. Measure first visible frame separately if you are measuring the browser experience.
age_s measures session age. ready_age_s is zero until ready, then measures elapsed ready time up to closure. Neither is a direct input-latency measurement.
End and cleanup
CallDELETE /sessions/{sid} when your workflow finishes, including when it fails. Closure stops new API operations and records the end of billable use. Cleanup can continue after the request returns.
200,released: true: cleanup is confirmed.202,cleanup_pending: true: closure is accepted; cleanup is pending.cleanup_status: allocation_uncertain: the service is still reconciling an uncertain allocation. Do not assume it is gone.
GET /sessions/requests/{request_key} until cleanup_complete is true. Capacity can remain occupied while cleanup is pending.
Your workflow should also tolerate early closure from exhausted credits, access revocation, service recovery, or startup failure. A selected duration is an upper bound, not a guarantee against interruptions.
What survives a session
A temporary phone keeps nothing: app installations, logins and files end with the session, so store screenshots or test outputs in your own system before ending it. Your saved Android phone keeps all of that between sessions, and your iPhone is never wiped at all.One idempotency key per logical Start
Send anIdempotency-Key header with POST /sessions. Use 16–128 ASCII letters, digits, underscores, or hyphens. A UUID is a suitable value.
The key belongs to your account. Replaying the same key with the same parsed JSON body returns the existing session identity instead of allocating another phone. JSON key ordering does not matter; changing fields or adding a formerly omitted default does.
Recover an ambiguous create
If your connection drops after sending the request, you may not know whether a phone was created. Look up the key:Illustrative response
id to continue polling. If no receipt is found, retry the original POST with the same key and body. Even if the earlier request arrives late, the key prevents a second allocation for that logical request.
Do not immediately generate another key because a request timed out.