> For the complete documentation index, see [llms.txt](https://axiomemu.gitbook.io/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://axiomemu.gitbook.io/docs/bridgeserver/api.md).

# HTTP API

Everything BridgeServer knows is available over plain HTTP on `HttpPort` (default `55981`). Responses are JSON, requests are `GET` only, and there is no write path.

## Endpoints

| Endpoint               | Returns                                                              |
| ---------------------- | -------------------------------------------------------------------- |
| `/v1/health`           | Status, version, connected HTTP clients, events stored               |
| `/v1/stream`           | Live event feed (Server-Sent Events)                                 |
| `/v1/feed/history`     | Recent events from the history store                                 |
| `/v1/status`           | Accounts, characters, guilds and the live online gauge               |
| `/v1/events/schedule`  | Current event timetable with countdowns                              |
| `/v1/rankings/{kind}`  | `resets` · `grandresets` · `killers` · `level` · `guilds` · `online` |
| `/v1/character/{name}` | Public character profile                                             |
| `/v1/guild/{name}`     | Guild profile with members                                           |
| `/v1/castle-siege`     | Current castle owner and siege state                                 |

Any other path returns `404`. A ranking or profile request returns `503` when the game database is not configured or has not finished its first refresh.

## Event Shape

Every event is one flat JSON object:

```json
{
  "t": 1754049312,
  "type": 23,
  "kind": "raredrop",
  "actor": { "name": "Nyx", "level": 400, "class": 16, "map": 30, "x": 128, "y": 128 },
  "item": 13,
  "itemName": "Dragon Soul",
  "itemLevel": 13,
  "exc": 1,
  "anc": 0,
  "map": 30, "x": 128, "y": 128
}
```

| Field    | Always present | Meaning                                                  |
| -------- | -------------- | -------------------------------------------------------- |
| `t`      | yes            | Unix timestamp                                           |
| `type`   | yes            | Numeric event type, used by the `type=` history filter   |
| `kind`   | yes            | Readable event kind - switch on this                     |
| `actor`  | most kinds     | Who caused it: `name`, `level`, `class`, `map`, `x`, `y` |
| `target` | pair events    | The other character, same shape as `actor`               |

Remaining fields depend on the kind. Consumers should switch on `kind` and ignore everything they do not recognise, so new event kinds never break an existing integration.

## Event Kinds

| `kind`                             | `type` | Fires when                                                                           |
| ---------------------------------- | ------ | ------------------------------------------------------------------------------------ |
| `login`                            | 1      | A character comes online                                                             |
| `logout`                           | 2      | A character goes offline                                                             |
| `chat`                             | 3      | Public chat (`channel: 0`), when chat export is on                                   |
| `post`                             | 3      | A global `/post` message (`channel: 1`)                                              |
| `stats`                            | 4      | Population snapshot, every 30 seconds                                                |
| `schedule`                         | 5      | Event timetable snapshot, every 60 seconds                                           |
| `levelup`                          | 6      | A character gains a level                                                            |
| `pk`                               | 10     | A player kills another player                                                        |
| `bosskill`                         | 11     | A configured boss class dies                                                         |
| `mobkill`                          | 12     | Any monster dies, when monster-kill export is on                                     |
| `gameevent`                        | 13     | Blood Castle, Devil Square, Chaos Castle, an invasion or Castle Siege starts or ends |
| `eventwin`                         | 14     | An event is won                                                                      |
| `trade`                            | 20     | A trade completes                                                                    |
| `pshopsell`                        | 21     | A personal shop sale completes                                                       |
| `chaosmix`                         | 22     | A Chaos Machine attempt resolves                                                     |
| `raredrop`                         | 23     | An excellent, ancient or socketed item drops on the ground                           |
| `sellpost`                         | 24     | An item is listed through the sell-post channel                                      |
| `reset` `grandreset` `masterreset` | 2      | A character resets                                                                   |

`stats` and `schedule` are snapshots: they are streamed live and served from their own endpoints, but never written to history or relayed to Discord.

## Live Feed

`/v1/stream` is a standard Server-Sent Events endpoint. Each event arrives as one `data:` frame containing the JSON object.

```javascript
const feed = new EventSource("http://your-host:55981/v1/stream");

feed.onmessage = (msg) => {
  const e = JSON.parse(msg.data);

  if (e.kind === "raredrop") {
    announce(`${e.actor.name} found ${e.itemName} +${e.itemLevel}`);
  }
};
```

Browsers reconnect automatically when the connection drops. Events that happened while you were disconnected are **not** replayed - use `/v1/feed/history` to fill a gap.

There is a fixed cap on simultaneous stream subscribers, and a slow subscriber is dropped rather than allowed to back everything up. Point one server-side consumer at the stream and fan out from there instead of opening a stream per website visitor.

## History

```bash
# last 100 events of any kind
curl "http://your-host:55981/v1/feed/history?limit=100"

# boss kills since a timestamp
curl "http://your-host:55981/v1/feed/history?type=11&since=1754049312"
```

| Parameter | Default | Effect                                                          |
| --------- | ------- | --------------------------------------------------------------- |
| `type`    | all     | Numeric event type from the table above                         |
| `limit`   | `50`    | Maximum events returned. Values above `500` are capped at `500` |
| `since`   | `0`     | Only events at or after this unix timestamp                     |

Events come back newest first.

## Status

`/v1/status` merges two sources:

```json
{
  "db":   { "onlineCount": 143, "totalAccounts": 5210, "totalCharacters": 12874, "totalGuilds": 233 },
  "live": { "t": 1754049312, "type": 4, "kind": "stats", "online": 143,
            "maps": [ { "map": 0, "count": 61 }, { "map": 2, "count": 24 } ] }
}
```

`db` comes from the game database and is `null` when no data source is configured. `live` is the most recent population gauge from the GameServer and is `null` until the first one arrives.

## Rankings and Profiles

`/v1/rankings/{kind}` returns an array of rows with the database column names as keys - `Name`, `cLevel`, `Class`, `ResetCount`, `MasterResetCount`, `Kills`, and so on depending on the ranking.

```bash
curl "http://your-host:55981/v1/rankings/resets"
curl "http://your-host:55981/v1/character/Kaelen"
curl "http://your-host:55981/v1/guild/Sahara"
curl "http://your-host:55981/v1/castle-siege"
```

Ranking lists are served from a cache rebuilt every `MuDbRefreshSeconds`, so they can be slightly stale. Character, guild and siege lookups are answered live.

## Deployment Notes

* **No authentication, no TLS, no rate limiting.** BridgeServer is a plain HTTP server on purpose. Put it behind your existing reverse proxy if you want any of those, exactly as you would for any small internal service.
* **Do not point browsers straight at it.** Read it from your website's backend or your bot, cache there, and serve your own visitors. That keeps subscriber slots free and stops the API being exposed publicly.
* **The API only reads.** No endpoint can change game state, and BridgeServer never writes to the game database.

## Common Issues

* **`503` on rankings or profiles** - the game database is not configured, or the first refresh has not completed
* **Stream connects, then goes quiet** - no events are being exported; check the [Bridge plugin config](/docs/data/plugins/bridge.md) on the GameServer
* **Stream refused** - every subscriber slot is taken; consolidate to one backend consumer
* **History empty after a restart** - `bridge.db` was deleted, or nothing has been exported yet
* **Rankings are stale** - expected within `MuDbRefreshSeconds`; lower it only if you accept the extra database load
* **Nothing responds at all** - BridgeServer is not running, or `HttpPort` is blocked between you and it

## Related

* [BridgeServer overview](/docs/bridgeserver/bridgeserver.md)
* [BridgeServer.ini](/docs/bridgeserver/bridgeserver-ini.md)
* [Bridge Config.xml](/docs/data/plugins/bridge.md) - which events get exported
