API
Check invite links from your own site
Bot lists, dashboards and CI jobs can use the NoAdmin API to find out what an invite link asks for. It is free, needs no key, and stores nothing.
Endpoints
GET/api/v1/analyze?input=Analyze one invite link or permission value.POST/api/v1/analyzeSend {"input": "..."} for one, or {"inputs": [...]} for up to 50.GET/api/v1/permissionsEvery Discord permission with its bit, value and risk level.GET/api/v1/openapi.jsonOpenAPI 3.1 spec for generating a client.GET/api/badge?invite=An SVG badge for a README or listing page.Every endpoint allows cross-origin requests, so you can call it from a browser. GET responses are cached for an hour.
Blocking Administrator on a bot list
Run the check when a bot is submitted and when its invite link changes. If administrator is true, reject the submission and link the developer to report_url, which shows what the bot asked for and what to request instead.
const res = await fetch("https://noadmin.info/api/v1/analyze", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ input: bot.invite }),
});
const report = await res.json();
if (report.valid && report.administrator) {
throw new Error(
`This invite requests Administrator. See ${report.report_url}`,
);
}var report struct {
Valid bool `json:"valid"`
Administrator bool `json:"administrator"`
ReportURL string `json:"report_url"`
}
q := url.Values{"input": {invite}}
resp, err := http.Get("https://noadmin.info/api/v1/analyze?" + q.Encode())
if err != nil {
return err
}
defer resp.Body.Close()
if err := json.NewDecoder(resp.Body).Decode(&report); err != nil {
return err
}
if report.Valid && report.Administrator {
return fmt.Errorf("invite requests Administrator, see %s", report.ReportURL)
}curl "https://noadmin.info/api/v1/analyze?input=https%3A%2F%2Fdiscord.com%2Foauth2%2Fauthorize%3Fclient_id%3D1234567890123456789%26permissions%3D8%26scope%3Dbot"Response fields
validFalse when the input is not a permission number or a discord.com invite link. The error field says why.administratorTrue when the invite requests Administrator. Check this field to block admin invites.verdictnone, minimal, reasonable, broad, excessive or administrator. Use it for softer warnings.permissionsThe permission integer as a string. It can be larger than a JavaScript number can hold exactly.grantedEach requested permission with its risk and a link to its reference page.report_urlA page that explains the result. Link to it from your rejection message.{
"input": "https://discord.com/oauth2/authorize?client_id=1234567890123456789&permissions=8&scope=bot",
"valid": true,
"source": "url",
"client_id": "1234567890123456789",
"scopes": [
"bot"
],
"permissions": "8",
"permissions_hex": "0x8",
"administrator": true,
"verdict": "administrator",
"verdict_label": "Administrator",
"summary": "Full, unrestricted control of every server this bot joins.",
"score": 0,
"counts": {
"low": 0,
"medium": 0,
"high": 0,
"critical": 1
},
"granted": [
{
"key": "ADMINISTRATOR",
"name": "Administrator",
"bit": 3,
"value": "8",
"risk": "critical",
"requires_2fa": true,
"url": "https://noadmin.info/permissions/administrator"
}
],
"unknown_bits": [],
"findings": [
{
"level": "critical",
"title": "Requests Administrator",
"body": "Administrator overrides every other permission and ignores all channel restrictions. Remove it and keep only what the bot uses."
}
],
"closest_example": null,
"report_url": "https://noadmin.info/analyze?invite=https%3A%2F%2Fdiscord.com%2Foauth2%2Fauthorize%3Fclient_id%3D1234567890123456789%26permissions%3D8%26scope%3Dbot",
"badge_url": "https://noadmin.info/api/badge?invite=https%3A%2F%2Fdiscord.com%2Foauth2%2Fauthorize%3Fclient_id%3D1234567890123456789%26permissions%3D8%26scope%3Dbot"
}Checking without the API
If you only need the Administrator check, you can do it yourself with no network call. Administrator is bit 3, value 8. Use BigInt or a 64-bit integer, because permission values do not fit in a JavaScript number. The bitfield guide explains why.
const ADMINISTRATOR = BigInt(8);
function requestsAdmin(invite: string): boolean {
const url = new URL(invite);
const perms = url.searchParams.get("permissions");
return perms !== null && /^\d+$/.test(perms)
&& (BigInt(perms) & ADMINISTRATOR) === ADMINISTRATOR;
}Custom invite links
valid: false for anything else. Decide whether your list accepts those links, or asks for the discord.com link directly.