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
🎁 Evidencia visual = reward extra
- Si tu PR incluye video demo o capturas de pantalla mostrando la funcionalidad pedida funcionando end-to-end, va a ser considerado para rewards de GrantFox en esta issue. No es obligatorio, pero suma mucho para la evaluación.
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🎁 Evidencia visual = reward extra