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
- Your website links each logged-in player to your vote page here, with their account name in the link.
- The player clicks Vote. The vote counts on the toplist immediately.
- 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).

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:
| Field | Example | Meaning |
|---|---|---|
server_id | 8 | Your listing's numeric id |
slug | muonline | Your listing's slug |
username | Hero123 | The u value from your reward link |
ip | 203.0.113.7 | The voter's IP address (for your own anti-abuse checks) |
voted_at | 1784200000 | Unix timestamp (UTC) of the vote — stable across retries |
success | 1 | Always 1 — only counted votes are sent |
test | 0 | 1 for test postbacks fired from your edit page |
sig | 9f2ab4… | 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, samesig) — 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://andhttps://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.