# HTTPS API and SDKs

Your machines and account over HTTPS: everything an agent or a script needs (writing rules,
turning delete protection off and answering invites stay in the app). Base URL: `https://api.shell.639cloud.com`. JSON in and
out.

## API keys

```sh
ssh keys@shell.639cloud.com new laptop    # prints the key once
ssh keys@shell.639cloud.com list
ssh keys@shell.639cloud.com revoke ID
```

Send it on every request as `Authorization: Bearer 639_…`. We store only a hash, so a lost key
can't be recovered: revoke it and make a new one.

## Quick start

```sh
export KEY=639_…
curl -s https://api.shell.639cloud.com/v1/catalog -H "Authorization: Bearer $KEY"
curl -s -X POST https://api.shell.639cloud.com/v1/machines \
  -H "Authorization: Bearer $KEY" -d '{"size": "s1", "image": "ubuntu"}'
curl -s -X POST https://api.shell.639cloud.com/v1/machines/ubuntu-1/exec \
  -H "Authorization: Bearer $KEY" -d '{"command": "uname -a"}'
curl -s -X DELETE https://api.shell.639cloud.com/v1/machines/ubuntu-1 -H "Authorization: Bearer $KEY"
```

Every call wakes a sleeping machine as needed.

## Endpoints

| | |
|---|---|
| `GET /v1/catalog` | sizes and images |
| `GET`, `POST /v1/machines` | list, create |
| `GET`, `PATCH`, `DELETE /v1/machines/{name}` | read, change (RAM, CPU, disk, sleep, network, inbound, name), delete |
| `POST /v1/machines/{name}/sleep`, `/restart` | sleep now, cold restart |
| `POST /v1/machines/{name}/exec` | run a command; add `?stream=1` for live output (Server-Sent Events) |
| `PUT`, `GET /v1/machines/{name}/files?path=…` | upload, download (up to 512 MB) |
| `GET`, `POST /v1/vpcs`, `DELETE /v1/vpcs/{name}` | private networks |
| `GET /v1/machines/{name}/bootlog` | a Full VM's boot log (plain text) |
| `PUT /v1/machines/{name}/protection` | delete protection on (`{"on": true}`); off only in the app |
| `POST`, `DELETE /v1/machines/{name}/vpc` | join, leave a VPC |
| `GET`, `POST /v1/ips`, `DELETE /v1/ips/{addr}` | public IPv4s |
| `GET /v1/usage?from=&to=&group_by=` | usage and cost, by machine or by a label |
| `GET /v1/events`, `GET`, `POST /v1/webhooks`, `DELETE /v1/webhooks/{id}` | what happened, as a list or a live stream, and webhooks (see Events and webhooks) |
| `GET`, `POST /v1/orgs`, `PATCH`, `DELETE /v1/orgs/{id}` | a platform's managed orgs; `639-Org: <id>` on any call acts in one (see Platforms) |
| `GET`, `POST /v1/templates`, `DELETE /v1/templates/{name}`, `POST /v1/templates/{name}/fork` | templates, fork many (beta; see Forking) |
| `GET /v1/machines/{name}/rules`, `POST …/rules/ack` | the rules agents get, and acknowledging them (see Rules for agents) |
| `GET`, `POST /v1/machines/{name}/notes`, … | the machine's notes |
| `GET /v1/history`, `GET /v1/notifications` | what happened, notices |

The full list, with every field: the OpenAPI spec and the API reference.
| `POST /v1/ips/{addr}/attach`, `/detach` | attach, detach |
| `GET`, `POST /v1/keys`, `DELETE /v1/keys/{id}` | API keys |

Errors are JSON, `{"error": "…"}`. Limits per key: 20 requests a second (bursts to 40), 30
creates a minute, and 5 machine deletes (sandboxes aside) in any 10 minutes; over that you get
`429` with `Retry-After`. Agents over MCP have the same call and delete limits (as tool errors), and
the delete limit is per person: all their keys and agents share it.

## Python

```python
from cloud639 import Client

c = Client()                     # reads CLOUD639_API_KEY
with c.create("s1", "ubuntu", delete_on_exit=True) as m:
    print(m.exec("uname -a").stdout)
```

## TypeScript

```ts
import { Client } from "cloud639";

const c = new Client();          // reads CLOUD639_API_KEY
await using m = await c.create({ size: "s1", image: "node", deleteOnDispose: true });
console.log((await m.exec("node -e 'console.log(6*7)'")).stdout);
```

Both SDKs have no dependencies.
