Wallet Endpoints
Operators integrate with the platform by implementing these endpoints:
Authentication
| Endpoint | When Called | Purpose |
|---|---|---|
POST /v1/session | Widget load | Exchange session_request_id for a JWT |
POST /v1/auth | Session check | Validate session and return player info |
Transactions
| Endpoint | When Called | Purpose |
|---|---|---|
POST /v1/withdrawals | Bet placement | Debit stake from bettor's balance |
POST /v1/deposits | Settlement | Credit payout to bettor's balance |
DELETE /v1/rollbacks/{id} | Withdrawal compensation | Reverse a failed withdrawal |
All transaction endpoints must be idempotent — the platform may retry on network failures.
The platform calls DELETE /v1/rollbacks/{id} only when a withdrawal succeeded but the bet placement failed in a subsequent step. The {id} is the transaction ID returned by the operator from the original POST /v1/withdrawals call.
Rollbacks are never called for deposits or settlements — only for withdrawals that need to be reversed.
The operator must credit the player's balance back by the original withdrawal amount.
| Outcome | Amount | Meaning |
|---|---|---|
| Won | stake × odds | Bettor's winnings |
| Lost | 0 | No payout — the platform still sends the call so the operator can close the bet |
| Voided / Refunded | stake | Full stake returned |
Negative amounts are never sent. Operators must handle zero-amount deposits as a settlement notification, not as a no-op.
Request Signing (HMAC-SHA256)
Every request from the platform includes an X-Payload-Signature header containing an HMAC-SHA256 signature of the raw request body. Operators must verify this signature before processing.
Algorithm
signature = HMAC-SHA256(request_body, shared_secret)
header = hex_encode(signature)
Headers Sent
| Header | Value |
|---|---|
X-Payload-Signature | Hex-encoded HMAC-SHA256 of the request body |
X-Timestamp | ISO 8601 UTC timestamp (for replay prevention) |
X-Nonce | UUID v4 (for replay prevention) |
Content-Type | application/json |
Verification Example
Given:
- Body:
{"amount":"10.50"} - Secret:
test-secret - Expected signature:
37f9186da8bef5457f94d56d1c76dc37f8c8854e35751cf7eb795da23d593329
Go
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"fmt"
)
func VerifySignature(body []byte, signature, secret string) bool {
mac := hmac.New(sha256.New, []byte(secret))
mac.Write(body)
expected := hex.EncodeToString(mac.Sum(nil))
return hmac.Equal([]byte(expected), []byte(signature))
}
func main() {
body := []byte(`{"amount":"10.50"}`)
secret := "test-secret"
mac := hmac.New(sha256.New, []byte(secret))
mac.Write(body)
sig := hex.EncodeToString(mac.Sum(nil))
fmt.Println(sig)
// Output: 37f9186da8bef5457f94d56d1c76dc37f8c8854e35751cf7eb795da23d593329
}
Node.js
const crypto = require('crypto');
function verifySignature(body, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(body)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(signature),
);
}
// Test vector
const body = '{"amount":"10.50"}';
const secret = 'test-secret';
const sig = crypto.createHmac('sha256', secret).update(body).digest('hex');
console.log(sig);
// Output: 37f9186da8bef5457f94d56d1c76dc37f8c8854e35751cf7eb795da23d593329
Python
import hashlib
import hmac
def verify_signature(body: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(secret.encode(), body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature)
# Test vector
body = b'{"amount":"10.50"}'
secret = "test-secret"
sig = hmac.new(secret.encode(), body, hashlib.sha256).hexdigest()
print(sig)
# Output: 37f9186da8bef5457f94d56d1c76dc37f8c8854e35751cf7eb795da23d593329
Replay Prevention
Operators should also validate:
- Timestamp — reject requests where
X-Timestampis older than 5 minutes - Nonce — store seen nonces and reject duplicates within the timestamp window
See Also
- Authentication Flow — how the two-JWT architecture works
- API Reference — full request/response schemas