bleh
Home Add to Discord Support
HomeFeaturesCommandsEmbedsServersDocsConfigStatus Support Add to Discord

Resources

API reference

The public JSON API the website and the dashboard run on: catalog, live stats, server wall, and the authenticated per-server routes.

API reference

Every route lives under /api on the site origin, and every response is JSON.

Public reads answer with an ok boolean first. Anything authenticated answers with ok: false and an error string instead of a payload, so a client can tell "the bot said no" from "the bot is unreachable".

{ "ok": true, "generatedAt": "2026-10-18T20:00:00.000Z" }

Public routes

No token, no cookies. These are cached for 30-300 seconds.

Method Path What it returns
GET /api/health ok, deployment state, command and category counts, last push time
GET /api/brand Bot name, avatar, invite URL, support server
GET /api/stats Servers, members, channels, uptime, latency
GET /api/stats/commands?limit=25 Most used commands with use counts
GET /api/stats/shortcuts?limit=24 Short aliases worth remembering
GET /api/catalog Every command with its metadata
GET /api/catalog?category=moderation The same, filtered by category
GET /api/catalog?q=ban&limit=20 The same, filtered by name, alias or description
GET /api/catalog/categories Categories with command and alias counts
GET /api/catalog/:name One command, by name or alias
GET /api/servers?invites=0 The public server wall (name, icon, member count, invite)

One command

GET /api/catalog/role returns the same card the bot prints in Discord:

{
  "ok": true,
  "command": {
    "name": "role",
    "aliases": ["r"],
    "category": "moderation",
    "description": "Add or remove a role from a member.",
    "usage": ",role <member> [role]",
    "cooldown": 5,
    "parameters": [
      { "name": "member", "required": true },
      { "name": "role", "required": false }
    ],
    "pages": [
      { "cmd": "all", "description": "add a role to every member", "parameters": ["(role)"] }
    ],
    "examples": [",role @User @Role", ",role all @Role"],
    "tierLabel": null,
    "premium": false,
    "docs": "/docs/commands/moderation",
    "page": "/commands/moderation/role"
  }
}

parameters is the legend: (name) and <name> are required, [name] is optional. pages is one entry per subcommand page - the same list ,role with no argument draws.

Authentication

The dashboard signs in with Discord OAuth2. The site never sees the token: it is handed back in the URL fragment after the callback and kept in the browser.

Method Path Notes
GET /api/auth/login Redirects to Discord
GET /api/auth/callback Returns to the site with the session
GET /api/me The signed-in user, their servers, owner flags

Authenticated requests send Authorization: Bearer <token> and are never cached.

Per-server routes

Every route below takes a guild id and checks that the signed-in user can manage that guild. A server the user is not in answers 403, not an empty list.

Method Path What it does
GET /api/guilds Servers the user and the bot are both in
GET /api/guilds/:id/config Every setting, its value and its schema
PATCH /api/guilds/:id/config { values: { key: value } }, partial
PATCH /api/guilds/:id/settings Rename the server or change its icon
GET /api/guilds/:id/structure Categories and channels, in server order
GET /api/guilds/:id/channels Text channels the dashboard can target
GET /api/guilds/:id/roles Every role except @everyone, highest first
GET /api/guilds/:id/logs The last 25 audit-log entries
GET /api/guilds/:id/autorole Auto roles and whether they are enabled
PATCH /api/guilds/:id/autorole { roles: [ids], enabled }
GET /api/guilds/:id/security Antinuke modules and their state
PATCH /api/guilds/:id/security/modules Turn a protection on or off
POST /api/guilds/:id/security/panic Lock the server down now
POST /api/guilds/:id/moderation/:action ban, unban, kick, mute, unmute, warn
GET /api/guilds/:id/moderation/warnings/:userId One member's warnings
GET /api/guilds/:id/tickets Tickets and their counts; ?open=true for open ones
POST /api/guilds/:id/tickets/panel Post (or refresh) the ticket panel
POST /api/guilds/:id/tickets/:channelId/claim Claim a ticket
POST /api/guilds/:id/tickets/:channelId/close Close and delete the ticket channel
GET /api/guilds/:id/tickets/:channelId/transcript HTML transcript of one ticket
GET /api/guilds/:id/dm The last mass DM, its history and opt-outs
GET /api/guilds/:id/dm/preview Who a campaign would reach, with counts
POST /api/guilds/:id/dm Start a campaign (confirm: true to send)
GET /api/guilds/:id/dm/:jobId Progress for one campaign
POST /api/guilds/:id/dm/:jobId/cancel Stop a running campaign
POST /api/guilds/:id/dm/optout { userId, on } — add or remove an opt-out

Mass DM is owner-tier: only the server owner, an extra owner, the configured owner role or a bot owner can read or start one. Every other per-server route needs only membership to read, and Manage Server to change something.

Owner routes

Bot owners only. A non-owner gets 403.

Method Path What it does
GET /api/admin/overview Every server, live stats and the owner list
GET /api/admin/shortcuts The most used aliases
GET /api/admin/guilds/:id/invite Mint (or reuse) an invite for one server
POST /api/admin/guilds/:id/leave Make the bot leave (confirm: true)
GET /api/admin/broadcast/preview Count and sample a broadcast audience
POST /api/admin/broadcast Start a DM broadcast
GET /api/admin/broadcast/:jobId Broadcast progress
POST /api/admin/broadcast/:jobId/cancel Stop a broadcast

PATCH /api/guilds/:id/config answers with what it applied and what it refused, so a stale dashboard tab fails one field instead of the whole form:

{
  "ok": true,
  "applied": { "prefix": "!" },
  "failed": []
}

When the bot is unreachable

The API proxies to the bot host. If that host is down, public reads fall back to the last snapshot the bot pushed and say so in source - push, capture or build. Private routes never fall back: they answer 503 rather than inventing a server state.