JavaScript and TypeScript
Post stats, check votes and verify webhooks with @omniplex/sdk.
@omniplex/sdk works in Node 20 and newer, Bun, Deno, Cloudflare Workers and any
other runtime with fetch and Web Crypto. It has no runtime dependencies, and
its types come from @omniplex/api-types, the same types omniplex.gg itself
uses.
npm install @omniplex/sdkPosting stats
import { Omniplex } from "@omniplex/sdk";
const omniplex = new Omniplex({ token: process.env.OMNIPLEX_TOKEN });
await omniplex.postBotStats({
servers: client.guilds.cache.size,
shards: client.shard?.count ?? 1,
status: "online",
});Or let the SDK post for you. It posts once straight away, then every 30 minutes
(or intervalMs, at least a minute), and returns a function that stops it:
const stop = omniplex.autoPostBotStats(
() => ({
servers: client.guilds.cache.size,
shards: client.shard?.count ?? 1,
}),
{
intervalMs: 15 * 60_000,
onError: (err) => console.warn("Posting stats to Omniplex failed", err),
},
);Without onError, failures are logged with console.error. The timer doesn't
keep your process alive on its own.
status reports your bot's presence: online, idle, dnd or offline.
Omniplex keeps showing the last value you posted, so post it regularly if you
use it. See Posting Bot Stats.
For a server, use a server token:
await omniplex.postServerStats({ totalMembers: 1200, onlineMembers: 340 });Checking votes
Checking votes doesn't need a token.
const omniplex = new Omniplex();
if (await omniplex.hasVoted(botId, userId)) {
// reward them
}
const vote = await omniplex.getBotVote(botId, userId);
if (vote.wait) {
console.log(`They can vote again in ${vote.wait.hours}h ${vote.wait.minutes}m`);
}hasVotedForServer and getServerVote do the same for servers. getBot,
getServer and getUser read public data; pass { includeLong: true } to
getBot or getServer to include the long description.
Webhooks
Set a secret on your webhook in the dashboard and choose HMAC signature.
The SDK also verifies the older splashtail and simple-auth methods.
Always verify the request. Omniplex occasionally sends one signed with the wrong secret to check that your endpoint rejects it.
Fetch-style handlers
For Bun, Deno, Cloudflare Workers and Next.js route handlers:
import { createWebhookHandler } from "@omniplex/sdk";
export const POST = createWebhookHandler(
process.env.OMNIPLEX_WEBHOOK_SECRET!,
async (event) => {
if (event.type === "NEW_VOTE" && !event.data.downvote && !event.data.auto) {
await rewardVoter(event.creator?.id);
}
},
);The handler answers 204 once your callback finishes, 401 when verification
fails and 405 for anything other than POST.
Express and other frameworks
Verify against the raw request body, before any JSON parsing:
import express from "express";
import { verifyWebhook, WebhookVerificationError } from "@omniplex/sdk";
app.post("/omniplex", express.raw({ type: "*/*" }), async (req, res) => {
try {
const event = await verifyWebhook({ body: req.body, headers: req.headers }, secret);
// handle the event
res.sendStatus(204);
} catch (err) {
if (err instanceof WebhookVerificationError) return res.sendStatus(401);
throw err;
}
});event is a union typed on event.type, so TypeScript narrows event.data
for you. The webhooks page lists every
event and its fields.
Errors
Failed requests throw an OmniplexError with the HTTP status, the API's
message, any validation context, and retryAfter in seconds when you're
rate limited. Posting without a token throws before any request is made.
import { OmniplexError } from "@omniplex/sdk";
try {
await omniplex.postBotStats({ servers: 10 });
} catch (err) {
if (err instanceof OmniplexError && err.status === 401) {
console.error("Your Omniplex token is invalid");
}
}Options
new Omniplex({
token: "...", // needed for posting stats
baseUrl: "https://api.omniplex.gg", // the default
maxRetries: 2, // retries for rate limits and failed GETs
userAgent: "my-bot/1.0",
fetch: customFetch, // bring your own fetch
});omniplex.request(path, options) calls any other endpoint with the same retry
and error handling.