Campaigns
Fetch personalized offers and campaigns for players
Campaigns endpoints allow you to fetch personalized offers for players based on their profile, behavior, and the targeting conditions you've configured.
Endpoints Overview
| Endpoint | Auth | Description |
|---|---|---|
POST /client/player/campaigns | JWT | Fetch campaigns from client |
POST /player/campaigns/refresh | API Key | Fetch campaigns from server |
Fetch Player Campaigns (Client)
Fetch all active offers and campaigns for a player from the client-side.
Endpoint
POST /client/player/campaignsAuthentication
JWT - Requires x-game-jwt header. The playerId and gameId are extracted from the JWT.
Request
{
viewingCampaigns?: boolean | null; // Optional - Set to true when player is viewing offers UI
}curl -X POST https://api.pixels.xyz/v1/client/player/campaigns \
-H "Content-Type: application/json" \
-H "x-game-jwt: YOUR_JWT_TOKEN" \
-d '{"viewingCampaigns": true}'Response
{
player: IClientPlayer; // Player object with snapshot and data
offers: IClientOffer[]; // Array of personalized offers
snapshot: IPlayerSnapshot; // Player's current profile
playerData: IPlayerData; // Player's currency data
}{
"player": {
"snapshot": {
"_id": "snapshot-123",
"gameId": "my-game",
"playerId": "player-123",
"username": "CoolPlayer",
"daysInGame": 45,
"loginStreak": 7,
"trustScore": 850
},
"data": {
"gameId": "my-game",
"playerId": "player-123",
"currencies": {
"coins": {
"id": "coins",
"name": "Coins",
"balance": 1500,
"image": "https://cdn.example.com/coins.png"
}
}
}
},
"offers": [
{
"offerId": "offer-abc123",
"instanceId": "instance-def456",
"playerId": "player-123",
"gameId": "my-game",
"name": "Weekend Special",
"description": "Spend 100 coins to get 50 gems!",
"image": "https://cdn.example.com/weekend-special.png",
"status": "surfaced",
"rewards": [
{
"kind": "item",
"rewardId": "gems",
"name": "Gems",
"amount": 50,
"image": "https://cdn.example.com/gems.png"
}
],
"completionConditions": {
"spendCurrency": {
"id": "coins",
"name": "Coins",
"amount": 100
}
},
"completionTrackers": {
"spendCurrency": 0
},
"createdAt": "2025-01-15T10:00:00Z",
"expiresAt": "2025-01-17T10:00:00Z"
}
],
"snapshot": {
"_id": "snapshot-123",
"gameId": "my-game",
"playerId": "player-123",
"username": "CoolPlayer",
"daysInGame": 45,
"loginStreak": 7,
"trustScore": 850,
"currencies": {
"coins": {
"balance": 1500,
"in": 2000,
"out": 500
}
},
"levels": {
"character": {
"level": 25
}
}
},
"playerData": {
"gameId": "my-game",
"playerId": "player-123",
"currencies": {
"coins": {
"id": "coins",
"name": "Coins",
"balance": 1500,
"image": "https://cdn.example.com/coins.png"
}
}
}
}Example Usage
async function loadPlayerOffers(jwt: string) {
const response = await fetch('https://api.pixels.xyz/v1/client/player/campaigns', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-game-jwt': jwt
},
body: JSON.stringify({
viewingCampaigns: true
})
});
const { offers, snapshot, playerData } = await response.json();
// Display offers to player
offers.forEach(offer => {
console.log(`${offer.name}: ${offer.description}`);
console.log(`Status: ${offer.status}`);
console.log(`Rewards:`, offer.rewards);
if (offer.completionConditions) {
console.log(`Completion:`, offer.completionConditions);
console.log(`Progress:`, offer.completionTrackers);
}
});
// Display player stats
console.log(`Player Level:`, snapshot.levels);
console.log(`Balance:`, playerData.currencies);
}Fetch Player Campaigns (Server)
Fetch all active offers and campaigns for a player from your server.
Endpoint
POST /player/campaigns/refreshAuthentication
API Key - Requires x-api-key and x-client-id headers
Request
{
playerId: string; // Required - Player's unique ID
viewingCampaigns?: boolean | null; // Optional - Set to true when player is viewing offers
}curl -X POST https://api.pixels.xyz/v1/player/campaigns/refresh \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-client-id: YOUR_CLIENT_ID" \
-d '{
"playerId": "player-123",
"viewingCampaigns": false
}'Response
{
player: IClientPlayer; // Player object with snapshot and data
offers: IClientOffer[]; // Array of personalized offers
token: string; // One-time token for dashboard access
gameId: string; // Game ID
playerSnapshot: IPlayerSnapshot; // Player's current profile
playerData: IPlayerData; // Player's currency data
}The response includes an additional token field which can be used to redirect the player to the Stacked dashboard.
{
"player": {
"snapshot": {...},
"data": {...}
},
"offers": [...],
"token": "session-token-abc123...",
"gameId": "my-game",
"playerSnapshot": {...},
"playerData": {...}
}Example Usage
async function refreshPlayerCampaigns(playerId: string) {
const response = await fetch('https://api.pixels.xyz/v1/player/campaigns/refresh', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': process.env.STACKED_API_KEY!,
'x-client-id': process.env.STACKED_CLIENT_ID!
},
body: JSON.stringify({
playerId,
viewingCampaigns: false
})
});
const { offers, playerSnapshot } = await response.json();
// Check if player has any claimable offers
const claimableOffers = offers.filter(o => o.status === 'claimable');
if (claimableOffers.length > 0) {
console.log(`Player ${playerId} has ${claimableOffers.length} claimable offers`);
}
return { offers, playerSnapshot };
}Offer Statuses
Each offer returned has a status field indicating its current state:
| Status | Description |
|---|---|
inQueue | Queued but not yet surfaced (max slots reached) |
surfaced | Active and tracking progress |
viewed | Player has seen the offer |
claimable | Ready to claim rewards |
claimed | Rewards already claimed |
expired | Time limit reached before completion |
Status Flow
Offers typically flow: surfaced → viewed → claimable → claimed. Setting viewingCampaigns: true automatically updates surfaced offers to viewed when fetched.
Stacked