API Documentation
Metin2 Vote Verification System
Easy, Free & Reliable Voting Rewards for Your Metin2 Private Server
Our Vote Verification System is a modern and innovative solution designed specifically for Metin2 Private Servers. It provides an engaging way for players to vote for their favorite servers while receiving in-game benefits.
The system is both easy to implement and highly reliable, making it an excellent choice for server owners looking to increase player engagement and server visibility.
Our goal is to create a win-win situation for both players and server owners. Players get rewarded for their loyalty with in-game benefits, while servers benefit from increased visibility and higher player engagement.
Vote4Buff System (Recommended)
Complete In-Game Voting & Reward System with Custom UI
Vote4Buff is our premium all-in-one voting solution that includes a beautiful in-game UI, WebSocket communication, and complete server integration. Players can vote, select from multiple bonus pools, and receive instant rewards without ever leaving the game!
System Architecture
The Vote4Buff system consists of three main components:
Client Side
- Python UI system (uivote4buff.py)
- Custom UI assets & graphics
- C++ WebSocket integration
- 11 language support
Server Side
- C++ API integration
- Bonus pool management
- Item reward system
- Real-time affect tracking
Our Platform
- Vote verification API
- Account-based tracking
- Anti-cheat protection
- Real-time vote status
Key Features
Perfect for: Server owners who want a professional, ready-to-use solution without spending weeks on custom development. Simply configure the bonus pools, integrate the files, and you're ready to go!
Download Vote4Buff Files
Get all the files you need for client and server integration
Vote4Buff is designed for martysama0134 v5.8 source base. If you're using a different source, some modifications may be required.
Package Contents
Client Files
- Python UI files (uivote4buff.py)
- Game file modifications
- UI graphics & assets
- 11 language locale files
- C++ WebSocket implementation
- UI script files
Includes libcurl.dll (32-bit included, 64-bit available)
Server Files
- char.h configuration
- Affect system modifications
- Chat command integration
- API communication layer
- Bonus management system
All necessary C++ source modifications included
Please login to download Vote4Buff files.
Configuration Guide
Configure bonus pools, item rewards, and API settings
All Vote4Buff configuration is done in the char.h file on your server. Below are detailed examples of each configuration option.
Step 1: API Credentials
First, you'll need to configure your Server ID and API Token (found in your dashboard):
// API SETTINGS from Metin2 Server List
static const std::string s_VOTE4BUFF_SERVER_ID = "YOUR_SERVER_ID"; // From dashboard
static const std::string s_VOTE4BUFF_API_TOKEN = "YOUR_API_TOKEN"; // From dashboard
static const int s_VOTE4BUFF_DURATION = 86400; // seconds (1 day) DO NOT MODIFY THIS !!!
Step 2: Configure Bonus Pools
You can define up to 3 bonus pools that players can choose from. Each pool can contain multiple bonuses:
// Bonuses must be set with its APPLY_ declaration.
// You can add as many bonuses as you want per slot.
static std::vector<std::vector<std::pair<int, int>>> s_VOTE4BUFF_BONUSES =
{
{ // Bonus Pool 1: PvP Focused
{ APPLY_ATTBONUS_HUMAN, 5 }, // +5% vs Players
{ APPLY_DEF_GRADE_BONUS, 50 }, // +50 Defense
},
{ // Bonus Pool 2: PvE Focused
{ APPLY_ATTBONUS_MONSTER, 5 }, // +5% vs Monsters
{ APPLY_ATTBONUS_INSECT, 5 }, // +5% vs Insects
{ APPLY_HP_REGEN, 10 }, // +10 HP Regen
},
{ // Bonus Pool 3: Farm Focused
{ APPLY_ITEM_DROP_BONUS, 10 }, // +10% Drop Rate
{ APPLY_EXP_DOUBLE_BONUS, 10 }, // +10% EXP
{ APPLY_GOLD_FIND, 15 }, // +15% Gold
},
};
Common bonus types: APPLY_ATTBONUS_HUMAN, APPLY_ATTBONUS_MONSTER, APPLY_DEF_GRADE_BONUS, APPLY_ITEM_DROP_BONUS, APPLY_EXP_DOUBLE_BONUS, APPLY_GOLD_FIND, APPLY_MAX_HP, APPLY_MAX_SP, APPLY_HP_REGEN, APPLY_SP_REGEN, APPLY_CRITICAL_PCT, APPLY_PENETRATE_PCT, and many more!
Step 3: Item Rewards (Optional)
Configure items that players receive automatically upon voting:
static std::vector<std::pair<DWORD, int>> s_VOTE4BUFF_ITEM_REWARDS =
{
// Leave empty if you don't want to give any items as rewards
// Format: { vnum, count }
{ 27007, 5 }, // 5x Red Potion (XXL)
{ 50084, 1 }, // 1x Gold Bar
{ 71027, 10 }, // 10x Dragon Coin
};
Step 4: Bonus Change Settings
Control cooldown and pricing when players want to switch between bonus pools:
// Cooldown when changing bonus (does not apply when choosing right after voting)
static const int s_VOTE4BUFF_CHANGE_BONUS_COOLDOWN = 300; // seconds (5 minutes)
// Price when changing bonus (does not apply when choosing right after voting)
static const int s_VOTE4BUFF_CHANGE_BONUS_PRICE = 15000; // yang (0 = free)
Note: After players vote, they can choose a bonus pool for FREE. The cooldown and price only apply when they want to switch pools later without voting again.
Installation Guide
Step-by-step instructions for integrating Vote4Buff
Make sure you have backups of your client and server files! File naming convention: Files with __ prefix need modifications, files without prefix can be copied directly.
Server Installation
Configure char.h
Open Source/Server/__char.h from the downloaded package.
- Locate
class CBuffOnAttributes;and add the configuration code above it (see Configuration section) - Set your
s_VOTE4BUFF_SERVER_IDands_VOTE4BUFF_API_TOKEN - Configure your bonus pools and item rewards
- Locate
bool DragonSoul_RefineWindow_CanRefine();and add the public method declarations
Apply Server Modifications
Integrate the server-side files from the package:
__affect.h- Modify your existing affect.h with the provided changes__chat_affect.cpp- Add Vote4Buff affect handling__cmd_general.cpp- Add command processing__desc_client.cpp- Client descriptor modifications
Note: Files with __ prefix indicate you need to merge the changes into your existing files.
Recompile Game Core
Compile your game server with the new modifications.
make clean && make Client Installation
Python UI Files
From the Client/root/ folder:
- Copy
uivote4buff.pyto your client'sroot/folder - Modify the following files as indicated:
__constInfo.py__game.py__interfaceModule.py__uiAffectShower.py
UI Graphics & Scripts
- Copy
Client/ui/game/vote4buff/folder to your pack'sui/game/directory - Copy
Client/uiscript/vote4buffwindow.pyto your uiscript folder
Language Files
Add locale strings for your supported languages from Client/locale/:
- Append
__locale_game.txtcontent to yourlocale_game.txt - Append
__locale_interface.txtcontent to yourlocale_interface.txt
Available languages: EN, DE, ES, PL, TR, RO, IT, PT, HU, GR, CZ
C++ Client Modifications
From Source/Client/UserInterface/:
- Copy
M2WebSocket.cppandM2WebSocket.hto your UserInterface folder - Apply modifications from files with
__prefix to your existing files - Ensure
libcurl.dllis in your client directory (32-bit included, download 64-bit if needed)
Add UI Button (Optional)
Vote4Buff doesn't add a default button. You need to call ToggleVote4Buff() from somewhere in your UI. For example:
- Add a button to your SystemDialog
- Bind it to a hotkey
- Add it to your QuickSlot menu
Or use the included Vote4BuffButton class which creates a draggable icon button
Recompile Client
Rebuild your client executable with the new modifications.
Testing
Test the integration:
- Login to your server
- Open the Vote4Buff window
- Vote on our platform: https://metin2-toplist.net/vote/en/YOUR_SERVER_ID-server-name/YOUR_ACCOUNT_ID
- Return to game and verify your vote
- Select a bonus pool and check if affects are applied
- Verify item rewards were received
Your players can now vote and receive rewards automatically. The Vote4Buff UI will show them when they can vote, let them choose bonus pools, and display countdown timers for active affects.
Advantages for Server Admins
Free Promotion
Most new players discover servers through toplists, making it an essential marketing tool
Simple Configuration
Detailed documentation and step-by-step guides make setup a breeze
Zero Coding Required
Straightforward REST API integration process
Optimized Performance
Client-side vote verification ensures minimal server load
Highly Reliable
Battle-tested system with built-in fraud prevention
Vote Verification
Ensure players really voted for your server before rewards
Advantages for Players
How Does the System Work?
The system features a clean and intuitive flow that players can easily understand. Best of all, vote checking happens via our API, ensuring you can verify legitimate votes!
Getting Started - Quick Start Guide
Choose your integration method based on your needs:
Vote4Buff System
Complete all-in-one solution with custom UI, WebSocket communication, and automatic reward system.
- Full in-game UI
- Multiple bonus pools
- Automatic item rewards
- Real-time countdown timers
- 11 languages support
Custom API Integration
Build your own implementation using our REST API for maximum flexibility and control.
- Full customization
- Your own UI design
- Custom reward logic
- IP or Account-based
General Setup Steps
Register Your Server
Create an account and add your server to our toplist at https://metin2-toplist.net/servers/create
Get Your API Credentials
Find your unique Server ID and API Token in your server dashboard. These are required for authentication.
Choose Your Integration Method
Download Vote4Buff for a ready-to-use solution, or integrate our API for custom implementation.
Test & Deploy
Test the voting system thoroughly, then deploy to your live server.
API Endpoint (For Custom Implementations)
If you're using the Vote4Buff System (recommended), this API is already integrated! This section is for server owners who want to build custom implementations.
https://metin2-toplist.net/api/check-vote
Required Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
api_token |
string | Yes | Your server's unique API token |
ip |
string | Optional* | Player's IP address (IPv4 or IPv6) |
account_id |
string | Optional* | Player's account ID/username for more accurate tracking |
For best results, use <code>account_id</code> for accurate player tracking. The <code>ip</code> method can be less reliable if players use VPNs or play from different locations.
Vote URL Format
Direct players to vote using this URL structure:
https://metin2-toplist.net/vote.{lang}/{server_id}-{server_slug}/{account_id}
Examples:
https://metin2-toplist.net/vote.en/123-awesome-server/PlayerName
https://metin2-toplist.net/vote.de/123-awesome-server/PlayerName
https://metin2-toplist.net/vote.tr/123-awesome-server/PlayerName
Supported languages: en, de, es, pl, tr, ro, it, pt, hu, gr, cz
Response Format
The API returns a JSON response with the following structure:
{
"success": true,
"voted": true,
"last_vote": "2025-11-11T14:30:00Z",
"next_vote_in": 0,
"message": "Vote verified successfully"
}
{
"success": true,
"voted": false,
"message": "No recent vote found"
}
{
"success": false,
"message": "Invalid API token"
}
Response Fields
| Field | Type | Description |
|---|---|---|
success |
boolean | Whether the API request was successful |
voted |
boolean | Whether a valid vote was found (only present if success=true) |
last_vote |
string | ISO 8601 timestamp of the last vote (only if voted=true) |
next_vote_in |
integer | Seconds until next vote is allowed (only if voted=true) |
message |
string | Human-readable message describing the result |
Code Examples
PHP Example
<?php
function checkVote($apiToken, $playerIP) {
$url = "https://metin2-toplist.net/api/check-vote";
$params = http_build_query([
'api_token' => $apiToken,
'ip' => $playerIP
]);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url . '?' . $params);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode !== 200) {
return ['success' => false, 'message' => 'API request failed'];
}
return json_decode($response, true);
}
$result = checkVote('YOUR_API_TOKEN', $_SERVER['REMOTE_ADDR']);
if ($result['success'] && $result['voted']) {
echo "Vote verified! Rewarding player...";
}
?>
Python Example
import requests
def check_vote(api_token, player_ip):
url = "https://metin2-toplist.net/api/check-vote"
params = {'api_token': api_token, 'ip': player_ip}
try:
response = requests.get(url, params=params, timeout=10)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
return {'success': False, 'message': f'API request failed: {str(e)}'}
result = check_vote('YOUR_API_TOKEN', '123.456.789.012')
if result.get('success') and result.get('voted'):
print("Vote verified! Rewarding player...")
C++ Example (for Game Servers)
#include <curl/curl.h>
#include <string>
#include <sstream>
static size_t WriteCallback(void* contents, size_t size, size_t nmemb, void* userp) {
((std::string*)userp)->append((char*)contents, size * nmemb);
return size * nmemb;
}
bool CheckVote(const std::string& apiToken, const std::string& playerIP) {
CURL* curl = curl_easy_init();
if (!curl) return false;
std::string readBuffer;
std::ostringstream url;
url << "https://metin2-toplist.net/api/check-vote"
<< "?api_token=" << apiToken
<< "&ip=" << playerIP;
curl_easy_setopt(curl, CURLOPT_URL, url.str().c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10L);
CURLcode res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
return (res == CURLE_OK) && (readBuffer.find("\"voted\":true") != std::string::npos);
}
void OnPlayerRequestReward(const std::string& playerName, const std::string& playerIP) {
if (CheckVote("YOUR_API_TOKEN", playerIP)) {
GiveItemToPlayer(playerName, REWARD_ITEM_VNUM, REWARD_COUNT);
SendNotice("Vote verified! You received your reward!");
} else {
SendNotice("No valid vote found. Please vote first!");
}
}
JavaScript/Node.js Example
async function checkVote(apiToken, playerIP) {
const url = new URL('https://metin2-toplist.net/api/check-vote');
url.searchParams.append('api_token', apiToken);
url.searchParams.append('ip', playerIP);
try {
const response = await fetch(url, {
method: 'GET',
headers: { 'Accept': 'application/json' }
});
if (!response.ok) throw new Error(`HTTP ${response.status}`);
return await response.json();
} catch (error) {
return { success: false, message: error.message };
}
}
checkVote('YOUR_API_TOKEN', '123.456.789.012').then(result => {
if (result.success && result.voted) {
console.log('Vote verified! Rewarding player...');
}
});
Integration Guide
Always store your API token securely and never expose it in client-side code. API calls should always be made from your server backend.
Step 1: Create Vote Button/Command
Add a vote button on your website or an in-game command that directs players to your server's vote page at https://metin2-toplist.net/servers/YOUR-SERVER-SLUG.
Step 2: Implement Vote Checking
When a player requests their reward (via website or in-game command), check if they've voted:
- Get the player's IP address
- Make an API request to our check-vote endpoint
- Parse the JSON response
- If
votedis true, grant the reward - Store that you've given this reward to prevent duplicate claims
Step 3: Handle Rewards
Best practices for reward handling:
- Track Given Rewards: Store in your database which votes you've already rewarded to prevent duplicate claims
- Vote Cooldown: Respect the 24-hour cooldown between votes
- Error Handling: Always handle API errors gracefully and inform players
- Logging: Log all vote verifications for debugging and analytics
Example Workflow
Troubleshooting
"Invalid API token" error
Solution: Double-check that you're using the correct API token from your server dashboard. Make sure there are no extra spaces or characters.
Vote not detected after player voted
Possible causes:
- Player is using a VPN/Proxy (IP addresses don't match)
- Vote hasn't been processed yet (wait 30 seconds and try again)
- Wrong IP address being sent to API
- Player voted for a different server
API timeout or connection errors
Solution: Ensure your server can make outbound HTTPS requests. Check your firewall settings. Implement retry logic with exponential backoff.
Players claiming rewards multiple times
Solution: Implement local tracking of rewarded votes. Store the vote timestamp and ensure you only reward each vote once.
IPv6 addresses not working
Solution: Ensure you're sending the full IPv6 address. Our API supports both IPv4 and IPv6.
Public Server Listing API (v1)
List, submit, and claim Metin2 servers programmatically. Perfect for other toplists, server management tools, or custom integrations.
https://metin2-toplist.net/api/v1
Rate Limits
| Endpoint | Method | Limit | Auth |
|---|---|---|---|
/api/v1/servers | GET | 60/min | — |
/api/v1/servers/{slug} | GET | 60/min | — |
/api/v1/servers | POST | 3/hour | — |
/api/v1/servers/claim | POST | 10/hour | ✅ |
List Servers
Retrieve a paginated list of active, launched servers. Supports filtering by category and language.
| Parameter | Type | Default | Description |
|---|---|---|---|
category | string | — | Filter by category: oldschool, newschool, fun, pvp, pvm, pve |
language | string | — | Filter by language code: EN, DE, TR, etc. |
sort | string | votes | Sort order: votes, newest, name |
page | integer | 1 | Page number |
per_page | integer | 25 | Results per page (max 50) |
curl -H "Accept: application/json" \
"https://metin2-toplist.net/api/v1/servers?category=pvp&language=EN&per_page=10"
Submit a New Server
Submit a new server listing via the API. The server enters a moderation queue and must be approved before it appears publicly.
All API-submitted servers start as inactive and require manual approval. This prevents spam and ensures listing quality.
| Field | Type | Required | Description |
|---|---|---|---|
name | string | ✅ | Server name (max 255 chars, must be unique) |
description | string | ✅ | Server description (min 20, max 5000 chars) |
website_url | string | — | Server website URL |
discord_url | string | — | Discord invite URL |
languages | array | ✅ | Language codes, e.g. ["EN", "DE"] (min 1, max 5) |
category | string | — | One of: oldschool, newschool, fun, pvp, pvm, pve |
launch_date | string | — | Future launch date (YYYY-MM-DD) |
owner_email | string | — | Contact email (optional, not shown publicly) |
curl -X POST "https://metin2-toplist.net/api/v1/servers" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"name": "Dragon Kingdom",
"description": "A classic PvP experience with custom dungeons and weekly events.",
"languages": ["EN", "DE"],
"category": "pvp",
"website_url": "https://dragon-kingdom.com",
"discord_url": "https://discord.gg/example"
}'
{
"success": true,
"message": "Server submitted successfully!",
"data": {
"id": 42,
"slug": "dragon-kingdom",
"status": "pending_review"
},
"claim_token": "a1b2c3d4...80 characters",
"note": "Save this token! Use it to claim your listing."
}
Claim Token System
When you submit a server, you receive a unique 80-character claim token. This token lets you link the listing to your account later.
The claim token is shown only once in the API response. Save it immediately — we store only the hash.
Submit
POST your server to /api/v1/servers and save the claim_token from the response.
Register
Create an account and paste the token in the optional "Claim Token" field.
Manage
Your server is now linked to your account with full dashboard access.
Error Codes
| Code | Meaning |
|---|---|
200 | Success |
201 | Server created (pending review) |
401 | Authentication required (claim endpoint) |
404 | Server not found / invalid claim token |
409 | Server already claimed |
410 | Claim token expired |
422 | Validation error / spam rejected |
429 | Rate limit exceeded |
Integration Examples
$response = file_get_contents('https://metin2-toplist.net/api/v1/servers?per_page=10');
$data = json_decode($response, true);
foreach ($data['data'] as $server) {
echo $server['name'] . ' — ' . $server['vote_count'] . ' votes' . PHP_EOL;
}
const res = await fetch('https://metin2-toplist.net/api/v1/servers?category=pvp');
const { data, meta } = await res.json();
data.forEach(server => {
console.log(`${server.name}: ${server.vote_count} votes`);
});
import requests
resp = requests.get('https://metin2-toplist.net/api/v1/servers', params={
'language': 'DE',
'sort': 'newest',
'per_page': 20
})
servers = resp.json()['data']
for s in servers:
print(f"{s['name']} — {s['vote_count']} votes")
Support & Resources
Test your integration thoroughly with a test account before deploying to production. Make sure to handle all edge cases and error scenarios.