A valid request URL is required to generate request examples{
"deviceId": "<string>",
"takeId": "<string>",
"source": "pool"
}{
"state": "preparing",
"takeId": "<string>",
"retryAfterMs": 123,
"message": "<string>"
}{
"error": {
"code": "backend_resolution_failed",
"message": "<string>",
"retryable": true
}
}{
"error": {
"code": "unauthorized",
"reason": "missing_credentials",
"hint": "<string>"
}
}{
"error": {
"code": "backend_resolution_failed",
"message": "<string>",
"retryable": true
}
}{
"error": {
"code": "not_found",
"message": "<string>"
}
}{
"error": {
"code": "fleet_at_capacity",
"message": "<string>"
},
"holding": 123,
"limit": 123,
"retryAfterMs": 123,
"takeId": "<string>"
}{
"error": {
"code": "payload_too_large",
"message": "<string>"
}
}{
"error": {
"code": "rate_limited",
"message": "<string>"
}
}{
"error": {
"code": "backend_resolution_failed",
"message": "<string>",
"retryable": true
}
}Take a device from the shared pool
For pay-as-you-go access. You did not buy a phone, you bought the right to use one, so there is no device of yours to list until you take one: this is the call that gets you a device for a session.
A free device is handed to you straight away. If none is free, one is prepared for you, and the call answers 202 rather than waiting: CALL IT AGAIN. Retrying is free and always safe. The same request is picked up where it left off however many times you send it, and nothing is ever ordered twice, so you do not need an idempotency key and there is none to send.
When you get a device, lease it with POST /v1/devices/{deviceId}/lease and drive it as normal. It is yours for that session only: RELEASING THE LEASE GIVES THE DEVICE BACK, and so does letting the lease expire. It then disappears from GET /v1/devices, and a later take may give you a different one. Nothing you leave on a device is kept for you between sessions.
Hosted deployments only. A local checkout does not mount this route, so calling it there is a 404.
A valid request URL is required to generate request examples{
"deviceId": "<string>",
"takeId": "<string>",
"source": "pool"
}{
"state": "preparing",
"takeId": "<string>",
"retryAfterMs": 123,
"message": "<string>"
}{
"error": {
"code": "backend_resolution_failed",
"message": "<string>",
"retryable": true
}
}{
"error": {
"code": "unauthorized",
"reason": "missing_credentials",
"hint": "<string>"
}
}{
"error": {
"code": "backend_resolution_failed",
"message": "<string>",
"retryable": true
}
}{
"error": {
"code": "not_found",
"message": "<string>"
}
}{
"error": {
"code": "fleet_at_capacity",
"message": "<string>"
},
"holding": 123,
"limit": 123,
"retryAfterMs": 123,
"takeId": "<string>"
}{
"error": {
"code": "payload_too_large",
"message": "<string>"
}
}{
"error": {
"code": "rate_limited",
"message": "<string>"
}
}{
"error": {
"code": "backend_resolution_failed",
"message": "<string>",
"retryable": true
}
}Authorizations
The control surface credential. Send Authorization: Bearer <token>.
Two kinds of token are accepted and they are told apart by shape, not by a separate header. A token beginning pbk_ is an org scoped API key, whose public half and secret half are generated together and of which only a hash of the secret is ever stored; anything else is treated as an OAuth 2.1 access token and verified against the authorization server's keys.
Both resolve to the same context: an org, a principal and a set of scopes. Nothing downstream branches on which channel you used, with one deliberate exception, key management, which requires a signed-in person so that a key can never mint another key.
Scopes are enforced when MCP tools are REGISTERED rather than when they are called, so a tool your credential cannot use is absent from tools/list rather than refused mid gesture.
Body
What kind of device you want. Send {} or nothing at all for the usual one.
The kind of device to take. Defaults to a cloud phone.
Response
A device is yours for this session. Lease it next.