• Username: demo
    Password: demo2025

Server voting webhooks

Voting Webhook Documentation

Voting Webhook allows your server to receive notifications whenever a user votes.

1. Webhook URL

The URL your server exposes to receive vote notifications. It must accept POST requests and respond with HTTP 200 for successful delivery.

This URL can be configured in the server thread settings when editing the thread. Votes cast while no URL is configured are not sent later.

https://yourserver.com/webhook.php

2. JSON Payload

Each vote will send the following JSON payload:

{
  "hash": "md5({webhook_secret}_{username}_{vote_date})",
  "username": "ExampleUser",
  "user_id": 123,
  "vote_date": 1700000000,
  "vote_weight": 1,
  "vote_id": 456,
  "custom": "PlayerNameOrToken"
}

Fields Explained

  • hash: Legacy verification hash. Its formula remains unchanged for existing integrations. It does not protect the new fields.
  • username: Name of the user who voted.
  • user_id: Unique identifier of the user.
  • vote_date: Unix timestamp when the vote was cast.
  • vote_weight: Numeric value representing the weight of the vote. Can be used to apply multipliers (e.g. bonus votes or premium users).
  • vote_id: Unique vote identifier within this forum. Store it to prevent duplicate rewards when a notification is delivered again.
  • custom: Character name or verification token supplied through the voting link. Empty when omitted; limited to 128 UTF-8 characters.

3. Webhook Secret

A secret string known only to your server and the voting system. It is used to generate the hash to verify authenticity.

The secret is generated automatically. You can regenerate it in thread settings at any time if needed.

4. Character Names and Verification Tokens

Add a URL-encoded custom parameter to the server's voting link:

https://forum.example/threads/your-server.123/server-vote?custom=PlayerNameOrToken

The value is preserved through confirmation and saved with the vote. Links to the thread itself can also include ?custom=...; its voting buttons preserve that value, including when confirmation is disabled. Values longer than 128 characters are rejected rather than truncated.

The game server must validate token ownership and enforce one-time use. A player can choose or change this value before voting. The webhook signature authenticates the notification, not ownership of a character.

5. HMAC-SHA256 Verification

Every notification includes X-Server-Voting-Signature: sha256=<hex digest>. The digest is an HMAC-SHA256 of the exact JSON request body using your webhook secret. Verify the raw body before decoding it; do not re-encode the JSON or fall back to the legacy hash if this verification fails.

<?php
$body = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_SERVER_VOTING_SIGNATURE'] ?? '';
$expected = 'sha256=' . hash_hmac('sha256', $body, $webhookSecret);

if (!hash_equals($expected, $signature))
{
    http_response_code(403);
    exit;
}

$payload = json_decode($body, true, 512, JSON_THROW_ON_ERROR);

After verification, atomically record vote_id and grant the reward. Use a unique database constraint and a transaction to prevent concurrent duplicate rewards. If you receive a vote that was already processed, return HTTP 200 without rewarding it again. When integrating multiple forums, identify each forum separately alongside its vote ID.

6. Legacy Verification

Existing receivers can continue using the original formula below. New integrations using character names or tokens should verify the HMAC signature, which protects all payload fields.

  1. Receive the POST request with JSON payload.
  2. Compute the hash: md5(webhook_secret + "_" + username + "_" + vote_date)
  3. Compare with the hash from the payload.
  4. If the hash matches, process the vote; otherwise reject the request.
  5. Return HTTP 200 OK to confirm the request was accepted.

7. Delivery and Retries

Notifications use XenForo's automatic job queue. Any HTTP 2xx response confirms delivery. Network failures, HTTP 429, and HTTP 5xx responses are retried, up to the number of attempts per vote set by the forum administrator (two by default, meaning one retry). Other HTTP responses stop delivery immediately.

The first retry is scheduled two minutes after a failure; each further delay doubles, up to one hour. A valid Retry-After header can extend that delay, up to 24 hours. Delays are minimum waiting periods: actual delivery also depends on XenForo processing its automatic jobs.

The JSON body from the first delivery attempt is stored and reused, including the original vote_id, custom, and vote weight. Each attempt is signed with the currently configured webhook secret. Keep the receiver's secret synchronized if you rotate it while notifications are pending.

A receiver may process a vote even if its response never reaches the forum. Deduplicate by vote_id before granting rewards, and return HTTP 200 for a duplicate that was already processed. Final delivery failures are stored with the vote. When the Log failed webhook deliveries add-on option is enabled, they are also recorded in XenForo's server error log without including the webhook URL or payload.

Timeouts, network failures and HTTP 5xx responses also count as consecutive endpoint failures for the server. After the number of consecutive failures set by the forum administrator (five by default), delivery for that server is suspended: new and pending votes are kept but not sent. Any other HTTP response resets the count. Delivery resumes, including the kept votes, when the server's webhook URL is changed or an administrator resumes it.

8. Endpoint Requirements

Use a public HTTP or HTTPS URL on port 80 or 443. HTTPS is recommended. Credentials in the URL, URL fragments, local hostnames, private networks, loopback, link-local, and reserved addresses are not accepted. Direct IPv6 URL literals are not supported; a public hostname may resolve to IPv4 or IPv6.

The URL is checked when submitted and again before every delivery attempt. All resolved addresses must be public. The connection is pinned to a checked address while preserving the hostname for HTTP and TLS verification. Delivery uses direct cURL connections with CURLOPT_CONNECT_TO support; configured HTTP proxies are bypassed.

Redirects are disabled by default. The Allow webhook redirects add-on option permits up to five HTTP 301, 302, 303, 307, or 308 redirects. Each destination is checked and pinned again, including destinations on other public hosts. Every hop resends the original signed POST body, including for HTTP 303. HTTPS to HTTP redirects, unsafe targets, and redirect loops are blocked.

Connections allow up to three seconds to connect, with one ten-second HTTP time budget shared by the entire redirect chain. DNS resolution uses the server's system resolver and its own timeout settings. DNS and network failures are retried; an unsafe endpoint, blocked redirect, or exceeded redirect limit stops automatic delivery.

0:00
0:00
Back
Top