WenBot Developer API
Pull your WenBot data into your own website — wager leaderboards, store items, giveaways and viewer points. Read-only, and free with the Elite plan.
Getting started
The API is available to streamers on Elite and above (Agency includes everything Elite has). Everything is a GET request that returns JSON.
- Open your dashboard → Settings & Account → Developer API.
- Create a key. Copy it — it is shown once and never again.
- Send it with every request, as shown below.
The base URL is https://wenbot.gg/api/v1.
API keys
There are two kinds, and the difference matters:
| Key | Where it goes | What it reads |
|---|---|---|
PUBLISHABLEwb_pk_live_… |
Safe in your website's front-end JavaScript. | Only what your public portal already shows: leaderboards, store, giveaways. |
SECRETwb_sk_live_… |
Your server only. Never in a web page. | Everything above, plus viewer points and redemption history. |
Lock your publishable key to your domain. In the dashboard, set the origin (for example https://yoursite.com). Without it, anyone who views your page source can use your key and spend your monthly quota.
A secret key never receives CORS headers, so a browser cannot use one even if it is pasted into a page. That is deliberate — it fails loudly rather than working insecurely.
Authentication
Secret keys go in the Authorization header. Never put one in a URL — query strings end up in server logs, browser history and Referer headers.
curl https://wenbot.gg/api/v1/viewer/someviewer \
-H "Authorization: Bearer wb_sk_live_YOUR_KEY"
Publishable keys may use the same header, an X-API-Key header, or a ?key= query parameter — whichever your site makes easiest.
fetch("https://wenbot.gg/api/v1/leaderboard", {
headers: { "X-API-Key": "wb_pk_live_YOUR_KEY" }
})
.then(r => r.json())
.then(res => console.log(res.data));
Rate limits & quota
| Limit | Value | On exceed |
|---|---|---|
| Requests per minute | 60, per key | 429 rate_limited |
| Requests per month | 100,000, per channel | 429 quota_exceeded |
Public responses carry Cache-Control: public, max-age=120. Respect it rather than polling — the underlying data refreshes about every two minutes, so a tighter loop burns your quota without returning anything new. Your current usage is shown on the Developer API page in your dashboard.
The monthly quota resets at the start of each calendar month (UTC). If your site genuinely needs more, get in touch and it can be raised for your channel.
Responses
Every response has the same envelope, so you can branch on ok before anything else.
{ "ok": true, "data": { … } }
{ "ok": false, "error": { "code": "plan_required", "message": "…" } }
Public responses also include cachedAt, a millisecond timestamp telling you how fresh the underlying data is.
Public endpoints
These work with either key type. They return the same data your public portal shows.
Your channel's display name, currency name, live status and which features are enabled.
The current wager leaderboard, any additional boards, and the period countdown.
Past leaderboard periods and their archived winners.
Your store catalogue: items, cost and stock.
The active giveaway if one is running, plus recent winners.
Your points leaderboard. Optional ?limit= (1–100, default 25).
Viewer endpoints
Secret key only. These return data about individual viewers, so they are never usable from a browser. Call them from your server and pass the result to your page.
A viewer's points balance, raffle tickets, wins and verification status in your channel.
{
"ok": true,
"data": {
"username": "someviewer",
"points": 2850,
"raffleTickets": 3,
"wins": 1,
"verified": true,
"firstSeenAt": 1756000000000,
"lastSeenAt": 1789000000000
}
}
That viewer's store redemption history, newest first. Optional ?limit= (1–100, default 25).
Error codes
| Code | HTTP | What it means |
|---|---|---|
invalid_key | 401 | The key is missing or not recognised. |
revoked_key | 401 | This key was revoked in the dashboard. Create a new one. |
wrong_key_type | 403 | A viewer endpoint was called with a publishable key. |
plan_required | 403 | API access needs Elite or above, or the feature needs a higher plan on your channel. |
origin_not_allowed | 403 | The request came from a domain not on the key's allowed list. |
rate_limited | 429 | More than 60 requests in a minute. Back off and retry. |
quota_exceeded | 429 | The monthly quota is used up. It resets next month. |
not_found | 404 | No such endpoint, viewer, or no portal data for the channel yet. |
server_error | 500 | Something broke on our end. Retry shortly. |
Full example
A leaderboard on your own site, using a publishable key locked to your domain:
<div id="board">Loading…</div>
<script>
fetch("https://wenbot.gg/api/v1/leaderboard", {
headers: { "X-API-Key": "wb_pk_live_YOUR_KEY" }
})
.then(function (r) { return r.json(); })
.then(function (res) {
if (!res.ok) throw new Error(res.error.code);
var rows = (res.data.primary && res.data.primary.entries) || [];
document.getElementById("board").innerHTML = rows.map(function (e, i) {
return "<div>" + (i + 1) + ". " + e.username + " — $" + e.wagered + "</div>";
}).join("");
})
.catch(function (err) {
document.getElementById("board").textContent = "Leaderboard unavailable";
console.error(err);
});
</script>
And a points balance, which must run on your server:
// Node — the secret key stays here, never in the page
const r = await fetch(
"https://wenbot.gg/api/v1/viewer/" + encodeURIComponent(username),
{ headers: { Authorization: "Bearer " + process.env.WENBOT_SECRET_KEY } }
);
const res = await r.json();
if (res.ok) console.log(res.data.points);
Something missing? This is v1 and it is read-only on purpose. If you need an endpoint that is not here, say so — the surface grows based on what people actually build.