REST API v1 · Developers · API reference

Moderation API reference

All 9 Moderation endpoints of the BotGG REST API v1: scopes, parameters, fields, errors and ready-to-run curl, JavaScript and Python examples.

Developer docs
On this page

Endpoints

Paths are relative to https://console.botgg.app/api/v1. Send your API key as Authorization: Bearer botgg_…; IDs are strings.

Moderation endpoints
EndpointScopeDescription
GET/guilds/{guildId}/moderation/casesmoderation:readList moderation cases
GET/guilds/{guildId}/moderation/cases/{number}moderation:readGet a moderation case
POST/guilds/{guildId}/moderation/users/{userId}/warnmoderation:writeWarn a member
POST/guilds/{guildId}/moderation/users/{userId}/timeoutmoderation:writeTime out a member
POST/guilds/{guildId}/moderation/users/{userId}/untimeoutmoderation:writeRemove a member’s timeout
POST/guilds/{guildId}/moderation/users/{userId}/kickmoderation:writeKick a member
POST/guilds/{guildId}/moderation/users/{userId}/banmoderation:writeBan a user
POST/guilds/{guildId}/moderation/users/{userId}/unbanmoderation:writeUnban a user
GET/guilds/{guildId}/moderation/actions/{actionId}moderation:writeGet the result of a moderation action

Besides its own errors below, every endpoint can return these common ones:

List moderation cases

GET/guilds/{guildId}/moderation/cases

Scope: moderation:readSensitive

Newest first (deleted cases are left out). Pass before=<nextCursor> for the next page.

Needs this feature enabled on the server: Moderation

Parameters
NameInTypeRequiredDescription
guildIdpathstringYesYour server’s ID · Discord ID (string)
actionquerystringNoOne of warn, timeout, untimeout, kick, ban, tempban, softban, unban, note, purge
sourcequerystringNoOne of command, automod, escalation, antiraid, antinuke, console, api
userIdquerystringNoOnly cases against this user
Discord ID (string)
moderatorIdquerystringNoDiscord ID (string)
activequerystringNo1 = only running warnings / timeouts / tempbans
One of 1, 0, true, false
limitqueryintegerNo1–100 · Default 25
beforequeryintegerNo1–999,999,999

Response

Response fields · 200
FieldTypeRequiredDescription
itemsarray of objectYes
items[].numberintegerYes
items[].actionstringYesOne of warn, timeout, untimeout, kick, ban, tempban, softban, unban, note, purge
items[].userIdstringYesThe target
items[].userTagstring | nullYes
items[].moderatorIdstringYes
items[].reasonstring | nullYes
items[].durationSecondsinteger | nullYes
items[].evidencearray of stringYes
items[].sourcestringYesOne of command, automod, escalation, antiraid, antinuke, console, api
items[].activebooleanYes
items[].expiresAtstring | nullYesISO 8601 date-time
items[].resolvedAtstring | nullYesISO 8601 date-time
items[].dmStatusstring | nullYesOne of sent, failed, off
items[].apiKeyobject | nullYesSet when the action was made with an API key
items[].apiKey.idinteger | nullYes
items[].apiKey.namestring | nullYes
items[].createdAtstring | nullYesISO 8601 date-time
nextCursorstring | nullYes
Response · 200
{
  "items": [
    {
      "number": 7,
      "action": "warn",
      "userId": "876543210987654321",
      "userTag": "example",
      "moderatorId": "234567890123456789",
      "reason": "Tournament prize",
      "durationSeconds": 3600,
      "evidence": [
        "example"
      ],
      "source": "command",
      "active": true,
      "expiresAt": "2026-10-07T12:00:00.000Z",
      "resolvedAt": "2026-10-07T12:00:00.000Z",
      "dmStatus": "sent",
      "apiKey": {
        "id": 98765,
        "name": "Example"
      },
      "createdAt": "2026-10-07T12:00:00.000Z"
    }
  ],
  "nextCursor": "98700"
}

Examples

curl
curl -s "https://console.botgg.app/api/v1/guilds/123456789012345678/moderation/cases?limit=25" \
  -H "Authorization: Bearer $BOTGG_API_KEY"
JavaScript (fetch)
// Node.js 18+ (built-in fetch) — on your server, never in a browser
const res = await fetch('https://console.botgg.app/api/v1/guilds/123456789012345678/moderation/cases?limit=25', {
  method: 'GET',
  headers: {
    Authorization: `Bearer ${process.env.BOTGG_API_KEY}`,
  },
});
const data = await res.json();
if (!res.ok) throw new Error(`${res.status} ${data.error}: ${data.message}`);
console.log(data);
Python (requests)
import os
import requests

res = requests.get(
    "https://console.botgg.app/api/v1/guilds/123456789012345678/moderation/cases",
    headers={
        "Authorization": f"Bearer {os.environ['BOTGG_API_KEY']}",
    },
    params={
        "limit": 25,
    },
    timeout=10,
)
data = res.json()
if not res.ok:
    raise RuntimeError(f"{res.status_code} {data['error']}: {data['message']}")
print(data)

Errors

Get a moderation case

GET/guilds/{guildId}/moderation/cases/{number}

Scope: moderation:readSensitive

With its timeline (created, reason / evidence edits, DM, expired, revoked, escalated).

Needs this feature enabled on the server: Moderation

Parameters
NameInTypeRequiredDescription
guildIdpathstringYesYour server’s ID · Discord ID (string)
numberpathstringYes

Response

Response fields · 200
FieldTypeRequiredDescription
numberintegerYes
actionstringYesOne of warn, timeout, untimeout, kick, ban, tempban, softban, unban, note, purge
userIdstringYesThe target
userTagstring | nullYes
moderatorIdstringYes
reasonstring | nullYes
durationSecondsinteger | nullYes
evidencearray of stringYes
sourcestringYesOne of command, automod, escalation, antiraid, antinuke, console, api
activebooleanYes
expiresAtstring | nullYesISO 8601 date-time
resolvedAtstring | nullYesISO 8601 date-time
dmStatusstring | nullYesOne of sent, failed, off
apiKeyobject | nullYesSet when the action was made with an API key
apiKey.idinteger | nullYes
apiKey.namestring | nullYes
createdAtstring | nullYesISO 8601 date-time
eventsarray of objectYes
events[].typestringYes
events[].actorIdstring | nullYes
events[].dataanyYes
events[].createdAtstring | nullYesISO 8601 date-time
Response · 200
{
  "number": 7,
  "action": "warn",
  "userId": "876543210987654321",
  "userTag": "example",
  "moderatorId": "234567890123456789",
  "reason": "Tournament prize",
  "durationSeconds": 3600,
  "evidence": [
    "example"
  ],
  "source": "command",
  "active": true,
  "expiresAt": "2026-10-07T12:00:00.000Z",
  "resolvedAt": "2026-10-07T12:00:00.000Z",
  "dmStatus": "sent",
  "apiKey": {
    "id": 98765,
    "name": "Example"
  },
  "createdAt": "2026-10-07T12:00:00.000Z",
  "events": [
    {
      "type": "example",
      "actorId": "234567890123456789",
      "data": null,
      "createdAt": "2026-10-07T12:00:00.000Z"
    }
  ]
}

Examples

curl
curl -s "https://console.botgg.app/api/v1/guilds/123456789012345678/moderation/cases/234567890123456789" \
  -H "Authorization: Bearer $BOTGG_API_KEY"
JavaScript (fetch)
// Node.js 18+ (built-in fetch) — on your server, never in a browser
const res = await fetch('https://console.botgg.app/api/v1/guilds/123456789012345678/moderation/cases/234567890123456789', {
  method: 'GET',
  headers: {
    Authorization: `Bearer ${process.env.BOTGG_API_KEY}`,
  },
});
const data = await res.json();
if (!res.ok) throw new Error(`${res.status} ${data.error}: ${data.message}`);
console.log(data);
Python (requests)
import os
import requests

res = requests.get(
    "https://console.botgg.app/api/v1/guilds/123456789012345678/moderation/cases/234567890123456789",
    headers={
        "Authorization": f"Bearer {os.environ['BOTGG_API_KEY']}",
    },
    timeout=10,
)
data = res.json()
if not res.ok:
    raise RuntimeError(f"{res.status_code} {data['error']}: {data['message']}")
print(data)

Errors

Warn a member

POST/guilds/{guildId}/moderation/users/{userId}/warn

Scope: moderation:writeSensitiveIdempotency-Key

Same as /warn: a warning case (counts toward escalation), DM per the Moderation settings. Acts in the name of the key’s creator, who must still have the matching Discord permission; the target must be below their and the bot’s highest role (never the owner, the bot or the creator). The bot runs it within a few seconds — poll GET …/moderation/actions/{actionId}. At most 10 actions a minute per key. Written to the audit log.

Needs this feature enabled on the server: Moderation

Parameters
NameInTypeRequiredDescription
guildIdpathstringYesYour server’s ID · Discord ID (string)
userIdpathstringYesThe member’s Discord user ID · Discord ID (string)
Idempotency-KeyheaderstringNoOptional. Send a unique value (a UUID) and reuse it when you retry: the change happens only once. How it works

Request body

Request body
FieldTypeRequiredDescription
reasonstringYesRequired. Shown in the case, the mod log and the member’s DM
1–500 characters
evidencearray of stringNoUp to 5 links
up to 5 items

Response

Response fields · 202
FieldTypeRequiredDescription
actionIdstringYes
actionstringYesOne of warn, timeout, untimeout, kick, ban, unban
userIdstringYes
statusstringYesOne of pending, running, done, failed
caseNumberinteger | nullYes
errorstring | nullYesRefusal code when failed (e.g. HIERARCHY_HIGHER, MODERATOR_MISSING_PERMISSION, NOT_BANNED, BOT_MISSING_PERMISSIONS)
requestedAtstring | nullYesISO 8601 date-time
Response · 202
{
  "actionId": "234567890123456789",
  "action": "warn",
  "userId": "876543210987654321",
  "status": "pending",
  "caseNumber": 10,
  "error": "example",
  "requestedAt": "2026-10-07T12:00:00.000Z"
}

Examples

curl
curl -s -X POST "https://console.botgg.app/api/v1/guilds/123456789012345678/moderation/users/876543210987654321/warn" \
  -H "Authorization: Bearer $BOTGG_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"reason":"Tournament prize","evidence":["example"]}'
JavaScript (fetch)
// Node.js 18+ (built-in fetch) — on your server, never in a browser
const res = await fetch('https://console.botgg.app/api/v1/guilds/123456789012345678/moderation/users/876543210987654321/warn', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.BOTGG_API_KEY}`,
    'Content-Type': 'application/json',
    'Idempotency-Key': crypto.randomUUID(), // reuse it when you retry this request
  },
  body: JSON.stringify({
    reason: 'Tournament prize',
    evidence: [
      'example',
    ],
  }),
});
const data = await res.json();
if (!res.ok) throw new Error(`${res.status} ${data.error}: ${data.message}`);
console.log(data);
Python (requests)
import os, uuid
import requests

res = requests.post(
    "https://console.botgg.app/api/v1/guilds/123456789012345678/moderation/users/876543210987654321/warn",
    headers={
        "Authorization": f"Bearer {os.environ['BOTGG_API_KEY']}",
        "Idempotency-Key": str(uuid.uuid4()),  # reuse it when you retry this request
    },
    json={
        "reason": "Tournament prize",
        "evidence": [
            "example",
        ],
    },
    timeout=10,
)
data = res.json()
if not res.ok:
    raise RuntimeError(f"{res.status_code} {data['error']}: {data['message']}")
print(data)

Errors

Time out a member

POST/guilds/{guildId}/moderation/users/{userId}/timeout

Scope: moderation:writeSensitiveIdempotency-Key

Same as /timeout: Discord timeout for durationSeconds, a case, DM per the settings. Acts in the name of the key’s creator, who must still have the matching Discord permission; the target must be below their and the bot’s highest role (never the owner, the bot or the creator). The bot runs it within a few seconds — poll GET …/moderation/actions/{actionId}. At most 10 actions a minute per key. Written to the audit log.

Needs this feature enabled on the server: Moderation

Parameters
NameInTypeRequiredDescription
guildIdpathstringYesYour server’s ID · Discord ID (string)
userIdpathstringYesThe member’s Discord user ID · Discord ID (string)
Idempotency-KeyheaderstringNoOptional. Send a unique value (a UUID) and reuse it when you retry: the change happens only once. How it works

Request body

Request body
FieldTypeRequiredDescription
reasonstringYesRequired. Shown in the case, the mod log and the member’s DM
1–500 characters
durationSecondsintegerYes1 minute to 28 days
60–2,419,200
evidencearray of stringNoUp to 5 links
up to 5 items

Response

Response fields · 202
FieldTypeRequiredDescription
actionIdstringYes
actionstringYesOne of warn, timeout, untimeout, kick, ban, unban
userIdstringYes
statusstringYesOne of pending, running, done, failed
caseNumberinteger | nullYes
errorstring | nullYesRefusal code when failed (e.g. HIERARCHY_HIGHER, MODERATOR_MISSING_PERMISSION, NOT_BANNED, BOT_MISSING_PERMISSIONS)
requestedAtstring | nullYesISO 8601 date-time
Response · 202
{
  "actionId": "234567890123456789",
  "action": "warn",
  "userId": "876543210987654321",
  "status": "pending",
  "caseNumber": 10,
  "error": "example",
  "requestedAt": "2026-10-07T12:00:00.000Z"
}

Examples

curl
curl -s -X POST "https://console.botgg.app/api/v1/guilds/123456789012345678/moderation/users/876543210987654321/timeout" \
  -H "Authorization: Bearer $BOTGG_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"reason":"Tournament prize","durationSeconds":3600,"evidence":["example"]}'
JavaScript (fetch)
// Node.js 18+ (built-in fetch) — on your server, never in a browser
const res = await fetch('https://console.botgg.app/api/v1/guilds/123456789012345678/moderation/users/876543210987654321/timeout', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.BOTGG_API_KEY}`,
    'Content-Type': 'application/json',
    'Idempotency-Key': crypto.randomUUID(), // reuse it when you retry this request
  },
  body: JSON.stringify({
    reason: 'Tournament prize',
    durationSeconds: 3600,
    evidence: [
      'example',
    ],
  }),
});
const data = await res.json();
if (!res.ok) throw new Error(`${res.status} ${data.error}: ${data.message}`);
console.log(data);
Python (requests)
import os, uuid
import requests

res = requests.post(
    "https://console.botgg.app/api/v1/guilds/123456789012345678/moderation/users/876543210987654321/timeout",
    headers={
        "Authorization": f"Bearer {os.environ['BOTGG_API_KEY']}",
        "Idempotency-Key": str(uuid.uuid4()),  # reuse it when you retry this request
    },
    json={
        "reason": "Tournament prize",
        "durationSeconds": 3600,
        "evidence": [
            "example",
        ],
    },
    timeout=10,
)
data = res.json()
if not res.ok:
    raise RuntimeError(f"{res.status_code} {data['error']}: {data['message']}")
print(data)

Errors

Remove a member’s timeout

POST/guilds/{guildId}/moderation/users/{userId}/untimeout

Scope: moderation:writeSensitiveIdempotency-Key

Same as /untimeout. Acts in the name of the key’s creator, who must still have the matching Discord permission; the target must be below their and the bot’s highest role (never the owner, the bot or the creator). The bot runs it within a few seconds — poll GET …/moderation/actions/{actionId}. At most 10 actions a minute per key. Written to the audit log.

Needs this feature enabled on the server: Moderation

Parameters
NameInTypeRequiredDescription
guildIdpathstringYesYour server’s ID · Discord ID (string)
userIdpathstringYesThe member’s Discord user ID · Discord ID (string)
Idempotency-KeyheaderstringNoOptional. Send a unique value (a UUID) and reuse it when you retry: the change happens only once. How it works

Request body

Request body
FieldTypeRequiredDescription
reasonstringYesRequired. Shown in the case, the mod log and the member’s DM
1–500 characters

Response

Response fields · 202
FieldTypeRequiredDescription
actionIdstringYes
actionstringYesOne of warn, timeout, untimeout, kick, ban, unban
userIdstringYes
statusstringYesOne of pending, running, done, failed
caseNumberinteger | nullYes
errorstring | nullYesRefusal code when failed (e.g. HIERARCHY_HIGHER, MODERATOR_MISSING_PERMISSION, NOT_BANNED, BOT_MISSING_PERMISSIONS)
requestedAtstring | nullYesISO 8601 date-time
Response · 202
{
  "actionId": "234567890123456789",
  "action": "warn",
  "userId": "876543210987654321",
  "status": "pending",
  "caseNumber": 10,
  "error": "example",
  "requestedAt": "2026-10-07T12:00:00.000Z"
}

Examples

curl
curl -s -X POST "https://console.botgg.app/api/v1/guilds/123456789012345678/moderation/users/876543210987654321/untimeout" \
  -H "Authorization: Bearer $BOTGG_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"reason":"Tournament prize"}'
JavaScript (fetch)
// Node.js 18+ (built-in fetch) — on your server, never in a browser
const res = await fetch('https://console.botgg.app/api/v1/guilds/123456789012345678/moderation/users/876543210987654321/untimeout', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.BOTGG_API_KEY}`,
    'Content-Type': 'application/json',
    'Idempotency-Key': crypto.randomUUID(), // reuse it when you retry this request
  },
  body: JSON.stringify({
    reason: 'Tournament prize',
  }),
});
const data = await res.json();
if (!res.ok) throw new Error(`${res.status} ${data.error}: ${data.message}`);
console.log(data);
Python (requests)
import os, uuid
import requests

res = requests.post(
    "https://console.botgg.app/api/v1/guilds/123456789012345678/moderation/users/876543210987654321/untimeout",
    headers={
        "Authorization": f"Bearer {os.environ['BOTGG_API_KEY']}",
        "Idempotency-Key": str(uuid.uuid4()),  # reuse it when you retry this request
    },
    json={
        "reason": "Tournament prize",
    },
    timeout=10,
)
data = res.json()
if not res.ok:
    raise RuntimeError(f"{res.status_code} {data['error']}: {data['message']}")
print(data)

Errors

Kick a member

POST/guilds/{guildId}/moderation/users/{userId}/kick

Scope: moderation:writeSensitiveIdempotency-Key

Same as /kick: DM (before the kick) per the settings, then the kick and a case. Acts in the name of the key’s creator, who must still have the matching Discord permission; the target must be below their and the bot’s highest role (never the owner, the bot or the creator). The bot runs it within a few seconds — poll GET …/moderation/actions/{actionId}. At most 10 actions a minute per key. Written to the audit log.

Needs this feature enabled on the server: Moderation

Parameters
NameInTypeRequiredDescription
guildIdpathstringYesYour server’s ID · Discord ID (string)
userIdpathstringYesThe member’s Discord user ID · Discord ID (string)
Idempotency-KeyheaderstringNoOptional. Send a unique value (a UUID) and reuse it when you retry: the change happens only once. How it works

Request body

Request body
FieldTypeRequiredDescription
reasonstringYesRequired. Shown in the case, the mod log and the member’s DM
1–500 characters
evidencearray of stringNoUp to 5 links
up to 5 items

Response

Response fields · 202
FieldTypeRequiredDescription
actionIdstringYes
actionstringYesOne of warn, timeout, untimeout, kick, ban, unban
userIdstringYes
statusstringYesOne of pending, running, done, failed
caseNumberinteger | nullYes
errorstring | nullYesRefusal code when failed (e.g. HIERARCHY_HIGHER, MODERATOR_MISSING_PERMISSION, NOT_BANNED, BOT_MISSING_PERMISSIONS)
requestedAtstring | nullYesISO 8601 date-time
Response · 202
{
  "actionId": "234567890123456789",
  "action": "warn",
  "userId": "876543210987654321",
  "status": "pending",
  "caseNumber": 10,
  "error": "example",
  "requestedAt": "2026-10-07T12:00:00.000Z"
}

Examples

curl
curl -s -X POST "https://console.botgg.app/api/v1/guilds/123456789012345678/moderation/users/876543210987654321/kick" \
  -H "Authorization: Bearer $BOTGG_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"reason":"Tournament prize","evidence":["example"]}'
JavaScript (fetch)
// Node.js 18+ (built-in fetch) — on your server, never in a browser
const res = await fetch('https://console.botgg.app/api/v1/guilds/123456789012345678/moderation/users/876543210987654321/kick', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.BOTGG_API_KEY}`,
    'Content-Type': 'application/json',
    'Idempotency-Key': crypto.randomUUID(), // reuse it when you retry this request
  },
  body: JSON.stringify({
    reason: 'Tournament prize',
    evidence: [
      'example',
    ],
  }),
});
const data = await res.json();
if (!res.ok) throw new Error(`${res.status} ${data.error}: ${data.message}`);
console.log(data);
Python (requests)
import os, uuid
import requests

res = requests.post(
    "https://console.botgg.app/api/v1/guilds/123456789012345678/moderation/users/876543210987654321/kick",
    headers={
        "Authorization": f"Bearer {os.environ['BOTGG_API_KEY']}",
        "Idempotency-Key": str(uuid.uuid4()),  # reuse it when you retry this request
    },
    json={
        "reason": "Tournament prize",
        "evidence": [
            "example",
        ],
    },
    timeout=10,
)
data = res.json()
if not res.ok:
    raise RuntimeError(f"{res.status_code} {data['error']}: {data['message']}")
print(data)

Errors

Ban a user

POST/guilds/{guildId}/moderation/users/{userId}/ban

Scope: moderation:writeSensitiveIdempotency-Key

Same as /ban: with durationSeconds a temporary ban the bot lifts automatically; deleteMessageSeconds deletes recent messages. Works for users who already left. Acts in the name of the key’s creator, who must still have the matching Discord permission; the target must be below their and the bot’s highest role (never the owner, the bot or the creator). The bot runs it within a few seconds — poll GET …/moderation/actions/{actionId}. At most 10 actions a minute per key. Written to the audit log.

Needs this feature enabled on the server: Moderation

Parameters
NameInTypeRequiredDescription
guildIdpathstringYesYour server’s ID · Discord ID (string)
userIdpathstringYesThe member’s Discord user ID · Discord ID (string)
Idempotency-KeyheaderstringNoOptional. Send a unique value (a UUID) and reuse it when you retry: the change happens only once. How it works

Request body

Request body
FieldTypeRequiredDescription
reasonstringYesRequired. Shown in the case, the mod log and the member’s DM
1–500 characters
deleteMessageSecondsintegerNoDelete the user’s messages of the last N seconds (≤ 7 days)
0–604,800
durationSecondsinteger | nullNoTemporary ban (≤ 365 days); omit for a permanent ban
60–31,536,000
evidencearray of stringNoUp to 5 links
up to 5 items

Response

Response fields · 202
FieldTypeRequiredDescription
actionIdstringYes
actionstringYesOne of warn, timeout, untimeout, kick, ban, unban
userIdstringYes
statusstringYesOne of pending, running, done, failed
caseNumberinteger | nullYes
errorstring | nullYesRefusal code when failed (e.g. HIERARCHY_HIGHER, MODERATOR_MISSING_PERMISSION, NOT_BANNED, BOT_MISSING_PERMISSIONS)
requestedAtstring | nullYesISO 8601 date-time
Response · 202
{
  "actionId": "234567890123456789",
  "action": "warn",
  "userId": "876543210987654321",
  "status": "pending",
  "caseNumber": 10,
  "error": "example",
  "requestedAt": "2026-10-07T12:00:00.000Z"
}

Examples

curl
curl -s -X POST "https://console.botgg.app/api/v1/guilds/123456789012345678/moderation/users/876543210987654321/ban" \
  -H "Authorization: Bearer $BOTGG_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"reason":"Tournament prize","deleteMessageSeconds":3600,"durationSeconds":3600,"evidence":["example"]}'
JavaScript (fetch)
// Node.js 18+ (built-in fetch) — on your server, never in a browser
const res = await fetch('https://console.botgg.app/api/v1/guilds/123456789012345678/moderation/users/876543210987654321/ban', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.BOTGG_API_KEY}`,
    'Content-Type': 'application/json',
    'Idempotency-Key': crypto.randomUUID(), // reuse it when you retry this request
  },
  body: JSON.stringify({
    reason: 'Tournament prize',
    deleteMessageSeconds: 3600,
    durationSeconds: 3600,
    evidence: [
      'example',
    ],
  }),
});
const data = await res.json();
if (!res.ok) throw new Error(`${res.status} ${data.error}: ${data.message}`);
console.log(data);
Python (requests)
import os, uuid
import requests

res = requests.post(
    "https://console.botgg.app/api/v1/guilds/123456789012345678/moderation/users/876543210987654321/ban",
    headers={
        "Authorization": f"Bearer {os.environ['BOTGG_API_KEY']}",
        "Idempotency-Key": str(uuid.uuid4()),  # reuse it when you retry this request
    },
    json={
        "reason": "Tournament prize",
        "deleteMessageSeconds": 3600,
        "durationSeconds": 3600,
        "evidence": [
            "example",
        ],
    },
    timeout=10,
)
data = res.json()
if not res.ok:
    raise RuntimeError(f"{res.status_code} {data['error']}: {data['message']}")
print(data)

Errors

Unban a user

POST/guilds/{guildId}/moderation/users/{userId}/unban

Scope: moderation:writeSensitiveIdempotency-Key

Same as /unban (ends a running tempban). 409 NOT_BANNED when the user isn’t banned. Acts in the name of the key’s creator, who must still have the matching Discord permission; the target must be below their and the bot’s highest role (never the owner, the bot or the creator). The bot runs it within a few seconds — poll GET …/moderation/actions/{actionId}. At most 10 actions a minute per key. Written to the audit log.

Needs this feature enabled on the server: Moderation

Parameters
NameInTypeRequiredDescription
guildIdpathstringYesYour server’s ID · Discord ID (string)
userIdpathstringYesThe member’s Discord user ID · Discord ID (string)
Idempotency-KeyheaderstringNoOptional. Send a unique value (a UUID) and reuse it when you retry: the change happens only once. How it works

Request body

Request body
FieldTypeRequiredDescription
reasonstringYesRequired. Shown in the case, the mod log and the member’s DM
1–500 characters

Response

Response fields · 202
FieldTypeRequiredDescription
actionIdstringYes
actionstringYesOne of warn, timeout, untimeout, kick, ban, unban
userIdstringYes
statusstringYesOne of pending, running, done, failed
caseNumberinteger | nullYes
errorstring | nullYesRefusal code when failed (e.g. HIERARCHY_HIGHER, MODERATOR_MISSING_PERMISSION, NOT_BANNED, BOT_MISSING_PERMISSIONS)
requestedAtstring | nullYesISO 8601 date-time
Response · 202
{
  "actionId": "234567890123456789",
  "action": "warn",
  "userId": "876543210987654321",
  "status": "pending",
  "caseNumber": 10,
  "error": "example",
  "requestedAt": "2026-10-07T12:00:00.000Z"
}

Examples

curl
curl -s -X POST "https://console.botgg.app/api/v1/guilds/123456789012345678/moderation/users/876543210987654321/unban" \
  -H "Authorization: Bearer $BOTGG_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"reason":"Tournament prize"}'
JavaScript (fetch)
// Node.js 18+ (built-in fetch) — on your server, never in a browser
const res = await fetch('https://console.botgg.app/api/v1/guilds/123456789012345678/moderation/users/876543210987654321/unban', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.BOTGG_API_KEY}`,
    'Content-Type': 'application/json',
    'Idempotency-Key': crypto.randomUUID(), // reuse it when you retry this request
  },
  body: JSON.stringify({
    reason: 'Tournament prize',
  }),
});
const data = await res.json();
if (!res.ok) throw new Error(`${res.status} ${data.error}: ${data.message}`);
console.log(data);
Python (requests)
import os, uuid
import requests

res = requests.post(
    "https://console.botgg.app/api/v1/guilds/123456789012345678/moderation/users/876543210987654321/unban",
    headers={
        "Authorization": f"Bearer {os.environ['BOTGG_API_KEY']}",
        "Idempotency-Key": str(uuid.uuid4()),  # reuse it when you retry this request
    },
    json={
        "reason": "Tournament prize",
    },
    timeout=10,
)
data = res.json()
if not res.ok:
    raise RuntimeError(f"{res.status_code} {data['error']}: {data['message']}")
print(data)

Errors

Get the result of a moderation action

GET/guilds/{guildId}/moderation/actions/{actionId}

Scope: moderation:writeSensitive

Only actions made with the same API key. done → caseNumber; failed → error (the bot re-checks everything right before acting).

Needs this feature enabled on the server: Moderation

Parameters
NameInTypeRequiredDescription
guildIdpathstringYesYour server’s ID · Discord ID (string)
actionIdpathstringYes

Response

Response fields · 200
FieldTypeRequiredDescription
actionIdstringYes
actionstringYesOne of warn, timeout, untimeout, kick, ban, unban
userIdstringYes
statusstringYesOne of pending, running, done, failed
caseNumberinteger | nullYes
errorstring | nullYesRefusal code when failed (e.g. HIERARCHY_HIGHER, MODERATOR_MISSING_PERMISSION, NOT_BANNED, BOT_MISSING_PERMISSIONS)
requestedAtstring | nullYesISO 8601 date-time
Response · 200
{
  "actionId": "234567890123456789",
  "action": "warn",
  "userId": "876543210987654321",
  "status": "pending",
  "caseNumber": 10,
  "error": "example",
  "requestedAt": "2026-10-07T12:00:00.000Z"
}

Examples

curl
curl -s "https://console.botgg.app/api/v1/guilds/123456789012345678/moderation/actions/234567890123456789" \
  -H "Authorization: Bearer $BOTGG_API_KEY"
JavaScript (fetch)
// Node.js 18+ (built-in fetch) — on your server, never in a browser
const res = await fetch('https://console.botgg.app/api/v1/guilds/123456789012345678/moderation/actions/234567890123456789', {
  method: 'GET',
  headers: {
    Authorization: `Bearer ${process.env.BOTGG_API_KEY}`,
  },
});
const data = await res.json();
if (!res.ok) throw new Error(`${res.status} ${data.error}: ${data.message}`);
console.log(data);
Python (requests)
import os
import requests

res = requests.get(
    "https://console.botgg.app/api/v1/guilds/123456789012345678/moderation/actions/234567890123456789",
    headers={
        "Authorization": f"Bearer {os.environ['BOTGG_API_KEY']}",
    },
    timeout=10,
)
data = res.json()
if not res.ok:
    raise RuntimeError(f"{res.status_code} {data['error']}: {data['message']}")
print(data)

Errors

Ready to level up your server?

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