# Open Code War API reference

Base URL `https://opencodewar.dev`. JSON over HTTPS, CORS `*`, no authentication for reads. Machine-readable spec: [https://opencodewar.dev/openapi.json](https://opencodewar.dev/openapi.json).
Writes (`/track`, `/register`, `/profile`, `/delete`, `/battle/*`) identify the caller by the anonymous `userId` the plugin generates on the device; they are documented for transparency, not as a public write API.

## Read endpoints

### GET /leaderboard
Ranking snapshot (rebuilt every 5 minutes).

| Query | Values | Default |
|---|---|---|
| `type` | `all` · `daily` · `weekly` · `weekend` · `monthly` | `daily` |
| `metric` | `prompts` · `chars` | `prompts` |
| `limit` | 1–500 | 100 |
| `scope` | `global` · `country` · `city` | `global` |
| `country` | ISO 3166-1 alpha-2 (with `scope=country`/`city`) | — |
| `city` | city name (with `scope=city`) | — |

Example: `curl "https://opencodewar.dev/leaderboard?type=all&metric=prompts&limit=10"`

### GET /user
Public profile + last-30-day daily usage. `?nickname=<registered nickname>` or `?id=<public_id>`. Never returns the secret `userId`.

### GET /user/hours
Hour-of-day histogram for one user. Same identifier query as `/user`, optional `day=YYYY-MM-DD`.

### GET /zones
Countries and cities that have registered users (for scope filters).

### GET /random
One random public profile (for discovery).

### GET /battle?code=<code>
Public state of a battle (members, period, standings).

### GET /health
`{ "ok": true }` liveness probe.

## Plugin endpoints (called by the installed plugin)

- `POST /track` — `{ userId, chars, agent, project? }`. Counts only; prompt text is never sent. 60 req/60 s per IP.
- `POST /register` — `{ userId, nickname }` set a display name (2–15 chars, letters/digits/Korean/underscore/space).
- `POST /profile` — `{ userId, bio?, role?, company?, city?, country?, links?, projects? }`.
- `POST /delete` — `{ userId }` erase everything for that id.
- `GET /briefing?userId=` — one-line session briefing shown in the terminal.
- `POST /battle/new` · `/battle/join` · `/battle/leave`, `GET /battle/mine` — battles (max 10 members, 24 h – 7 d).

## Pages

- `/u/<nickname>` — profile page (HTML; OG tags rewritten per user).
- `/og/<public_id>.png` — 1200×630 developer card image.
- `/b/<code>` — battle page.

## Errors

Every error is JSON `{ "error": "<snake_case_code>" }` with a 4xx/5xx status (`invalid_nickname`, `not_found`, `rate_limited`, …). Unknown paths return 404 with a markdown body unless the request has `Accept: application/json`.
