# Challenge

Challenges are time-bound engagement goals that reward users for hitting a cumulative `completionTargetValue` within a defined aggregation period. Unlike streaks, challenges measure total progress toward a single target — not consecutive periods — making them ideal for sprint-style campaigns.

:::tip
A challenge can have multiple milestones at different target values, creating a progressive reward ladder. When any milestone threshold is crossed, a Reward Log is automatically issued for the user.
:::

## How streaks vs challenges differ

| | Streak | Challenge |
|---|---|---|
| Goal | Complete N **consecutive** periods | Accumulate progress toward a **total target** |
| Fails when | A period is missed | The challenge window ends before the target is met |
| Status when missed | `broken` | `failed` |
| Reset | Starts fresh next period | Starts fresh next challenge window |

---

## How it works

1. **Create a challenge** — define a name, aggregation method, aggregation period, and a `completionTargetValue` (the total activity needed to win).
2. **Attach milestones** — link `Milestone` records to the challenge for intermediate reward checkpoints.
3. **Log activity** — send `Challenge Log` entries as users perform qualifying actions. The platform aggregates them automatically.
4. **Track progress** — `Challenge Progress` records are maintained per user, tracking `currentProgressValue`, status, and timestamps.
5. **Earn rewards** — when a milestone threshold or `completionTargetValue` is crossed, a `Reward Log` entry is created with a coupon code.

---

## Fields

### Basic information

| Field | Type | Required | Max length | Description |
|---|---|---|---|---|
| `name` | string | ✅ | 256 | The name of the challenge |
| `description` | string | ✅ | 1 024 | A brief description of the challenge |
| `status` | enum | ✅ | — | `draft` · `live` · `paused` |
| `completionTargetValue` | number | ✅ | — | The total cumulative value a user must reach to complete the challenge |

### Aggregation settings

Aggregation controls how the platform measures cumulative progress from incoming `Challenge Log` entries.

| Field | Type | Required | Default | Options | Description |
|---|---|---|---|---|---|
| `aggregationMethod` | enum | ✅ | `sum` | `sum` · `count` | How log values are combined — `sum` adds `activityValue`, `count` counts the number of log entries |
| `aggregationPeriod` | enum | ✅ | `daily` | `daily` · `weekly` · `monthly` | The time window that defines the challenge duration |

:::note
Unlike streaks, challenges do not have a separate `aggregationTargetValue`. Progress accumulates directly toward `completionTargetValue` across all log entries within the challenge window.
:::

**Example:** a challenge with `aggregationMethod: sum`, `aggregationPeriod: monthly`, and `completionTargetValue: 500` requires the user to accumulate $500 of spend within the current month to complete the challenge.

### Real-world examples

**🛍️ E-commerce — "Monthly Big Spender" challenge**

Win a reward by spending $500 in a single month. Milestone at $200 gives 5% off; completing $500 gives free shipping for 3 months.

```json
{
  "name": "Monthly Big Spender",
  "description": "Spend $500 this month to unlock exclusive rewards.",
  "status": "live",
  "aggregationMethod": "sum",
  "aggregationPeriod": "monthly",
  "completionTargetValue": 500
}
```

---

**☕ Food & Beverage — "10 Visits This Month" challenge**

Visit 10 times in a month to earn a free item. Milestone at 5 visits gives a discount.

```json
{
  "name": "10 Visits This Month",
  "description": "Visit us 10 times this month and earn a free item.",
  "status": "live",
  "aggregationMethod": "count",
  "aggregationPeriod": "monthly",
  "completionTargetValue": 10
}
```

> `aggregationMethod: count` — each `Challenge Log` entry counts as 1 visit regardless of `activityValue`.

---

**🏋️ Fitness — "Weekly Burn 5 000 Calories" challenge**

Log 5 000 calories burned in a single week to win a gym merchandise voucher.

```json
{
  "name": "Weekly Burn 5K",
  "description": "Burn 5,000 calories this week and earn a reward.",
  "status": "live",
  "aggregationMethod": "sum",
  "aggregationPeriod": "weekly",
  "completionTargetValue": 5000
}
```

---

**📚 EdTech — "Complete 20 Lessons This Month" challenge**

Finish 20 lessons in a month to unlock a premium content pack.

```json
{
  "name": "20 Lessons Challenge",
  "description": "Complete 20 lessons this month to unlock premium content.",
  "status": "live",
  "aggregationMethod": "count",
  "aggregationPeriod": "monthly",
  "completionTargetValue": 20
}
```

### Milestones

| Field | Type | Description |
|---|---|---|
| `milestones` | Milestone[] | Read-only. Milestones linked to this challenge. Manage them from the **Milestones** tab. |

---

## End-user display (EUD)

All EUD fields are **localisable** — supply a `languageCode` query parameter when reading to receive the translated value.

### Labels

| Field | Default | Max length | Description |
|---|---|---|---|
| `eudTitle` | — | 48 | Title shown to the end user |
| `eudDescription` | — | 1 024 | Description shown to the end user |
| `eudIcon` | *(default challenge icon)* | — | Icon image. Allowed: PNG, JPEG, JPG, GIF, SVG · Max size: 100 KB |
| `eudInProgressLabel` | `In Progress` | 32 | Status label while challenge is active |
| `eudCompletedLabel` | `Completed` | 32 | Status label when challenge is won |
| `eudNotStartedLabel` | `Not Started` | 32 | Status label before any activity |
| `eudFailedLabel` | `Failed` | 32 | Status label when the challenge window closes without completion |
| `eudViewDetailsButtonText` | `View Details` | 32 | CTA button label |

### Messages

Messages support **template variables** resolved at runtime:

| Variable | Description | Example value |
|---|---|---|
| `{{$helpers.periodText}}` | Human-readable period name from `aggregationPeriod` | `daily` → `day` · `weekly` → `week` · `monthly` → `month` |
| `{{$helpers.remainingValue}}` | Amount still needed to reach the next milestone | `150.00` (user has $350, next milestone at $500 → $150 remaining) |
| `{{$helpers.currentProgressValue}}` | Total accumulated value | `150.00` |
| `{{$helpers.nextMilestoneRemainingValue}}` | Value needed for next milestone | `150.00` |
| `{{$helpers.completionTargetValue}}` | Target value for the current period | `500.00` |
| `{{$helpers.formattedChallengeToBeFailedAt}}` | Expiration time for active period in user's locale time format | `2026-07-20 23:59:59` |


| Field | Default | Max length |
|---|---|---|
| `eudCompletedChallengeMessage` | `Congratulations! You have completed this challenge! Shop more next {{$helpers.periodText}} to start a new challenge!` | 256 |
| `eudFailedChallengeMessage` | `Your challenge has failed. Don\'t worry, shop more next {{$helpers.periodText}} to start a new challenge!` | 256 |
| `eudMilestoneNextToBeAchievedMessage` | `Shop for ${{$helpers.nextMilestoneRemainingValue}} or more to complete the next milestone!` | 256 |
| `eudToBeFailedChallengeMessage` | `Your challenge will fail if you don\'t shop for ${{$helpers.remainingValue}} or more by {{$helpers.formattedChallengeToBeFailedAt}}.` | 256 |

**Rendered examples** — for a monthly spend challenge where the user spent $350 and the next milestone is at $500:

| Variable | Resolved value |
|---|---|
| `$helpers.periodText` | `month` |
| `$helpers.nextMilestoneRemainingValue` | `150.00` |
| `$helpers.remainingValue` | `150.00` |
| `$helpers.formattedChallengeToBeFailedAt` | `2026-07-20 23:59:59` |
| `$helpers.currentProgressValue` | `350.00` |
| `$helpers.completionTargetValue` | `500.00` |

> *Shop for $150.00 or more to complete the next milestone!*

On completion, `eudCompletedChallengeMessage` will render as:

> *Congratulations! You have completed this challenge! Shop more next month to start a new challenge!*

On failure, `eudFailedChallengeMessage` will render as:

> *Your challenge has failed. Don't worry, shop more next month to start a new challenge!*

---

## Access & permissions

| Caller | Allowed operations |
|---|---|
| Admin | CREATE · GET · LIST · UPDATE · DELETE |
| End user | GET · LIST |
| Guest (unauthenticated) | GET · LIST |

---

## Related resources

| Resource | Description |
|---|---|
| [Milestone](/milestone) | Reward checkpoints attached to a challenge |
| [Challenge Log](/api#tag/Challenge-Log) | Individual activity events logged against a challenge |
| [Challenge Progress](/api#tag/Challenge-Progress) | Per-user progress state for a challenge |
| [Reward Log](/api#tag/Reward-Log) | Rewards issued when a milestone or completion threshold is reached |

---

## API reference

See the [API Reference](/api/challenge) for full request/response schemas and interactive examples for:

- `GET /schema/challenge/record` — list challenges
- `POST /schema/challenge/record` — create a challenge
- `GET /schema/challenge/record/{id}` — get a challenge by ID
- `PATCH /schema/challenge/record/{id}` — update a challenge
- `DELETE /schema/challenge/record/{id}` — delete a challenge
