NEW Premium advertising is now available View placements →

RUNESOURCE DEVELOPERS

Vote postback documentation

Reward players automatically after RuneSource confirms a verified vote.

HTTPS POSTHMAC-SHA256Form encoded

SERVER OWNER GUIDE

Set up vote rewards

Follow these steps once for each server. The callback endpoint belongs on your own website—it receives RuneSource's confirmation and rewards the correct in-game account.

Signature verification is required. Your receiver must validate the X-RuneSource-Signature header with your callback secret. If it is missing or invalid, return HTTP 403 and never reward the player.
1

Create a receiver

Create a public endpoint on your server website, such as:

https://play.yourserver.com/runesource-callback.php

Use the complete PHP example below. The URL must use HTTPS and must not require a player login.

2

Open callback settings

Sign in to RuneSource, open Dashboard, find your server, and select Vote callback.

3

Save the callback URL and secret

Paste the endpoint into Public HTTPS callback URL and save. Copy the generated signing secret into your receiver's $callbackSecret.

Required: This secret verifies X-RuneSource-Signature. Both values must match character for character or the callback must be rejected. Keep it private.
4

Add your vote button

Your website must insert the signed-in player's URL-encoded game name:

$voteUrl = 'https://runesource.org/vote.php?id=YOUR_SERVER_ID&username=' . rawurlencode($playerName);
5

Store and reward the vote

After validating the signature, save vote_id and queue the reward for player_name. Make the vote ID unique so it can never reward twice.

6

Test it

Start from your website's vote button. Confirm RuneSource shows Voting as PlayerName, complete the vote, and ensure your endpoint returns HTTP 200–299.

Before going live
  • Public HTTPS callback URL
  • Matching callback secrets
  • Form-encoded POST accepted
  • source=runesource accepted
  • Required: X-RuneSource-Signature verified against the untouched raw body
  • Missing or invalid signatures return HTTP 403
  • Unique vote_id enforced
  • HTTP 200 returned on success

OVERVIEW

How it works

  1. 1
    Send the player to RuneSource

    Include their in-game username in the vote link.

  2. 2
    The player completes a verified vote

    RuneSource validates and records the vote.

  3. 3
    RuneSource calls your endpoint

    Your server receives a signed HTTPS POST.

  4. 4
    Reward the player

    Verify and store the unique vote ID first.

STEP 2

Receive the postback

Fields are sent as application/x-www-form-urlencoded. In PHP, read them from $_POST, not JSON.

FieldExampleDescription
sourcerunesourceFixed source identifier
providerRuneSourceProvider display name
eventvote.createdEvent type
vote_id123Unique vote ID
server_id3RuneSource server ID
server_nameCatalystListed server name
usernameOsmerekName supplied in the vote link
player_nameOsmerekUsername compatibility alias
voted_at2026-08-26T19:53:04+00:00UTC ISO-8601 time

Headers

Content-Type: application/x-www-form-urlencoded
User-Agent: RuneSource-Vote-Callback/1.3
X-Vote-Source: runesource
X-RuneSource-Provider: RuneSource
X-RuneSource-Event: vote.created
X-RuneSource-Vote-ID: 123
X-RuneSource-Signature: sha256=SIGNATURE

SECURITY · REQUIRED

Signature verification is mandatory

Every callback includes X-RuneSource-Signature. Sign the untouched raw request body with your callback secret and compare it safely. Never process or reward a vote when this check fails.

$rawBody = file_get_contents('php://input');
$received = $_SERVER['HTTP_X_RUNESOURCE_SIGNATURE'] ?? '';
$expected = 'sha256=' . hash_hmac('sha256', $rawBody, $callbackSecret);

if (!hash_equals($expected, $received)) {
    http_response_code(403);
    exit('Invalid signature');
}
Keep the callback secret private. Generate a new one from your callback settings if it is exposed.

COPY-READY

Complete PHP receiver

<?php
declare(strict_types=1);

$callbackSecret = 'PASTE_YOUR_RUNESOURCE_CALLBACK_SECRET';
$rawBody = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_RUNESOURCE_SIGNATURE'] ?? '';
$expected = 'sha256=' . hash_hmac('sha256', $rawBody, $callbackSecret);

if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    http_response_code(405); exit('POST required');
}
if (!hash_equals($expected, $signature)) {
    http_response_code(403); exit('Invalid signature');
}
if (($_POST['source'] ?? '') !== 'runesource') {
    http_response_code(403); exit('Invalid source');
}

$voteId = filter_var($_POST['vote_id'] ?? null, FILTER_VALIDATE_INT);
$player = trim((string)($_POST['player_name'] ?? $_POST['username'] ?? ''));
if (!$voteId || $player === '') {
    http_response_code(400); exit('Missing vote_id or player_name');
}

// Check and store vote_id before rewarding $player.
// Grant or queue the player's reward here.

http_response_code(200);
header('Content-Type: application/json');
echo json_encode(['ok' => true]);

DELIVERY

Response codes

2xxAccepted

Successfully received.

400Bad request

Missing or invalid fields.

403Rejected

Source or signature rejected.

5xxServer error

Your endpoint failed.

RuneSource records a successful delivery only for HTTP 200–299.

HELP

Troubleshooting

Why do I receive “Invalid source”?

Accept lowercase runesource from the source field or X-Vote-Source. A placeholder title such as “TopG” must not be used to reject RuneSource.

Why does it return 403?

Ensure the callback secret matches exactly and calculate the signature from the untouched raw body.

Why are POST fields empty?

The request is form encoded. Use $_POST; use php://input only to verify the signature.

Should it require login or CSRF?

No. It must be a public HTTPS endpoint authenticated by the HMAC signature.

How do I stop duplicate rewards?

Store vote_id with a unique database constraint and never reward the same ID twice.