# AlloyMC API reference

Base URL: https://api.alloymc.dev/v1. Endpoints marked (token) need `Authorization: Bearer <token>`. OpenAPI: https://api.alloymc.dev/v1/openapi.json

## Status

Is it up, and what's the newest Alloy.

### GET /v1/launcher/releases/latest

Newest Alloy release and its signed update files.

200 The newest release:

```json
{
  "published": "2026-10-30T18:15:43Z",
  "updates": {
    "windows-x86_64": {
      "sha256": "…",
      "size": 5666631,
      "url": "https://github.com/…"
    }
  },
  "version": "0.2.1"
}
```

### GET /v1/status

Server status.

200 Up:

```json
{
  "launcher": "0.2.1",
  "ok": true,
  "version": "0.1.9"
}
```


## Users

Public profiles and who follows whom.

### GET /v1/users/{handle}

A public profile.

- `handle` (path, required): 

### GET /v1/users/{handle}/avatar.png

Avatar image. The linked Minecraft head or the person's sigil, as a crisp pixel PNG.

- `handle` (path, required): 
- `s` (query): Size in pixels, rounded down to a multiple of 8.

### PUT /v1/users/{handle}/follow (token)

Follow someone.

- `handle` (path, required): 

### DELETE /v1/users/{handle}/follow (token)

Unfollow someone.

- `handle` (path, required): 

### GET /v1/users/{handle}/followers

Who follows someone, newest first.

- `handle` (path, required): 
- `before` (query): Cursor from the previous page's next.

200 Up to 50 people and a cursor:

```json
{
  "next": 0,
  "users": [
    {
      "accent": "lapis",
      "avatarUrl": "https://api.alloymc.dev/v1/users/someone/avatar.png",
      "displayName": "Someone",
      "handle": "someone"
    }
  ]
}
```

### GET /v1/users/{handle}/following

Who someone follows, newest first.

- `handle` (path, required): 
- `before` (query): 


## Me

The signed-in account. Needs a bearer token.

### GET /v1/me (token)

Your account.

### PATCH /v1/me (token)

Change your profile. Send only the fields to change: handle, displayName, bio, pronouns, links, accent, avatar ("sigil" or "minecraft:<uuid>"), private.

Request body:

```json
{
  "accent": "amethyst",
  "bio": "Builds castles. Breaks modpacks."
}
```

### GET /v1/me/sessions (token)

Where you're signed in.

### DELETE /v1/me/sessions/{id} (token)

Sign one session out.

- `id` (path, required): 


## Minecraft

Link a Minecraft account with Mojang's own proof, and its skin renders.

### POST /v1/me/minecraft (token)

Finish linking. AlloyMC asks Mojang's hasJoined who joined with that server ID. The Minecraft token never reaches AlloyMC.

Request body:

```json
{
  "serverId": "alloymc1f3a9c0d2e7b4",
  "username": "Notch"
}
```

### POST /v1/me/minecraft/challenge (token)

Start linking a Minecraft account. Returns a server ID valid for two minutes. Pass it to Mojang's POST https://sessionserver.mojang.com/session/minecraft/join with the player's own access token, exactly as when joining a server; then call POST /v1/me/minecraft.

200 A server ID:

```json
{
  "expiresIn": 120,
  "serverId": "alloymc1f3a9c0d2e7b4"
}
```

### DELETE /v1/me/minecraft/{uuid} (token)

Unlink a Minecraft account.

- `uuid` (path, required): 

### GET /v1/minecraft/{uuid}

Find the AlloyMC profile behind a player. Looks up a Minecraft account by UUID (with or without dashes). Answers only when the player is linked to a public AlloyMC profile and shown on it; otherwise 404, so hidden links stay hidden.

- `uuid` (path, required): Minecraft UUID, with or without dashes

200 The player and their AlloyMC profile:

```json
{
  "bodyUrl": "https://api.alloymc.dev/v1/minecraft/069a79f444e94726a5befca90e38aaf5/body.png",
  "headUrl": "https://api.alloymc.dev/v1/minecraft/069a79f444e94726a5befca90e38aaf5/head.png",
  "name": "Notch",
  "slim": false,
  "user": {
    "accent": "amethyst",
    "avatarUrl": "https://api.alloymc.dev/v1/users/kestrel/avatar.png?v=1a2b3c4d",
    "displayName": "Kestrel",
    "handle": "kestrel",
    "profileUrl": "https://alloymc.dev/@kestrel"
  },
  "uuid": "069a79f444e94726a5befca90e38aaf5"
}
```

### GET /v1/minecraft/{uuid}/body.png

Full-body front render of a linked account.

- `uuid` (path, required): 
- `s` (query): Width in pixels; the height is twice that.

### GET /v1/minecraft/{uuid}/head.png

Head render of a linked account.

- `uuid` (path, required): 
- `s` (query): 


## Auth

How Alloy turns a browser sign-in into a token.

### POST /v1/auth/token

Trade a sign-in code for a token. Alloy opens https://alloymc.dev/auth/app?challenge=…&state=…&device=… in the browser (PKCE S256). After the person allows it, the browser returns to alloy://auth?code=…&state=…; Alloy posts the code and its verifier here. Codes last five minutes and work once.

Request body:

```json
{
  "code": "…",
  "verifier": "…"
}
```

200 A token, valid 90 days and renewed while used:

```json
{
  "token": "…",
  "tokenType": "Bearer",
  "user": {
    "handle": "elchi"
  }
}
```

### DELETE /v1/auth/token (token)

Sign this token out.

