---
title: Create your first machine
description: Install an SDK, boot a machine, and drive it — from nothing to a running, driven computer.
---

## Install

<CodeGroup>

```bash TypeScript
npm install @raster/sdk
```

```bash Python
uv add raster
```

</CodeGroup>

The SDK authenticates with an API key, which you create under Keys in the dashboard. The
plaintext is shown once, at creation, and never again.

```bash
export RASTER_API_KEY=sk_...
export RASTER_BASE_URL=https://api.example.com/v1
```

There is no default base URL. A wrong-but-plausible hostname baked into a published SDK sends
your key somewhere nobody chose, so the deployment names its own API or the constructor refuses.

## Create a machine

<CodeGroup>

```ts TypeScript
import { Client } from "@raster/sdk";

const client = new Client();
const machine = await client.machines.create({ name: "research", size: "small" });

// running is not the same as ready: a machine has a working shell before it
// has a working desktop.
const display = await machine.waitForDesktop();
```

```python Python
from raster import Client

client = Client()
machine = client.machines.create(name="research", size="small")

# running is not the same as ready: a machine has a working shell before it
# has a working desktop.
display = machine.wait_for_desktop()
```

</CodeGroup>

## Drive its computer

With `display` resolved, the machine has a working desktop. Drive it the same way a person
would:

<CodeGroup>

```ts TypeScript
await machine.browser.open("https://example.com");
await machine.keyboard.type("hello");
await machine.mouse.click({ at: { x: 640, y: 400 } });

const shot = await machine.screen.screenshot({ format: "png" });
const result = await machine.terminal.exec(["uname", "-sr"]);
```

```python Python
machine.browser.open("https://example.com")
machine.keyboard.type("hello")
machine.mouse.click(at={"x": 640, "y": 400})

shot = machine.screen.screenshot(format="png")
result = machine.terminal.exec(["uname", "-sr"])
```

</CodeGroup>

`shot` is a screenshot of a real desktop your code just drove, and `result` is the output of a
command it just ran. That's a complete round trip: a machine created, booted, and driven.

Coordinates are the display's own pixels and nothing is scaled for you, so take a screenshot and
read them off it. A coordinate outside the display is refused rather than clamped.

## Clean up

<CodeGroup>

```ts TypeScript
await machine.close(); // release the input lease and close the session
await machine.stop(); // keeps the disk; delete() destroys it
```

```python Python
machine.close()          # or use `with machine:` and let the block do it
machine.stop()           # keeps the disk; delete() destroys it
```

</CodeGroup>

Do call `close`. Without it the machine holds the input lease until it expires, and nobody else
can type.

## Next

- **[Take input control](/docs/how-to/take-input-control)** — hand the keyboard back and forth
  with a person.
- **[What a machine can do](/docs/reference)** — every capability and its limits.
- **[SDKs](/docs/sdk)** — the full surface, one page per area, both languages side by side.
- **[How machines behave](/docs/explanation/how-machines-behave)** — the reasoning behind sizes,
  readiness, coordinates, and exit codes.
