> ## Documentation Index
> Fetch the complete documentation index at: https://docs.myrax.app/llms.txt
> Use this file to discover all available pages before exploring further.

# HTTP API

> Authentication, endpoints and streaming

Everything the panel does goes through this API — there is no hidden channel.
All endpoints are JSON over the panel's port.

## Authentication

`POST /api/login` with the admin credentials sets a `myrax_session` cookie.
Every other endpoint (except `/api/health` and `/api/session`) requires it.
Login is rate-limited per IP.

<CodeGroup>
  ```js login.js theme={null}
  const res = await fetch("http://server:1487/api/login", {
    method: "POST",
    headers: { "content-type": "application/json" },
    body: JSON.stringify({ username: "admin", password: "secret" }),
    credentials: "include" // keep the myrax_session cookie
  });
  if (!res.ok) throw new Error(`login failed: ${res.status}`);
  ```

  ```go login.go theme={null}
  jar, _ := cookiejar.New(nil)
  client := &http.Client{Jar: jar} // jar keeps the myrax_session cookie

  body, _ := json.Marshal(map[string]string{
  	"username": "admin",
  	"password": "secret",
  })
  res, err := client.Post("http://server:1487/api/login",
  	"application/json", bytes.NewReader(body))
  if err != nil || res.StatusCode != http.StatusOK {
  	log.Fatalf("login failed: %v %d", err, res.StatusCode)
  }
  ```
</CodeGroup>

Errors come back as `{"error": "message"}` with a matching HTTP status.

## Reading metrics

`GET /api/stats` returns one snapshot; `GET /api/events/stats` streams the
same payload as server-sent events every second.

<CodeGroup>
  ```js stats.js theme={null}
  // one snapshot
  const stats = await (await fetch("/api/stats", { credentials: "include" })).json();
  console.log(stats.cpu.usagePercent, stats.memory.usedPercent);

  // live stream (SSE)
  const events = new EventSource("/api/events/stats");
  events.onmessage = (event) => {
    const stats = JSON.parse(event.data);
    console.log(stats.cpu.usagePercent);
  };
  ```

  ```go stats.go theme={null}
  // one snapshot
  res, _ := client.Get("http://server:1487/api/stats")
  var stats map[string]any
  json.NewDecoder(res.Body).Decode(&stats)

  // live stream (SSE) — read "data:" lines off the open response
  res, _ = client.Get("http://server:1487/api/events/stats")
  scanner := bufio.NewScanner(res.Body)
  for scanner.Scan() {
  	line := scanner.Text()
  	if data, ok := strings.CutPrefix(line, "data: "); ok {
  		fmt.Println(data)
  	}
  }
  ```
</CodeGroup>

## Endpoints

### Session

| Method | Path           | What it does        |
| ------ | -------------- | ------------------- |
| GET    | `/api/health`  | liveness, no auth   |
| GET    | `/api/session` | am I logged in      |
| POST   | `/api/login`   | log in, sets cookie |
| POST   | `/api/logout`  | drop the session    |

### System

| Method | Path                   | What it does                           |
| ------ | ---------------------- | -------------------------------------- |
| GET    | `/api/stats`           | CPU, RAM, disk, network, host snapshot |
| GET    | `/api/events/stats`    | the same as SSE, 1s interval           |
| GET    | `/api/processes`       | process list (`?limit=N`)              |
| POST   | `/api/processes/kill`  | kill by PID                            |
| GET    | `/api/services`        | systemd units                          |
| POST   | `/api/services/action` | start / stop / restart a unit          |
| GET    | `/api/network`         | per-interface rates                    |
| GET    | `/api/disks`           | mounted volumes                        |
| GET    | `/api/logs`            | journal snapshot                       |
| GET    | `/api/events/logs`     | journal tail as SSE                    |

### Control

| Method | Path                    | What it does                                  |
| ------ | ----------------------- | --------------------------------------------- |
| GET    | `/api/config`           | current config                                |
| PUT    | `/api/config`           | update bind / port / panel path / credentials |
| GET    | `/api/updates`          | latest release info                           |
| POST   | `/api/actions/update`   | self-update                                   |
| POST   | `/api/actions/reboot`   | reboot the server                             |
| POST   | `/api/actions/shutdown` | power off                                     |
| POST   | `/api/actions/reload`   | restart the panel service                     |

### Plugins

| Method | Path                                         | What it does                           |
| ------ | -------------------------------------------- | -------------------------------------- |
| GET    | `/api/plugins`                               | installed plugins + runtime statuses   |
| GET    | `/api/plugins/store`                         | built-in catalog with install state    |
| POST   | `/api/plugins/install`                       | install by name, URL or path           |
| POST   | `/api/plugins/enable` / `disable` / `remove` | manage                                 |
| GET    | `/api/plugins/{id}/logs`                     | runtime log                            |
| POST   | `/api/plugins/{id}/restart`                  | restart runtime                        |
| POST   | `/api/plugins/{id}/update`                   | re-install from source                 |
| ANY    | `/api/plugins/{id}/proxy/{path}`             | HTTP proxy to the plugin runtime       |
| WS     | `/api/plugins/{id}/ws/{path}`                | websocket proxy to the plugin runtime  |
| GET    | `/addons/{id}/{file}`                        | plugin static assets (JS, CSS, images) |

The two proxy routes are how plugin frontends talk to their backends — see
[Runtime](/plugins/dev/runtime).
