Mechaniki
Ekwipunek i Kuźnia
Walka
Postać
Rzemiosło i Sklepy
Eksploracja i Łupy
Chowańce
Ekonomia i Handel
Społeczność
Rywalizacja i Wydarzenia
Pierwsze kroki
Wydarzenia i Wyzwania
Dla twórców
API w praktyce: przykłady użycia
Gotowe scenariusze wykorzystania publicznego API: co chcesz zbudować, które endpointy wywołać i w jakiej kolejności, na co uważać - oraz działający kod do skopiowania. Każdy przykład korzysta z prawdziwego adresu API gry.
Pełna dokumentacja wszystkich endpointów Parametry, przykładowe odpowiedzi, token gildii, limity i kody błędów.Scenariusze
Strona z rankingiem i buildami najlepszych graczy
Dla kogo Strony fanowskie, blogi z poradnikami, serwisy społeczności.
Cel Pokazać aktualny top graczy serwera, a po kliknięciu w gracza jego pełny build: ekwipunek z ulepszeniami, CP i klasę.
Krok po kroku
-
1
Pobierz ranking - od razu dostajesz nick, poziom, avatar, gildię i broń każdego gracza.
GET /api/v1/servers/s1/rankings/characters/level?limit=100 -
2
Po kliknięciu w gracza pobierz jego profil z buildem.
GET /api/v1/servers/s1/characters/{characterRef}
Wskazówki
- Ranking odświeża się co minutę - trzymaj go w pamięci swojej strony co najmniej tyle samo.
- Profil prywatny ma profile_public: false i build: null - pokaż wtedy samą kartę gracza.
- Profile pobieraj dopiero po kliknięciu, a nie wszystkie naraz - limit to 60 zapytań na minutę.
Gotowa strona HTML + JavaScript (zapisz jako top10.html i otwórz w przeglądarce)
<!doctype html>
<html lang="en">
<meta charset="utf-8">
<title>Berserk Rush - Top 10</title>
<style>
body { font-family: sans-serif; background: #111; color: #eee; }
li { margin: 6px 0; cursor: pointer; }
img { width: 32px; height: 32px; vertical-align: middle; border-radius: 4px; }
</style>
<ol id="top"></ol>
<pre id="build"></pre>
<p><small>Data: Berserk Rush</small></p>
<script>
const API = 'https://berserkrush.pl/api/v1/servers/s1';
async function api(path) {
const response = await fetch(API + path + (path.includes('?') ? '&' : '?') + 'lang=en');
const body = await response.json();
if (!response.ok) throw new Error(body.error.code);
return body.data;
}
async function showBuild(id) {
const hero = await api('/characters/' + id);
const out = document.getElementById('build');
if (!hero.profile_public) {
out.textContent = hero.name + ' keeps the profile private.';
return;
}
const gear = hero.build.equipment.map(e => `${e.slot}: ${e.item.name} +${e.upgrade_level} (${e.rarity})`);
out.textContent = `${hero.name} - CP ${hero.combat_power}\n` + gear.join('\n');
}
api('/rankings/characters/level?limit=10').then(top => {
const list = document.getElementById('top');
for (const hero of top) {
const li = document.createElement('li');
const avatar = Object.assign(document.createElement('img'), { src: hero.avatar_url, alt: '' });
li.append(avatar, ` ${hero.name} - lvl ${hero.level_label} (${hero.weapon_type})`); // text node, safe
li.onclick = () => showBuild(hero.id);
list.appendChild(li);
}
});
</script>
</html>
Bot na Discorda z komendami o graczach i gildiach
Dla kogo Serwery Discord gildii i społeczności graczy.
Cel Odpowiadać na komendy !top, !hero i !guild aktualnymi danymi z gry, bez wychodzenia z Discorda.
Krok po kroku
-
1
!top - pierwsza piątka rankingu poziomów.
GET /api/v1/servers/s1/rankings/characters/level?limit=5 -
2
!hero Nick - poziom, gildia, ELO i CP gracza.
GET /api/v1/servers/s1/characters/{characterRef} -
3
!guild Nazwa - poziom, liczba członków i lider gildii.
GET /api/v1/servers/s1/guilds/{guildRef}
Wskazówki
- Nieznany nick albo gildia to odpowiedź 404 z kodem character_not_found albo guild_not_found - odpowiedz wtedy krótkim komunikatem.
- Nicki i nazwy gildii przepuszczaj przez encodeURIComponent - mogą zawierać spacje i polskie znaki.
- Na anglojęzycznym serwerze dodaj ?lang=en, żeby tytuły i nazwy przedmiotów były po angielsku.
Bot w Node.js (discord.js v14)
// Minimal Discord bot (discord.js v14, Node 18+): !top, !hero <name>, !guild <name>
import { Client, GatewayIntentBits } from 'discord.js';
const API = 'https://berserkrush.pl/api/v1/servers/s1';
const client = new Client({
intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages, GatewayIntentBits.MessageContent],
});
async function api(path) {
const response = await fetch(API + path);
return response.ok ? (await response.json()).data : null; // 404 = character_not_found / guild_not_found
}
client.on('messageCreate', async (message) => {
const [command, ...args] = message.content.trim().split(/\s+/);
const name = encodeURIComponent(args.join(' '));
if (command === '!top') {
const top = await api('/rankings/characters/level?limit=5');
if (!top) return message.reply('The game API is not available right now.');
await message.reply(top.map(h => `#${h.rank} ${h.name} (${h.level_label}, ${h.weapon_type})`).join('\n'));
}
if (command === '!hero' && name) {
const hero = await api(`/characters/${name}`);
if (!hero) return message.reply('No such character.');
const guild = hero.guild ? ` [${hero.guild.name}]` : '';
const power = hero.profile_public ? `, CP ${hero.combat_power}` : ' (private profile)';
await message.reply(`${hero.name}${guild}: level ${hero.level_label}, ELO ${hero.arena.elo}${power}`);
}
if (command === '!guild' && name) {
const guild = await api(`/guilds/${name}`);
if (!guild) return message.reply('No such guild.');
await message.reply(`${guild.name}: level ${guild.level}, ${guild.members}/${guild.max_members} members, leader ${guild.leader?.name ?? '-'}`);
}
});
client.login(process.env.DISCORD_TOKEN);
Tygodniowy raport skarbnika gildii
Dla kogo Liderzy i skarbnicy gildii (wymaga tokena gildii).
Cel Raz w tygodniu wysłać na kanał gildii stan skarbca, najhojniejszych członków i listę osób, które nic nie wpłaciły.
Krok po kroku
-
1
Pobierz stan skarbca razem z limitami.
GET /api/v1/servers/s1/guild -
2
Pobierz sumy wpłat z ostatnich 7 dni - lista zawiera też członków z samymi zerami.
GET /api/v1/servers/s1/guild/donations/summary?days=7&sort=gold
Wskazówki
- Skrypt uruchamiaj na swoim serwerze (np. cron raz w tygodniu), a token trzymaj w zmiennej środowiskowej.
- Członkowie, którzy odeszli, a wpłacali w tym tygodniu, są w osobnej liście former_members.
- Po przekazaniu przywództwa token przestaje działać (token_invalid) - nowy lider musi wygenerować nowy.
Skrypt w Pythonie wysyłający raport na webhook Discorda
# Weekly treasury report for the guild Discord channel - run it once a week (cron) on YOUR server.
# pip install requests; env: BERSERK_GUILD_TOKEN (brk_s1_...), DISCORD_WEBHOOK_URL
import os
import requests
API = "https://berserkrush.pl/api/v1/servers/s1"
HEADERS = {"Authorization": f"Bearer {os.environ['BERSERK_GUILD_TOKEN']}"}
guild = requests.get(f"{API}/guild", headers=HEADERS, timeout=10).json()["data"]
summary = requests.get(f"{API}/guild/donations/summary", params={"days": 7, "sort": "gold"},
headers=HEADERS, timeout=10).json()["data"]
treasury = guild["treasury"]
lines = [
f"**{guild['name']}** - {summary['period']['from']} .. {summary['period']['to']}",
f"Treasury: {treasury['gold']:,} / {treasury['gold_cap']:,} gold, {treasury['gems']} / {treasury['gems_cap']} gems",
f"Donated: {summary['totals']['gold']:,} gold, {summary['totals']['exp']:,} EXP",
"",
"Top donors:",
]
for row in summary["members"][:5]:
lines.append(f"- {row['character']['name']}: {row['gold']:,} gold, {row['exp']:,} EXP")
idle = [row["character"]["name"] for row in summary["members"] if row["donations"] == 0]
if idle:
lines += ["", "No donations this week: " + ", ".join(idle)]
requests.post(os.environ["DISCORD_WEBHOOK_URL"], json={"content": "\n".join(lines)}, timeout=10)
Synchronizacja wpłat do własnej bazy lub arkusza
Dla kogo Twórcy paneli do zarządzania gildią (wymaga tokena gildii).
Cel Co kilka minut dociągać tylko nowe wpłaty i trzymać pełną historię u siebie - pod własne statystyki, rangi albo nagrody dla członków.
Krok po kroku
-
1
Pobieraj wpłaty z parametrem since ustawionym na najnowsze updated_at z poprzedniej synchronizacji, strona po stronie do meta.last_page.
GET /api/v1/servers/s1/guild/donations?since=2026-09-21T12:00:00Z&per_page=100 -
2
Opcjonalnie odśwież skład gildii, żeby przypisać wpłaty do obecnych członków i ról.
GET /api/v1/servers/s1/guild/members
Wskazówki
- Zapisuj wpłaty po polu id (upsert) - automatyczna dotacja EXP to jeden wpis na dobę, który rośnie do północy.
- Cofnij since o minutę względem ostatniej synchronizacji - nakładające się okna są niegroźne, bo robisz upsert.
- Odpowiedź 401 token_invalid oznacza unieważniony token - zatrzymaj synchronizację i poproś lidera o nowy.
Skrypt w Node.js zapisujący wpłaty do pliku JSON
// sync-donations.mjs - keeps every guild donation in donations.json (Node 18+, run on YOUR server).
// Auto EXP donations are one row per player per day that keeps growing - always upsert by id.
import { readFile, writeFile } from 'node:fs/promises';
const API = 'https://berserkrush.pl/api/v1/servers/s1';
const headers = { Authorization: `Bearer ${process.env.BERSERK_GUILD_TOKEN}` };
async function sync() {
const store = JSON.parse(await readFile('donations.json', 'utf8').catch(() => '{"since":null,"rows":{}}'));
let newest = store.since;
let page = 1;
let lastPage = 1;
do {
const query = new URLSearchParams({ per_page: '100', page: String(page) });
if (store.since) {
// Go back one minute - overlapping windows are harmless because rows are upserted.
query.set('since', new Date(Date.parse(store.since) - 60_000).toISOString());
}
const response = await fetch(`${API}/guild/donations?${query}`, { headers });
const body = await response.json();
if (!response.ok) throw new Error(body.error.code); // token_invalid = token revoked or leader changed
for (const row of body.data) {
store.rows[row.id] = row;
if (!newest || Date.parse(row.updated_at) > Date.parse(newest)) newest = row.updated_at;
}
lastPage = body.meta.last_page;
page++;
} while (page <= lastPage);
store.since = newest;
await writeFile('donations.json', JSON.stringify(store, null, 2));
}
await sync();
setInterval(() => sync().catch(console.error), 10 * 60 * 1000);
Analiza mety: popularne klasy i bronie w czołówce
Dla kogo Autorzy poradników, teoretycy buildów, twórcy statystyk.
Cel Sprawdzić, jakimi broniami grają najlepsi i jakie przedmioty dominują w buildach czołówki.
Krok po kroku
-
1
Pobierz top 100 - pole weapon_type w każdym wpisie wystarcza do policzenia rozkładu klas bez dodatkowych zapytań.
GET /api/v1/servers/s1/rankings/characters/arena?limit=100 -
2
Dla wybranych graczy pobierz profile i policz przedmioty w poszczególnych slotach.
GET /api/v1/servers/s1/characters/{characterRef}
Wskazówki
- Między profilami rób około sekundy przerwy, żeby zmieścić się w limicie 60 zapytań na minutę.
- Profile prywatne i ukryte sekcje (hidden_sections) pomijaj w statystykach, zamiast traktować je jak zera.
- Ranking arena pokazuje najlepszych w PvP, ranking level najdalej rozwinięte postacie - porównanie obu to ciekawy materiał.
Skrypt w Pythonie liczący rozkład klas i najpopularniejsze bronie
# Weapon types of the top 100 PvP players and the most popular weapons among the top 20 builds.
import collections
import time
import requests
API = "https://berserkrush.pl/api/v1/servers/s1"
top = requests.get(f"{API}/rankings/characters/arena", params={"limit": 100}, timeout=10).json()["data"]
print("Weapon types in top 100:", collections.Counter(hero["weapon_type"] for hero in top).most_common())
weapons = collections.Counter()
for hero in top[:20]:
profile = requests.get(f"{API}/characters/{hero['id']}", params={"lang": "en"}, timeout=10).json()["data"]
time.sleep(1.1) # stay under 60 requests per minute
if profile["build"] is None: # private profile
continue
for piece in profile["build"]["equipment"]:
if piece["slot"] == "main_hand":
weapons[piece["item"]["name"]] += 1
print("Most popular weapons in top 20:", weapons.most_common(5))
Wyszukiwarka łupów: gdzie zdobyć przedmiot
Dla kogo Strony z poradnikami, boty, nakładki dla graczy.
Cel Po wpisaniu nazwy przedmiotu pokazać potwory i mapy, z których wypada.
Krok po kroku
-
1
Znajdź przedmiot po fragmencie polskiej nazwy.
GET /api/v1/servers/s1/items?search=wilcza&per_page=1 -
2
Pobierz szczegóły przedmiotu - pole dropped_by zawiera potwory i ich mapy.
GET /api/v1/servers/s1/items/{itemId} -
3
Opcjonalnie pokaż całą mapę z potworami i najcenniejszymi łupami.
GET /api/v1/servers/s1/maps/{mapId}
Wskazówki
- Wyszukiwarka porównuje polskie nazwy (pole name_pl), a pole name zwraca nazwę w języku z parametru lang.
- Pusta lista dropped_by oznacza, że przedmiotu nie upuszczają potwory - pochodzi np. ze skrzyń, od Kowala albo z handlu.
- Dane katalogowe zmieniają się rzadko - możesz trzymać je u siebie nawet przez kilka godzin.
Funkcja w JavaScript
// "Where does it drop?" - finds an item by (Polish) name and lists the monsters and maps that drop it.
const API = 'https://berserkrush.pl/api/v1/servers/s1';
async function whereDoesItDrop(query) {
const found = await fetch(`${API}/items?per_page=1&lang=en&search=${encodeURIComponent(query)}`).then(r => r.json());
const item = found.data[0];
if (!item) return `Nothing matches "${query}".`;
const { data } = await fetch(`${API}/items/${item.id}?lang=en`).then(r => r.json());
if (data.dropped_by.length === 0) return `${data.name}: not dropped by monsters (chests, crafting or trade).`;
const sources = data.dropped_by.map(m => `${m.monster} (lvl ${m.level}${m.map ? ', ' + m.map.name : ''})`);
return `${data.name}: ${sources.join('; ')}`;
}
whereDoesItDrop('wilcza').then(console.log);
Więcej pomysłów
- Nakładka na stream (OBS): top 5 rankingu tygodniowego z odliczaniem do resetu z meta.resets_at.
- Strona rekrutacyjna: lista gildii z trybem rekrutacji, minimalnym poziomem i liczbą wolnych miejsc.
- Porównywarka postaci: dwa profile obok siebie, slot po slocie.
- Automatyczne role na Discordzie gildii według ról ze składu gildii (endpoint z tokenem).
- Przewodnik po mapach: mapa, jej potwory, bossowie i najcenniejsze łupy w jednym widoku.
Zbudowałeś coś ciekawego albo brakuje Ci danych w API? Napisz na naszym Discordzie.