Brazil's biggest MU Online portal — since 2003
Tutorial Intermediate Website

How to build a Vote4Coins system (Gtop100, XtremeTop) in MU Online

Build a complete Vote4Coins system for your MU Online server, rewarding players who vote on lists like Gtop100 and XtremeTop via a secure callback (postback), with anti-fraud, cooldown and automatic coin crediting.

BR Bruno · Updated on Jul 10, 2025 · ⏱ 12 read
Quick answer

Voting lists like Gtop100 and XtremeTop are one of the cheapest organic growth engines a MU Online server can have. The more votes you accumulate, the higher you appear in the ranking, and the more new players discover the server without spending a cent on ads. The problem is that no one votes for f

Voting lists like Gtop100 and XtremeTop are one of the cheapest organic growth engines a MU Online server can have. The more votes you accumulate, the higher you appear in the ranking, and the more new players discover the server without spending a cent on ads. The problem is that no one votes for free for very long — that is why Vote4Coins exists: a system that trades votes for in-game coins. In this intermediate-level tutorial you will build that system from scratch, focusing on what really matters: crediting only votes confirmed by the list, through the callback (postback), and hardening everything against fraud.

The classic mistake of beginners is crediting the reward the moment the player clicks the "Vote" button. That is an invitation to fraud: the player clicks, gets the coin, closes the tab without completing the vote, and repeats. The right way is to understand that there are two distinct moments — the redirect (the player goes to the list) and the callback (the list confirms to your server that the vote was valid). The reward lives in the second moment. All the field, parameter and table names here are examples and vary by version of the distribution and by list; always check each site's current documentation and your database schema.

Prerequisites

  • A PHP 7.4+ website (ideally 8.x) with access to the website and game databases.
  • An administrator account registered on each list you are going to use (Gtop100, XtremeTop, TopG, XtremeTop100, etc.).
  • Your server already registered on those lists, with the Site ID / server ID and the secret key (sometimes called "postback key", "callback key" or "incentive hash") in hand.
  • A login system on the website that identifies the player's game account (to know who receives the reward).
  • HTTPS active — many lists require a secure callback URL.
  • A notion of how to credit coins in the game database (WCoin, VIP credits, event points — varies by version).

How the voting flow with callback works

Before coding, understand the full path of a rewarded vote. There are six steps, and each one has a clear role.

  1. The logged-in player clicks "Vote on Gtop100" on your site.
  2. Your backend records a pending vote and redirects the player to the list's URL, embedding an identifier (usually the IP or a pingUsername with the player's login).
  3. The player solves the CAPTCHA and confirms the vote on the list.
  4. The list validates the vote (unique IP in the period, correct CAPTCHA) and makes an HTTP request to your callback stating that the vote was successful.
  5. Your callback validates the origin and the secret key, finds the player by the identifier and credits the reward idempotently.
  6. The player returns to the site and sees the updated balance; the cooldown starts counting.
StepWho executes itTrust it to credit?
Click "Vote"PlayerNo
RedirectYour backendNo
Confirmation on the listPlayer + listNot yet
Callback/postbackThe list's serverYes, after validating
CreditingYour backend

Modeling the votes and rewards tables

Create, in the website database, a table to track each vote. It controls the cooldown and the callback's idempotency.

CREATE TABLE votes (
    id          BIGINT AUTO_INCREMENT PRIMARY KEY,
    account     VARCHAR(20) NOT NULL,        -- game account
    site        VARCHAR(30) NOT NULL,        -- 'gtop100', 'xtremetop', ...
    ip          VARCHAR(45) NOT NULL,
    status      ENUM('pending','confirmed') DEFAULT 'pending',
    reward      INT NOT NULL DEFAULT 0,
    created_at  DATETIME DEFAULT CURRENT_TIMESTAMP,
    confirmed_at DATETIME NULL,
    INDEX idx_cooldown (account, site, created_at),
    INDEX idx_ip (ip, site, created_at)
);

A second configuration table helps keep the rewards and cooldowns per list without touching the code:

CREATE TABLE vote_sites (
    site        VARCHAR(30) PRIMARY KEY,
    display_name VARCHAR(60) NOT NULL,
    reward      INT NOT NULL,         -- e.g. 200 WCoin per vote
    cooldown_h  INT NOT NULL DEFAULT 12,
    secret_key  VARCHAR(120) NOT NULL,
    vote_url    VARCHAR(255) NOT NULL
);

Step by step: the vote redirect

When the player clicks to vote, you record the pending vote and send them to the list. The identifier sent depends on the list: some use the player's IP to match the callback; others accept a pingUsername with the login. Generic example:

<?php
session_start();
$account = $_SESSION['account'] ?? null;
if (!$account) { header('Location: /login'); exit; }

$site = $_GET['site'] ?? '';
$cfg  = buscarVoteSite($site);              // reads from vote_sites
if (!$cfg) { http_response_code(404); exit; }

// check the cooldown before allowing another vote
if (emCooldown($account, $site, $cfg['cooldown_h'])) {
    header('Location: /votar?erro=cooldown'); exit;
}

// record a pending vote
registrarVotoPendente($account, $site, $_SERVER['REMOTE_ADDR'], $cfg['reward']);

// redirect to the list (URL and parameters VARY by list)
$url = str_replace('{USER}', urlencode($account), $cfg['vote_url']);
header("Location: {$url}");

The vote_url for Gtop100, for example, usually follows the server page pattern with an incentive parameter (pingUsername). On XtremeTop, the match is normally by IP. Check each list's documentation for the exact parameters — they change over time.

Step by step: the callback (postback)

This is the heart of the system. The list makes a request to your callback when the vote is valid. The format varies a lot:

  • Gtop100 normally sends a POST with fields like Successful (1 = success, 0 = failure), pingUsername (the identifier you sent), pingIP and a VoteID, plus a key-based verification.
  • XtremeTop100 usually makes a simple GET to your callback passing the voter's IP, and you must match that IP to the most recent pending vote.

The code pattern, however, is always the same: validate, match, credit idempotently, respond.

<?php
// Gtop100 callback (example — fields vary)
$sucesso = $_POST['Successful'] ?? '0';
$user    = $_POST['pingUsername'] ?? '';
$ip      = $_POST['pingIP'] ?? $_SERVER['REMOTE_ADDR'];

// 1. validate the origin: secret key and/or the list server's IP
if (!validarChaveSecreta('gtop100', $_POST)) {
    http_response_code(403); exit('invalid');
}

if ($sucesso === '1') {
    // 2. find that player/list's pending vote
    $voto = buscarVotoPendente($user, 'gtop100');
    if ($voto) {
        creditarVoto($voto['id']);   // idempotent
    }
}
echo 'ok';   // many lists expect a specific response

Note that the callback does not trust the player's browser — the request comes from the list's server. Even so, validate the secret key and, if possible, restrict by the list's IP range, because an attacker can try to call your callback directly to forge votes.

Idempotent crediting of the reward

The crediting function must ensure that the same pending vote does not become coins twice. Use the status transition as a lock:

<?php
function creditarVoto(int $voteId): void
{
    global $siteDb, $gameDb;

    // lock: only credit if it is still 'pending'
    $upd = $siteDb->prepare(
        "UPDATE votes SET status='confirmed', confirmed_at=NOW()
         WHERE id=? AND status='pending'"
    );
    $upd->execute([$voteId]);
    if ($upd->rowCount() === 0) return;   // already credited

    $v = /* fetch account and reward from the vote */;

    // credit in the GAME database (table/column VARY by version)
    $gameDb->prepare(
        "UPDATE MEMB_INFO SET WCoin = WCoin + ? WHERE memb___id = ?"
    )->execute([$v['reward'], $v['account']]);
}

If the callback is resent (some lists repeat on timeout), the WHERE status='pending' guarantees a single credit. The WCoin column in MEMB_INFO is the typical Season 6 case; your version may use Cash, its own points table or a VIP credit system. Varies by version — confirm before.

Anti-fraud: cooldown, IP and secret key

Vote4Coins is a magnet for abuse. Reinforce three barriers:

  1. Per-account and per-list cooldown: respect the list's official interval (12 or 24 h). Block a new pending vote before that deadline.
  2. IP control: record the IP and limit votes per IP in the period, making it harder for the same player to multi-account.
  3. Callback validation: a mandatory secret key and, when possible, verification of the list server's source IP. Never accept a callback just because it "looks" right.
<?php
function emCooldown(string $acc, string $site, int $horas): bool {
    global $siteDb;
    $q = $siteDb->prepare(
        "SELECT 1 FROM votes
         WHERE account=? AND site=? AND status='confirmed'
           AND created_at > (NOW() - INTERVAL ? HOUR) LIMIT 1"
    );
    $q->execute([$acc, $site, $horas]);
    return (bool)$q->fetch();
}

Voting page for the player

On the panel, show each list with a "Vote" button and the remaining cooldown time. An example structure to render it dynamically:

const sites = [
  { site: "gtop100",   nome: "Gtop100",    reward: 200, cooldownRestante: 0 },
  { site: "xtremetop", nome: "XtremeTop100", reward: 150, cooldownRestante: 3600 },
];
// disable the button while cooldownRestante > 0 and show a countdown

Make it clear to the player how much they earn per vote and the interval — transparency reduces support tickets. If you are building the server's entire structure, Vote4Coins is just one of the web modules; see the general guide on how to create a MU Online server to understand where it fits.

Common errors and fixes

SymptomLikely causeFix
Player voted but got nothingCallback not configured or wrong URL on the listRegister the correct postback URL in the list's panel
Reward credited without votingCredited on the click, not on the callbackOnly credit on the confirmed callback (Successful=1)
Vote credited twiceNo idempotencyUse UPDATE ... WHERE status='pending' as a lock
Callback rejected (403)Mismatched secret keyReconfirm the secret key in the list's panel and in vote_sites
Player votes several times in a rowCooldown not appliedCheck the cooldown per account and IP before the redirect
Callback forged by third partiesNo origin validationValidate the secret key and restrict the list's source IP

Security and best practices

  • Never expose the list's secret key on the front end or in Git.
  • Treat the callback as untrusted input until you validate the key and origin.
  • Log received callbacks (payload + IP) to audit for fraud.
  • Matching by pingUsername is more reliable than matching by raw IP, when the list allows it.
  • If a player complains about an unpaid vote, first check whether the list actually sent the callback — often the CAPTCHA failed on their side.
  • Cap the total daily reward per account to curb abuse even with multiple lists.

Launch checklist

  • Server registered on each list with the Site ID and secret key saved
  • votes and vote_sites tables created
  • Callback URL configured on each list, with HTTPS
  • Secret key validation implemented in each handler
  • Idempotent crediting tested (a duplicate callback does not pay twice)
  • Cooldown per account and per IP working
  • Real coin table/column name confirmed for your game DB version
  • Voting page with a cooldown countdown
  • Callback logs enabled for auditing
  • End-to-end test with a real vote on each list

With this system you turn every active player into a daily promoter of the server, climb the rankings organically and still give a fair reward in return — all automatically, securely and proof against anyone trying to game the vote click.

Frequently asked questions

What is Vote4Coins in MU Online?

It is a system that rewards players with in-game coins (WCoin, credits or points) whenever they vote for your server on ranking sites like Gtop100 and XtremeTop, raising your position in the lists and your exposure.

How does the voting site tell you the vote was valid?

Through a callback (also called a postback or pingback): when the vote is confirmed, the list makes an HTTP request to a URL on your site, providing the player's identifier. Only at that moment should the reward be credited.

Why shouldn't I credit as soon as the player clicks to vote?

Because the click does not guarantee a valid vote. The player may close the page, the CAPTCHA may fail or they may vote from an already-used IP. Only the callback confirmed by the list guarantees that the vote counted.

How do I stop a player from voting several times in a row?

Combine the list's official cooldown (usually 12 or 24 hours) with your own record of votes per account and per IP, plus validating the callback via the secret key and the list's source IP.

Can I use more than one voting list at the same time?

Yes, and it is recommended. Each list has its own callback and cooldown. You just create one handler per list and a unified votes table to control rewards and avoid duplication.

BR
Events, maps & items editor

Bruno specializes in MU Online events, maps, bosses and item economy. He documents every detail based on real gameplay.

Keep reading

Related articles