# Mac API reference

Everything the MCP tools and the CLI do goes through this REST API, so anything that speaks HTTP can drive a Mac.

Terminal

```bash
curl -s https://nomac.app/api/v1/me \
  -H "Authorization: Bearer $NOMAC_API_KEY"
```

## Basics

- **Base URL** `https://nomac.app/api/v1`
- **Auth** `Authorization: Bearer nmk_…`, with a key from [nomac.app/dash/keys](/content/dash/keys/index.html), `nomac login` or `POST /api-keys`.
- **Errors** Always `{ "error": { "code", "message" } }` with a meaningful status. `402` is no credit left (or Mac use paused for the account); `422` is a failed precondition, such as no Apple connection or invalid input.
- **Retries** Where an endpoint takes an `Idempotency-Key`, keep the same key and body when retrying: you get the original operation back, never a second one.

## Credit

- $0.90 an hour, charged on each session's ready time in whole minutes, one minute at least. 
- Credit comes in $10 packs of 11.1 hours, 1 to 10 at a time, and never expires. There is no subscription and nothing is charged automatically.

### GET /mac/credits

- Returns the `credits` left (spendable, paid, promotional, and reserved, as microdollar strings), the `spendable_seconds` of Mac time they buy, and recent `purchases`.

### POST /mac/credits/checkout

- Body `{ "packs": 1-10 }`, with a stable `Idempotency-Key`. 
- Answers with an `action`: `open_checkout_url` with a `url` for the person to pay, `check_payment` while a payment is verified, or `checkout_ended`, with a `message` an agent can relay.

## Sessions

### POST /mac/sessions

- Starts a Mac, with a stable `Idempotency-Key`. Answers `session`; read it until it is `ready`. With no credit, it answers 402 `insufficient_credit` with a `buy_url` for the person.
- **limits** `max_duration_seconds` (7,200 by default, 28,800 at most), `idle_timeout_seconds` (600) and `spend_cap_microunits` ($5).
- **access** `prompts: "ask"` keeps macOS's usual prompts; by default, the Mac is fully open to the agent, its login password in `$NOMAC_MAC_PASSWORD`. `gatekeeper: "on" | "off"`.
- **permissions** `{ "com.example.App": ["camera", "microphone"] }` or "all": privacy permissions granted at start.
- **public_key** An SSH public key. Leave it out for HTTPS-only access.
- **access.drive** The drive at `~/drive`: left out (or `"account"`), the account's default, or a new drive of the Mac's own while another Mac has the default; a name, that drive, made empty the first time ( `"default"` is the default itself); `"none"`, no drive.
- **access.drive_from** A drive of the account to copy into the drive made for this Mac (its last save); 404 `drive_not_found` if there is none of that name.
- **reuse** With a drive name: when that drive is on a running Mac, answers that Mac (`reused: true`) instead of `drive_in_use`.
- **parallel** A second Mac beside the account's running one, for an account that has bought credit.
- **queue_seconds** 300 to 3,600: wait in line, free, instead of a 409, while the account runs as many Macs as it may, the drive asked for is on another Mac, or no Mac is free...

## Drives

### GET /mac/drives

- List the account's drives, the default first: name, space used, the Mac using each, recent versions and when each is deleted unused. Up to 10 per account.

### GET / DELETE / PATCH /mac/drives/:name

- Reads one drive, empties it (no Mac may be using it; the next Mac that names it gets a new, empty one, and for a drive-N a new drive under a new number), or renames it with `{ "name": "new-name" }` (never the default).

### GET /mac/sessions

- The account's sessions, to find a Mac again after a lost answer.

### GET / DELETE /mac/sessions/:id

- Reads a session, or stops it. Stopping deletes the Mac and every file outside `~/drive`; read it until `cleanup_confirmed`. Waiting and setup are free; ready time counts, including time between commands.

### GET /mac/capabilities

- Supported interfaces and profiles. A session's own `image` lists its macOS, Xcode, Simulator runtimes and tools.

### GET / PUT / DELETE /mac/defaults

- What every new Mac starts with: `{ prompts?, gatekeeper?, permissions? }`, as a start's `access`. `PUT` replaces them and `DELETE` goes back to fully open. Answers `defaults` and `effective`.

## Commands

### POST /mac/sessions/:id/jobs?wait=30

- Runs a command, with a stable `Idempotency-Key`. Body `{ argv: ["/usr/bin/uname", "-a"], cwd?, env?, timeout_seconds? }`.

### GET /mac/sessions/:id/jobs/:job?wait=30

- Reads a job and, with `wait`, waits up to 50 seconds for it to end.

### GET /mac/sessions/:id/jobs/:job/output?stream=stdout&cursor=0

- The full output: decode `data_base64` and continue at `next_cursor`, for stdout and stderr. Up to 8 MiB is kept, and then the last 64 KiB of each stream

## Files and links

### POST /mac/sessions/:id/files

- Writes a file of up to 3 MiB: `{ path, content? | content_base64?, executable? }`.

### GET /mac/sessions/:id/files?path=build.log

- Reads a file of up to 3 MiB (`max_bytes`): `{ path, size, modified_at, truncated, encoding, content | content_base64 }`.

## Access

### GET /mac/sessions/:id/password

- The Mac's login password for this session: `{ user, password, variable }`, also `$NOMAC_MAC_PASSWORD` on the Mac. Each read is audited, and the password is erased when the session ends.

## Secrets

### GET /secrets

- Names, kinds, where each goes, sizes, delivery and recent activity. Never values.

### POST /secrets/requests

- `{ name, kind, description, destination?, delivery? }`. Answers a `url` where a person enters the value in the browser within 24 hours, so it never passes through a chat.

## Signing

### GET /apple

- Connected Apple accounts and signing identities every Mac receives, with any notice. Never a key.

### POST /apple/signing

- `{ issuer_id? }`. Sets up a distribution identity: an uploaded certificate, the one Apple already issued for NoMac's key, or a new one.
