# Milestone

Milestones are reward checkpoints attached to a parent record — a **Streak** or a **Challenge**. When a user's progress reaches the `milestoneTargetValue`, the platform automatically issues a `Reward Log` entry containing a coupon code for that user.

:::tip
A single streak or challenge can have multiple milestones at different target values, creating a progressive reward ladder that keeps users motivated throughout the journey.
:::

## How it works

1. **Create a milestone** — set a `milestoneTargetValue` and link it to a parent streak or challenge via `linkedSchemaSlug` + `linkedSchemaRecordId`.
2. **User logs activity** — `Streak Log` or `Challenge Log` entries accumulate progress on the parent record.
3. **Threshold crossed** — when the user's `currentProgressValue` reaches `milestoneTargetValue`, the `afterUpdate` trigger fires automatically.
4. **Reward issued** — a `Reward Log` is created for the user with a coupon code, `rewardIssuedAt` timestamp, and optional `rewardExpiryAt`.

---

## Fields

### Basic information

| Field | Type | Required | Max length | Description |
|---|---|---|---|---|
| `linkedSchemaSlug` | string | ✅ | 32 | Slug of the parent schema this milestone belongs to — `streak` or `challenge` |
| `linkedSchemaRecordId` | UUID | ✅ | — | ID of the specific streak or challenge record this milestone is attached to |
| `name` | string | ✅ | 256 | Internal name of the milestone |
| `description` | string | ✅ | 1 024 | Brief description of the milestone |
| `milestoneTargetValue` | number | ✅ | — | The progress value at which this milestone is achieved |
| `status` | enum | ✅ | — | `draft` · `live` · `paused` |

#### Linking a milestone to a parent

`linkedSchemaSlug` and `linkedSchemaRecordId` together identify the exact parent record:

```json
{
  "linkedSchemaSlug": "streak",
  "linkedSchemaRecordId": "a1b2c3d4-0000-0000-0000-000000000000"
}
```

The same pattern applies for challenges:

```json
{
  "linkedSchemaSlug": "challenge",
  "linkedSchemaRecordId": "e5f6a7b8-0000-0000-0000-000000000000"
}
```

---

## Real-world examples

**🛍️ E-commerce — progressive spend streak milestones**

A 7-day spend streak with two milestone reward checkpoints:

```json
// Milestone 1 — reward at day 3
{
  "linkedSchemaSlug": "streak",
  "linkedSchemaRecordId": "<streak-uuid>",
  "name": "3-Day Streak Milestone",
  "description": "Awarded after 3 consecutive days of spending $50+",
  "milestoneTargetValue": 3,
  "status": "live"
}

// Milestone 2 — reward at day 7 (streak completion)
{
  "linkedSchemaSlug": "streak",
  "linkedSchemaRecordId": "<streak-uuid>",
  "name": "7-Day Streak Milestone",
  "description": "Awarded on full streak completion after 7 consecutive days",
  "milestoneTargetValue": 7,
  "status": "live"
}
```

---

**☕ Food & Beverage — weekly visit challenge milestone**

A challenge requiring 8 visits in a month, with a midpoint reward:

```json
// Milestone — reward at 4 visits
{
  "linkedSchemaSlug": "challenge",
  "linkedSchemaRecordId": "<challenge-uuid>",
  "name": "Halfway There",
  "description": "Awarded after the customer's 4th visit this month",
  "milestoneTargetValue": 4,
  "status": "live"
}
```

---

**🏋️ Fitness — monthly activity milestone ladder**

A 3-month streak with monthly milestone checkpoints:

```json
// Month 1 milestone
{
  "linkedSchemaSlug": "streak",
  "linkedSchemaRecordId": "<streak-uuid>",
  "name": "First Month Complete",
  "description": "Logged 1,500 activity minutes in month 1",
  "milestoneTargetValue": 1,
  "status": "live"
}

// Month 3 milestone (full completion)
{
  "linkedSchemaSlug": "streak",
  "linkedSchemaRecordId": "<streak-uuid>",
  "name": "3-Month Champion",
  "description": "Logged 1,500+ activity minutes every month for 3 months",
  "milestoneTargetValue": 3,
  "status": "live"
}
```

---

## 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 of the milestone shown to the end user |
| `eudDescription` | — | 1 024 | Description of the milestone shown to the end user |
| `eudIcon` | *(default milestone icon)* | — | Milestone icon. Allowed: PNG, JPEG, JPG, GIF, SVG · Max size: 100 KB |
| `eudMilestoneRewardTitle` | — | 48 | Title of the reward shown when the milestone is achieved |

### Messages

| Field | Default | Max length | Description |
|---|---|---|---|
| `eudMilestoneRewardInstructionMessage` | `Use the offer code at checkout to redeem your reward! Valid till {{rewardValidTill}}.` | 1 024 | Instructions shown to the user after the milestone reward is issued |

#### Template variable

| Variable | Description | Example value |
|---|---|---|
| `{{rewardValidTill}}` | The expiry date/time of the issued reward, formatted for display | `4/10/2026, 9:15:38 PM` |

**Rendered example** — a user achieves a milestone and their reward expires on 30 April 2026:

> *Use the offer code at checkout to redeem your reward! Valid till 4/10/2026, 9:15:38 PM.*

---

## Access & permissions

| Caller | Allowed operations |
|---|---|
| Admin | CREATE · GET · LIST · UPDATE · DELETE |
| End user | *(not directly accessible — milestones are surfaced via streak/challenge)* |

---

## Related resources

| Resource | Description |
|---|---|
| [Streak](/streak) | Parent streak that owns this milestone |
| [Challenge](/challenge) | Parent challenge that owns this milestone |
| [Reward Log](/reward_log) | Reward entries automatically created when a milestone is reached |

---

## API reference

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

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