This guide explains how to integrate with our webhook system to receive real-time notifications about prize payout events. Webhooks allow you to stay informed about prize payouts as they happen, enabling you to update your systems, send notifications, or trigger other actions.
When you configure a webhook endpoint, you'll receive HTTP POST requests containing JSON payloads with information about prize payout events. Each webhook can handle multiple types of events, making it efficient to process different stages of the prize payout lifecycle.
Prize payout has been created
When a new prize payout is created
Prize payout has been successfully processed
When a prize payout completes successfully
When a prize payout fails after retries
Player has opted into a campaign
When a player opts into a campaign
Player has opted out of a campaign
When a player opts out of a campaign
Create a public HTTP endpoint that can receive POST requests. Your endpoint should:
- Accept POST requests
- Return a 2xx status code (200, 201, 202) to acknowledge receipt
- Handle JSON payloads
- Be idempotent (safe to receive duplicate requests)
const express = require("express");
const app = express();
app.use(express.json());
app.post("/webhooks/prizes", (req, res) => {
const payload = req.body;
console.log("Received webhook:", payload);
processWebhookEvent(payload);
res.status(200).json({ received: true });
});
function processWebhookEvent(payload) {
switch (payload.event_type) {
case "PRIZE_PAYOUT_CREATED":
handlePrizePayoutCreated(payload);
break;
case "PRIZE_PAYOUT_SUCCEEDED":
handlePrizePayoutSucceeded(payload);
break;
case "PRIZE_PAYOUT_FAILED":
handlePrizePayoutFailed(payload);
break;
case "PLAYER_OPTED_IN":
handlePlayerOptedIn(payload);
break;
case "PLAYER_OPTED_OUT":
handlePlayerOptedOut(payload);
break;
}
}
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route('/webhooks/prizes', methods=['POST'])def webhook_handler():
payload = request.get_json()
print(f"Received webhook: {payload}")
process_webhook_event(payload)
return jsonify({"received": True}), 200def process_webhook_event(payload):
event_type = payload.get('event_type')
if event_type == 'PRIZE_PAYOUT_CREATED':
handle_prize_payout_created(payload)
elif event_type == 'PRIZE_PAYOUT_SUCCEEDED':
handle_prize_payout_succeeded(payload)
elif event_type == 'PRIZE_PAYOUT_FAILED':
handle_prize_payout_failed(payload)
elif event_type == 'PLAYER_OPTED_IN':
handle_player_opted_in(payload)
elif event_type == 'PLAYER_OPTED_OUT':
handle_player_opted_out(payload)
All webhooks send JSON payloads with this structure:
{
"campaign_id": "campaign-123",
"request_id": "550e8400-e29b-41d4-a716-446655440000",
"player_id": "player-hash-abc123",
"player_currency": "USD",
"event_type": "PRIZE_PAYOUT_CREATED",
"status": "TODO",
"prize_type": "cash",
"amount": 100.5,
"bonus_id": 456}
Unique campaign identifier
Unique request identifier (UUID)
Player's currency (e.g., "USD", "EUR")
Type of event that triggered the webhook
Current status of the prize payout
Type of prize (cash, free_spins, bonus_amount, etc.)
Prize amount (for applicable prize types)
Optional bonus identifier
Percentage value (for deposit bonuses)
Item name (for catalog items)
Item value (for catalog items)
Different prize types include different fields in the payload:
{
"campaign_id": "summer-campaign-2024",
"request_id": "550e8400-e29b-41d4-a716-446655440000",
"player_id": "player-abc123",
"player_currency": "USD",
"event_type": "PRIZE_PAYOUT_SUCCEEDED",
"status": "SUCCESS",
"prize_type": "cash",
"amount": 100.5,
"bonus_id": 456}
{
"campaign_id": "slot-tournament-2024",
"request_id": "550e8400-e29b-41d4-a716-446655440001",
"player_id": "player-def456",
"player_currency": "EUR",
"event_type": "PRIZE_PAYOUT_CREATED",
"status": "TODO",
"prize_type": "free_spins",
"amount": 50,
"game_id": 123,
"bonus_id": 789}
{
"campaign_id": "welcome-bonus",
"request_id": "550e8400-e29b-41d4-a716-446655440002",
"player_id": "player-ghi789",
"player_currency": "GBP",
"event_type": "PRIZE_PAYOUT_SUCCEEDED",
"status": "SUCCESS",
"prize_type": "bonus_amount",
"amount": 75.25,
"bonus_id": 101}
{
"campaign_id": "deposit-match",
"request_id": "550e8400-e29b-41d4-a716-446655440003",
"player_id": "player-jkl012",
"player_currency": "USD",
"event_type": "PRIZE_PAYOUT_CREATED",
"status": "TODO",
"prize_type": "deposit_bonus",
"percentage_value": 100.0,
"bonus_id": 202}
{
"campaign_id": "loyalty-rewards",
"request_id": "550e8400-e29b-41d4-a716-446655440004",
"player_id": "player-mno345",
"player_currency": "USD",
"event_type": "PRIZE_PAYOUT_SUCCEEDED",
"status": "SUCCESS",
"prize_type": "catalog_item",
"item": "Gaming Headset",
"value": 25.0,
"bonus_id": 303}
Player opt-in and opt-out events have a simpler payload structure compared to prize payout events. These events are triggered when players choose to participate in or withdraw from campaigns.
{
"player_id": "player-abc123",
"campaign_id": "summer-campaign-2024",
"event_type": "PLAYER_OPTED_IN"}
{
"player_id": "player-def456",
"campaign_id": "winter-tournament-2024",
"event_type": "PLAYER_OPTED_OUT"}
Unique campaign identifier
Type of event (PLAYER_OPTED_IN
or PLAYER_OPTED_OUT
)
If you provide an API key when setting up your webhook, we'll include it in the Authorization header:
Authorization: Bearer your-secret-api-key
To verify that webhooks are coming from us, check the Authorization header:
app.post("/webhooks/prizes", (req, res) => {
const authHeader = req.headers.authorization;
const expectedToken = "Bearer your-secret-api-key";
if (authHeader !== expectedToken) {
return res.status(401).json({ error: "Unauthorized" });
}
});
# Python example@app.route('/webhooks/prizes', methods=['POST'])def webhook_handler():
auth_header = request.headers.get('Authorization')
expected_token = 'Bearer your-secret-api-key'
if auth_header != expected_token:
return jsonify({"error": "Unauthorized"}), 401
All webhook requests include these headers:
Content-Type: application/json
Authorization: Bearer {api_key} # if api_key is provided
User-Agent: Unibo-Webhooks/1.0
Your endpoint should return a 2xx status code (200, 201, 202) to acknowledge receipt. If you return an error status code, we'll log the failure but won't retry.
res.status(200).json({ received: true });
res.status(202).json({ processing: true });
res.status(500).json({ error: "Something went wrong" });
Webhooks might be sent multiple times. Design your endpoint to handle this gracefully:
return res.status(200).json({ already_processed: true });
}
storeProcessedRequest(requestId);
For better performance, process webhooks asynchronously:
app.post("/webhooks/prizes", (req, res) => {
res.status(202).json({ accepted: true });
setImmediate(() => {
processWebhookAsync(req.body);
});
});
app.post("/webhooks/prizes", (req, res) => {
try {
const payload = req.body;
if (!payload.event_type) {
console.error("Invalid payload received:", payload);
return res.status(400).json({ error: "Invalid payload" });
}
processWebhook(payload);
res.status(200).json({ received: true });
} catch (error) {
console.error("Error processing webhook:", error);
res.status(500).json({ error: "Internal server error" });
}
});
function handlePrizePayoutSucceeded(payload) {
if (payload.prize_type === "cash") {
updatePlayerBalance(payload.player_id, payload.amount);
sendNotification(payload.player_id, `You received $${payload.amount}!`);
}
}
function handlePrizePayoutCreated(payload) {
console.log(`New prize payout created: ${payload.request_id}`);
trackingService.createPayoutRecord(payload);
sendNotification(payload.player_id, "Your prize is being processed!");
}
function handlePrizePayoutFailed(payload) {
console.error(`Prize payout failed: ${payload.request_id}`);
trackingService.markPayoutFailed(payload);
supportService.createTicket({
type: "payout_failed",
player_id: payload.player_id,
request_id: payload.request_id,
campaign_id: payload.campaign_id,
});
}
function trackPrizePayoutAnalytics(payload) {
const analytics = {
campaign_id: payload.campaign_id,
player_id: payload.player_id,
event_type: payload.event_type,
prize_type: payload.prize_type,
amount: payload.amount,
timestamp: new Date().toISOString(),
};
analyticsService.track("prize_payout", analytics);
}
function handlePrizePayoutSucceeded(payload) {
crmService.updatePlayer(payload.player_id, { last_prize: payload.amount });
marketingService.trigger("prize_won", payload);
loyaltyService.addPoints(payload.player_id, payload.amount);
}
function handlePlayerOptedIn(payload) {
playerService.updateCampaignStatus(
payload.player_id,
payload.campaign_id,
"opted_in"
);
notificationService.send(
payload.player_id,
`Welcome to ${payload.campaign_id}!`
);
analyticsService.track("player_opted_in", {
player_id: payload.player_id,
campaign_id: payload.campaign_id,
timestamp: new Date().toISOString(),
});
}
function handlePlayerOptedOut(payload) {
playerService.updateCampaignStatus(
payload.player_id,
payload.campaign_id,
"opted_out"
);
notificationService.send(
payload.player_id,
"You've been removed from the campaign."
);
analyticsService.track("player_opted_out", {
player_id: payload.player_id,
campaign_id: payload.campaign_id,
timestamp: new Date().toISOString(),
});
}
Make sure your endpoint handles all event types you've configured:
created: {
event_type: "PRIZE_PAYOUT_CREATED",
status: "TODO",
},
succeeded: {
event_type: "PRIZE_PAYOUT_SUCCEEDED",
status: "SUCCESS",
},
failed: {
event_type: "PRIZE_PAYOUT_FAILED",
status: "FAILED",
},
player_opted_in: {
event_type: "PLAYER_OPTED_IN",
player_id: "player-test-123",
campaign_id: "test-campaign-2024",
},
player_opted_out: {
event_type: "PLAYER_OPTED_OUT",
player_id: "player-test-456",
campaign_id: "test-campaign-2024",
},
};
Test how your endpoint handles:
- Invalid JSON
- Missing required fields
- Authentication failures
- Network timeouts
: Check that your endpoint is publicly accessible and returns 2xx status codes
: Verify your API key is correct and properly formatted
: Ensure your endpoint can handle JSON payloads
: Implement idempotency using the request_id
field
to see what you're receiving
for any errors
is correct and accessible
first to ensure basic connectivity
If you're having issues with webhook integration:
Check your server logs for error messages
Verify your endpoint is accessible from the internet
Test with a simple webhook testing service
Contact our support team with specific error details
Currently, there are no rate limits on webhook delivery. However, we recommend:
- Processing webhooks quickly (within 30 seconds)
- Implementing proper error handling
- Using asynchronous processing for heavy operations
: Always use HTTPS for your webhook endpoint
: Check the Authorization header for valid API keys
: Verify that payloads contain expected fields
: Consider rate limiting on your endpoint
: Watch for unusual webhook activity