# Client summaries

> One row per client adding up their workouts, nutrition, habits, metrics, health data and check-ins over a period.

Source: https://hubfit.com/developers/api/client-summaries


One row per client you can reach, adding up what they did over a period (their workouts, nutrition, habits, metrics, health data and check-ins), to compare clients (who trained fewer than 3 times this week, who is under their protein target, who lost weight this month) without fetching every record.

Endpoints:

- `GET /v1/client-summaries`: [List client summaries](https://hubfit.com/developers/api/client-summaries#list-client-summaries)

## Client summary object

### Attributes

- `client` (object)
  - `id` (string): Its unique ID.
  - `name` (string)
- `workouts` (object): The workouts the client completed in the period.
  - `workoutCount` (integer): How many workouts the client completed in the period.
  - `lastCompletedAt` (timestamp, nullable): When the client last completed a workout at all, which can be after the period. `null` if they never have.
  - `totals` (object): Added up over the workouts in the period.
    - `setCount` (integer)
    - `reps` (number)
    - `volume` (number): Weight times reps over every set, in `weightUnit`.
  - `newPersonalRecordCount` (integer): How many personal records the workouts in the period set.
  - `weightUnit` (enum): The unit of every weight here, which is the client's unit setting. Weights aren't converted, the way amounts come with their currency. HubFit doesn't record the unit each workout was logged in, so a client who changed their setting may have older workouts logged in the other unit. Known values `kg`, `lb`.
- `nutrition` (object): A day counts toward `loggedDayCount` and the averages once it has food in it. Clients who track in Cronometer have no logs here.
  - `loggedDayCount` (integer): How many days in the period the client logged food.
  - `lastLoggedDate` (date, nullable): The last day the client logged anything (food, a photo or a note), which can be after the period. `null` if they never have.
  - `averageNutrients` (object, nullable): The daily average over the days logged. `null` if the client logged no food in the period.
    - `calories` (number)
    - `proteinGrams` (number)
    - `carbsGrams` (number)
    - `fatGrams` (number)
    - `fiberGrams` (number)
    - `sugarGrams` (number)
    - `saturatedFatGrams` (number)
    - `monounsaturatedFatGrams` (number)
    - `polyunsaturatedFatGrams` (number)
  - `averageTarget` (object, nullable): The average of the days logged's targets, each value over the days it was set. `null` if none of those days had a target.
    - `calories` (number, nullable)
    - `proteinGrams` (number, nullable)
    - `carbsGrams` (number, nullable)
    - `fatGrams` (number, nullable)
- `habits` (array of objects): Each habit that was running in the period, up to today. Empty if the client had none, or the coach turned habits off for them.
  - `id` (string): Its unique ID.
  - `name` (string)
  - `emoji` (string)
  - `goal` (object)
    - `type` (enum): `numeric` when the client logs an amount (steps, litres), `completion` when they tick it off. Known values `numeric`, `completion`.
    - `value` (number, nullable): The amount to reach each period. For a `completion` habit, how many ticks (1 a day, or 1 to 7 a week).
    - `unit` (string, nullable): The unit the coach picked, like `steps`, `km` or `cups`. `null` for a `completion` habit.
    - `period` (enum): Whether the goal is for each day, each Monday-to-Sunday week, or each month. Known values `day`, `week`, `month`.
  - `completedPeriodCount` (integer): How many of the `expectedPeriodCount` days, weeks or months the client met the goal, as the app records it.
  - `expectedPeriodCount` (integer): The habit's days, weeks or months (its goal's `period`) in the period while it was running, up to today. A week counts when any of it falls in the period.
- `metrics` (array of objects): Each of the client's metrics, or the one named with `metricName`, in the order the coach added them. Empty if the client has none, or the coach turned metrics off for them.
  - `id` (string): Its unique ID.
  - `name` (string)
  - `unit` (string, nullable)
  - `entryCount` (integer): The entries in the period.
  - `firstEntry` (object, nullable): The period's earliest entry. `null` if it has none.
    - `id` (string): Its unique ID.
    - `date` (date): The client's own calendar day the entry is for.
    - `value` (number): In the metric's `unit`.
  - `lastEntry` (object, nullable): The period's latest entry, picked the same way as a metric's `lastEntry`. `null` if it has none.
    - `id` (string): Its unique ID.
    - `date` (date): The client's own calendar day the entry is for.
    - `value` (number): In the metric's `unit`.
  - `average` (number, nullable): The mean of the period's entries, to 1 decimal place, as the app shows it. `null` with no entries.
- `health` (object): From Apple Health or Health Connect, each average over the days that have it. `source` is `null` for a client who hasn't connected either.
  - `source` (enum, nullable): Where the data comes from, or `null` if the client hasn't connected Apple Health or Health Connect. New sources can appear. Known values `apple_health`, `health_connect`.
  - `lastSyncedAt` (timestamp, nullable)
  - `recordedDayCount` (integer): How many days in the period have any data.
  - `averageSteps` (integer, nullable)
  - `averageActiveCalories` (integer, nullable)
  - `averageSleepSeconds` (integer, nullable)
  - `averageRestingHeartRateBpm` (integer, nullable)
- `checkIns` (array of objects): One entry per check-in form the client submitted for a day in the period, latest first. Empty if they submitted none. A check-in counts on the day it's for (`checkInDate`), the client's own day or the day they backdated it to. For submissions waiting for your review, use `GET /check-in-submissions?status=awaiting_review`.
  - `name` (string): The form's name on its latest submission in the period. Forms are told apart by the form itself, so a renamed form is one entry.
  - `submissionCount` (integer)
  - `lastSubmittedAt` (timestamp)
  - `lastSubmissionId` (string): The latest submission, to read with `GET /check-in-submissions/{submissionId}`.

### Example

```json
{
  "client": {
    "id": "6ad6af41d3199442d31b2743",
    "name": "Jordan Miller"
  },
  "workouts": {
    "workoutCount": 4,
    "lastCompletedAt": "2026-10-26T14:32:05.000Z",
    "totals": {
      "setCount": 18,
      "reps": 142,
      "volume": 18450
    },
    "newPersonalRecordCount": 1,
    "weightUnit": "lb"
  },
  "nutrition": {
    "loggedDayCount": 6,
    "lastLoggedDate": "2026-10-26",
    "averageNutrients": {
      "calories": 2350,
      "proteinGrams": 180,
      "carbsGrams": 240,
      "fatGrams": 70,
      "fiberGrams": 32,
      "sugarGrams": 45,
      "saturatedFatGrams": 22,
      "monounsaturatedFatGrams": 28,
      "polyunsaturatedFatGrams": 14
    },
    "averageTarget": {
      "calories": 2350,
      "proteinGrams": 180,
      "carbsGrams": 240,
      "fatGrams": 70
    }
  },
  "habits": [
    {
      "id": "6ad6af3f8234ff3e82336c41",
      "name": "10,000 steps a day",
      "emoji": "🚶",
      "goal": {
        "type": "numeric",
        "value": 10000,
        "unit": "steps",
        "period": "day"
      },
      "completedPeriodCount": 5,
      "expectedPeriodCount": 7
    }
  ],
  "metrics": [
    {
      "id": "6ad6af776298037662967079",
      "name": "Weight",
      "unit": "lb",
      "entryCount": 24,
      "firstEntry": {
        "id": "6ad6af5ec77bd15dc77a3e5c",
        "date": "2026-09-28",
        "value": 186.2
      },
      "lastEntry": {
        "id": "6ad6af4305c6094205c47641",
        "date": "2026-10-26",
        "value": 182.4
      },
      "average": 184.1
    }
  ],
  "health": {
    "source": "apple_health",
    "lastSyncedAt": "2026-10-26T14:32:05.000Z",
    "recordedDayCount": 7,
    "averageSteps": 9120,
    "averageActiveCalories": 540,
    "averageSleepSeconds": 26100,
    "averageRestingHeartRateBpm": 58
  },
  "checkIns": [
    {
      "name": "Weekly check-in",
      "submissionCount": 4,
      "lastSubmittedAt": "2026-10-26T14:32:05.000Z",
      "lastSubmissionId": "6ad6af38570dcf37570c3c3a"
    }
  ]
}
```

## List client summaries

`GET https://api.hubfit.com/v1/client-summaries`

For each client you can reach (team members with the Standard role only see their assigned clients), or one with `clientId`, what they did over a period, in the sections you name in `include`. Clients come newest first, as in `GET /clients`, including those who logged nothing. Requires `clients:read`.

### Query parameters

- `include` (array of enums, required): The sections each row has, comma-separated, such as `workouts,nutrition`. Ask only for the ones you need, since each one adds to every row. One of `workouts`, `nutrition`, `habits`, `metrics`, `health`, `checkIns`.
- `clientId` (string): Only this client's summary. A client you can't reach is a 404, and an archived one a 409.
- `clientIds` (array of strings): Only these clients, up to 25, comma-separated. A filter like the rest, so a client you can't reach or who is archived is left out. Compare `totalCount` with how many you asked for. Not with `clientId`.
- `startDate` (date, required): The first day of the period, included, as `YYYY-MM-DD`. Workouts count on their day in your own calendar (the timezone in your HubFit settings), as the app shows them to you; the other sections count the client's own days.
- `endDate` (date, required): The last day of the period, included, as `YYYY-MM-DD`. The period is at most 31 days, counting both ends, or 366 when `include` is only `metrics`.
- `metricName` (string): Only the metric with this name, ignoring case, as the app matches names. `weight` finds `Weight` but not `Body weight`. Needs `metrics` in `include`.
- `limit` (integer): How many clients a page holds. At most 25, fewer than other lists, as a row with every section is about 600 tokens. Default `25`.
- `cursor` (string): The `nextCursor` from the previous page.

### Returns

A page of summaries, one per client.

### Example request

cURL:

```bash
curl -G https://api.hubfit.com/v1/client-summaries \
  -H "Authorization: Bearer $HUBFIT_API_KEY" \
  -d include=workouts%2Cnutrition \
  -d startDate=2026-10-20 \
  -d endDate=2026-10-26
```

Node.js:

```javascript
const response = await fetch("https://api.hubfit.com/v1/client-summaries?include=workouts%2Cnutrition&startDate=2026-10-20&endDate=2026-10-26", {
  headers: {
    Authorization: `Bearer ${process.env.HUBFIT_API_KEY}`,
  },
});

const { data, nextCursor } = await response.json();
```

Python:

```python
import os
import requests

response = requests.get(
    "https://api.hubfit.com/v1/client-summaries",
    headers={"Authorization": f"Bearer {os.environ['HUBFIT_API_KEY']}"},
    params={
        "include": "workouts,nutrition",
        "startDate": "2026-10-20",
        "endDate": "2026-10-26",
    },
)

page = response.json()
data, next_cursor = page["data"], page["nextCursor"]
```

### Example response (200 OK)

```json
{
  "data": [
    {
      "client": {
        "id": "6ad6af41d3199442d31b2743",
        "name": "Jordan Miller"
      },
      "workouts": {
        "workoutCount": 4,
        "lastCompletedAt": "2026-10-26T14:32:05.000Z",
        "totals": {
          "setCount": 18,
          "reps": 142,
          "volume": 18450
        },
        "newPersonalRecordCount": 1,
        "weightUnit": "lb"
      },
      "nutrition": {
        "loggedDayCount": 6,
        "lastLoggedDate": "2026-10-26",
        "averageNutrients": {
          "calories": 2350,
          "proteinGrams": 180,
          "carbsGrams": 240,
          "fatGrams": 70,
          "fiberGrams": 32,
          "sugarGrams": 45,
          "saturatedFatGrams": 22,
          "monounsaturatedFatGrams": 28,
          "polyunsaturatedFatGrams": 14
        },
        "averageTarget": {
          "calories": 2350,
          "proteinGrams": 180,
          "carbsGrams": 240,
          "fatGrams": 70
        }
      },
      "habits": [
        {
          "id": "6ad6af3f8234ff3e82336c41",
          "name": "10,000 steps a day",
          "emoji": "🚶",
          "goal": {
            "type": "numeric",
            "value": 10000,
            "unit": "steps",
            "period": "day"
          },
          "completedPeriodCount": 5,
          "expectedPeriodCount": 7
        }
      ],
      "metrics": [
        {
          "id": "6ad6af776298037662967079",
          "name": "Weight",
          "unit": "lb",
          "entryCount": 24,
          "firstEntry": {
            "id": "6ad6af5ec77bd15dc77a3e5c",
            "date": "2026-09-28",
            "value": 186.2
          },
          "lastEntry": {
            "id": "6ad6af4305c6094205c47641",
            "date": "2026-10-26",
            "value": 182.4
          },
          "average": 184.1
        }
      ],
      "health": {
        "source": "apple_health",
        "lastSyncedAt": "2026-10-26T14:32:05.000Z",
        "recordedDayCount": 7,
        "averageSteps": 9120,
        "averageActiveCalories": 540,
        "averageSleepSeconds": 26100,
        "averageRestingHeartRateBpm": 58
      },
      "checkIns": [
        {
          "name": "Weekly check-in",
          "submissionCount": 4,
          "lastSubmittedAt": "2026-10-26T14:32:05.000Z",
          "lastSubmissionId": "6ad6af38570dcf37570c3c3a"
        }
      ]
    }
  ],
  "nextCursor": "eyJpZCI6IjZhZDZhZjNmMjljNTk3ZjE1In0",
  "totalCount": 48
}
```
