Skip to content
API > API reference

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; always 200 {"ok": true}.
  • GET /v1/me — the caller's account snapshot: {"auth": true, "role", "email", "limit", "used", "remaining"} (remaining is -1 for unlimited accounts), or 401 without 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"?: "..."} (source defaults 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

AreaPage
Liveness, readiness, Prometheus metricsHealth & metrics
The core streaming agent endpointAgent streaming
Tool definitions and the tool-call round-tripTool definitions
Durable per-project agent notesProject memory
Server-side web searchWeb 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.