Context
The XP store accumulates events but there's no way to query them. An XP history endpoint enables analytics, personal history views, and debugging XP calculation issues.
What to implement
Route: GET /api/agents/:id/xp/history
Returns paginated XP events:
{
"agentId": "...",
"totalXp": 1450,
"events": [
{ "id": "...", "type": "quest_completed", "xp": 100, "questId": "...", "timestamp": "..." },
{ "id": "...", "type": "badge_unlocked", "xp": 50, "badgeId": "...", "timestamp": "..." }
],
"page": 1,
"pageSize": 20,
"total": 47
}
Query params
?page=1&pageSize=20 — pagination (max pageSize: 100)
?type=quest_completed — filter by event type
?from=2026-01-01&to=2026-06-30 — date range filter
Event types
'quest_completed' | 'badge_unlocked' | 'district_unlocked' | 'manual_grant' | 'xp_decay'
Acceptance criteria
Context
The XP store accumulates events but there's no way to query them. An XP history endpoint enables analytics, personal history views, and debugging XP calculation issues.
What to implement
Route: GET /api/agents/:id/xp/history
Returns paginated XP events:
{ "agentId": "...", "totalXp": 1450, "events": [ { "id": "...", "type": "quest_completed", "xp": 100, "questId": "...", "timestamp": "..." }, { "id": "...", "type": "badge_unlocked", "xp": 50, "badgeId": "...", "timestamp": "..." } ], "page": 1, "pageSize": 20, "total": 47 }Query params
?page=1&pageSize=20— pagination (max pageSize: 100)?type=quest_completed— filter by event type?from=2026-01-01&to=2026-06-30— date range filterEvent types
'quest_completed' | 'badge_unlocked' | 'district_unlocked' | 'manual_grant' | 'xp_decay'Acceptance criteria
?type=filter returns only matching events?from=/to=date range filter workstotalXpmatches sum of all event XP values