r6.rank_changedRainbow SixThe ranked tier changed (e.g. Emerald → Diamond).
{
"from": {
"rank": "Emerald I",
"rp": 3980
},
"to": {
"rank": "Diamond V",
"rp": 4012,
"kd": "1.21"
},
"delta": 32
}Instead of polling, let Arenyze call you. Add an HTTPS endpoint in Profile → Developer, choose the events and the players, and receive signed JSON within minutes of the change.
Every delivery is a POST with a JSON body:
{
"id": "evt_10423",
"type": "thefinals.league_changed",
"game": "thefinals",
"player": "balise#2431",
"occurred_at": "2026-11-03T00:16:57.000Z",
"data": {
"player": "balise#2431",
"display": "Balise#2431",
"url": "https://thefinals.arenyze.com/player/Balise%232431",
"from": "Diamond 2",
"to": "Diamond 1",
"direction": 1,
"rank": 47,
"score": 54011
},
"text": "Balise#2431 moved from Diamond 2 to Diamond 1."
}| Header | Value |
|---|---|
Arenyze-Signature | t=<unix seconds>,v1=<hex HMAC-SHA256> |
Arenyze-Event | The event type. |
Arenyze-Delivery | Unique delivery id (use it to de-duplicate). |
User-Agent | Arenyze-Webhooks/1.0 |
Compute HMAC-SHA256 of <t>.<raw body> with the endpoint secret (whsec_…, shown once when you create or rotate it) and compare with v1. Reject timestamps older than 5 minutes.
import crypto from "node:crypto";
import express from "express";
const app = express();
app.post("/arenyze", express.raw({ type: "application/json" }), (req, res) => {
const sig = req.get("Arenyze-Signature") || "";
const { t, v1 } = Object.fromEntries(sig.split(",").map(p => p.split("=")));
const expected = crypto.createHmac("sha256", process.env.ARENYZE_WEBHOOK_SECRET)
.update(`${t}.${req.body}`).digest("hex");
const fresh = Math.abs(Date.now() / 1000 - Number(t)) < 300;
if (!fresh || !v1 || !crypto.timingSafeEqual(Buffer.from(v1), Buffer.from(expected))) {
return res.status(400).send("bad signature");
}
const event = JSON.parse(req.body);
console.log(event.type, event.text);
res.sendStatus(204); // answer fast; do the work async
});import hmac, hashlib, os, time
from flask import Flask, request, abort
app = Flask(__name__)
SECRET = os.environ["ARENYZE_WEBHOOK_SECRET"].encode()
@app.post("/arenyze")
def arenyze():
parts = dict(p.split("=", 1) for p in request.headers.get("Arenyze-Signature", "").split(","))
body = request.get_data()
expected = hmac.new(SECRET, f"{parts.get('t')}.".encode() + body, hashlib.sha256).hexdigest()
if abs(time.time() - int(parts.get("t", 0))) > 300 or not hmac.compare_digest(expected, parts.get("v1", "")):
abort(400)
event = request.get_json()
print(event["type"], event["text"])
return "", 2042xx within 8 seconds is a success. Anything else is retried after 1 min, 5 min, 30 min, 2 h, 6 h and 12 h.404 and 410 stop the retries at once.arenyze.test).r6.rank_changedRainbow SixThe ranked tier changed (e.g. Emerald → Diamond).
{
"from": {
"rank": "Emerald I",
"rp": 3980
},
"to": {
"rank": "Diamond V",
"rp": 4012,
"kd": "1.21"
},
"delta": 32
}r6.rp_changedRainbow SixRP changed — a ranked match was played.
{
"from": {
"rank": "Gold II",
"rp": 2710
},
"to": {
"rank": "Gold II",
"rp": 2734,
"kd": "1.05"
},
"delta": 24
}thefinals.rank_changedTHE FINALSPosition or score on the live Ranked board changed.
{
"from": {
"rank": 61,
"score": 53210
},
"to": {
"rank": 47,
"score": 54011,
"league": "Diamond 1"
},
"rankDelta": 14
}thefinals.league_changedTHE FINALSLeague changed. direction is 1 up, -1 down.
{
"from": "Diamond 2",
"to": "Diamond 1",
"direction": 1,
"rank": 47,
"score": 54011
}thefinals.club_changedTHE FINALSJoined, left or switched club (null = no club).
{
"from": "BERGR",
"to": "VGG"
}thefinals.renamedTHE FINALSEmbark name changed. Watched players, or every rename with the global feed.
{
"from": "Balise#9424",
"to": "Balise#2431",
"global": true
}thefinals.ban_detectedTHE FINALSRemoved from the leaderboards. Watched players, or the global feed.
{
"banType": "removed",
"banTypeLabel": "Removed from the leaderboard",
"status": "suspected",
"lastRank": 6647,
"lastLeague": "Platinum 2",
"season": "s12",
"global": true
}endfield.level_changedEndfieldAuthority level changed.
{
"from": 52,
"to": 53
}endfield.world_level_changedEndfieldWorld level changed.
{
"from": 5,
"to": 6
}endfield.operators_changedEndfieldNumber of operators on the account changed.
{
"from": 21,
"to": 22
}Type to search 100 pages and endpoints.