Vote Postback API

Reward your players in-game for every vote. One link on your site, one small script on your server — done in ten minutes.

How it works

  1. Your website links each logged-in player to your vote page here, with their account name in the link.
  2. The player clicks Vote. The vote counts on the toplist immediately.
  3. We send a signed HTTP POST (the postback) to your server with the account name — your script credits the reward (WCoins, credits, buffs… your call).

The vote button

Put a ready-made button on your website so players vote in one click — no coding needed. You don't need the reward postback to use it; it works on its own. Add ?u=ACCOUNT to the link only if you also want to reward voters in-game (see the steps below).

Vote for us on MU Online Top 100

Paste this where you want the button, replacing YOUR-SLUG with your listing's slug (and ACCOUNT with the player's account name if you use rewards — otherwise delete ?u=ACCOUNT):

<a href="https://www.muonlinetop100.com/server/YOUR-SLUG?u=ACCOUNT" target="_blank" rel="noopener">
  <img src="https://www.muonlinetop100.com/vote-button.png"
       alt="Vote for us on MU Online Top 100" width="220" height="64" style="border:0">
</a>

Want it crisp on high-resolution screens? Swap vote-button.png for vote-button.svg. Your listing's edit page shows this snippet already filled in with your slug and a live preview.

Step 1 — the reward vote link

Link players to your server page with their account name in the u parameter (allowed: letters, digits, . _ -, up to 32 chars):

https://www.muonlinetop100.com/server/YOUR-SLUG?u=ACCOUNT

Generate it server-side on your site, e.g. in PHP:

<a href="https://www.muonlinetop100.com/server/YOUR-SLUG?u=<?= urlencode($accountName) ?>"
   target="_blank" rel="noopener">Vote for us — get your reward!</a>

Your exact link (with your real slug) is shown on your listing's edit page under Vote rewards (postback).

Step 2 — configure your postback URL

On the edit page of your listing, set Vote postback URL to an endpoint on your server (e.g. https://yourserver.com/vote-reward.php) and save. Your postback secret appears on the same page. Then hit Send test postback to verify everything end-to-end.

Step 3 — receive the postback

After each successful vote made through your reward link, we POST these application/x-www-form-urlencoded fields to your URL:

FieldExampleMeaning
server_id8Your listing's numeric id
slugmuonlineYour listing's slug
usernameHero123The u value from your reward link
ip203.0.113.7The voter's IP address (for your own anti-abuse checks)
voted_at1784200000Unix timestamp (UTC) of the vote — stable across retries
success1Always 1 — only counted votes are sent
test01 for test postbacks fired from your edit page
sig9f2ab4…HMAC-SHA256 signature (hex, lowercase) — verify it!

The signature is computed over the other fields joined with | in this exact order:

sig = HMAC_SHA256( server_id|slug|username|ip|voted_at|success|test , your_secret )

Copy-paste PHP receiver

<?php
// vote-reward.php — MU Online Top 100 vote postback receiver.
// Put this on your web server and set it as your "Vote postback URL".

$secret = 'YOUR_POSTBACK_SECRET'; // from your listing's edit page

$serverId = $_POST['server_id'] ?? '';
$slug     = $_POST['slug']      ?? '';
$username = $_POST['username']  ?? '';
$ip       = $_POST['ip']        ?? '';
$votedAt  = $_POST['voted_at']  ?? '';
$success  = $_POST['success']   ?? '';
$test     = $_POST['test']      ?? '0';
$sig      = $_POST['sig']       ?? '';

// 1) Verify the signature — rejects anything not sent by muonlinetop100.com.
$expected = hash_hmac(
    'sha256',
    $serverId . '|' . $slug . '|' . $username . '|' . $ip . '|' . $votedAt . '|' . $success . '|' . $test,
    $secret
);
if (!hash_equals($expected, $sig)) {
    http_response_code(403);
    exit('bad signature');
}

// 2) Test postbacks (sent from your edit page) — confirm and stop.
if ($test === '1') {
    exit('OK test received');
}

// 3) Reject ancient replays. Failed deliveries are retried for up to 24h,
//    so accept anything younger than 48h and rely on step 4 for duplicates.
if ((int)$votedAt < time() - 172800) {
    exit('OK expired');
}

// 4) Credit the reward ONCE per vote. Retries resend the IDENTICAL payload,
//    so (username, voted_at) — or the sig itself — is your idempotency key:
//
//    INSERT INTO vote_rewards (account, voted_at)
//    SELECT '$username', $votedAt
//    WHERE NOT EXISTS (SELECT 1 FROM vote_rewards
//                      WHERE account = '$username' AND voted_at = $votedAt);
//    -- if that inserted 1 row: add WCoins/credits to the account here.
//    (Use prepared statements — $username and $ip are player-influenced!)

exit('OK');

Delivery & retries

  • Postbacks are delivered by a background job, usually within a few minutes of the vote (never on the player's click, so voting stays instant).
  • If your endpoint is unreachable, we retry with growing gaps (≈5 min, then up to 12 h between tries) for about 24 hours, then give up.
  • Retries resend the identical payload (same voted_at, same sig) — always dedupe on (username, voted_at) so a player is never rewarded twice for one vote.
  • Respond with any HTTP 2xx within a few seconds to confirm delivery. Redirects are not followed.
  • Your endpoint must be reachable over the public internet via IPv4; both http:// and https:// work (https with a valid certificate recommended).
  • The status of your last deliveries is shown on your listing's edit page.

Good to know

  • Votes without a ?u= account still count for your ranking — they just don't trigger a postback.
  • Players can vote once per 12 hours per connection; your reward flow inherits that cooldown automatically.
  • Keep your secret private. If it ever leaks, regenerate it from your edit page.

Set up vote rewards for my server