{"openapi":"3.1.0","info":{"title":"cormac API","version":"1.0.0","description":"What cormac knows about servers you own, over plain JSON: daily statistics, progression leaderboards, ticket analytics, honeypot counts, and everything about one member. Keys with write scopes can also change a member's XP and automod strikes and exemptions; every change shows in the server's Recent changes.\n\nRate limited to 60 requests a minute and 10,000 a day per key, and writes to 30 a minute.","contact":{"name":"cormac","url":"https://cormac.gg"},"license":{"name":"CC0-1.0","identifier":"CC0-1.0"}},"servers":[{"url":"https://api.cormac.gg"}],"tags":[{"name":"Servers","description":"The servers a key can reach, and what each one has switched on."},{"name":"Members","description":"One member as cormac knows them, and the few things about them a key can change: XP, automod strikes, and automod rule exemptions."},{"name":"Statistics","description":"Daily member, message, moderation and voice counts, with per-channel, hourly and voice breakdowns."},{"name":"Progression","description":"Leaderboard standings and individual level and XP."},{"name":"Tickets","description":"Support volume, response times, ratings, and the live open queue."},{"name":"Honeypot","description":"Spam-bot trap counts, in total and per trap channel."},{"name":"Moderation","description":"Numbered moderation cases: warnings, notes, timeouts, kicks and bans."},{"name":"Diagnostics","description":"What a server has configured incorrectly, as cormac sees it."}],"security":[{"bearerAuth":[]}],"paths":{"/v1/guilds":{"get":{"operationId":"listServers","summary":"List your servers","description":"Servers you own where cormac+ is active. Plugin lists are empty here; fetch a single server to see its plugins.\n\nThe key must belong to the server owner, and cormac+ must be active on the server. Requires the `guilds:read` scope.","tags":["Servers"],"x-required-scope":"guilds:read","parameters":[],"responses":{"200":{"description":"Success","content":{"application/json":{"example":{"guilds":[{"id":"1467281625954914369","name":"Zeta Studio","iconUrl":"https://cdn.discordapp.com/...","memberCount":1284,"premiumActive":true,"enabledPlugins":[]}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionInactive"},"403":{"$ref":"#/components/responses/ForbiddenScope"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/UpstreamUnavailable"}}}},"/v1/guilds/{guildId}":{"get":{"operationId":"getServer","summary":"One server","description":"Summary plus the plugins switched on right now, which decides what else this key can read.\n\nThe key must belong to the server owner, and cormac+ must be active on the server. Requires the `guilds:read` scope.","tags":["Servers"],"x-required-scope":"guilds:read","parameters":[{"name":"guildId","in":"path","required":true,"description":"Discord server id. Must be a server you own with cormac+ active.","schema":{"type":"string","pattern":"^\\d{17,20}$"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"example":{"guild":{"id":"1467281625954914369","name":"Zeta Studio","iconUrl":"https://cdn.discordapp.com/...","memberCount":1284,"premiumActive":true,"enabledPlugins":["tickets","progression"]}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionInactive"},"403":{"$ref":"#/components/responses/ForbiddenScope"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/UpstreamUnavailable"}}}},"/v1/guilds/{guildId}/members/{userId}":{"get":{"operationId":"member","summary":"One member","description":"Everything cormac knows about one member of your server: their Discord profile and roles, then one section for each plugin that keeps something about members, such as their XP, automod strikes, starboard posts and tickets.\n\nA plugin section appears only when the plugin is on and the key may read it. `progression` needs `progression:read`, `tickets` needs `tickets:read` and `moderation` needs `moderation:read`; the rest come with `members:read`. Every member plugin left out is listed in `unavailable` with the reason, so a missing section never looks like an empty one.\n\nA section is `null` when the plugin is on but holds nothing for this member yet, such as no XP or anti-ping never set up. Honeypot, Logging and Welcome keep nothing about individual members, so they never appear.\n\n`tickets.closed` lists the 25 newest closed tickets the member opened, claimed, closed or wrote in; `closedTotal` counts all of them. Form answers, close reasons and rating comments are never included: they are text people wrote, and the API carries no message content.\n\n`automod.exemptions` says which rules leave the member alone and why: listed by name (`user`), through a role, or as owner, Administrator or Bot Master. Only `user` exemptions can be changed through the API. `recentChanges` lists dashboard and API changes this member made.\n\n`member.voice` is the voice channel they are in right now, or `null`. Online status and activities such as \"Playing\" are not available: they need a Discord permission cormac does not request.\n\nThe member has to be in the server. Someone who left is a 404, even if cormac still holds their XP.\n\nThe key must belong to the server owner, and cormac+ must be active on the server. Requires the `members:read` scope.","tags":["Members"],"x-required-scope":"members:read","parameters":[{"name":"guildId","in":"path","required":true,"description":"Discord server id. Must be a server you own with cormac+ active.","schema":{"type":"string","pattern":"^\\d{17,20}$"}},{"name":"userId","in":"path","required":true,"description":"Discord user id.","schema":{"type":"string","pattern":"^\\d{17,20}$"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"example":{"guildId":"1467281625954914369","member":{"userId":"263304948291207170","username":"mira","globalName":"Mira","nickname":"mira | mod","displayName":"mira | mod","avatarUrl":"https://cdn.discordapp.com/...","bot":false,"accountCreatedAt":1612137600,"joinedAt":1700000000,"boostingSince":null,"timedOutUntil":null,"roles":[{"id":"1486015573702869174","name":"Moderator","color":3447003,"position":12}],"dashboardAccess":"bot_master","voice":{"channelId":"1467281626626003066","channelName":"Lounge","selfMute":false,"selfDeaf":false,"serverMute":false,"serverDeaf":false,"streaming":true,"video":false}},"plugins":{"progression":{"rank":4,"level":18,"xp":640,"nextLevelAt":19000,"totalXp":17740,"messages":1290,"lastXpAt":1791105120},"antiping":{"enabled":true,"action":"delete_reply","replyMessage":"{author}, please don't ping me.","updatedAt":1787337000},"automod":{"exemptions":[{"ruleId":"block-invites","ruleName":"Block invites","ruleEnabled":true,"via":"role","roleId":"1486015573702869174"}],"strikes":[{"counter":"spam","count":1,"threshold":3,"windowSeconds":3600,"lastStrikeAt":1791063600,"cooldownUntil":null}]},"starboard":{"posts":3,"stars":41,"top":[{"channelId":"1500847305706836070","messageId":"1501203337610461245","boardChannelId":"1486015573702869175","boardMessageId":"1501203391742149783","stars":22,"createdAt":1790953200}]},"tickets":{"open":[],"closed":[{"transcriptId":"9f2c41d07a6be3a1c5d8e2f4b6a8c0d1e3f5a7b9","channelId":"1500847305706836071","categoryId":"general_support","categoryName":"General support","openedAt":1790766300,"closedAt":1790770800,"roles":["claimer","closer"],"messages":14}],"closedTotal":37,"ratings":{"count":0,"average":null}},"moderation":{"total":2,"counts":{"warn":1,"timeout":1},"recent":[{"caseNumber":58,"type":"timeout","source":"automod","moderatorId":null,"reason":"Slow down","durationSeconds":600,"ruleName":"Message spam","createdAt":1790953800}]}},"recentChanges":[{"at":1791106200,"area":"honeypot","summary":"Turned on Honeypot"}],"unavailable":[]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionInactive"},"403":{"$ref":"#/components/responses/ForbiddenScope"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/UpstreamUnavailable"}}}},"/v1/guilds/{guildId}/members/{userId}/progression":{"patch":{"operationId":"changeMemberXp","summary":"Change a member's XP","description":"Set a member's XP or level, or add to it or take from it. Their reward roles move to match, the same as with `/xp` in Discord, and no level-up message is posted.\n\n`addXp` is the one write where a retry changes the outcome, so send an `Idempotency-Key` with it if you retry on timeouts. Changes to one member run one at a time inside cormac, together with XP earned from messages, so a burst of calls never loses one.\n\n`previous` has no rank: working it out again would mean ranking every member twice.\n\nEvery change shows in the server's Recent changes on the dashboard, with the key's name and prefix and the reason if you send one. Writes are server-side only: browsers are refused at the CORS preflight, so a key that can change data never has to sit in a web page.\n\nThe key must belong to the server owner, and cormac+ must be active on the server. Requires the `progression:write` scope. The progression plugin must be enabled on the server.","tags":["Members"],"x-required-scope":"progression:write","x-required-plugin":"progression","parameters":[{"name":"guildId","in":"path","required":true,"description":"Discord server id. Must be a server you own with cormac+ active.","schema":{"type":"string","pattern":"^\\d{17,20}$"}},{"name":"userId","in":"path","required":true,"description":"Discord user id.","schema":{"type":"string","pattern":"^\\d{17,20}$"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Any string up to 255 characters you choose for this change, such as a UUID. A retry with the same key gets the first response back instead of making the change again, for 24 hours. Reusing a key for a different request is a 400; retrying while the first is still running is a 409 `IDEMPOTENCY_CONFLICT`. A 5xx is not kept, so the same key can be retried.","schema":{"type":"string"}},{"name":"X-Audit-Log-Reason","in":"header","required":false,"description":"Why, in up to 200 characters, URI-encoded as Discord expects. It shows next to the change in the server's Recent changes.","schema":{"type":"string"}}],"requestBody":{"required":true,"description":"Send exactly one of these.","content":{"application/json":{"schema":{"type":"object","properties":{"xp":{"type":"integer","minimum":0,"description":"Set total XP to exactly this. Up to the XP level 1,000 starts at."},"level":{"type":"integer","minimum":0,"maximum":1000,"description":"Set the level, at the XP that level starts at."},"addXp":{"type":"integer","minimum":-1000000,"maximum":1000000,"description":"Add this much, or take it away when negative. Not 0. Total XP never drops below 0."}},"additionalProperties":false,"oneOf":[{"required":["xp"]},{"required":["level"]},{"required":["addXp"]}]},"example":{"addXp":1400}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"example":{"guildId":"1467281625954914369","userId":"263304948291207170","previous":{"level":18,"xp":640,"nextLevelAt":19000,"totalXp":17740},"current":{"level":19,"xp":140,"nextLevelAt":21000,"totalXp":19140,"rank":3,"messages":1290,"lastXpAt":1791105120}}}}},"400":{"description":"The request is malformed:\n\n- `guildId` is not a Discord id.\n- `userId` is not a Discord id.\n- The body is not JSON, or has anything other than exactly one of `xp`, `level` or `addXp`.\n- The value is not a whole number, is negative where it can't be, or is past its limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"code":"BAD_REQUEST","message":"Send exactly one of xp, level or addXp"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionInactive"},"403":{"$ref":"#/components/responses/ForbiddenScope"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/WriteConflict"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/UpstreamUnavailable"}}}},"/v1/guilds/{guildId}/members/{userId}/automod/strikes":{"delete":{"operationId":"clearMemberStrikes","summary":"Clear automod strikes","description":"Forget a member's automod strikes, and any escalation cooldown, on every counter or on one. The next violation starts counting from zero.\n\n`cleared` names the counters that still had strikes or a cooldown. Clearing a member with none is not an error; `cleared` is just empty.\n\nEvery change shows in the server's Recent changes on the dashboard, with the key's name and prefix and the reason if you send one. Writes are server-side only: browsers are refused at the CORS preflight, so a key that can change data never has to sit in a web page.\n\nThe key must belong to the server owner, and cormac+ must be active on the server. Requires the `automod:write` scope. The automod plugin must be enabled on the server.","tags":["Members"],"x-required-scope":"automod:write","x-required-plugin":"automod","parameters":[{"name":"guildId","in":"path","required":true,"description":"Discord server id. Must be a server you own with cormac+ active.","schema":{"type":"string","pattern":"^\\d{17,20}$"}},{"name":"userId","in":"path","required":true,"description":"Discord user id.","schema":{"type":"string","pattern":"^\\d{17,20}$"}},{"name":"counter","in":"query","required":false,"description":"Clear only this counter, as named in the rule. Defaults to every counter.","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Any string up to 255 characters you choose for this change, such as a UUID. A retry with the same key gets the first response back instead of making the change again, for 24 hours. Reusing a key for a different request is a 400; retrying while the first is still running is a 409 `IDEMPOTENCY_CONFLICT`. A 5xx is not kept, so the same key can be retried.","schema":{"type":"string"}},{"name":"X-Audit-Log-Reason","in":"header","required":false,"description":"Why, in up to 200 characters, URI-encoded as Discord expects. It shows next to the change in the server's Recent changes.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"example":{"guildId":"1467281625954914369","userId":"263304948291207170","cleared":["spam"]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionInactive"},"403":{"$ref":"#/components/responses/ForbiddenScope"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/WriteConflict"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/UpstreamUnavailable"}}}},"/v1/guilds/{guildId}/members/{userId}/automod/exemptions/{ruleId}":{"put":{"operationId":"exemptMember","summary":"Exempt from an automod rule","description":"Add the member to a rule's exempt members, so the rule leaves them alone. Doing it twice is fine: `changed` says whether this call did anything.\n\nA rule exempts at most 100 members, the same as on the dashboard. Rule ids are on the member endpoint's `automod.exemptions` and in the dashboard. An unknown rule is a 404.\n\nA dashboard save of the Automod page replaces the whole configuration, so an exemption added here while someone has the page open is undone if they save without reloading.\n\nEvery change shows in the server's Recent changes on the dashboard, with the key's name and prefix and the reason if you send one. Writes are server-side only: browsers are refused at the CORS preflight, so a key that can change data never has to sit in a web page.\n\nThe key must belong to the server owner, and cormac+ must be active on the server. Requires the `automod:write` scope. The automod plugin must be enabled on the server.","tags":["Members"],"x-required-scope":"automod:write","x-required-plugin":"automod","parameters":[{"name":"guildId","in":"path","required":true,"description":"Discord server id. Must be a server you own with cormac+ active.","schema":{"type":"string","pattern":"^\\d{17,20}$"}},{"name":"userId","in":"path","required":true,"description":"Discord user id.","schema":{"type":"string","pattern":"^\\d{17,20}$"}},{"name":"ruleId","in":"path","required":true,"description":"Automod rule id, as the member endpoint's `automod.exemptions` and the dashboard show it.","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Any string up to 255 characters you choose for this change, such as a UUID. A retry with the same key gets the first response back instead of making the change again, for 24 hours. Reusing a key for a different request is a 400; retrying while the first is still running is a 409 `IDEMPOTENCY_CONFLICT`. A 5xx is not kept, so the same key can be retried.","schema":{"type":"string"}},{"name":"X-Audit-Log-Reason","in":"header","required":false,"description":"Why, in up to 200 characters, URI-encoded as Discord expects. It shows next to the change in the server's Recent changes.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"example":{"guildId":"1467281625954914369","userId":"263304948291207170","ruleId":"block-invites","exempt":true,"changed":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionInactive"},"403":{"$ref":"#/components/responses/ForbiddenScope"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/WriteConflict"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/UpstreamUnavailable"}}},"delete":{"operationId":"unexemptMember","summary":"Stop exempting from a rule","description":"Take the member off a rule's exempt members. They can still be exempt another way, through a role or as owner, Administrator or Bot Master; the member endpoint says which.\n\nEvery change shows in the server's Recent changes on the dashboard, with the key's name and prefix and the reason if you send one. Writes are server-side only: browsers are refused at the CORS preflight, so a key that can change data never has to sit in a web page.\n\nThe key must belong to the server owner, and cormac+ must be active on the server. Requires the `automod:write` scope. The automod plugin must be enabled on the server.","tags":["Members"],"x-required-scope":"automod:write","x-required-plugin":"automod","parameters":[{"name":"guildId","in":"path","required":true,"description":"Discord server id. Must be a server you own with cormac+ active.","schema":{"type":"string","pattern":"^\\d{17,20}$"}},{"name":"userId","in":"path","required":true,"description":"Discord user id.","schema":{"type":"string","pattern":"^\\d{17,20}$"}},{"name":"ruleId","in":"path","required":true,"description":"Automod rule id, as the member endpoint's `automod.exemptions` and the dashboard show it.","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Any string up to 255 characters you choose for this change, such as a UUID. A retry with the same key gets the first response back instead of making the change again, for 24 hours. Reusing a key for a different request is a 400; retrying while the first is still running is a 409 `IDEMPOTENCY_CONFLICT`. A 5xx is not kept, so the same key can be retried.","schema":{"type":"string"}},{"name":"X-Audit-Log-Reason","in":"header","required":false,"description":"Why, in up to 200 characters, URI-encoded as Discord expects. It shows next to the change in the server's Recent changes.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"example":{"guildId":"1467281625954914369","userId":"263304948291207170","ruleId":"block-invites","exempt":false,"changed":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionInactive"},"403":{"$ref":"#/components/responses/ForbiddenScope"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/WriteConflict"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/UpstreamUnavailable"}}}},"/v1/guilds/{guildId}/stats":{"get":{"operationId":"dailyStatistics","summary":"Daily statistics","description":"Day-by-day counts for the server: joins, leaves, kicks, bans, timeouts, boosts, messages sent, edited and deleted, voice joins and voice minutes, plus member count and active members. Every day in the range has a point, zero when nothing happened, so a series can be charted as it comes.\n\nDays are UTC calendar days, and `from` and `to` are both inclusive. The response echoes the range cormac actually applied, which can be narrower than the one asked for when it reaches past the history cormac keeps.\n\n`kind` says how to read a series. A `count` adds up across days, so `total` is the sum over the range. A `gauge` (`member_count`, `active_members`) is a level on each day: `total` is the latest day's value, and `average` is usually the number you want.\n\n`average` is the mean per day over the range, rounded to one decimal. `memberCount` is the member count right now, not a day in the range.\n\nThe key must belong to the server owner, and cormac+ must be active on the server. Requires the `stats:read` scope.","tags":["Statistics"],"x-required-scope":"stats:read","parameters":[{"name":"guildId","in":"path","required":true,"description":"Discord server id. Must be a server you own with cormac+ active.","schema":{"type":"string","pattern":"^\\d{17,20}$"}},{"name":"metric","in":"query","required":false,"description":"Comma-separated metrics to return, in that order, such as `member_join,message_sent`. Defaults to every metric. An unknown name is a 400 that lists the valid ones.\n\n- `member_join`: Times someone joined. A member who leaves and rejoins counts each time, and bots count too.\n- `member_leave`: Times someone left, including kicks and bans. A member who leaves twice counts twice.\n- `member_kick`: Kicks, by anyone. Read from the audit log, so only counted while cormac has View Audit Log.\n- `member_ban`: Bans, by anyone, including bans issued through other bots.\n- `member_unban`: Bans lifted.\n- `member_timeout`: Timeouts put on members who were not already timed out. Extending a timeout does not count again. Timeouts on members cormac has not seen recently are read from the audit log, so those are only counted while cormac has View Audit Log.\n- `member_early_leave`: Members who left within 7 days of joining. Only counted when cormac knows when the member joined, so it can run low.\n- `member_count`: Gauge: the member count from the day's last hourly snapshot.\n- `message_sent`: Messages sent by members. Bots, webhooks and system messages are not counted.\n- `message_deleted`: Messages deleted one at a time, by their author or by staff. Messages cormac knows came from a bot are not counted.\n- `message_bulk_deleted`: Messages removed in bulk: purge commands, or bans that clear history.\n- `message_edited`: Text edits to recent messages cormac still has in memory. Edits to older messages are not counted.\n- `active_members`: Gauge: distinct members who sent a message or joined voice that day.\n- `voice_join`: Times a member connected to voice. Each connection counts, so one member joining three times is 3; moving between channels is not a new join.\n- `voice_minutes`: Minutes members spent in voice channels. Bots are not counted.\n- `boost`: Members who started boosting. A member adding another boost is not counted again.","schema":{"type":"array","items":{"type":"string","enum":["member_join","member_leave","member_kick","member_ban","member_unban","member_timeout","member_early_leave","member_count","message_sent","message_deleted","message_bulk_deleted","message_edited","active_members","voice_join","voice_minutes","boost"]}},"style":"form","explode":false},{"name":"from","in":"query","required":false,"description":"First day, inclusive, in UTC. Defaults to 29 days before `to`, so the default range is 30 days.","schema":{"type":"string","format":"date"}},{"name":"to","in":"query","required":false,"description":"Last day, inclusive, in UTC. Defaults to today. The range may span at most 365 days.","schema":{"type":"string","format":"date"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"example":{"guildId":"1467281625954914369","from":"2026-09-28","to":"2026-10-04","memberCount":1284,"series":[{"metric":"member_join","kind":"count","total":45,"average":6.4,"daily":[{"day":"2026-09-28","count":6},{"day":"2026-09-29","count":4},{"day":"2026-09-30","count":9},{"day":"2026-10-01","count":3},{"day":"2026-10-02","count":5},{"day":"2026-10-03","count":11},{"day":"2026-10-04","count":7}]},{"metric":"member_count","kind":"gauge","total":1284,"average":1272.3,"daily":[{"day":"2026-09-28","count":1262},{"day":"2026-09-29","count":1264},{"day":"2026-09-30","count":1270},{"day":"2026-10-01","count":1271},{"day":"2026-10-02","count":1274},{"day":"2026-10-03","count":1281},{"day":"2026-10-04","count":1284}]}]}}}},"400":{"description":"The request is malformed:\n\n- `guildId` is not a Discord id.\n- `from` or `to` is not a real date in `YYYY-MM-DD` form.\n- `from` is after `to`.\n- The range spans more than 365 days, counting both ends.\n- `metric` names a metric that does not exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"code":"BAD_REQUEST","message":"Unknown metric \"member_joins\". Valid metrics: member_join, member_leave, member_kick, member_ban, member_unban, member_timeout, member_early_leave, member_count, message_sent, message_deleted, message_bulk_deleted, message_edited, active_members, voice_join, voice_minutes, boost"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionInactive"},"403":{"$ref":"#/components/responses/ForbiddenScope"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/UpstreamUnavailable"}}}},"/v1/guilds/{guildId}/stats/channels":{"get":{"operationId":"channelStatistics","summary":"Channel activity","description":"Channels ranked by activity over the range, busiest first: messages sent and minutes spent in voice. Channels with no activity in the range are left out.\n\nDays are UTC calendar days, and `from` and `to` are both inclusive. The response echoes the range cormac actually applied, which can be narrower than the one asked for when it reaches past the history cormac keeps.\n\nMessages in a thread count toward the channel the thread lives in. `name` is the channel's current name, or `null` once it has been deleted. `type` is one of `text`, `voice`, `announcement`, `thread`, `forum`, `stage` or `other`.\n\nThe key must belong to the server owner, and cormac+ must be active on the server. Requires the `stats:read` scope.","tags":["Statistics"],"x-required-scope":"stats:read","parameters":[{"name":"guildId","in":"path","required":true,"description":"Discord server id. Must be a server you own with cormac+ active.","schema":{"type":"string","pattern":"^\\d{17,20}$"}},{"name":"from","in":"query","required":false,"description":"First day, inclusive, in UTC. Defaults to 29 days before `to`, so the default range is 30 days.","schema":{"type":"string","format":"date"}},{"name":"to","in":"query","required":false,"description":"Last day, inclusive, in UTC. Defaults to today. The range may span at most 365 days.","schema":{"type":"string","format":"date"}},{"name":"limit","in":"query","required":false,"description":"How many channels to return, from 1 to 100.","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"responses":{"200":{"description":"Success","content":{"application/json":{"example":{"guildId":"1467281625954914369","from":"2026-09-05","to":"2026-10-04","channels":[{"channelId":"1467281626626003065","name":"general","type":"text","messages":8412,"voiceMinutes":0},{"channelId":"1467281626626003066","name":"Lounge","type":"voice","messages":2240,"voiceMinutes":6180},{"channelId":"1467281626626003068","name":"memes","type":"text","messages":1950,"voiceMinutes":0}]}}}},"400":{"description":"The request is malformed:\n\n- `guildId` is not a Discord id.\n- `from` or `to` is not a real date in `YYYY-MM-DD` form.\n- `from` is after `to`.\n- The range spans more than 365 days, counting both ends.\n- `limit` is not a whole number from 1 to 100.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"code":"BAD_REQUEST","message":"limit must be a whole number from 1 to 100"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionInactive"},"403":{"$ref":"#/components/responses/ForbiddenScope"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/UpstreamUnavailable"}}}},"/v1/guilds/{guildId}/stats/hourly":{"get":{"operationId":"hourlyStatistics","summary":"Activity by hour","description":"When the server is busy: messages and member joins over the range, by weekday and hour of the day in the time zone you ask for. Shaped for a heatmap.\n\n`messages` and `joins` are 7 rows of 24 numbers, read as `messages[weekday][hour]`. Weekday 0 is Sunday; hour 0 is midnight in `timezone`.\n\n`from` and `to` still pick UTC days; `tz` only decides which weekday and hour each message or join lands in. Daylight-saving changes inside the range are applied day by day.\n\nThe key must belong to the server owner, and cormac+ must be active on the server. Requires the `stats:read` scope.","tags":["Statistics"],"x-required-scope":"stats:read","parameters":[{"name":"guildId","in":"path","required":true,"description":"Discord server id. Must be a server you own with cormac+ active.","schema":{"type":"string","pattern":"^\\d{17,20}$"}},{"name":"from","in":"query","required":false,"description":"First day, inclusive, in UTC. Defaults to 29 days before `to`, so the default range is 30 days.","schema":{"type":"string","format":"date"}},{"name":"to","in":"query","required":false,"description":"Last day, inclusive, in UTC. Defaults to today. The range may span at most 365 days.","schema":{"type":"string","format":"date"}},{"name":"tz","in":"query","required":false,"description":"IANA time zone for the weekday and hour buckets, such as `Europe/Vilnius` or `America/New_York`. Fixed offsets like `+02:00` are not accepted, since they ignore daylight saving.","schema":{"type":"string","default":"UTC"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"example":{"guildId":"1467281625954914369","from":"2026-09-05","to":"2026-10-04","timezone":"Europe/Vilnius","messages":[[31,16,10,5,5,5,10,21,36,52,62,73,83,78,73,78,94,114,140,161,172,151,104,57],[19,10,6,3,3,3,6,13,22,32,38,45,51,48,45,48,58,70,86,99,106,93,64,35],[20,10,7,3,3,3,7,14,24,34,41,48,54,51,48,51,61,75,92,105,112,99,68,37],[22,11,7,4,4,4,7,14,25,36,43,50,58,54,50,54,65,79,97,112,119,104,72,40],[23,11,8,4,4,4,8,15,27,38,46,53,61,57,53,57,68,84,103,118,125,110,76,42],[26,13,9,4,4,4,9,18,31,44,53,62,70,66,62,66,79,97,119,136,145,128,88,48],[34,17,11,6,6,6,11,22,39,56,67,78,90,84,78,84,101,123,151,174,185,162,112,62]],"joins":[[1,0,0,0,0,0,0,1,1,2,2,2,3,2,2,2,3,4,4,5,5,5,3,2],[1,0,0,0,0,0,0,0,1,1,1,1,2,2,1,2,2,2,3,3,3,3,2,1],[1,0,0,0,0,0,0,0,1,1,1,1,2,2,1,2,2,2,3,3,4,3,2,1],[1,0,0,0,0,0,0,0,1,1,1,2,2,2,2,2,2,2,3,3,4,3,2,1],[1,0,0,0,0,0,0,0,1,1,1,2,2,2,2,2,2,3,3,4,4,3,2,1],[1,0,0,0,0,0,0,1,1,1,2,2,2,2,2,2,2,3,4,4,5,4,3,2],[1,1,0,0,0,0,0,1,1,2,2,2,3,3,2,3,3,4,5,5,6,5,4,2]]}}}},"400":{"description":"The request is malformed:\n\n- `guildId` is not a Discord id.\n- `from` or `to` is not a real date in `YYYY-MM-DD` form.\n- `from` is after `to`.\n- The range spans more than 365 days, counting both ends.\n- `tz` is not an IANA time zone name.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"code":"BAD_REQUEST","message":"tz must be an IANA time zone name, such as Europe/Vilnius or America/New_York"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionInactive"},"403":{"$ref":"#/components/responses/ForbiddenScope"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/UpstreamUnavailable"}}}},"/v1/guilds/{guildId}/stats/voice":{"get":{"operationId":"voiceStatistics","summary":"Voice activity","description":"Voice joins and minutes spent in voice for each day, the total minutes, and the voice channels that were used, most minutes first.\n\nDays are UTC calendar days, and `from` and `to` are both inclusive. The response echoes the range cormac actually applied, which can be narrower than the one asked for when it reaches past the history cormac keeps.\n\n`joins` counts connections, not people: a member who joins voice twice in a day counts twice. `channels` lists only channels with voice time in the range; `name` is `null` once a channel has been deleted.\n\nThe key must belong to the server owner, and cormac+ must be active on the server. Requires the `stats:read` scope.","tags":["Statistics"],"x-required-scope":"stats:read","parameters":[{"name":"guildId","in":"path","required":true,"description":"Discord server id. Must be a server you own with cormac+ active.","schema":{"type":"string","pattern":"^\\d{17,20}$"}},{"name":"from","in":"query","required":false,"description":"First day, inclusive, in UTC. Defaults to 29 days before `to`, so the default range is 30 days.","schema":{"type":"string","format":"date"}},{"name":"to","in":"query","required":false,"description":"Last day, inclusive, in UTC. Defaults to today. The range may span at most 365 days.","schema":{"type":"string","format":"date"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"example":{"guildId":"1467281625954914369","from":"2026-09-28","to":"2026-10-04","totalMinutes":2432,"joins":[{"day":"2026-09-28","count":18},{"day":"2026-09-29","count":12},{"day":"2026-09-30","count":15},{"day":"2026-10-01","count":11},{"day":"2026-10-02","count":14},{"day":"2026-10-03","count":24},{"day":"2026-10-04","count":29}],"minutes":[{"day":"2026-09-28","count":310},{"day":"2026-09-29","count":285},{"day":"2026-09-30","count":402},{"day":"2026-10-01","count":268},{"day":"2026-10-02","count":330},{"day":"2026-10-03","count":461},{"day":"2026-10-04","count":376}],"channels":[{"channelId":"1467281626626003066","name":"Lounge","minutes":1490},{"channelId":"1467281626626003071","name":"Gaming","minutes":712},{"channelId":"1467281626626003074","name":"Study hall","minutes":230}]}}}},"400":{"description":"The request is malformed:\n\n- `guildId` is not a Discord id.\n- `from` or `to` is not a real date in `YYYY-MM-DD` form.\n- `from` is after `to`.\n- The range spans more than 365 days, counting both ends.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"code":"BAD_REQUEST","message":"The range 2025-01-01 to 2026-10-04 spans 642 days; the maximum is 365"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionInactive"},"403":{"$ref":"#/components/responses/ForbiddenScope"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/UpstreamUnavailable"}}}},"/v1/guilds/{guildId}/progression/leaderboard":{"get":{"operationId":"leaderboard","summary":"Progression leaderboard","description":"Ranked members with level and XP. This is the endpoint for \"most active members\" on your own site.\n\nThe key must belong to the server owner, and cormac+ must be active on the server. Requires the `progression:read` scope. The progression plugin must be enabled on the server.","tags":["Progression"],"x-required-scope":"progression:read","x-required-plugin":"progression","parameters":[{"name":"guildId","in":"path","required":true,"description":"Discord server id. Must be a server you own with cormac+ active.","schema":{"type":"string","pattern":"^\\d{17,20}$"}},{"name":"limit","in":"query","required":false,"description":"page size, capped at 100","schema":{"type":"integer","minimum":0}},{"name":"offset","in":"query","required":false,"description":"ranked position to start from","schema":{"type":"integer","minimum":0}}],"responses":{"200":{"description":"Success","content":{"application/json":{"example":{"guildId":"1467281625954914369","total":412,"limit":10,"offset":0,"members":[{"userId":"263304948291207170","rank":1,"level":42,"xp":180,"totalXp":96400}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionInactive"},"403":{"$ref":"#/components/responses/ForbiddenScope"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/PluginDisabled"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/UpstreamUnavailable"}}}},"/v1/guilds/{guildId}/progression/members/{userId}":{"get":{"operationId":"memberProgression","summary":"One member's progression","description":"Level, XP and rank for one member of your server. 404 if they hold no progression there.\n\nThe key must belong to the server owner, and cormac+ must be active on the server. Requires the `progression:read` scope. The progression plugin must be enabled on the server.","tags":["Progression"],"x-required-scope":"progression:read","x-required-plugin":"progression","parameters":[{"name":"guildId","in":"path","required":true,"description":"Discord server id. Must be a server you own with cormac+ active.","schema":{"type":"string","pattern":"^\\d{17,20}$"}},{"name":"userId","in":"path","required":true,"description":"Discord user id.","schema":{"type":"string","pattern":"^\\d{17,20}$"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"example":{"guildId":"1467281625954914369","member":{"userId":"263304948291207170","rank":1,"level":42,"xp":180,"totalXp":96400}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionInactive"},"403":{"$ref":"#/components/responses/ForbiddenScope"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/PluginDisabled"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/UpstreamUnavailable"}}}},"/v1/guilds/{guildId}/tickets/analytics":{"get":{"operationId":"ticketAnalytics","summary":"Ticket analytics","description":"The same analytics payload the dashboard renders. Volumes, close times, first-response times, and close-time ratings, over the last 30 days. `totalClosedTickets` is all time.\n\nThe key must belong to the server owner, and cormac+ must be active on the server. Requires the `tickets:read` scope. The tickets plugin must be enabled on the server.","tags":["Tickets"],"x-required-scope":"tickets:read","x-required-plugin":"tickets","parameters":[{"name":"guildId","in":"path","required":true,"description":"Discord server id. Must be a server you own with cormac+ active.","schema":{"type":"string","pattern":"^\\d{17,20}$"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"example":{"guildId":"1467281625954914369","premiumActive":true,"windowDays":30,"summary":{"totalClosedTickets":412,"windowOpenedTickets":96,"windowClosedTickets":91,"ticketsWithFirstResponse":88,"averageFirstResponseSeconds":364,"averageMessagesPerTicket":14.2,"ratingCount":63,"averageRating":4.6},"ratingDistribution":{"1":1,"2":2,"3":6,"4":18,"5":36},"topCategories":[{"categoryId":"billing","categoryName":"Billing","ticketCount":34,"share":0.37}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionInactive"},"403":{"$ref":"#/components/responses/ForbiddenScope"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/PluginDisabled"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/UpstreamUnavailable"}}}},"/v1/guilds/{guildId}/tickets/queue":{"get":{"operationId":"ticketQueue","summary":"Open ticket queue","description":"Every open ticket right now: who opened it, who claimed it, how old it is, and which ones are overdue. The live view for an external support dashboard.\n\nThe key must belong to the server owner, and cormac+ must be active on the server. Requires the `tickets:read` scope. The tickets plugin must be enabled on the server.","tags":["Tickets"],"x-required-scope":"tickets:read","x-required-plugin":"tickets","parameters":[{"name":"guildId","in":"path","required":true,"description":"Discord server id. Must be a server you own with cormac+ active.","schema":{"type":"string","pattern":"^\\d{17,20}$"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"example":{"guildId":"1467281625954914369","summary":{"totalOpen":4,"unclaimed":1,"responseOverdue":0,"inactivityWarningDue":1,"autoCloseDue":0},"queue":[{"channelId":"1500847305706836070","channelName":"ticket-0042","categoryId":"general_support","categoryName":"General support","openerId":"263304948291207170","claimerId":null,"status":"open","createdAt":1787160000,"lastActivityAt":1787163000,"ageSeconds":4448}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionInactive"},"403":{"$ref":"#/components/responses/ForbiddenScope"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/PluginDisabled"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/UpstreamUnavailable"}}}},"/v1/guilds/{guildId}/honeypot/stats":{"get":{"operationId":"honeypotStats","summary":"Honeypot catches","description":"How many spam bots the honeypot has removed, in total and per trap channel. A satisfying number to put on a wall.\n\nThe key must belong to the server owner, and cormac+ must be active on the server. Requires the `honeypot:read` scope. The honeypot plugin must be enabled on the server.","tags":["Honeypot"],"x-required-scope":"honeypot:read","x-required-plugin":"honeypot","parameters":[{"name":"guildId","in":"path","required":true,"description":"Discord server id. Must be a server you own with cormac+ active.","schema":{"type":"string","pattern":"^\\d{17,20}$"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"example":{"guildId":"1467281625954914369","totalModerated":212,"perChannel":{"1500847305706836070":148,"1486015573702869174":64}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionInactive"},"403":{"$ref":"#/components/responses/ForbiddenScope"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/PluginDisabled"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/UpstreamUnavailable"}}}},"/v1/guilds/{guildId}/moderation/cases":{"get":{"operationId":"moderationCases","summary":"Moderation cases","description":"The server's numbered moderation cases, newest first: warnings, notes, timeouts, kicks and bans, whether they came from a cormac command, automod, the honeypot or someone acting in Discord itself.\n\n`source` says where a case came from. `discord` means the action was taken outside cormac, in Discord or by another bot, and read from the audit log. `moderatorId` is `null` when nobody is known, as for automod and the honeypot.\n\nUnlike the member endpoint, this works for people who are no longer in the server, which is most of the people who were banned. Filter with `userId`.\n\nCases are recorded only while the Moderation plugin is on. A deleted case is gone from the list and its number is not reused.\n\nThe key must belong to the server owner, and cormac+ must be active on the server. Requires the `moderation:read` scope. The moderation plugin must be enabled on the server.","tags":["Moderation"],"x-required-scope":"moderation:read","x-required-plugin":"moderation","parameters":[{"name":"guildId","in":"path","required":true,"description":"Discord server id. Must be a server you own with cormac+ active.","schema":{"type":"string","pattern":"^\\d{17,20}$"}},{"name":"userId","in":"query","required":false,"description":"only cases about this user","schema":{"type":"string"}},{"name":"type","in":"query","required":false,"description":"only cases of this type\n\n- `warn`: a warning, which the member was told about\n- `note`: a note only staff see\n- `timeout`: a timeout; `durationSeconds` says how long\n- `untimeout`: a timeout ended early\n- `kick`: a kick\n- `ban`: a ban\n- `softban`: a ban lifted at once, to clear their messages\n- `unban`: a ban lifted","schema":{"type":"string","enum":["warn","note","timeout","untimeout","kick","ban","softban","unban"]}},{"name":"before","in":"query","required":false,"description":"only cases numbered below this; the next page","schema":{"type":"integer","minimum":0}},{"name":"limit","in":"query","required":false,"description":"page size, capped at 100","schema":{"type":"integer","minimum":0}}],"responses":{"200":{"description":"Success","content":{"application/json":{"example":{"guildId":"1467281625954914369","cases":[{"caseNumber":61,"type":"ban","source":"command","userId":"263304948291207170","moderatorId":"1486015573702869180","reason":"Scam links in #general","durationSeconds":null,"ruleName":null,"createdAt":1791110000,"updatedAt":1791110000}],"nextBefore":61}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionInactive"},"403":{"$ref":"#/components/responses/ForbiddenScope"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/PluginDisabled"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/UpstreamUnavailable"}}}},"/v1/guilds/{guildId}/diagnostics":{"get":{"operationId":"diagnostics","summary":"Setup diagnostics","description":"Per-plugin configuration health: missing channels, broken permissions, incomplete setup. Poll it to catch a misconfigured server before your members do.\n\nThe key must belong to the server owner, and cormac+ must be active on the server. Requires the `diagnostics:read` scope.","tags":["Diagnostics"],"x-required-scope":"diagnostics:read","parameters":[{"name":"guildId","in":"path","required":true,"description":"Discord server id. Must be a server you own with cormac+ active.","schema":{"type":"string","pattern":"^\\d{17,20}$"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"example":{"guildId":"1467281625954914369","summary":{"totalIssues":1,"warningCount":1,"errorCount":0,"affectedPluginCount":1},"plugins":[{"plugin":"logging","status":"warning","issues":[{"code":"logging.channel_missing","severity":"warning","message":"Members module has no log channel configured."}]}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionInactive"},"403":{"$ref":"#/components/responses/ForbiddenScope"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/UpstreamUnavailable"}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"An API key created from your cormac profile page, sent as `Authorization: Bearer cormac_live_...`. The `x-api-key` header is accepted too.\n\nEach key carries the scopes chosen when it was created:\n- `guilds:read`: List your servers and read one server, including its plugin list.\n- `stats:read`: Member, message, moderation and voice statistics, with per-channel and hourly breakdowns.\n- `members:read`: Look up one member: their Discord profile and what each enabled plugin keeps about them.\n- `progression:read`: Leaderboard standings and a single member's level and XP.\n- `tickets:read`: Ticket analytics and the live open ticket queue.\n- `honeypot:read`: Honeypot catch counts, in total and per trap channel.\n- `diagnostics:read`: The setup diagnostics report for a server.\n- `moderation:read`: Moderation cases: the server's case list and each member's warnings, timeouts, kicks and bans.\n- `progression:write`: Set, add or remove a member's XP, or set their level. Reward roles follow.\n- `automod:write`: Clear a member's automod strikes, and exempt them from a rule or stop exempting them."}},"schemas":{"Error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","description":"Stable, machine-readable reason.","enum":["BAD_REQUEST","UNAUTHORIZED","FORBIDDEN_SCOPE","SUBSCRIPTION_INACTIVE","NOT_FOUND","METHOD_NOT_ALLOWED","PLUGIN_DISABLED","IDEMPOTENCY_CONFLICT","RATE_LIMITED","UPSTREAM_UNAVAILABLE"]},"message":{"type":"string","description":"For humans; wording may change."}}}},"responses":{"BadRequest":{"description":"The request is malformed, such as an id that is not a Discord id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"code":"BAD_REQUEST","message":"Guild id must be a Discord snowflake"}}}},"Unauthorized":{"description":"The key is missing, malformed, or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"code":"UNAUTHORIZED","message":"Invalid or revoked API key"}}}},"ForbiddenScope":{"description":"The key is valid but lacks the scope, or was not granted this server.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"code":"FORBIDDEN_SCOPE","message":"This key was not granted the stats:read scope"}}}},"SubscriptionInactive":{"description":"cormac+ is not active on the server.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"code":"SUBSCRIPTION_INACTIVE","message":"cormac+ is not active on this server"}}}},"NotFound":{"description":"No such server, or it is not one the key owner owns. Both answer the same way so a caller cannot probe for servers that are not theirs. Endpoints that name a member also answer 404 when that user is not in the server.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"code":"NOT_FOUND","message":"Guild not found"}}}},"PluginDisabled":{"description":"The plugin behind this endpoint is switched off on the server.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"code":"PLUGIN_DISABLED","message":"The tickets plugin is not enabled on this server"}}}},"IdempotencyConflict":{"description":"A request with the same Idempotency-Key is still being handled. Retry once it finishes.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"code":"IDEMPOTENCY_CONFLICT","message":"A request with this Idempotency-Key is still being handled"}}}},"WriteConflict":{"description":"The plugin behind this endpoint is switched off on the server (`PLUGIN_DISABLED`), or a request with the same Idempotency-Key is still being handled (`IDEMPOTENCY_CONFLICT`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"pluginDisabled":{"value":{"code":"PLUGIN_DISABLED","message":"The automod plugin is not enabled on this server"}},"idempotencyConflict":{"value":{"code":"IDEMPOTENCY_CONFLICT","message":"A request with this Idempotency-Key is still being handled"}}}}}},"RateLimited":{"description":"Rate limit exceeded. `retry-after` gives the seconds to wait.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"code":"RATE_LIMITED","message":"Rate limit exceeded"}}}},"UpstreamUnavailable":{"description":"cormac could not be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"code":"UPSTREAM_UNAVAILABLE","message":"Unable to reach cormac right now"}}}}}}}