Home / Developers / GTA FiveM
🚗

GTA FiveM

Lua FiveM Resources

Overview

Let your FiveM community earn in-game rewards for voting. This Lua resource uses the topgservers vote-check API to verify votes and grant money, items, or custom rewards through your server's framework (ESX, QBCore, or standalone).

Prerequisites

  • A FiveM server with a framework (ESX, QBCore, or standalone)
  • topgservers API key — generate one in My Servers → API
  • Webhook secret (optional, for real-time rewards)
  • Server artifact build 5848+ recommended

Installation

1 Create the resource folder

Create a `topg-vote` folder inside your `resources/` directory with the standard FiveM layout.

Directory structure
resources/
└── topg-vote/
    ├── fxmanifest.lua
    ├── config.lua
    └── server.lua

2 Create the manifest

Register the resource with FiveM.

fxmanifest.lua
fx_version 'cerulean'
game 'gta5'

name 'topg-vote'
description 'topgservers vote reward integration'
version '1.0.0'

server_scripts {
    'config.lua',
    'server.lua'
}

3 Start the resource

Add `ensure topg-vote` to your `server.cfg`, then restart the server or run `refresh` + `start topg-vote` in the console.

Configuration

config.lua
Config = {}

Config.ApiKey = "tgs_your_api_key_here"
Config.WebhookSecret = "whsec_your_secret_here"

-- How often to poll the vote-check API (seconds)
Config.PollInterval = 60

-- Reward settings
Config.RewardMoney = 5000         -- In-game currency to give
Config.RewardMessage = "Thanks for voting on topgservers! You received $5,000."

-- Framework: "esx", "qbcore", or "standalone"
Config.Framework = "esx"

Vote Check

Call the /api/v1/vote-check endpoint to determine if a player has voted today.

server.lua — vote check
local rewarded = {}

function CheckPlayerVote(playerId, playerName)
    if rewarded[playerId] then return end

    PerformHttpRequest(
        "https://topgservers.net/api/v1/vote-check?username=" ..
            playerName,
        function(statusCode, body, headers)
            if statusCode ~= 200 then return end

            local data = json.decode(body)
            if data and data.voted then
                rewarded[playerId] = true
                GrantReward(playerId)
            end
        end,
        "GET",
        "",
        { ["Authorization"] = "Bearer " .. Config.ApiKey }
    )
end

-- Poll all connected players
CreateThread(function()
    while true do
        Wait(Config.PollInterval * 1000)
        for _, playerId in ipairs(GetPlayers()) do
            local name = GetPlayerName(playerId)
            if name then
                CheckPlayerVote(playerId, name)
            end
        end
    end
end)

Webhook Receiver

Verify the X-TopG-Signature header using HMAC-SHA256 to ensure webhook payloads are authentic.

server.lua — webhook HMAC verification
-- FiveM does not natively support running an HTTP server,
-- so webhook handling requires an external proxy or middleware.
--
-- Option A: Use a lightweight Node.js sidecar that receives
-- webhooks and triggers a server event via direct connection.
--
-- Option B: Use the polling approach above (recommended for FiveM).
--
-- If using a sidecar, verify the HMAC signature in Node.js:

--[[
  Node.js sidecar example:

  const crypto = require('crypto');
  const express = require('express');
  const app = express();

  app.use(express.raw({ type: 'application/json' }));

  app.post('/webhook', (req, res) => {
    const sig = req.headers['x-topg-signature'];
    const parts = sig.split(',');
    const timestamp = parts.find(p => p.startsWith('t=')).slice(2);
    const hash = parts.find(p => p.startsWith('v1=')).slice(3);

    const expected = crypto
      .createHmac('sha256', process.env.WEBHOOK_SECRET)
      .update(timestamp + '.' + req.body)
      .digest('hex');

    if (expected !== hash) return res.status(401).end();

    const data = JSON.parse(req.body);
    // Forward to FiveM via HTTP endpoint or direct TCP
    res.status(200).end();
  });

  app.listen(8090);
]]

Reward Examples

Reward examples
function GrantReward(playerId)
    if Config.Framework == "esx" then
        -- ESX money
        local xPlayer = ESX.GetPlayerFromId(playerId)
        if xPlayer then
            xPlayer.addMoney(Config.RewardMoney)
        end
    elseif Config.Framework == "qbcore" then
        -- QBCore money
        local Player = QBCore.Functions.GetPlayer(playerId)
        if Player then
            Player.Functions.AddMoney('cash', Config.RewardMoney)
        end
    else
        -- Standalone: trigger a custom event
        TriggerClientEvent('topg:rewardGranted', playerId)
    end

    TriggerClientEvent('chat:addMessage', playerId, {
        args = { "topgservers", Config.RewardMessage }
    })
end

Notes & Tips

FiveM's `PerformHttpRequest` runs on a separate thread and won't block the game loop. The `rewarded` table resets on resource restart. For persistence, save rewarded player IDs to a database (MySQL/oxmysql) keyed by the current date.