Examples
Starting-point samples in Roblox Lua, curl, and TypeScript. Placeholders only — never paste real credentials into this documentation or your client.
Roblox Lua
Compact server startlua
-- Server Script only (ServerScriptService). Enable HttpService.
local HttpService = game:GetService("HttpService")
local API_BASE = "https://api-staging.talqen.net/v1"
local API_KEY = "<TALQEN_TEST_API_KEY>" -- ServerStorage / secret store
local function startShift(player)
local response = HttpService:RequestAsync({
Url = API_BASE .. "/activity/shifts/start",
Method = "POST",
Headers = {
["Authorization"] = "Bearer " .. API_KEY,
["Content-Type"] = "application/json",
["Idempotency-Key"] = "start-" .. player.UserId .. "-" .. HttpService:GenerateGUID(false),
},
Body = HttpService:JSONEncode({
robloxUserId = tostring(player.UserId),
universeId = tostring(game.GameId),
placeId = tostring(game.PlaceId),
serverId = game.JobId,
}),
})
if not response.Success then
warn("Talqen start failed", response.StatusCode)
return nil
end
local payload = HttpService:JSONDecode(response.Body)
return payload.data.shift.id
endHelper ModuleScriptlua
-- Starting point only. Place in ServerScriptService.
-- Never use a LocalScript. Never store keys in ReplicatedStorage.
local HttpService = game:GetService("HttpService")
local Players = game:GetService("Players")
local API_BASE = "https://api-staging.talqen.net/v1"
local API_KEY = "<TALQEN_TEST_API_KEY>"
local activeShifts = {}
local function talqenRequest(method, path, body, idempotencyKey)
local headers = {
["Authorization"] = "Bearer " .. API_KEY,
["Content-Type"] = "application/json",
}
if idempotencyKey then
headers["Idempotency-Key"] = idempotencyKey
end
local ok, response = pcall(function()
return HttpService:RequestAsync({
Url = API_BASE .. path,
Method = method,
Headers = headers,
Body = body and HttpService:JSONEncode(body) or nil,
})
end)
if not ok then
warn("Talqen request failed")
return nil
end
if not response.Success then
-- Log status and request id only — never log the API key.
warn("Talqen API error", response.StatusCode, response.Headers["x-request-id"])
return nil
end
return HttpService:JSONDecode(response.Body)
end
local function startShift(player)
local payload = talqenRequest("POST", "/activity/shifts/start", {
robloxUserId = tostring(player.UserId),
universeId = tostring(game.GameId),
placeId = tostring(game.PlaceId),
serverId = game.JobId,
}, "start-" .. player.UserId .. "-" .. HttpService:GenerateGUID(false))
if payload and payload.data and payload.data.shift then
activeShifts[player.UserId] = payload.data.shift.id
return payload.data.shift.id
end
end
local function heartbeatShift(shiftId)
talqenRequest("POST", "/activity/shifts/" .. shiftId .. "/heartbeat", {
serverId = game.JobId,
}, "heartbeat-" .. shiftId .. "-" .. HttpService:GenerateGUID(false))
end
local function stopShift(shiftId, reason)
talqenRequest("POST", "/activity/shifts/" .. shiftId .. "/stop", {
reason = reason or "manual",
}, "stop-" .. shiftId .. "-" .. HttpService:GenerateGUID(false))
end
return {
startShift = startShift,
heartbeatShift = heartbeatShift,
stopShift = stopShift,
activeShifts = activeShifts,
}Clock-in RemoteEventlua
-- Starting point: custom clock-in RemoteEvent handled server-side.
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Talqen = require(script.Parent.TalqenClient) -- your ModuleScript helper
local clockIn = Instance.new("RemoteEvent")
clockIn.Name = "TalqenClockIn"
clockIn.Parent = ReplicatedStorage
clockIn.OnServerEvent:Connect(function(player)
-- Enforce your own eligibility rules here (team, rank, etc.).
local shiftId = Talqen.startShift(player)
if shiftId then
-- Store shiftId server-side for heartbeat and disconnect cleanup.
end
end)Team change trackinglua
-- Starting point: track Team changes as shift boundaries.
local Teams = game:GetService("Teams")
local Talqen = require(script.Parent.TalqenClient)
local STAFF_TEAM_NAME = "Staff"
local function onTeamChanged(player)
local isStaff = player.Team and player.Team.Name == STAFF_TEAM_NAME
local existing = Talqen.activeShifts[player.UserId]
if isStaff and not existing then
Talqen.startShift(player)
elseif (not isStaff) and existing then
Talqen.stopShift(existing, "manual")
Talqen.activeShifts[player.UserId] = nil
end
end
-- Wire Player:GetPropertyChangedSignal("Team") / team assignment in your game.Disconnect cleanuplua
-- Starting point: clean up on disconnect and shutdown.
local Players = game:GetService("Players")
local Talqen = require(script.Parent.TalqenClient)
Players.PlayerRemoving:Connect(function(player)
local shiftId = Talqen.activeShifts[player.UserId]
if shiftId then
Talqen.stopShift(shiftId, "player_left")
Talqen.activeShifts[player.UserId] = nil
end
end)
game:BindToClose(function()
for userId, shiftId in pairs(Talqen.activeShifts) do
Talqen.stopShift(shiftId, "server_shutdown")
Talqen.activeShifts[userId] = nil
end
end)curl
Start shiftbash
curl -X POST "https://api-staging.talqen.net/v1/activity/shifts/start" \
-H "Authorization: Bearer <TALQEN_TEST_API_KEY>" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: start-<ROBLOX_USER_ID>-001" \
-d '{
"robloxUserId": "<ROBLOX_USER_ID>",
"universeId": "<UNIVERSE_ID>",
"placeId": "<PLACE_ID>",
"serverId": "<SERVER_ID>"
}'Leaderboardbash
curl "https://api-staging.talqen.net/v1/activity/leaderboard?period=week&limit=25" \
-H "Authorization: Bearer <TALQEN_TEST_API_KEY>"TypeScript
Start shiftts
const API_BASE = "https://api-staging.talqen.net/v1";
const API_KEY = "<TALQEN_TEST_API_KEY>";
async function startShift(input: {
robloxUserId: string;
universeId: string;
placeId: string;
serverId: string;
idempotencyKey: string;
}) {
const response = await fetch(`${API_BASE}/activity/shifts/start`, {
method: "POST",
headers: {
Authorization: `Bearer ${API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": input.idempotencyKey,
},
body: JSON.stringify({
robloxUserId: input.robloxUserId,
universeId: input.universeId,
placeId: input.placeId,
serverId: input.serverId,
}),
});
const requestId = response.headers.get("x-request-id");
const body = await response.json();
if (!response.ok) {
throw new Error(
`Talqen error ${body?.error?.code ?? response.status} (requestId=${requestId})`,
);
}
return body.data as {
shift: { id: string; status: string; startedAt: string; lastHeartbeatAt: string };
existing?: boolean;
};
}Heartbeatts
async function heartbeatShift(shiftId: string, idempotencyKey: string) {
const response = await fetch(
`${API_BASE}/activity/shifts/${shiftId}/heartbeat`,
{
method: "POST",
headers: {
Authorization: `Bearer ${API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": idempotencyKey,
},
body: JSON.stringify({ serverId: "<SERVER_ID>" }),
},
);
if (!response.ok) {
const body = await response.json();
throw new Error(body?.error?.message ?? "Heartbeat failed");
}
return response.json();
}
