Challenges
Time-limited goals with XP and achievement rewards to drive short-term engagement.
Challenges are time-limited goals that users can join and complete for rewards. They create short-term engagement bursts.
How it works
- Admin creates a challenge with start/end dates, goal type, and rewards. An
event_countchallenge also names the event it counts (event_name). - Users discover active challenges and opt in (join)
- Progress is tracked automatically based on the goal type, counting activity from the challenge's start
- When a user meets the goal, they receive XP and/or an achievement
SDK usage
Get active challenges
Get the user's progress
progress is the fraction of the goal reached, from 0 to 1. GET /v1/client/challenges returns the active challenges with the caller's user_progress, user_status and is_joined on each.
Join a challenge
The SDK has no join method. Join over HTTP with the user's session:
Joining is idempotent; a second join returns the existing membership.
Get my challenges
Returns every challenge the user joined, newest first, with its status (active, completed or failed) and the challenge's name, goal and dates.
Goal types
| Type | Description | How progress is tracked |
|---|---|---|
event_count | Track an event N times | Counts the user's events named event_name between start and end |
xp_earned | Earn N XP | Sums XP earned between start and end |
streak_maintained | Keep streak for N days | Longest streak the user reached between start and end |
Counting one event
An event_count challenge counts one event, named by event_name, matched
exactly against the names your app tracks. A "10 workouts this week" challenge
with event_name: "workout_completed" completes on the user's tenth
workout_completed event; their other events don't count. event_name is
required when you create an event_count challenge and rejected on the other
goal types.
An event_count challenge created before event_name existed has
event_name: null. It is skipped: progress stays where it is and the
challenge never completes. Set event_name on it (PATCH the challenge, or
amba_challenges_update) to turn it on; progress then counts the named event
from the challenge's start.
When progress updates
Amba evaluates challenges about every 5 minutes, after the app's activity. A
participant's user_progress and completion catch up within about 5 minutes of
the event, XP or streak that moves them. Progress counts activity since the
challenge's start_at, including activity from before the user joined, so a
user who already did the work completes on the next evaluation after joining.
On completion, Amba:
- marks the participant
completedand emitsgamification.challenge.completed; - grants
reward_xp, emittinggamification.xp.granted, and onegamification.level.upfor each level the reward crosses; - unlocks
reward_achievement_id.
Your webhooks subscribed to those events receive them. Each reward is granted
once per participant. A few minutes after a challenge's end_at, participants
still short of the goal are marked failed.
Challenges that ended before 2026-10-10, when Amba began evaluating challenges, are left exactly as they were: their participants are not completed, failed or rewarded.
Admin API reference
| Method | Path | Description |
|---|---|---|
POST | /v1/admin/projects/:projectId/challenges | Create challenge |
GET | /v1/admin/projects/:projectId/challenges | List challenges (filter by status) |
Client API reference
| Method | Path | Description |
|---|---|---|
GET | /v1/client/challenges | Get active challenges with progress |
GET | /v1/client/challenges/active | Active challenges (the SDK's getActive) |
GET | /v1/client/challenges/:id/progress | The user's progress (getProgress) |
POST | /v1/client/challenges/:id/join | Join a challenge |
POST | /v1/client/challenges/:id/claim | Confirm a completed challenge's reward |
GET | /v1/client/challenges/mine | Get user's joined challenges |
MCP tools
| Tool | Description |
|---|---|
amba_challenges_create | Create a challenge with goal, dates, and rewards |
amba_challenges_list | List challenges filtered by status |