REST API v1 · Developers

BotGG developer API: connect your Discord server to anything

The BotGG REST API lets your own website, game server or backend read and change your Discord server’s BotGG data — pay out Bank prizes, sync XP from your game, reward invites or show leaderboards on your site. Create a key in the console, send one HTTPS request, done.

  • Base URL: https://console.botgg.app/api/v1
  • JSON over HTTPS, Authorization: Bearer API keys with per-resource scopes
  • A machine-readable OpenAPI 3.1 description of every endpoint
  • Free plan: 2 keys, 60 requests per minute per key
Developer docs
On this page

Overview

What members do with BotGG in Discord — balances, levels, invites and more — is also available to your own code. Each part of BotGG is a resource with its own endpoints and scopes; the API reference lists them all.

  • Base URL: https://console.botgg.app/api/v1. HTTPS only.
  • Requests and responses are JSON (Content-Type: application/json).
  • IDs are Discord snowflakes (17–20 digits) and are always sent and returned as strings.
  • Every key belongs to one server and works only for that server — see authentication.
  • Server-to-server only: requests from browsers are rejected, so keys never end up in front-end code.

Quick start

  1. Open the console, pick your server and go to API in the sidebar (you need the Manage Server permission).
  2. Create a key: give it a name (for example “Website”), choose the scopes and an optional expiry. Copy the key right away — it is shown only once.
  3. Store it as a secret on your server, for example in the BOTGG_API_KEY environment variable.
  4. Make your first request — here, read a member’s Bank balance (scope bank:read).
curl
curl -s https://console.botgg.app/api/v1/guilds/123456789012345678/bank/members/876543210987654321 \
  -H "Authorization: Bearer $BOTGG_API_KEY"
Response · 200
{
  "userId": "876543210987654321",
  "balance": 1250,
  "currency": { "name": "Coin", "plural": "Coins", "emoji": "🪙" }
}

Every resource needs its feature enabled on the server; otherwise its endpoints answer 409 FEATURE_DISABLED (BANK_DISABLED for the Bank). All error codes are on the errors page.

API reference by resource

One reference page per resource, generated from the same registry that runs the API — parameters, request and response fields, scopes, error codes and ready-to-run curl, JavaScript and Python examples:

All endpoints

All paths are relative to https://console.botgg.app/api/v1. {guildId} is your server’s ID and {userId} is a member’s Discord ID. Endpoints marked Sensitive need a scope that acts on members or exposes moderation data.

All REST API v1 endpoints
EndpointScopeDescription
GET/guilds/{guildId}guild:readGet the server
GET/guilds/{guildId}/rolesguild:readList roles
GET/guilds/{guildId}/channelsguild:readList channels
GET/guilds/{guildId}/members/{userId}guild:readGet a member
GET/guilds/{guildId}/bank/members/{userId}bank:readGet a member’s balance
GET/guilds/{guildId}/bank/members/{userId}/transactionsbank:readList a member’s transactions
POST/guilds/{guildId}/bank/members/{userId}/transactionsbank:writeAdd to or remove from a member’s balance
GET/guilds/{guildId}/bank/leaderboardbank:readTop balances
GET/guilds/{guildId}/levels/members/{userId}levels:readGet a member’s level
GET/guilds/{guildId}/levels/leaderboardlevels:readXP leaderboard
POST/guilds/{guildId}/levels/members/{userId}/xp-changeslevels:writeAdd, remove or set a member’s XP
GET/guilds/{guildId}/levels/xp-changes/{changeId}levels:writeGet the status of an XP change
GET/guilds/{guildId}/invites/members/{userId}invites:readGet a member’s invites
GET/guilds/{guildId}/invites/leaderboardinvites:readInvites leaderboard
POST/guilds/{guildId}/invites/members/{userId}/bonusinvites:writeAdd or remove bonus invites
GET/guilds/{guildId}/ticketstickets:readList tickets
GET/guilds/{guildId}/tickets/{ticketNo}tickets:readGet a ticket
GET/guilds/{guildId}/tickets/{ticketNo}/transcripttickets:readGet a closed ticket’s transcript
POST/guilds/{guildId}/tickets/{ticketNo}/closetickets:writeClose a ticket
GET/guilds/{guildId}/applications/formsapplications:readList application forms
GET/guilds/{guildId}/applications/submissionsapplications:readList applications
GET/guilds/{guildId}/applications/submissions/{number}applications:readGet an application
POST/guilds/{guildId}/applications/submissions/{number}/decisionapplications:writeAccept or deny an application
GET/guilds/{guildId}/appealsappeals:readList ban appeals
GET/guilds/{guildId}/appeals/{number}appeals:readGet a ban appeal
POST/guilds/{guildId}/appeals/{number}/approveappeals:write SensitiveApprove a ban appeal (unban)
POST/guilds/{guildId}/appeals/{number}/rejectappeals:write SensitiveReject a ban appeal
GET/guilds/{guildId}/moderation/casesmoderation:read SensitiveList moderation cases
GET/guilds/{guildId}/moderation/cases/{number}moderation:read SensitiveGet a moderation case
POST/guilds/{guildId}/moderation/users/{userId}/warnmoderation:write SensitiveWarn a member
POST/guilds/{guildId}/moderation/users/{userId}/timeoutmoderation:write SensitiveTime out a member
POST/guilds/{guildId}/moderation/users/{userId}/untimeoutmoderation:write SensitiveRemove a member’s timeout
POST/guilds/{guildId}/moderation/users/{userId}/kickmoderation:write SensitiveKick a member
POST/guilds/{guildId}/moderation/users/{userId}/banmoderation:write SensitiveBan a user
POST/guilds/{guildId}/moderation/users/{userId}/unbanmoderation:write SensitiveUnban a user
GET/guilds/{guildId}/moderation/actions/{actionId}moderation:write SensitiveGet the result of a moderation action
GET/guilds/{guildId}/shop/storesshop:readList stores
GET/guilds/{guildId}/shop/itemsshop:readList items
GET/guilds/{guildId}/shop/items/{itemId}shop:readGet an item
PATCH/guilds/{guildId}/shop/items/{itemId}shop:write SensitiveRestock or turn an item on/off
GET/guilds/{guildId}/shop/members/{userId}/inventoryshop:readA member’s inventory
GET/guilds/{guildId}/shop/purchasesshop:readList purchases
GET/guilds/{guildId}/shop/purchases/{purchaseId}shop:readGet a purchase
POST/guilds/{guildId}/shop/members/{userId}/purchasesshop:write SensitiveBuy an item for a member
POST/guilds/{guildId}/shop/members/{userId}/grantsshop:write SensitiveGive an item to a member for free
POST/guilds/{guildId}/shop/purchases/{purchaseId}/refundshop:write SensitiveRefund a purchase
GET/guilds/{guildId}/giveawaysgiveaways:readList giveaways
POST/guilds/{guildId}/giveawaysgiveaways:writeStart a giveaway
GET/guilds/{guildId}/giveaways/{giveawayId}giveaways:readGet a giveaway
GET/guilds/{guildId}/giveaways/{giveawayId}/entriesgiveaways:readList a giveaway’s entrants
POST/guilds/{guildId}/giveaways/{giveawayId}/endgiveaways:writeEnd a giveaway now
POST/guilds/{guildId}/giveaways/{giveawayId}/rerollgiveaways:writeReroll winners
GET/guilds/{guildId}/flowsflows:readList flows
GET/guilds/{guildId}/flows/runs/{executionId}flows:readGet a flow run
POST/guilds/{guildId}/flows/{workflowId}/runsflows:run SensitiveRun a flow

The same description is available as an OpenAPI 3.1 document — import it into Postman, Insomnia or a client generator. It is served live (no key needed) at https://console.botgg.app/api/v1/openapi.json.

How the API behaves

  • Authentication and API keys — key format, scopes, expiry, revoking and security practices.
  • Errors — the error format and every error code with its HTTP status.
  • Rate limits — requests per minute per key by plan and the X-RateLimit-* headers.
  • Idempotent retries — the Idempotency-Key header that makes retried writes safe.
  • Webhooks — signed events BotGG sends to your server, with verification code.
  • AI assistants and MCP — using the API from AI tools.

Complete examples

A complete balance change with one idempotency key per change, waiting on 429/503 and handling INSUFFICIENT_FUNDS. Run it on your server, never in the browser.

Node.js · bank.mjs
// Node.js 22+ (built-in fetch). Run it on your server — never in a browser or game client.
const API = 'https://console.botgg.app/api/v1';
const KEY = process.env.BOTGG_API_KEY; // a key with the bank:write scope, kept in a secret
const GUILD_ID = '123456789012345678';

export async function changeBalance(userId, type, amount, reason) {
  // One Idempotency-Key per logical change: every retry below reuses it, so the change happens once.
  const idempotencyKey = crypto.randomUUID();

  for (let attempt = 1; attempt <= 3; attempt++) {
    const res = await fetch(`${API}/guilds/${GUILD_ID}/bank/members/${userId}/transactions`, {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${KEY}`,
        'Content-Type': 'application/json',
        'Idempotency-Key': idempotencyKey,
      },
      body: JSON.stringify({ type, amount, reason }),
    });
    const data = await res.json();

    if (res.ok) return data; // 201 — or the original response, replayed

    if (res.status === 429 || res.status === 503) {
      const seconds = Number(res.headers.get('Retry-After')) || attempt * 2;
      await new Promise((resolve) => setTimeout(resolve, seconds * 1000));
      continue;
    }
    if (data.error === 'INSUFFICIENT_FUNDS') {
      throw new Error(`Not enough balance: the member has ${data.balance}`);
    }
    throw new Error(`${res.status} ${data.error}: ${data.message}`);
  }
  throw new Error('BotGG API is busy, try again later');
}

const tx = await changeBalance('876543210987654321', 'add', 100, 'Tournament prize');
console.log(`New balance: ${tx.balance}`);
Python · bank.py
# Python 3 + requests. Run it on your server — never ship the key to clients.
import os, time, uuid
import requests

API = "https://console.botgg.app/api/v1"
KEY = os.environ["BOTGG_API_KEY"]  # a key with the bank:write scope
GUILD_ID = "123456789012345678"

def change_balance(user_id, type_, amount, reason=None):
    idempotency_key = str(uuid.uuid4())  # one per logical change, reused on every retry
    for attempt in range(1, 4):
        res = requests.post(
            f"{API}/guilds/{GUILD_ID}/bank/members/{user_id}/transactions",
            headers={"Authorization": f"Bearer {KEY}", "Idempotency-Key": idempotency_key},
            json={"type": type_, "amount": amount, "reason": reason},
            timeout=10,
        )
        data = res.json()
        if res.ok:
            return data  # 201 — or the original response, replayed
        if res.status_code in (429, 503):
            time.sleep(int(res.headers.get("Retry-After", attempt * 2)))
            continue
        raise RuntimeError(f"{res.status_code} {data['error']}: {data['message']}")
    raise RuntimeError("BotGG API is busy, try again later")

print(change_balance("876543210987654321", "add", 100, "Tournament prize")["balance"])

Frequently asked questions

Is the BotGG API free?

Yes. Every server can create 2 API keys with 60 requests per minute per key for free. Pro raises that to 10 keys and 600 requests per minute.

Can I call the API from JavaScript in the browser?

No. The API only accepts server-to-server requests: anything with an Origin header is rejected. Call it from your backend and pass the result to your page — that way your key stays secret.

How do I give members currency from my game or website?

Create a key with the bank:write scope and send POST /guilds/{guildId}/bank/members/{userId}/transactions with {"type":"add","amount":100}. Add an Idempotency-Key header so retries never pay twice.

Is there an OpenAPI specification?

Yes. The API publishes an OpenAPI 3.1 document generated from the endpoint registry, live at https://console.botgg.app/api/v1/openapi.json and as a download on every docs page. Import it into Postman, Insomnia or a code generator.

What happens if my API key leaks?

Revoke it in the console right away — it stops working immediately — then create a new one. Every Bank change made with a key is in the Bank ledger with the key’s name, so you can review what it did.

Ready to level up your server?

Add BotGG for free, then switch features on in the web console.