Developers
Bot API documentation
A small, read-only API so server owners can show data about their own Discord server on their website, in their tools and in widgets.
Authentication
Create a token on the Bot API page of your dashboard and send it in the Authorization header: Authorization: Bearer <token>. A token belongs to one server and can only read that server. It is shown once; DayZ Hub stores only its fingerprint.
curl -H "Authorization: Bearer dhba_..." \ https://dayzhub.net/api/v1/bot/guilds/<guildId>
Base URL: https://dayzhub.net/api/v1/bot
Endpoints
| Method | Path | Scope |
|---|---|---|
GET | /me | — |
GET | /guilds/{guildId} | guild:read |
GET | /guilds/{guildId}/features | guild:read |
GET | /guilds/{guildId}/giveaways | giveaways:read |
GET | /guilds/{guildId}/giveaways/{id} | giveaways:read |
GET | /guilds/{guildId}/tickets/summary | tickets:read |
GET | /guilds/{guildId}/leaderboard/levels | leveling:read |
GET | /guilds/{guildId}/shop/products | shop:read |
GET | /guilds/{guildId}/suggestions/summary | suggestions:read |
GET | /guilds/{guildId}/server-status | server-status:read |
Every answer is JSON in the same envelope. Lists are paged with limit (1 to 100) and the cursor from page.nextCursor.
{ "ok": true, "data": [ ... ], "page": { "limit": 25, "hasMore": true, "nextCursor": "eyJpZCI6Ij..." } }
Scopes
Each token holds only the scopes you gave it. All scopes are read-only; nothing can be changed through this API.
guild:read | Plan status and the list of features |
giveaways:read | Giveaways (active and ended) with entry counts |
tickets:read | Ticket counts by status and category (no ticket content) |
leveling:read | Level leaderboard (opted-out members are anonymous) |
shop:read | Public donation-shop products |
suggestions:read | Suggestion counts by status |
server-status:read | Public game-server status (only when publicly listed) |
Member privacy
Members appear only where the feature already shows them publicly, as a Discord id. A member who opted out of data processing is always shown as anonymous, as below. Names, messages, tickets and form answers are never part of the API.
{ "id": null, "anonymous": true }
Limits
Limits follow the plan of the server. Premium 1: 2 active tokens, 60 requests per minute per token. Premium 2: 5 tokens, 120 per minute. Premium 3: 10 tokens, 300 per minute. A free trial or a sponsored server counts as Premium 1. Each IP address may make 300 requests per minute. Over the limit you get 429 with a Retry-After header. A plan that goes down revokes no token: the tokens you have keep working, only new ones are blocked until you are under the limit. The server needs a paid plan or an active trial.
Caching
Answers carry an ETag and a short private cache. Send If-None-Match to get 304 when nothing changed. Polling every 30 to 60 seconds is plenty.
Browsers and CORS
Call the API from your server. CORS is off by default. If a web page must call it from a visitor's browser, set one allowed website on the token; requests from any other origin are refused. Anything in a web page is visible to visitors.
Your token, plan and limits
GET /me needs no plan check. Besides the token itself it returns plan (premium1, premium2, premium3 or none), limits (tokens and perMinute of that plan) and tokensUsed (active tokens of the server). rateLimitPerMin is the rate this token gets right now.
{ "ok": true, "data": { "guildId": "123456789012345678", "name": "Website", "prefix": "dhba_aB3dE", "scopes": ["guild:read"],
"allowedOrigin": null, "rateLimitPerMin": 120, "createdAt": "2026-10-01T12:00:00.000Z",
"plan": "premium2", "limits": { "tokens": 5, "perMinute": 120 }, "tokensUsed": 2 } }
Request ids
Every answer carries an X-Request-Id header. If you send your own X-Request-Id (up to 64 letters, digits and . _ : -) it is kept, otherwise one is generated. Errors repeat it as requestId. Quote it when you contact support.
X-Request-Id: 3f2b8c1e-5a7d-4e0b-9c64-1d2e3f4a5b6c
{ "ok": false, "error": "rate_limited", "code": "rate_limited", "message": "Too many requests", "requestId": "3f2b8c1e-5a7d-4e0b-9c64-1d2e3f4a5b6c" }
Errors
Errors are JSON with ok: false, a stable code in code (error holds the same value), a short message and the requestId. Decide by the code, never by the message text.
400 bad_request / bad_cursor | A parameter is not valid (limit, cursor, status or id). |
401 unauthorized / invalid_token | Missing, malformed, unknown or revoked token. |
403 guild_mismatch | The guild in the path is not the guild of the token. |
403 missing_scope | The token does not have the scope this endpoint needs. |
403 origin_not_allowed | The Origin header does not match the token's allowed website. |
403 plan_required | The server has no paid plan or active trial. |
403 feature_not_in_plan | The feature is not part of the server's plan. |
404 not_found / shop_not_enabled | Nothing there (or the shop is not enabled). |
405 method_not_allowed | Only GET is available; the API is read-only. |
429 rate_limited | Too many requests. Wait for Retry-After seconds. |
503 unavailable | Temporarily unavailable. Try again later. |