Provide the following HTTP headers on every request.
Content-Type: application/json
{
"userId": "[USER_TELEGRAM_ID]"
}
The payload is the exact raw JSON request body sent to the endpoint. Compute X-Signature over this exact string as UTF-8 bytes, and send the identical string as the HTTP body. Any change in whitespace, key order, or a trailing newline changes the signature.
using System;
using [System.Net](<http://System.Net>).Http;
using [System.Security](<http://System.Security>).Cryptography;
using System.Text;
using System.Text.Json;
static string ComputeSignatureBase64(string secret, string payload)
{
using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(secret));
var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(payload));
return Convert.ToBase64String(hash);
}
// Build payload as a compact JSON string (no extra whitespace)
var payloadObj = new { userId = telegramUserId.ToString() };
var json = JsonSerializer.Serialize(payloadObj, new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
WriteIndented = false
});
var signature = ComputeSignatureBase64(partnerSecret, json);
using var client = new HttpClient();
using var req = new HttpRequestMessage([HttpMethod.Post](<http://HttpMethod.Post>), $"{{[<https://webhook.p1.rumblearcade.io/quests/{questId}>](<https://webhook.p1.rumblearcade.io/quests/{questId}>)}}")
{
Content = new StringContent(json, Encoding.UTF8, "application/json")
};
req.Headers.Add("X-Partner-Id", partnerId);
req.Headers.Add("X-Signature", signature);
var resp = await client.SendAsync(req);
resp.EnsureSuccessStatusCode();
import crypto from 'crypto';
import fetch from 'node-fetch';
function computeSignatureBase64(secret: string, payload: string): string {
const hmac = crypto.createHmac('sha256', Buffer.from(secret, 'utf8'));
const hash = hmac.update(Buffer.from(payload, 'utf8')).digest();
return Buffer.from(hash).toString('base64');
}
const payloadObj = { userId: String(telegramUserId) };
const body = JSON.stringify(payloadObj); // compact JSON
const signature = computeSignatureBase64(partnerSecret, body);
const res = await fetch(`{{[<https://webhook.p1.rumblearcade.io/quests/${questId}>}}`](<https://webhook.p1.rumblearcade.io/quests/${questId}>}}`), {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Partner-Id': partnerId,
'X-Signature': signature,
},
body,
});
if (!res.ok) {
throw new Error(`Request failed: ${res.status}`);
}
<aside> ⚠️
Use the identical string for both the signature and the HTTP body. Differences in whitespace or key order will produce a different signature.
</aside>