> ## Documentation Index
> Fetch the complete documentation index at: https://docs.run.cloud/llms.txt
> Use this file to discover all available pages before exploring further.

# Simulator agent integration

> Connect an assistant to run.cloud: authentication, mobile sessions, controls, billing, and review prompts

Use this page when integrating run.cloud with an assistant or reviewing a
simulator connector. The scope is iOS simulators and Android emulators: start a
device, inspect its screen, send input, and release it when the task is done.

## Connection contract

An assistant needs a terminal that can run `runcloud`, or a Node.js runtime that
can use `@run-cloud/sdk`. Use the released CLI and SDK rather than implementing
their underlying HTTP calls yourself. The default API origin is
`https://api.run.cloud`.

| Interface         | Use                                                                        |
| ----------------- | -------------------------------------------------------------------------- |
| `runcloud` CLI    | Terminal tools and coding agents; use `--json` where available.            |
| `@run-cloud/sdk`  | Typed tools in an assistant's Node.js runtime.                             |
| Simulator skill   | Instructions for choosing commands, handling credentials, and cleaning up. |
| Local A2A adapter | Agent2Agent 1.0 JSON-RPC using the official A2A SDK; see below.            |

<Note>
  The local adapter is an Agent2Agent (A2A) protocol connection, distinct from
  calling the CLI or SDK directly. It is not a hosted public A2A endpoint or
  MCP server. A platform must be able to run it alongside the calling agent;
  contact [support@run.cloud](mailto:support@run.cloud) if it requires a remote URL.
</Note>

Install the simulator skill if your platform supports skills:

```bash theme={null}
npx skills add newly-app/run-cloud-examples --skill run-cloud-ios-simulator
```

See [Agent Skills](/skills/agents) for additional runtimes and installation options.

## Standard Agent2Agent connection

The public [A2A simulator example](https://github.com/newly-app/run-cloud-examples/tree/main/a2a-simulator)
uses the official `@a2a-js/sdk` client and server with the published run.cloud
SDK. Start it locally with Node.js 20 or newer:

```bash theme={null}
git clone --depth 1 https://github.com/newly-app/run-cloud-examples.git
cd run-cloud-examples/a2a-simulator
npm ci
npm test
npm start
```

The agent card is at `http://127.0.0.1:3100/.well-known/agent-card.json` and
advertises the A2A 1.0 JSON-RPC endpoint at `/a2a`. Every operation requires
the caller's own run.cloud API key as a Bearer credential. The adapter never
substitutes an operator's key. Keep it on loopback; do not expose it as an
unsecured public service.

Send one structured data part, for example:

```json theme={null}
{"operation":"create","platform":"ios","orgId":"your-organization","idempotencyKey":"your-stable-request-id"}
```

Supported operations are `account`, `usage`, `create`, `get`, `open-url`,
`accessibility`, `tap`, `press-button` (Home), `screenshot`, and `delete`.
Existing-device operations take `platform` and `sessionId`. Creation enforces
a five-minute hard limit and a 60-second inactivity timeout. The calling agent
must release its session in `finally` and preserve allocation IDs on retries.

The adapter returns immediate messages; it does not advertise streaming or
persistent tasks. The calling agent maps user prompts into these operations.
Account authentication does not authorize wallet payments, and this example
does not initiate a payment.

## Account registration and authentication

Each integration uses the customer's own run.cloud account and credential.
There is no shared reviewer account or public API key.

1. Sign in or create an account at [run.cloud/login](https://run.cloud/login/).
   Email sign-in requires access to the verification inbox.
2. Select the organization that will own the sessions and pay for their usage.
   Check membership before creating resources. If the account has no organization,
   resolve account setup with support before proceeding.
3. For an SDK integration, create a named API key in the
   [dashboard](https://run.cloud/dashboard/) and store it in your platform's secret
   store as `RUN_CLOUD_API_KEY`. Never put it in a prompt, URL, or source file.
4. For CLI use, sign in once or inject that API key into the tool's environment.

```bash theme={null}
npm install -g runcloud
runcloud login --email agent-owner@example.com
runcloud account --json
```

The email command signs in without opening a browser, but still requires the
verification code. An agent may retrieve it only from an inbox it is authorized
to access. For a runtime with an existing API key, set
`RUN_CLOUD_API_URL=https://api.run.cloud` alongside `RUN_CLOUD_API_KEY` and skip
the login command. See [Install the CLI](/cli/install).

Check SDK credentials with `cloud.credential()`, account memberships with
`cloud.account()`, and cumulative usage with `cloud.usage({ orgId })`. Keep
credentials isolated between users; never substitute the connector operator's
credential when a user's key fails.

For a fully automated registration check, the public example includes an
opt-in harness for an authorized Purelymail inbox. It requests a fresh signup
code, reads only mail addressed to its new tagged alias over TLS IMAP, creates
an account and API key, and checks CLI, SDK, and A2A authentication. Follow its
[registration instructions](https://github.com/newly-app/run-cloud-examples/tree/main/a2a-simulator#autonomous-registration-check).
Never give an agent inbox access without the owner's authorization.

The [redacted verification report](https://github.com/newly-app/run-cloud-examples/blob/main/a2a-simulator/VERIFICATION.md)
records a successful fresh registration against the public API with no manual
code entry, including rejection of missing and invalid credentials. That run
made no payment and created no simulator; it is registration/authentication
evidence, not proof of wallet approval or a paid session.

## Billing and payment authorization

Sessions use the selected organization's run.cloud billing. Funding an account
and consuming simulator time are separate events: account credit is not a
fixed-duration session purchase. Usage is metered while a session is active;
releasing it stops future metering. Review billing access and available credit
in the [dashboard](https://run.cloud/dashboard/billing/) before allocating.

The CLI and SDK described here do not expose an agent-wallet top-up operation.
Do not interpret a payment-required error as a payable MPP or x402 challenge,
or assume that a checkout URL means funds have arrived. A platform requiring
agent-executed Link, MPP, or x402 funding must confirm that payment integration
with [support@run.cloud](mailto:support@run.cloud) before promising an unattended
signup-to-paid-session flow. Never retry a charge blindly after a timeout.

Authentication success, account credit, recorded usage, and a settled payment
are different checks. Report them separately. See
[Access Control and Metering](/billing/access-control) and [Limits](/limits).

## Runnable simulator workflow

Install `@run-cloud/sdk` in a Node.js 20+ project:

```bash theme={null}
npm install @run-cloud/sdk
```

Supply these variables through the runtime's configuration:

* `RUN_CLOUD_API_KEY`: the customer's secret API key.
* `RUN_CLOUD_ORG_ID`: the organization selected from the account's memberships.
* `RUN_CLOUD_REQUEST_ID`: a unique ID for this allocation. Preserve it when
  retrying a request whose response was lost; use a new ID for a new allocation.
* `SIMULATOR_PLATFORM`: `ios` (default) or `android`.

Save this as `simulator-review.mjs` and run `node simulator-review.mjs`.
It creates one metered session, opens a website, captures the screen, presses
Home, captures the result, and releases the device even if an interaction fails.

```javascript theme={null}
import { writeFile } from "node:fs/promises";
import { Client } from "@run-cloud/sdk";

const apiKey = process.env.RUN_CLOUD_API_KEY;
const orgId = process.env.RUN_CLOUD_ORG_ID;
const requestId = process.env.RUN_CLOUD_REQUEST_ID;
const platform = process.env.SIMULATOR_PLATFORM ?? "ios";
if (!apiKey || !orgId || !requestId) {
  throw new Error("API key, organization ID, and request ID are required");
}
if (platform !== "ios" && platform !== "android") {
  throw new Error("SIMULATOR_PLATFORM must be ios or android");
}

const cloud = new Client({ apiKey });
const credential = await cloud.credential();
if (!credential.runCloud || !credential.orgs.includes(orgId)) {
  throw new Error("The credential does not authorize this organization");
}
await cloud.account();
const usageBefore = await cloud.usage({ orgId });
const mobile = platform === "ios" ? cloud.ios : cloud.android;
const session = await mobile.create({
  orgId,
  idempotencyKey: requestId,
  displayName: "Agent simulator review",
  inactivityTimeout: "60s",
  hardTimeout: "5m",
});

try {
  await mobile.openUrl(session.id, "https://run.cloud");
  await writeFile("before.png", await mobile.screenshot(session.id), { mode: 0o600 });
  const acknowledgement = await mobile.pressButton(session.id, "home");
  await writeFile("after.png", await mobile.screenshot(session.id), { mode: 0o600 });
  console.log({ sessionId: session.id, actionStatus: acknowledgement.status });
} finally {
  await mobile.delete(session.id);
}

const released = await mobile.get(session.id);
const usageAfter = await cloud.usage({ orgId });
console.log({ sessionId: session.id, status: released.status, usageBefore, usageAfter });
```

An input acknowledgement confirms dispatch, not that the screen has finished
rendering. Inspect the screenshots and capture again if the device is still
transitioning. Usage may appear after release; pending usage is not evidence of
a failed payment. Organization-wide usage also includes other sessions.

Session responses contain a signed viewer URL. Treat it as a secret: return it
only to the authorized user, never to a shared log. Screenshots can contain
private app data and must be reviewed before sharing.

## Map requests to tools

| User request                               | SDK tool                                             |
| ------------------------------------------ | ---------------------------------------------------- |
| Check my account and organization access   | `cloud.credential()`, `cloud.account()`              |
| Start an iOS simulator or Android emulator | `cloud.ios.create(...)`, `cloud.android.create(...)` |
| Inspect the current session                | `mobile.get(sessionId)`                              |
| Open a website or deep link                | `mobile.openUrl(sessionId, url)`                     |
| Tap a position on the screen               | `mobile.tap(sessionId, { x, y })`                    |
| Enter text                                 | `mobile.typeText(sessionId, text)`                   |
| Press Home                                 | `mobile.pressButton(sessionId, "home")`              |
| Capture the display                        | `mobile.screenshot(sessionId)`                       |
| End the session                            | `mobile.delete(sessionId)`                           |
| Report recorded usage                      | `cloud.usage({ orgId })`                             |

Tap coordinates are normalized: `(0, 0)` is the upper-left corner and `(1, 1)`
the lower-right. See [Simulator controls](/platform/simulator-interactions),
[Open URLs](/platform/open-urls), and [SDK reference](/sdk/latest) for the full
argument and response types. Install your own app using a simulator-compatible
iOS build or Android APK; see [iOS sessions](/ios/run-simulator) and
[Android sessions](/android/run-emulator).

## Suggested review prompts

These prompts describe requests to map to the tools above; they do not imply
approval or compatibility with any particular assistant platform.

1. "Connect my run.cloud account and check which organization I can use. Keep
   my API key private."
2. "Start an iOS simulator on run.cloud with a five-minute maximum lifetime.
   Give me its session ID and privately share its viewer link."
3. "Open [https://run.cloud](https://run.cloud) on that simulator and show me a screenshot."
4. "Press Home on the simulator and show me the resulting screen."
5. "End my simulator session, confirm it was released, and report recorded
   usage separately from payment status."

Repeat with an Android emulator when reviewing Android support. Keep the
session ID, platform, and owning organization in the agent's task state so
later commands address the same device.

## Review checklist

* Missing or invalid credentials cannot create or control a session.
* The authenticated user belongs to the selected organization.
* Allocation retries use the same idempotency key; unrelated requests do not.
* The session becomes usable and screenshots confirm the requested interactions.
* The session is released on success and on failure, with an inactivity timeout
  and a hard lifetime limit as backstops.
* Keys, verification codes, signed URLs, and private screen contents stay out of
  public transcripts.
* A paid-flow claim includes confirmed account funding and recorded simulator
  usage; neither successful login nor a generated checkout link is sufficient.

For connector review or a platform-specific interface, contact
[support@run.cloud](mailto:support@run.cloud) and include this page, the intended
prompts, and the required authentication and payment methods. Do not send API
keys or wallet credentials.
