External rewards guide
This guide explains external rewards in practical terms so your integration team can move fast.
What is an external reward?
An external reward is a reward that lives in your own system (CRM, sportsbook platform, wallet, bonus service, etc.), but is triggered by SavageTech events.
Examples:
- Free bet in your sportsbook
- Bonus credit in your CRM
- Promo code generated by your campaign system
In SavageTech, each external reward has an externalRewardId and a foreignKey.
Your system uses these values to decide what to grant.
Two execution modes
1) Default bonus engine (no custom integration)
If no custom engine is registered for your vendor, SavageTech uses the default engine.
- External rewards can still be assigned in SavageTech.
- No automatic call is made to your CRM/API.
- You can handle fulfillment separately in your own backend flow.
2) Custom bonus engine (recommended for full automation)
With a custom engine, SavageTech calls your integration logic when an external reward is granted.
- SavageTech triggers your custom
CallVendorAPIlogic. - Your CRM/API grants the actual bonus.
- The reward flow stays automatic for mission completion and manual rewarding.
Common integration flow
- Player completes mission (or an admin sends a manual reward).
- SavageTech detects reward type
External. - SavageTech calls the vendor bonus engine.
- Custom engine calls your CRM/API to grant the reward.
- Success is returned and the player sees reward feedback in the widget.
Flow diagram (mission + manual grant)
API examples
List external rewards
curl -X GET "https://your-api/api/v1/externalRewards?page=1&limit=20" \
-H "Authorization: Bearer <token>"
Example response:
{
"externalRewards": [
{
"externalRewardId": "welcome-bonus-10",
"foreignKey": "CRM_CAMPAIGN_1001",
"name": "Welcome Bonus 10"
}
],
"pagination": {
"page": 1,
"limit": 20,
"total": 1
}
}
Assign an external reward manually
Use this when you want to reward on demand (not only via mission completion).
curl -X POST "https://your-api/api/v1/players/player-123/reward" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"items": [
{
"type": "External",
"externalRewardId": "welcome-bonus-10"
}
],
"customMessage": "You unlocked a bonus!"
}'
Example: backend-to-backend custom engine call
Below is a simple Node.js-style example showing what your custom engine logic might do when SavageTech asks it to grant a reward:
async function grantExternalRewardToCrm(playerId: string, foreignKey: string) {
const response = await fetch("https://crm.example.com/api/bonuses/assign", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${process.env.CRM_API_TOKEN}`
},
body: JSON.stringify({
playerId,
campaignKey: foreignKey
})
});
if (!response.ok) {
throw new Error("CRM bonus assignment failed");
}
return response.json();
}
Best practices
- Keep bonus fulfillment server-to-server only.
- Make your CRM/API reward endpoint idempotent (safe retry behavior).
- Log reward requests with player ID + external reward ID + foreign key.
- Return clear error codes so failed grants can be retried safely.
Endpoints at a glance
GET /api/v1/externalRewardsGET /api/v1/externalRewards/{id}POST /api/v1/players/{playerId}/reward(withtype: "External")
If you want, I can also add a short sequence diagram to this page that visually shows the mission-complete -> bonus-engine -> CRM flow.