# Health Rewards

## Health Rewards

### Overview

The **Terra Health Rewards** product lets you turn the raw activity, sleep and physiological data you already receive through the Terra API into **actionable, gamified points** that drive user engagement.

* **Science‑based & adaptive** – Points are calculated from evidence‑backed metrics (sleep duration, HRV, steps, floors climbed and more) and automatically adjust to each individual’s baseline.
* **Real‑time** – Rewards are generated on demand
* **Configurable** – Limits, category weights and streak bonuses can be tweaked in **Dashboard → Health Rewards** (see screenshots below).
* **Monetisable** – Combine earned points with in‑app currency, coupons or badge systems to incentivise healthier habits.

<figure><img src="https://464213908-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FVGMJVuZnZyOtvV4b53cY%2Fuploads%2FgFFeVRtmruj80LrAiBOj%2Fimage.png?alt=media&#x26;token=5151fcc2-2556-421c-8757-a64bdc8f3cb7" alt=""><figcaption></figcaption></figure>

***

### How It Works

1. **Enable Rewards**\
   \&#xNAN;*Open the dashboard, navigate to **Health Rewards** and toggle the product to “Enabled”.*\
   Here you can:
   * assign **daily point caps** (overall or per category),
   * choose **weights** for each goal (e.g. “Hours Slept = 3 pts”, “Steps = 1 pt”),
   * add **streak bonuses** (e.g. “≥10 pts 2 days in a row → +1 pt”).\
     All changes apply instantly to new calculations.
2. **Request points**\
   Call the Rewards endpoints (see below) providing the *user\_id* and a *start\_date* (and optionally *end\_date*).\
   Terra fetches the necessary `daily`, `sleep`, `activity`, data, runs the algorithm in real time, then returns a **total** plus a **human‑readable breakdown** for every day.

***

### Endpoints

> Base URL `https://api.tryterra.co/v2`\
> All calls require the standard `dev-id` & `x-api-key` headers.

| Method | Path                            | Purpose                                            |
| ------ | ------------------------------- | -------------------------------------------------- |
| `GET`  | `/rewards/points`               | Calculate points for a period                      |
| `POST` | `/rewards/points/spent`         | Deduct points (e.g. when a user redeems a voucher) |
| `GET`  | `/rewards/points/spent/history` | Retrieve a chronological list of redeemed points   |

#### 1  Get points

```http
GET /rewards/points?user_id=USER123&start_date=2024‑08‑01&end_date=2024‑08‑07&store=true
dev-id: YOUR_DEV_ID
```

**Query parameters**

| Name         | Type         | Required | Description                                         |
| ------------ | ------------ | -------- | --------------------------------------------------- |
| `user_id`    | string       | ✓        | Terra user identifier                               |
| `start_date` | `YYYY‑MM‑DD` | ✓        | First date (inclusive)                              |
| `end_date`   | `YYYY‑MM‑DD` |          | Last date (exclusive). Defaults to start\_date + 1. |

<details>

<summary><strong>Successful response (200)</strong></summary>

```json
{
  "status": "success",
  "total": 147,
  "daily": [
    {
      "date": "2024-08-06",
      "raw_total": 12,
      "breakdown": {
        "sleep": {
          "streaks": [
            {
              "achieved": true,
              "goal": "Achieve 3 sleep points or more for at least 2 consecutive days",
              "points": 1,
              "max": 1
            }
          ],
          "raw_total": 4,
          "hours": {
            "achieved": 8,
            "goal": "Achieve 7.0-9.0 hours in bed",
            "points": 3,
            "max": 3
          },
          "bedtime": {
            "achieved": "11:00 PM",
            "goal": "Go to bed between 10:10 PM and 11:10 PM",
            "points": 2,
            "max": 2
          },
          "efficiency": {
            "achieved": 95,
            "goal": "Achieve a sleep efficiency of 88% or higher",
            "points": 2,
            "max": 2
          },
          "quality": {
            "achieved": 69,
            "goal": "Achieve a sleep quality of 77% or higher",
            "points": 0,
            "max": 2
          },
          "max": 4
        },
        "movement": {
          "floors": {
            "achieved": 0,
            "goal": "Achieve 3 floors climbed",
            "points": 0,
            "max": 1
          },
          "steps_proportional": {
            "achieved": 7266,
            "goal": "Achieve up to 10000 steps",
            "points": 1,
            "max": 2
          },
          "streaks": [
            {
              "achieved": false,
              "goal": "Achieve 2 movement points or more for at least 2 consecutive days",
              "points": 0,
              "max": 1
            }
          ],
          "raw_total": 1,
          "steps": {
            "achieved": 7266,
            "goal": "Achieve 10000 steps",
            "points": 0,
            "max": 1
          },
          "floors_proportional": {
            "achieved": 0,
            "goal": "Achieve up to 3 floors climbed",
            "points": 0,
            "max": 1
          },
          "max": 2
        },
        "streaks": [
          {
            "achieved": true,
            "goal": "Achieve 10 points or more for at least 2 consecutive days",
            "points": 1,
            "max": 1
          }
        ],
        "health_data": {
          "resting_heart_rate": {
            "consistency": {
              "achieved": 74,
              "goal": "Achieve a resting heart rate of 81 or lower",
              "points": 1,
              "max": 1
            },
            "improvement": {
              "achieved": 74,
              "goal": "Achieve a resting heart rate of 66 or lower",
              "points": 0,
              "max": 1
            }
          },
          "streaks": [
            {
              "achieved": true,
              "goal": "Achieve 1 health data points or more for at least 2 consecutive days",
              "points": 1,
              "max": 1
            }
          ],
          "raw_total": 1,
          "max": 1,
          "hrv": {
            "consistency": {
              "achieved": 22,
              "goal": "Achieve an HRV of 23 or higher",
              "points": 0,
              "max": 1
            },
            "improvement": {
              "achieved": 22,
              "goal": "Achieve an HRV of 28 or higher",
              "points": 0,
              "max": 1
            }
          }
        },
        "activity": {
          "streaks": [
            {
              "achieved": true,
              "goal": "Achieve 3 activity points or more for at least 2 consecutive days",
              "points": 1,
              "max": 1
            }
          ],
          "raw_total": 8,
          "target": {
            "achieved": {
              "moderate": 22,
              "vigorous": 44
            },
            "goal": "Achieve 30 minutes of moderate or 15 minutes of vigorous activity",
            "points": 5,
            "max": 5
          },
          "max": 8,
          "extra": {
            "achieved": {
              "moderate": 22,
              "vigorous": 44
            },
            "goal": "Achieve up to 15 extra minutes of moderate or 8 extra minutes of vigorous activity",
            "points": 2,
            "max": 2
          },
          "proportional": {
            "achieved": {
              "moderate": 22,
              "vigorous": 44
            },
            "goal": "Achieve up to 30 minutes of moderate or 15 minutes of vigorous activity",
            "points": 5,
            "max": 5
          }
        }
      },
      "streak_total": 4,
      "max": 12
    }
  ]
}
```

</details>

Key fields:

| Field                   | Description                                                                                                       |
| ----------------------- | ----------------------------------------------------------------------------------------------------------------- |
| `total`                 | All‑time points earned (including streak bonuses, minus redemptions).                                             |
| `daily[*].raw_total`    | Points *before* streak bonuses that day.                                                                          |
| `daily[*].breakdown`    | Per‑category goals (activity, sleep, movement, health\_data) with **goal**, **achieved**, **points** and **max**. |
| `daily[*].streak_total` | Points awarded from streak goals for that day.                                                                    |

#### 2  Spend points

```http
POST /rewards/points/spent?user_id=USER123
dev-id: YOUR_DEV_ID
Content-Type: application/json

{ "points": 50 }
```

*Deducts 50 points from the user’s balance. A 400 error is returned if the user has insufficient points.*

#### 3  Redemption history

```http
GET /rewards/points/spent/history?user_id=USER123&start_date=2024‑01‑01&end_date=2024‑12‑31
dev-id: YOUR_DEV_ID
```

Returns an ordered array `[ [points, timestamp] ]`.

***

### Response Object Anatomy

Below is a trimmed version of the example response highlighting the structure you will typically work with:

```json
{
  "daily": [
    {
      "date": "2024‑08‑06",
      "breakdown": {
        "activity": {
          "proportional": { "goal": "Up to 30 mins", "achieved": {...}, "points": 5, "max": 5 },
          "target":       { "goal": "30 mins",        "points": 5 },
          "extra":        { "goal": "Extra 15 mins",  "points": 2 },
          "streaks":      [ { "goal": "≥3 activity pts for 2 days", "points": 1 } ],
          "raw_total": 8,
          "max": 8
        },
        "sleep":   { … },
        "movement":{ … },
        "health_data": { … }
      },
      "raw_total": 12,
      "streak_total": 4,
      "max": 12
    }
  ],
  "total": 147
}
```

> **Tip – Parsing points quickly**\
> If you only need the numeric score, read `daily[*].raw_total + daily[*].streak_total`.\
> If you want to visualise goals, iterate over `breakdown` and use the `goal` / `achieved` strings to populate the UI.

***

### Dashboard Configuration

The Health Rewards UI (see screenshots) is laid out by **category**:

| Category        | Example Goals                                          |
| --------------- | ------------------------------------------------------ |
| **Activity**    | Minutes of moderate / vigorous activity                |
| **Movement**    | Steps & floors climbed                                 |
| **Sleep**       | Hours in bed, bedtime consistency, efficiency, quality |
| **Health Data** | HRV, resting heart‑rate consistency & improvement      |

Use **Limits & Streaks** to:

* Set an **overall cap** (e.g., 30 pts / day)
* Add **global streaks** (e.g., ≥20 pts for 5 days → +3 pts)
* Define **per‑category streaks** (e.g., Movement ≥5 pts for 3 days → +1 pt)

All configuration is stored in Terra and read by the API at calculation time.

***

### Example Use Case – “Weekly Wellness Challenge”

1. **Configure Goals**
   * Dashboard → Health Rewards
   * Overall daily limit = 30 pts
   * Activity proportional = max 5, target = 5, extra = 2
   * Movement steps = 1, proportional = 2
   * Sleep hours/efficiency/quality = 2 each
   * Add streak: ≥20 pts for 7 days → +5 bonus
2. **Frontend Implementation**
   * Show a progress bar that calls **GET /rewards/points** every morning for yesterday’s date.
   * Display breakdown tool‑tips using the `goal` and `achieved` strings.
3. **Redemption Flow**
   * When a user taps “Redeem 100 pts for free shipping”, call **POST /rewards/points/spent**.
   * Show the new balance (`total` field) returned in the 200 response.
4. **Leaderboard**
   * Aggregate `raw_total + streak_total` per user over the week to show top performers.

***

### Best Practices

* **Sync ahead of time** – Make sure wearable data is pulled **before** you calculate rewards for a day.
* **Store on server‑side** – Use `store=true` (default) so that the canonical balance lives with Terra and cannot be tampered with client‑side.
* **Handle nulls gracefully** – If a metric is missing (e.g., HRV), its goal will remain but `points` might be `0`.
* **Rate limits** – Reward endpoints share the same rate limits as other `v2` calls (60 req/min default). Aggregate user calls where possible.

***

### FAQ

| Question                                      | Answer                                                                                                           |
| --------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| **Can I backfill rewards?**                   | Yes. Provide a historical `start_date`/`end_date`; Terra will fetch past data and compute points retro‑actively. |
| **What time zone are dates evaluated in?**    | All dates are interpreted in **local time**.                                                                     |
| **Can I override an individual user’s goal?** | Not yet. Goals are global per developer account.                                                                 |
| **Why are my users getting 0 points?**        | Check that the necessary data (sleep, daily summary) exists and that rewards are enabled for your dev ID.        |

***

Need help? Reach out via a dashboard support ticket.
