Overview & auth
The Mel relay HTTP API: base URLs, auth, and wire compatibility.
The Mel relay is the only backend the Mel app talks to. It holds provider API keys server-side, routes auto requests to a concrete model, streams agent responses, and stores account and memory state. These pages document its public HTTP surface so you can build your own client against it.
Base URL
The hosted base URL is baked into the app at build time (MEL_RELAY_URL). For local development the default is http://127.0.0.1:7711 — the app auto-spawns a sibling relay there when you run from source.
Content types
- Request bodies are JSON; responses are JSON — with one exception.
- POST /v1/agent/stream responds with newline-delimited JSON (
application/x-ndjson), one event object per line. - GET /metrics returns Prometheus text exposition.
Authentication
Every authenticated request carries a Bearer token:
Authorization: Bearer <token>You get a token from POST /v1/auth/signin:
curl -s https://<relay-host>/v1/auth/signin \
-H 'Content-Type: application/json' \
-d '{"email": "you@example.com", "password": "..."}'
# → {"token": "...", "email": "...", "role": "...", "limit": 200}Pass token on subsequent requests. Related endpoints:
POST /v1/auth/signup— self-serve signup: a new account is created and a session token is returned (200 {"token": "...", "email", "role", "limit"}), same shape as signin.409 {"error": "email_taken", ...}if the email exists.POST /v1/auth/signout— invalidates the presented token; always200 {"ok": true}.GET /v1/me— the caller's account snapshot:{"auth": true, "role", "email", "limit", "used", "remaining"}(remainingis-1for unlimited accounts), or401without a valid token.POST /v1/waitlist— public product-updates newsletter signup (the path is kept for wire compatibility; it now feeds the newsletter):{"email": "...", "source"?: "..."}(sourcedefaults to"web").
When the relay runs without an auth store configured (bare local dev), all endpoints are open and GET /v1/me reports {"auth": false}.
Identity is always derived server-side from the Bearer token — there is no user_id on the wire, and any client-supplied value is ignored.
Error shape
Unless noted otherwise, errors are {"error": "<machine_code>", "message": "<human text>"} with a matching HTTP status: 400 invalid request, 401 unauthorized, 403 forbidden, 409 conflict, 503 dependency unavailable. /v1/agent/stream reports post-header failures as an {"event": "error"} NDJSON line instead.
Wire compatibility promise
Event and message shapes are frozen. New fields are only ever added additively (optional, defaulted), so old clients keep working. Fields are never removed or renamed. If you build against today's shapes, tomorrow's relay will still speak them.
Endpoint map
| Area | Page |
|---|---|
| Liveness, readiness, Prometheus metrics | Health & metrics |
| The core streaming agent endpoint | Agent streaming |
| Tool definitions and the tool-call round-trip | Tool definitions |
| Durable per-project agent notes | Project memory |
| Server-side web search | Web search |
There is also POST /v1/suggest, which powers the app's inline ghost autocomplete: body {"partial", "cwd", "recent"}, response {"suggestion": "..."} — one completed command line that strictly extends partial — or {"suggestion": null} when the model has no confident, safe completion (also when partial is under 2 characters).
The canonical single-page reference lives in the repository at
docs/relay-api.md; a build-time test fails if an endpoint is added without documenting it there.