Desenvolvedores
Visão geral
O GameServers BR permite que o criador de um servidor gere um widget incorporável (iframe ou script) para exibir métricas públicas em tempo quase real, com proteção por token e limite de requisições.
O que o widget exibe
- Quantidade total de views (views_total)
- Avaliação média (rating_avg) e total de avaliações (rating_count)
- Número total de votos (votes_total)
- Contadores por período: votos (24h / 7d / 30d)
- Status online/offline (opcional; depende de IP/porta configurados)
Exemplos responsivos (iframe)
Use estes padrões para o widget se adaptar ao seu layout.
<div style="max-width: 360px;">
<iframe
src="https://GAMESERVERSBR.COM.BR/widget/servidor/ID/TOKEN?theme=dark&lang=pt"
style="width:100%; height:260px; border:0;"
loading="lazy"
></iframe>
</div>
<div style="display:flex; justify-content:center;">
<iframe
src="https://GAMESERVERSBR.COM.BR/widget/servidor/ID/TOKEN"
width="320"
height="260"
style="border:0;"
></iframe>
</div>
height conforme necessário.Playground (gera o código automaticamente)
Preencha os campos abaixo para gerar o snippet pronto e visualizar uma prévia.
Como ativar (criador do servidor)
- Acesse: Painel → Painel do servidor
- Abra a aba Webhook/Widget
- Ative o webhook/widget, ajuste tema/idioma/métricas e copie o código
- Se o link/token vazar, use Regenerar token
Opção 1: incorporar via iframe (recomendado)
Compatível com a maioria dos sites e fóruns que aceitam iframe.
<iframe
src="https://GAMESERVERSBR.COM.BR/widget/servidor/ID/TOKEN?theme=dark&lang=pt"
width="320"
height="260"
style="border:0;"
loading="lazy"
referrerpolicy="no-referrer-when-downgrade"
></iframe>
width e height para encaixar no seu layout.
theme:darkoulightlang:ptouenrefresh: 15 a 600 (segundos)metrics: lista separada por vírgula (ex.:views,rating,votes_total,status)
Opção 2: incorporar via script (quando iframe não é permitido)
Esta opção insere um iframe automaticamente no local do script.
Use quando o site aceitar <script>, mas não permitir colar <iframe> diretamente.
<div data-wyd-widget="1"></div>
<script async src="https://GAMESERVERSBR.COM.BR/widget/servidor/ID/TOKEN.js?theme=dark&lang=pt"></script>
.js: width, height, metrics, refresh.Segurança e limites
- Assinatura ativa: o widget público requer que o servidor tenha assinatura ativa e que o plano inclua
webhook/widget. - Token por servidor: a URL do widget inclui um token. Se vazar, regenere no painel.
- Ativar/desativar: o criador pode desativar o widget a qualquer momento.
- Rate limit: limite por IP/servidor para evitar abuso.
- Status online: é opcional e cacheado (para reduzir carga).
Dados (JSON) para integração externa
O widget consome um endpoint JSON. Você pode usar o mesmo endpoint para integrações customizadas.
GET https://GAMESERVERSBR.COM.BR/widget/servidor/ID/TOKEN/data
?preview=1.
Em sites externos, o modo preview não deve ser usado.
{
"server": {
"id": 123,
"title": "Meu Servidor",
"slug": "meu-servidor",
"url": "https://GAMESERVERSBR.COM.BR/servidor/meu-servidor"
},
"metrics": {
"views_total": 1024,
"votes_total": 250,
"rating_avg": 4.65,
"rating_count": 57,
"votes_day": 12,
"votes_week": 60,
"votes_month": 180,
"status": {
"online": true,
"checked_at": 1730000000,
"latency_ms": 42
}
},
"generated_at": "2026-01-18T00:00:00Z"
}
API pública (sem login)
Endpoints públicos para ranking e perfis. Retornam JSON e não usam cookies.
503 com {"error":"route_disabled"}.
GET https://GAMESERVERSBR.COM.BR/api/rankings/users?period=daily&metric=xp&page=1&per_page=50
period (daily/weekly/monthly/all), metric (xp/votes/reviews/referrals), start (YYYY-mm-dd), page, per_page.
GET https://GAMESERVERSBR.COM.BR/api/profile/USERNAME
404 not_found: username inexistente503 route_disabled: rota temporariamente indisponível
API (login externo)
Para integrações externas que precisam autenticar um usuário do GameServers BR, disponibilizamos um login via API que retorna um token Bearer.
POST https://GAMESERVERSBR.COM.BR/api/auth/login
Content-Type: application/json
<?php
$baseUrl = 'https://GAMESERVERSBR.COM.BR';
$payload = [
'email' => 'usuario@exemplo.com',
'password' => 'SENHA_DO_USUARIO',
'twofa_code' => '123456',
'label' => 'Meu App',
'ttl_days' => 30,
];
$ch = curl_init($baseUrl . '/api/auth/login');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
]);
$body = curl_exec($ch);
$status = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($status !== 200) {
echo "Login falhou: HTTP {$status}\n{$body}\n";
exit(1);
}
$data = json_decode((string)$body, true);
$token = (string)($data['access_token'] ?? '');
echo "TOKEN: {$token}\n";
const baseUrl = 'https://GAMESERVERSBR.COM.BR';
const loginRes = await fetch(baseUrl + '/api/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
email: 'usuario@exemplo.com',
password: 'SENHA_DO_USUARIO',
twofa_code: '123456',
label: 'Meu App',
ttl_days: 30,
}),
});
const loginJson = await loginRes.json();
if (!loginRes.ok) throw new Error(JSON.stringify(loginJson));
const token = loginJson.access_token;
const meRes = await fetch(baseUrl + '/api/me', {
headers: { Authorization: `Bearer ${token}` },
});
const meJson = await meRes.json();
console.log(meJson.user);
// Exemplo: pequeno server Crow que faz login via API e devolve o token.
// Dependências sugeridas: Crow + libcurl
#include <crow.h>
#include <curl/curl.h>
static size_t writeCb(void* contents, size_t size, size_t nmemb, void* userp) {
((std::string*)userp)->append((char*)contents, size * nmemb);
return size * nmemb;
}
static std::pair<long, std::string> postJson(const std::string& url, const std::string& jsonBody) {
CURL* curl = curl_easy_init();
if (!curl) return {0, ""};
std::string out;
struct curl_slist* headers = nullptr;
headers = curl_slist_append(headers, "Content-Type: application/json");
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, jsonBody.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeCb);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &out);
curl_easy_perform(curl);
long status = 0;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &status);
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
return {status, out};
}
int main() {
crow::SimpleApp app;
const std::string baseUrl = "https://GAMESERVERSBR.COM.BR";
CROW_ROUTE(app, "/login")([]{
const std::string body = R"({
\"email\":\"usuario@exemplo.com\",
\"password\":\"SENHA_DO_USUARIO\",
\"twofa_code\":\"123456\",
\"label\":\"Meu App\",
\"ttl_days\":30
})";
auto [status, resp] = postJson(baseUrl + "/api/auth/login", body);
return crow::response((int)status, resp);
});
app.port(18080).multithreaded().run();
}
{
"email": "usuario@exemplo.com",
"password": "SENHA_DO_USUARIO",
"twofa_code": "123456",
"label": "Meu App",
"ttl_days": 30
}
{
"token_type": "Bearer",
"access_token": "TOKEN_AQUI",
"expires_at": "2026-02-20 12:00:00",
"user": {
"id": 123,
"name": "Nome do Usuário",
"email": "usuario@exemplo.com",
"role": "user",
"username": "meuusername"
}
}
GET https://GAMESERVERSBR.COM.BR/api/me
Authorization: Bearer TOKEN_AQUI
POST https://GAMESERVERSBR.COM.BR/api/auth/logout
Authorization: Bearer TOKEN_AQUI
POST https://GAMESERVERSBR.COM.BR/api/auth/refresh
Authorization: Bearer TOKEN_AQUI
Content-Type: application/json
{
"label": "Meu App (refresh)",
"ttl_days": 30
}
401 invalid_credentials: email/senha incorretos401 twofa_required: conta com 2FA ativo (envietwofa_code)401 twofa_invalid: código 2FA inválido ou reutilizado403 account_inactive: conta desativada/pendente429 rate_limited: muitas tentativas (aguarde)503 route_disabled: rota temporariamente indisponível
Integração: resgate de votos (donos de servidor)
Este fluxo permite que o dono do servidor consulte votos recentes e os resgate (1x por voto), desde que o usuário tenha o servidor favoritado. Isso é útil para converter votos em moeda/benefício no seu site/game.
- Requer
Authorization: Bearer ...(token do dono do servidor) - Scopes necessários:
servers:votes:reade/ouservers:votes:redeem - O voto só é elegível se o usuário tiver favoritado o servidor
- Cada voto pode ser resgatado apenas 1 vez
GET https://GAMESERVERSBR.COM.BR/api/servers/SERVER_ID/votes/pending?limit=50
Authorization: Bearer TOKEN_AQUI
POST https://GAMESERVERSBR.COM.BR/api/servers/SERVER_ID/votes/VOTE_ID/redeem
Authorization: Bearer TOKEN_AQUI
Content-Type: application/json
{
"external_ref": "order-12345",
"amount": 100,
"currency": "GOLD",
"metadata": {
"game_user": "NickNoJogo"
}
}
<?php
$baseUrl = 'https://GAMESERVERSBR.COM.BR';
$serverId = 123;
$voteId = 456;
$token = 'TOKEN_AQUI';
function httpJson(string $method, string $url, array $headers, ?array $body = null): array {
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
if ($body !== null) {
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
}
$resp = (string)curl_exec($ch);
$status = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
return [$status, $resp];
}
// 1) pending
[$st1, $b1] = httpJson('GET', $baseUrl . "/api/servers/{$serverId}/votes/pending?limit=50", [
'Authorization: Bearer ' . $token,
]);
echo "pending HTTP {$st1}\n{$b1}\n";
// 2) redeem
[$st2, $b2] = httpJson('POST', $baseUrl . "/api/servers/{$serverId}/votes/{$voteId}/redeem", [
'Authorization: Bearer ' . $token,
'Content-Type: application/json',
], [
'external_ref' => 'order-12345',
'amount' => 100,
'currency' => 'GOLD',
'metadata' => ['game_user' => 'NickNoJogo'],
]);
echo "redeem HTTP {$st2}\n{$b2}\n";
const baseUrl = 'https://GAMESERVERSBR.COM.BR';
const serverId = 123;
const voteId = 456;
const token = 'TOKEN_AQUI';
// 1) pending
const pendingRes = await fetch(`${baseUrl}/api/servers/${serverId}/votes/pending?limit=50`, {
headers: { Authorization: `Bearer ${token}` },
});
const pendingJson = await pendingRes.json();
console.log('pending', pendingRes.status, pendingJson);
// 2) redeem
const redeemRes = await fetch(`${baseUrl}/api/servers/${serverId}/votes/${voteId}/redeem`, {
method: 'POST',
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
external_ref: 'order-12345',
amount: 100,
currency: 'GOLD',
metadata: { game_user: 'NickNoJogo' },
}),
});
const redeemJson = await redeemRes.json();
console.log('redeem', redeemRes.status, redeemJson);
// Exemplo: endpoints no seu app Crow que chamam a API do portal.
// Dependências sugeridas: Crow + libcurl
#include <crow.h>
#include <curl/curl.h>
static size_t writeCb(void* contents, size_t size, size_t nmemb, void* userp) {
((std::string*)userp)->append((char*)contents, size * nmemb);
return size * nmemb;
}
static std::pair<long, std::string> http(const std::string& method, const std::string& url, const std::string& bearer, const std::string& bodyJson) {
CURL* curl = curl_easy_init();
if (!curl) return {0, ""};
std::string out;
struct curl_slist* headers = nullptr;
headers = curl_slist_append(headers, ("Authorization: Bearer " + bearer).c_str());
if (method == "POST") headers = curl_slist_append(headers, "Content-Type: application/json");
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, method.c_str());
if (method == "POST") curl_easy_setopt(curl, CURLOPT_POSTFIELDS, bodyJson.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeCb);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &out);
curl_easy_perform(curl);
long status = 0;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &status);
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
return {status, out};
}
int main() {
crow::SimpleApp app;
const std::string baseUrl = "https://GAMESERVERSBR.COM.BR";
// GET /pending?server_id=123
CROW_ROUTE(app, "/pending")([&](const crow::request& req) {
const std::string bearer = req.get_header_value("x-token"); // passe o token por header no seu app
const std::string sid = req.url_params.get("server_id") ? req.url_params.get("server_id") : "0";
auto [st, body] = http("GET", baseUrl + "/api/servers/" + sid + "/votes/pending?limit=50", bearer, "");
return crow::response((int)st, body);
});
// POST /redeem?server_id=123&vote_id=456
CROW_ROUTE(app, "/redeem").methods(crow::HTTPMethod::POST)([&](const crow::request& req) {
const std::string bearer = req.get_header_value("x-token");
const std::string sid = req.url_params.get("server_id") ? req.url_params.get("server_id") : "0";
const std::string vid = req.url_params.get("vote_id") ? req.url_params.get("vote_id") : "0";
const std::string body = R"({\"external_ref\":\"order-12345\",\"amount\":100,\"currency\":\"GOLD\",\"metadata\":{\"game_user\":\"NickNoJogo\"}})";
auto [st, out] = http("POST", baseUrl + "/api/servers/" + sid + "/votes/" + vid + "/redeem", bearer, body);
return crow::response((int)st, out);
});
app.port(18081).multithreaded().run();
}
401 unauthorized: token inválido/expirado403 insufficient_scope: faltam scopes no token403 forbidden: servidor não pertence ao token404 vote_not_found: voto não existe ou não pertence ao servidor409 favorite_required: usuário não favoritou o servidor409 already_redeemed: voto já resgatado503 route_disabled: rota temporariamente indisponível
Webhook Mercado Pago (pagamentos/assinaturas)
Endpoint para receber eventos do Mercado Pago. Em produção, este webhook é fail-closed se não houver token/assinatura configurados.
POST https://GAMESERVERSBR.COM.BR/webhooks/mercadopago
- Token compartilhado: enviar
?token=...ou headerx-webhook-token - Assinatura: headers
x-signature+x-request-id(HMAC SHA256) quando configurada no painel do Mercado Pago
403 webhook_not_configured: em produção quando não existe token nem assinatura configurados401 unauthorized: token/assinatura inválidos quando proteção está configurada200 ok: evento aceito (mesmo que o evento não gere ação local)
live_mode=false podem ser tolerados para facilitar testes.
FAQ (problemas comuns)
Not found).
.js), que injeta um iframe automaticamente. Se nem script for permitido,
a alternativa é usar apenas um link/botão para a página do servidor.
status deve estar habilitada.