Comment Ça Marche
L'API Vote Rewards de metin2.gg permet à votre serveur Metin2 de détecter automatiquement quand les joueurs votent et d'accorder des récompenses en jeu. Le flux est simple : les joueurs votent sur metin2.gg avec leur nom de personnage, et votre serveur interroge notre API pour vérifier et réclamer ces votes.
Il existe deux modes d'intégration — choisissez celui qui convient à votre configuration :
Polling (Recommandé)
Votre serveur appelle périodiquement notre API pour vérifier les nouveaux votes. Le plus simple à implémenter — fonctionne avec n'importe quelle configuration de serveur Metin2. Ajoutez simplement une requête HTTP au code de votre serveur de jeu.
Webhooks (Avancé)
metin2.gg envoie une notification à votre serveur dès qu'un joueur vote. En temps réel, mais nécessite un endpoint HTTPS accessible publiquement de votre côté.
Authentification
Toutes les requêtes API nécessitent une clé API envoyée via le header X-API-Key. Les clés suivent le format mg_live_... et sont générées depuis le panneau de votre serveur.
X-API-Key: mg_live_5bef...1a70Votre clé API est liée à un seul serveur et n'est affichée qu'une seule fois lors de la génération. Si vous la perdez, régénérez-en une nouvelle depuis le panneau (l'ancienne clé est immédiatement invalidée).
Comment Obtenir Votre Clé API
- 1Allez dans Mon Panneau → Mes Serveurs. Cliquez sur le nom de votre serveur pour ouvrir sa page de gestion.
- 2Sur la page de gestion, vérifiez la propriété (enregistrement DNS TXT ou balise meta) si ce n'est pas déjà fait.
- 3Ajoutez un lien retour vers metin2.gg sur le site de votre serveur pour débloquer le statut Partenaire.
- 4Sur la page de gestion de votre serveur, cliquez sur le bouton "Paramètres API". Puis cliquez sur "Générer une Clé API" et copiez-la — elle n'est affichée qu'une seule fois.
Vérifier le Statut du Vote
Vérifiez si un joueur spécifique a un vote non réclamé. Si un vote en attente existe, il est automatiquement réclamé (marqué comme utilisé) pour que le même vote ne puisse pas être réclamé deux fois.
GET /api/v1/vote/check?player_id=PlayerName HTTP/1.1
Host: metin2.gg
X-API-Key: mg_live_YOUR_KEY_HEREParamètres de Requête
| Parameter | Type | Required | Description |
|---|---|---|---|
| player_id | string | Yes | Le nom du personnage que le joueur a utilisé pour voter. Insensible à la casse. |
Réponse
Le joueur a un vote non réclamé (maintenant réclamé)
{
"voted": true,
"player_id": "PlayerName",
"vote_id": "550e8400-e29b-41d4-a716-446655440000",
"voted_at": "2026-03-02T14:30:00Z"
}Aucun vote en attente pour ce joueur
{
"voted": false
}Lister les Votes Non Réclamés
Récupérez tous les votes non réclamés pour votre serveur. Utile pour le traitement par lots — par exemple, un cron job qui s'exécute toutes les 5 minutes et accorde les récompenses pour tous les votes en attente en une fois.
GET /api/v1/vote/unclaimed?limit=50 HTTP/1.1
Host: metin2.gg
X-API-Key: mg_live_YOUR_KEY_HEREParamètres de Requête
| Parameter | Type | Required | Description |
|---|---|---|---|
| limit | integer | No | Nombre maximum de votes à retourner (1–100, par défaut 50). |
Réponse
{
"votes": [
{
"vote_id": "550e8400-e29b-41d4-a716-446655440000",
"player_id": "PlayerName",
"voted_at": "2026-03-02T14:30:00Z"
},
{
"vote_id": "660e8400-e29b-41d4-a716-446655440001",
"player_id": "AnotherPlayer",
"voted_at": "2026-03-02T14:32:00Z"
}
],
"total": 2
}Réclamer des Votes en Lot
Marquez plusieurs votes comme réclamés en une seule requête. Utilisez ceci après avoir traité les votes du endpoint unclaimed.
POST /api/v1/vote/claim HTTP/1.1
Host: metin2.gg
Content-Type: application/json
X-API-Key: mg_live_YOUR_KEY_HERE
{
"vote_ids": [
"550e8400-e29b-41d4-a716-446655440000",
"660e8400-e29b-41d4-a716-446655440001"
]
}Corps de la Requête (JSON)
| Parameter | Type | Required | Description |
|---|---|---|---|
| vote_ids | string[] | Yes | Tableau d'UUIDs de votes à réclamer. Maximum 100 par requête. |
Réponse
{
"claimed": 2,
"failed": 0
}Webhooks
Au lieu du polling, vous pouvez recevoir des notifications push en temps réel quand un joueur vote. Configurez votre URL webhook dans le panneau du serveur sous Paramètres API.
Payload du Webhook
POST https://your-server.com/api/vote-webhook HTTP/1.1
Content-Type: application/json
X-Metin2GG-Signature: a1b2c3d4e5f6...
{
"event": "vote.created",
"vote_id": "550e8400-e29b-41d4-a716-446655440000",
"server_id": "your-server-uuid",
"player_id": "PlayerName",
"voted_at": "2026-03-02T14:30:00Z",
"timestamp": "2026-03-02T14:30:01Z"
}Vérification de la Signature
Chaque requête webhook inclut un header X-Metin2GG-Signature contenant un digest hex HMAC-SHA256 du corps brut de la requête, signé avec votre secret API. Vérifiez toujours cette signature avant de faire confiance au payload.
import hmac
import hashlib
def verify_webhook(request_body: bytes, signature: str, secret: str) -> bool:
"""Verify the X-Metin2GG-Signature header."""
expected = hmac.new(
secret.encode("utf-8"),
request_body,
hashlib.sha256,
).hexdigest()
return hmac.compare_digest(expected, signature)
# Usage in your webhook handler:
# body = request.body (raw bytes)
# sig = request.headers["X-Metin2GG-Signature"]
# if not verify_webhook(body, sig, "your_api_secret"):
# return HttpResponse(status=403)<?php
function verifyWebhook(string $body, string $signature, string $secret): bool {
$expected = hash_hmac('sha256', $body, $secret);
return hash_equals($expected, $signature);
}
// Usage in your webhook handler:
// $body = file_get_contents('php://input');
// $sig = $_SERVER['HTTP_X_METIN2GG_SIGNATURE'] ?? '';
// if (!verifyWebhook($body, $sig, 'your_api_secret')) {
// http_response_code(403);
// exit('Invalid signature');
// }Intégration Metin2 : Commande Python
Placez ce script dans le système de commandes Python de votre serveur de jeu. Quand un joueur tape /reward en jeu, il vérifie metin2.gg pour un vote en attente et accorde la récompense.
# vote_reward.py — Drop into your game server's command scripts
# Works with Python 2.7+ (common in Metin2 servers)
import json
import os
METIN2GG_API_KEY = "mg_live_YOUR_KEY_HERE"
METIN2GG_API_URL = "https://metin2.gg/api/v1/vote/check"
def check_vote(player_name):
"""Check if player has a pending vote and auto-claim it."""
url = "%s?player_id=%s" % (METIN2GG_API_URL, player_name)
# Method 1: Use urllib2 (Python 2) or urllib.request (Python 3)
try:
try:
import urllib2
req = urllib2.Request(url)
req.add_header("X-API-Key", METIN2GG_API_KEY)
resp = urllib2.urlopen(req, timeout=5)
data = json.loads(resp.read())
except ImportError:
import urllib.request
req = urllib.request.Request(url)
req.add_header("X-API-Key", METIN2GG_API_KEY)
resp = urllib.request.urlopen(req, timeout=5)
data = json.loads(resp.read().decode("utf-8"))
return data.get("voted", False)
except Exception:
pass
# Method 2: Fallback to curl (works even with broken SSL)
try:
cmd = 'curl -s -H "X-API-Key: %s" "%s"' % (METIN2GG_API_KEY, url)
raw = os.popen(cmd).read()
data = json.loads(raw)
return data.get("voted", False)
except Exception:
return None
# Example usage in your game command handler:
# def cmd_reward(player):
# result = check_vote(player.GetName())
# if result is True:
# player.GiveItem(50011, 10) # Example: 10x Dragon God Coins
# player.ChatInfoMessage("Vote reward claimed!")
# elif result is False:
# player.ChatInfoMessage("No pending vote. Vote at metin2.gg!")
# else:
# player.ChatInfoMessage("Could not reach metin2.gg. Try again.")Intégration Metin2 : Fichier Quest (Lua)
Ce fichier quest crée une interaction NPC où les joueurs peuvent vérifier le statut de leur vote. Il appelle une commande côté serveur qui déclenche la vérification de vote Python.
quest vote_reward begin
state start begin
when login or letter begin
send_letter("Vote Reward")
end
when button or info begin
say_title("Vote Reward")
say("")
say("Vote for our server on metin2.gg")
say("and claim your reward here!")
say("")
local s = select("Check My Vote", "How to Vote", "Close")
if s == 1 then
-- Triggers the Python command that checks the API
cmdchat("checkvote "..pc.get_name())
elseif s == 2 then
say_title("How to Vote")
say("")
say("1. Open metin2.gg in your browser")
say("2. Find our server page")
say("3. Enter your character name")
say("4. Click the Vote button")
say("5. Come back here to claim your reward!")
say("")
end
end
end
endIntégration Metin2 : Panneau Web PHP
Si votre serveur a un panneau web (basé PHP), utilisez ce snippet pour vérifier et réclamer les votes depuis le panneau. Fonctionne avec tout environnement PHP 7+ avec cURL.
<?php
/**
* check_vote.php — Vote check for PHP-based web panels
* Requires PHP 7.0+ with cURL extension
*/
$apiKey = "mg_live_YOUR_KEY_HERE";
$playerName = $_GET["player"] ?? "";
if (empty($playerName)) {
echo json_encode(["error" => "Missing player name"]);
exit;
}
// Check vote status
$ch = curl_init(
"https://metin2.gg/api/v1/vote/check?player_id=" . urlencode($playerName)
);
curl_setopt_array($ch, [
CURLOPT_HTTPHEADER => ["X-API-Key: $apiKey"],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 10,
CURLOPT_SSL_VERIFYPEER => true,
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode !== 200) {
echo json_encode(["error" => "API returned HTTP $httpCode"]);
exit;
}
$data = json_decode($response, true);
if ($data["voted"] ?? false) {
// Player has voted — grant reward via your game DB
// Example: INSERT INTO player.reward_queue (player, item_vnum, count) ...
echo json_encode([
"success" => true,
"message" => "Vote reward granted!",
"vote_id" => $data["vote_id"],
]);
} else {
echo json_encode([
"success" => false,
"message" => "No pending vote found.",
]);
}Limites de Taux et Codes d'Erreur
L'API impose des limites de taux pour assurer une utilisation équitable. Limites actuelles :
- 60 requests per minute per API key
- 1,000 requests per hour per API key
| Statut | Description |
|---|---|
| 200 OK | Requête réussie. |
| 400 Bad Request | Paramètres manquants ou invalides. Vérifiez le format de player_id ou vote_ids. |
| 401 Unauthorized | Clé API manquante ou invalide. Assurez-vous d'inclure le header X-API-Key. |
| 403 Forbidden | L'accès API est désactivé — généralement parce que le lien retour a été supprimé. Ajoutez à nouveau le lien retour et vérifiez. |
| 404 Not Found | Le endpoint n'existe pas. Vérifiez le chemin de l'URL. |
| 429 Too Many Requests | Limite de taux dépassée. Attendez et réessayez après la valeur du header Retry-After (en secondes). |
| 500 Internal Server Error | Quelque chose s'est mal passé de notre côté. Réessayez après quelques secondes. |
Stratégie de Réessai
On 429 errors, read the Retry-After header (value in seconds) and wait before retrying. For 500 errors, retry with exponential backoff (1s, 2s, 4s).
FAQ Dépannage
J'obtiens 401 Unauthorized à chaque requête
Assurez-vous d'envoyer la clé API dans le header X-API-Key (pas comme paramètre de requête ni dans le corps). La clé doit commencer par mg_live_.
L'API dit voted: false mais le joueur affirme avoir voté
Le joueur a peut-être voté sans entrer son nom de personnage, ou utilisé un nom différent. Vérifiez l'URL du lien de vote — elle doit inclure ?player_id=NOM_EXACT. Les noms sont insensibles à la casse.
J'obtiens 403 Forbidden
Votre accès API est en pause, probablement parce que le lien retour vers metin2.gg a été supprimé de votre site. Ajoutez-le à nouveau et cliquez sur 'Vérifier Maintenant' dans le panneau pour re-vérifier.
Puis-je tester l'API sans vrais votes ?
Il n'y a actuellement pas de mode sandbox. Votez sur votre propre listing de serveur avec un nom de personnage de test pour vérifier l'intégration de bout en bout.
Mon script Python ne peut pas se connecter (timeout ou erreur SSL)
La plupart des serveurs Metin2 utilisent Python 2.7 qui a des certificats SSL obsolètes. Utilisez le fallback os.popen('curl ...') montré dans l'exemple Python, ou mettez à jour le bundle CA Python de votre serveur.
À quelle fréquence dois-je interroger l'API ?
Pour le endpoint /check (par joueur) : appelez-le quand le joueur demande sa récompense (ex. commande /reward). Pour /unclaimed (lot) : toutes les 3–5 minutes via cron est idéal. Ne pas interroger plus d'une fois par minute.
Plusieurs serveurs peuvent-ils partager une clé API ?
Non. Chaque clé API est liée à un listing de serveur. Si vous gérez plusieurs serveurs, générez une clé séparée pour chacun depuis leurs pages de panneau respectives.
Que se passe-t-il si mon endpoint webhook est en panne ?
metin2.gg réessaie les livraisons webhook échouées jusqu'à 5 fois avec un backoff exponentiel. Si toutes les tentatives échouent, le vote reste non réclamé et peut toujours être récupéré via les endpoints de polling.
Prêt à Intégrer ?
Ajoutez votre serveur à metin2.gg, générez une clé API et commencez à récompenser les votants en quelques minutes.