# HTTP surfaces

`mehen` is the supported client; nothing here is needed to use Mehen. This page is for reading what goes over the wire.

## Machine requests

Machines talk to the vault under `https://app.mehen.dev/v1/`. Every request from an enrolled machine carries a `Mehen-Proof` header, a signature over the method, the full URL and a hash of the exact body ([Keys, proofs and signing](https://docs.mehen.dev/security/keys-and-signing.md#device-proofs)). There is no bearer token.

| Route | What it is |
| --- | --- |
| `POST /v1/enrol`, `GET /v1/enrol/:enrolment`, `POST /v1/enrol/:enrolment/renew` | Start an enrolment, poll it, renew its lease in place. Signed by the key being enrolled. |
| `GET /v1/me` | This machine's identity, owner, scope and state. |
| `GET /v1/items`, `GET /v1/items/:slug` | Items this machine may use, and one item's public description. |
| `POST /v1/relay` | One HTTP request through the vault relay. |
| `POST /v1/intakes`, `GET /v1/intakes/:id`, `POST /v1/intakes/:id/cancel` | Ask for a credential, poll the intake, cancel your own. |
| `POST /v1/connect`, `GET /v1/connect/:id`, `POST /v1/connect/:id/cancel` | Ask for an OAuth connection, poll it, cancel your own. |
| `GET /v1/approvals/:id` | Poll an approval; `?wait=1` long-polls up to 25 seconds. |
| `GET /v1/pending` | This machine's own open asks, and the one notice a machine gets, that it was added to the workspace. |
| `POST /v1/projects`, `GET /v1/projects/:id`, `/v1/projects/:id/vars/:name` | Create a project, read it, set a variable. |
| `POST /v1/runs`, `POST /v1/runs/:id/renew`, `DELETE /v1/runs/:id`, `POST /v1/lease` | Start, renew and end a run; fetch a lease mid-run. |
| `POST /v1/freeze` | Freeze the workspace. |
| `POST /v1/devices/self/revoke` | Revoke this machine. |
| `GET /v1/seal-key` | Unauthenticated: the vault's public seal key, which browsers seal secret fields to. |

## Headers

| Header | Direction | Meaning |
| --- | --- | --- |
| `Mehen-Proof` | request | The machine's signature over this exact request. |
| `Mehen-Error: 1` | response | The vault refused; the body is an error object ([Errors and exit codes](https://docs.mehen.dev/reference/errors.md)). |
| `Mehen-Upstream: 1` | response | A relayed upstream response, never a vault refusal. |
| `Mehen-Item` | response | The item that acted, `<slug> (<account>)`, so the transcript says which account was used. |
| `Mehen-Cli` | response | On every `/v1` answer: `minimum=<v>`, with `; recommended=<v>` when the vault sets one. A `mehen` below the minimum is refused with `cli_outdated` (HTTP 426), except freeze and self-revoke. |
| `User-Agent` | request | `mehen/<version>`. |

An upstream 403 and a vault refusal are never the same thing: only the vault's carries `Mehen-Error`.

## Errors

```ts
type ApiError = {
  error: ErrorCode
  message: string
  next?: { url?: string; command?: string; say: string }
  approval?: string
  bindingCode?: string
  choices?: { slug: string; account: string | null }[]
  retryAfter?: number
  expiresAt?: string
  deciders?: string[]
  transition?: ...
}
```

Every code, its HTTP status and the exit code `mehen` gives it are in [Errors and exit codes](https://docs.mehen.dev/reference/errors.md), and as JSON at [`/reference/errors.json`](https://docs.mehen.dev/reference/errors.json).

## The release channel

Releases are served from `https://mehen.dev/dl/`:

| Path | What it is |
| --- | --- |
| `/dl/latest.json` | The signed manifest of the current release. |
| `/dl/v<version>/manifest.json` | One release's signed manifest: `{ version, commit, builtAt, files, signatures }`, each file with its name, platform, size and SHA-256, compressed and uncompressed. |
| `/dl/v<version>/mehen-<os>-<arch>.gz` | The binary, for `darwin` or `linux` on `arm64` or `x64`. |

`https://mehen.dev/install` is the installer for a machine with no `mehen`. Its last line is the receipt, `mehen-install: {"v":1,"result":"installed","version":...,"path":...,"onPath":...,"env":...,"rc":{...}}`, where `result` is `installed`, `already-installed` or `forced`. [Keys, proofs and signing](https://docs.mehen.dev/security/keys-and-signing.md#releases) says how a release is checked.
