# Reward Log

Reward Logs are **automatically created by the platform** whenever an end user reaches a milestone's `milestoneTargetValue`. Each log contains the coupon code for that reward and timestamps tracking its full lifecycle — from issuance through redemption or expiry.

:::info
Reward Logs are never created manually. They are generated by the platform whenever a milestone is achieved in a streak, challenge, or mission.
:::

## How it works

1. **Milestone threshold crossed** — an end user's progress on a streak, challenge, or mission reaches a milestone's `milestoneTargetValue`.
2. **Reward Log created** — the platform automatically creates a Reward Log entry when a user achieves a milestone.
   - **Gamopanda-handled coupons (`handleCoupon: true` on the parent [Reward](/reward))**: Gamopanda automatically assigns or auto-generates a `couponCode` and stamps `rewardIssuedAt` and `rewardExpiryAt`.
   - **Client-handled coupons (`handleCoupon: false` on the parent [Reward](/reward))**: The `couponCode` is left `null` and your backend updates the Reward Log with the coupon code and expiry timestamps via `PATCH`.
3. **End user sees the reward** — the reward is surfaced in the end-user widget with the coupon code and redemption instructions from the parent milestone's `eudMilestoneRewardInstructionMessage`.
4. **Reward expires** — if `rewardExpiryAt` is set and the coupon has not been redeemed by that time, the reward is shown expired to the user on the dashboard.

---

## Fields

| Field | Type | Required | Notes |
|---|---|---|---|
| `linkedSchemaSlug` | string | ✅ | Slug of the parent schema — `streak`, `challenge`, or `mission`. Set by the system; max 32 chars. |
| `linkedSchemaRecordId` | UUID | ✅ | ID of the specific streak, challenge, or mission record. Non-editable after creation. |
| `milestoneId` | UUID | ✅ | ID of the milestone that triggered this reward. Non-editable after creation. |
| `milestone` | object | — | Read-only joined milestone object. |
| `couponCode` | string | ❌ | The coupon code issued to the end user. Automatically set by Gamopanda if `handleCoupon` is enabled, or updated by your backend if `handleCoupon` is disabled. |
| `rewardIssuedAt` | datetime | ❌ | Timestamp when the reward was issued to the user |
| `rewardExpiryAt` | datetime | ❌ | Timestamp when the reward expires. |
| `periodKey` | string | - | The time-period key for the reward. Mirrors the parent streak/challenge/mission period — e.g., `monthly_2026-04` for monthly, `weekly_2026-15` for weekly, `daily_2026-04-10` for daily. Max 16 chars. Non-editable. |
| `uniqueIdentifier` | string | - | Auto-generated composite key: `linkedSchemaSlug + linkedSchemaRecordId + ownedById + periodKey`. Ensures one reward per user per milestone per period. Max 256 chars. Non-editable |

---

## Lifecycle states

A Reward Log moves through the following states based on its timestamps:

| State | Condition |
|---|---|
| **Issued** | `rewardIssuedAt` is set; `rewardExpiryAt` are null or in the future |
| **Expired** | `rewardExpiryAt` is in the past |

---

## Real-world examples

**🛍️ E-commerce — 3-day streak milestone reward**

A user completes 3 consecutive days of spending and achieves a milestone. The Reward Log is created by the system automatically:

```json
{
  "linkedSchemaSlug": "streak",
  "linkedSchemaRecordId": "a1b2c3d4-0000-0000-0000-000000000000",
  "milestoneId": "m1m2m3m4-0000-0000-0000-000000000000",
  "periodKey": "2026-04-08",
  "ownedById": "user-uuid-here"
}
```

If `handleCoupon` is set to `false` on the parent reward configuration, update the Reward Log with your client-generated coupon code and timestamps:

```json
PATCH /schema/reward_log/record/{id}
{
  "rewardIssuedAt": "2026-04-09T10:05:00Z",
  "couponCode": "coupon-code-here",
  "rewardExpiryAt": "2026-05-09T10:05:00Z"
}
```


## Access & permissions

| Caller | Allowed operations | Notes |
|---|---|---|
| Admin | GET · LIST · UPDATE | No CREATE or DELETE — logs are system-generated only |
| End user | GET · LIST | Can read their own reward logs; cannot write |
| Guest user | *(none)* | Not accessible to unauthenticated callers |

:::warning
Reward Logs **cannot be created or deleted** via the API. Attempting a `POST` or `DELETE` will return `405 Method Not Allowed`. They are created exclusively by the platform when a milestone threshold is crossed.
:::

---

## Related resources

| Resource | Description |
|---|---|
| [Milestone](/milestone) | Parent milestone that defines the target value and coupon for this reward |
| [Streak](/streak) | Parent streak whose progress can trigger milestone rewards |
| [Challenge](/challenge) | Parent challenge whose progress can trigger milestone rewards |
| [Mission](/mission) | Parent mission whose progress can trigger milestone rewards |
| [Reward](/reward) | Reward configuration that defines the coupon code and expiry timestamps |
| [Member](/member) | The end user (`ownedById`) whose progress is updated by this log |

---

## API reference

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

- `GET /schema/reward_log/record` — list reward logs
- `GET /schema/reward_log/record/{id}` — get a reward log by ID
- `PATCH /schema/reward_log/record/{id}` — update a reward log
