Every request needs your server's API key, either as a bearer token or a header:
Authorization: Bearer rgd_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
or
X-Api-Key: rgd_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
A key only ever reads data for the one server it was generated on. Limit: 60 requests/minute per server.
Basic config for your server.
{
"guildId": "...",
"guildName": "...",
"verifiedRoleConfigured": true,
"vpnBlockingEnabled": false,
"premium": true
}
Generates a RoGoid verification link for that Discord member in your server no separate session or backend integration needed. Have your own panel/bot call this and send the member the link (as a button, DM, whatever); clicking it takes them straight into the same Roblox OAuth flow /verify uses, and RoGoid applies the verified role/nickname the moment it completes.
{
"url": "https://rogoid.xyz/verify?state=...",
"verifiedRoleConfigured": true
}
verifiedRoleConfigured is false if this server hasn't picked a verified role yet the link still works, but /verify will show a setup notice instead of starting Roblox sign-in until an admin configures one from the dashboard.
The Roblox account a Discord member is currently verified as in your server. 404 if not verified.
{
"discordId": "...",
"robloxId": "...",
"robloxUsername": "...",
"robloxDisplayName": "...",
"verificationMethod": "oauth",
"verifiedAt": "2026-09-01T12:00:00.000Z"
}
Ban records RoGoid holds for your server.
{ "bans": [ { "discordId": "...", "reason": "...", "bannedBy": "...", "createdAt": "..." } ] }
Members flagged for having a linked Roblox account shared with another Discord account that's currently in your server or banned from it. Returns 403 without RoGoid+.
{
"flagged": [
{
"discordId": "...",
"verifiedRobloxIds": ["..."],
"linkedAccounts": [ { "discordId": "...", "robloxId": "...", "status": "in_server" } ]
}
]
}
You can put your own bot in front of verification instead of using RoGoid's /verify command or panel. Your bot's only job is to hand the member a link everything after that is still RoGoid.
RoGoid still has to be installed in the server. It's what actually assigns the verified role and sets the nickname, using its own permissions, so this replaces the prompt rather than replacing RoGoid. That means:
The flow is:
GET /api/v1/verify-link/:discordId with your API key.url.To react when verification finishes (send a confirmation, unlock a channel), point a webhook at your bot RoGoid will POST to it as soon as the member is verified.
Each link is generated for one specific member in your server, so build it when they ask for it don't post a single shared link in a channel, or everyone who clicks it verifies as the person it was made for.
Example (discord.js v14)
This uses Components V2 containers, not the older Embed API RoGoid's own bot has fully moved off embeds in favor of containers, and we'd recommend the same for anything you build against this API.
const { ActionRowBuilder, ButtonBuilder, ButtonStyle, ContainerBuilder, TextDisplayBuilder, SeparatorBuilder, SeparatorSpacingSize, MessageFlags } = require('discord.js');
client.on('interactionCreate', async (interaction) => {
if (!interaction.isChatInputCommand() || interaction.commandName !== 'verify') return;
const res = await fetch(
`https://rogoid.xyz/api/v1/verify-link/${interaction.user.id}`,
{ headers: { Authorization: 'Bearer YOUR_API_KEY' } }
);
if (!res.ok) {
return interaction.reply({ content: 'Verification is unavailable right now.', ephemeral: true });
}
const { url, verifiedRoleConfigured } = await res.json();
if (!verifiedRoleConfigured) {
return interaction.reply({ content: 'This server has no verified role set up yet.', ephemeral: true });
}
const container = new ContainerBuilder()
.setAccentColor(0xf5ea51)
.addTextDisplayComponents(
new TextDisplayBuilder().setContent(
'# Verify with Roblox\n\nClick below to link your Roblox account. Your role is applied automatically once you finish.'
)
)
.addSeparatorComponents(new SeparatorBuilder().setSpacing(SeparatorSpacingSize.Large).setDivider(true))
.addActionRowComponents(
new ActionRowBuilder().addComponents(
new ButtonBuilder().setLabel('Verify').setStyle(ButtonStyle.Link).setURL(url)
)
);
await interaction.reply({
components: [container],
flags: MessageFlags.IsComponentsV2 | MessageFlags.Ephemeral
});
});
Reply ephemerally so the link stays private to the member who asked for it. To check whether someone is already verified before showing the button, call GET /api/v1/verifications/:discordId first a 404 means they aren't verified yet.
Instead of polling, you can have RoGoid POST to your own endpoint the moment something happens. Set the URL under Webhook on your server's Settings page you'll get a signing secret when you save.
Events
member.verified a member finished verification in your servermember.unverified a member's verification was removed therePayload
{
"event": "member.verified",
"sentAt": "2026-09-08T20:00:00.000Z",
"data": {
"guildId": "...",
"discordId": "...",
"robloxId": "...",
"robloxUsername": "...",
"robloxDisplayName": "...",
"verificationMethod": "oauth"
}
}
member.unverified carries guildId, discordId, robloxId and robloxUsername, and the Roblox fields may be null if there was no active link left to read.
Verifying the signature
Every request carries these headers:
X-RoGoid-Event the event nameX-RoGoid-Timestamp milliseconds since epochX-RoGoid-Signature HMAC-SHA256 of timestamp + "." + rawBody, using your signing secretCheck it against the raw request body, before any JSON parsing re-serialising the object first will produce a different string and the signature won't match.
const crypto = require('crypto');
app.post('/rogoid-webhook', express.raw({ type: 'application/json' }), (req, res) => {
const timestamp = req.get('X-RoGoid-Timestamp');
const signature = req.get('X-RoGoid-Signature');
const expected = crypto
.createHmac('sha256', process.env.ROGOID_WEBHOOK_SECRET)
.update(`${timestamp}.${req.body}`)
.digest('hex');
const valid = signature
&& signature.length === expected.length
&& crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
if (!valid) return res.sendStatus(401);
if (Math.abs(Date.now() - Number(timestamp)) > 5 * 60 * 1000) return res.sendStatus(401);
const { event, data } = JSON.parse(req.body);
console.log(event, data.discordId, data.robloxUsername);
res.sendStatus(200);
});
Delivery behaviour
2xx as soon as you receive it and do your work afterwards. RoGoid gives up after 5 seconds./verifications/:discordId if you need certainty.https and publicly reachable private and internal addresses are rejected.401 missing/invalid key · 403 premium required (alts only) · 404 not found · 429 rate limited.
Questions or requests: Join Discord