Authentication
Operator-facing endpoints (/operator/launch, /operator/games, /operator/currencies) require HMAC-SHA256 request signing with replay protection.
Required Headers
| Header | Description |
|---|---|
X-Operator-ID |
Your operator UUID |
X-Timestamp |
Current Unix epoch seconds (e.g., 1708700000). Must be within ±30s of server time. |
X-HMAC-SHA256 |
Hex-encoded HMAC-SHA256 signature (see below) |
Computing the Signature
Get the current Unix timestamp as a decimal string (e.g., "1708700000").
Serialize the JSON request body as compact JSON (no extra whitespace or newlines). For GET requests, use an empty string.
Concatenate: timestamp + compact_body
Compute HMAC-SHA256 of the concatenated string using your operator secret key.
Hex-encode the result and pass it in the X-HMAC-SHA256 header. Pass the same timestamp in X-Timestamp.
The server normalizes the request body to compact JSON before verifying the signature. You must sign the compact (minified) form of your JSON payload. Requests with a timestamp skew greater than 30 seconds are rejected.
Code Examples
POST Requests
import hmac, hashlib, json, time, requests
operator_id = "your-operator-uuid"
secret = "your-hmac-secret"
payload = {"playerId": "player-1", "currency": "USD", "gameCode": "dice-alpha", "countryCode": "US"}
body = json.dumps(payload, separators=(",", ":"))
timestamp = str(int(time.time()))
signature = hmac.new(
secret.encode(), (timestamp + body).encode(), hashlib.sha256
).hexdigest()
resp = requests.post(
"https://rgs.example.com/operator/launch",
json=json.loads(body),
headers={
"X-Operator-ID": operator_id,
"X-Timestamp": timestamp,
"X-HMAC-SHA256": signature,
},
)
const crypto = require("crypto");
const operatorId = "your-operator-uuid";
const secret = "your-hmac-secret";
const body = JSON.stringify({
playerId: "player-1",
currency: "USD",
gameCode: "dice-alpha",
countryCode: "US",
});
const timestamp = Math.floor(Date.now() / 1000).toString();
const signature = crypto
.createHmac("sha256", secret)
.update(timestamp + body)
.digest("hex");
const resp = await fetch("https://rgs.example.com/operator/launch", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Operator-ID": operatorId,
"X-Timestamp": timestamp,
"X-HMAC-SHA256": signature,
},
body,
});
body, _ := json.Marshal(map[string]string{
"playerId": "player-1",
"currency": "USD",
"gameCode": "dice-alpha",
"countryCode": "US",
})
timestamp := strconv.FormatInt(time.Now().Unix(), 10)
mac := hmac.New(sha256.New, []byte("your-hmac-secret"))
mac.Write([]byte(timestamp))
mac.Write(body)
signature := hex.EncodeToString(mac.Sum(nil))
req, _ := http.NewRequest("POST",
"https://rgs.example.com/operator/launch",
bytes.NewReader(body))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Operator-ID", "your-operator-uuid")
req.Header.Set("X-Timestamp", timestamp)
req.Header.Set("X-HMAC-SHA256", signature)
BODY='{"playerId":"player-1","currency":"USD","gameCode":"dice-alpha","countryCode":"US"}'
SECRET="your-hmac-secret"
TIMESTAMP=$(date +%s)
SIG=$(echo -n "${TIMESTAMP}${BODY}" \
| openssl dgst -sha256 -hmac "$SECRET" \
| awk '{print $2}')
curl -X POST https://rgs.example.com/operator/launch \
-H "Content-Type: application/json" \
-H "X-Operator-ID: your-operator-uuid" \
-H "X-Timestamp: $TIMESTAMP" \
-H "X-HMAC-SHA256: $SIG" \
-d "$BODY"
GET Requests
For GET endpoints like /operator/games, sign only the timestamp (empty body):
TIMESTAMP=$(date +%s)
SIG=$(echo -n "$TIMESTAMP" | openssl dgst -sha256 -hmac "$SECRET" | awk '{print $2}')
curl https://rgs.example.com/operator/games \
-H "X-Operator-ID: your-operator-uuid" \
-H "X-Timestamp: $TIMESTAMP" \
-H "X-HMAC-SHA256: $SIG"
Verifying Callbacks
The RGS signs all outgoing callbacks (authenticate, debit, credit, balance, rollback) with the same HMAC-SHA256 scheme. Each callback includes X-Timestamp and X-HMAC-SHA256 headers — the signature covers timestamp + compact_json_body.
Your server should verify both the timestamp freshness (within ±30s) and the HMAC signature on every incoming callback.
import hmac, hashlib, time
def verify_callback(request, secret):
timestamp = request.headers["X-Timestamp"]
signature = request.headers["X-HMAC-SHA256"]
body = request.get_data(as_text=True)
# Check timestamp freshness
if abs(time.time() - int(timestamp)) > 30:
return False
# Verify HMAC
expected = hmac.new(
secret.encode(), (timestamp + body).encode(), hashlib.sha256
).hexdigest()
return hmac.compare_digest(signature, expected)
const crypto = require("crypto");
function verifyCallback(req, secret) {
const timestamp = req.headers["x-timestamp"];
const signature = req.headers["x-hmac-sha256"];
const body = JSON.stringify(req.body);
// Check timestamp freshness
if (Math.abs(Date.now() / 1000 - parseInt(timestamp)) > 30) {
return false;
}
// Verify HMAC
const expected = crypto
.createHmac("sha256", secret)
.update(timestamp + body)
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}