# Clients

> List and find the clients you coach, read one, and add new clients with an onboarding flow.

Source: https://hubfit.com/developers/api/clients


A client is someone you coach in HubFit. Creating one adds them to your workspace, as adding a client in the app does, and can email them their login details and run an onboarding flow for them.

Team members with the Standard role only reach the clients assigned to them. **Deleted clients** are never returned. **Archived clients** appear in the list when you ask for them with `status`, and asking for anything else about one answers `409 client_archived` until you unarchive them in HubFit.

Endpoints:

- `GET /v1/clients`: [List clients](https://hubfit.com/developers/api/clients#list-clients)
- `POST /v1/clients`: [Create a client](https://hubfit.com/developers/api/clients#create-client)
- `GET /v1/clients/{clientId}`: [Get a client](https://hubfit.com/developers/api/clients#get-client)

## Client object

### Attributes

- `id` (string): Its unique ID.
- `name` (string)
- `email` (string)
- `status` (enum): `archived` clients only appear in the client list: unarchive them in HubFit to read anything else of theirs. Known values `active`, `archived`.
- `tags` (array of objects): Alphabetical.
  - `id` (string): Its unique ID.
  - `name` (string)
- `dateOfBirth` (date, nullable)
- `sex` (enum, nullable): Known values `male`, `female`.
- `heightCm` (number, nullable): Always in centimetres. `preferredUnits.length` is how the client prefers to see it.
- `timezone` (string): IANA time zone, e.g. `Europe/London`. Dates on the client (`dateOfBirth`, `coachingPeriod`) are calendar dates in this time zone.
- `preferredUnits` (object): The units the client prefers to see measurements in. Values in the API are always metric (e.g. `heightCm`); convert with these when showing them to the client.
  - `weight` (enum): Known values `kg`, `lb`.
  - `length` (enum): Known values `cm`, `inch`.
- `coachingPeriod` (object, nullable): The dates the coach set for this client's coaching (Set Duration in the app), inclusive. `null` if the coach hasn't set them.
  - `startDate` (date, nullable)
  - `endDate` (date, nullable)
- `lastCheckInAt` (timestamp, nullable)
- `lastActiveAt` (timestamp, nullable): When the client last used the app. `null` if they never have.
- `createdAt` (timestamp): When it was created.

### Example

```json
{
  "id": "6ad6af41d3199442d31b2743",
  "name": "Jordan Miller",
  "email": "jordan.miller@example.com",
  "status": "active",
  "tags": [
    {
      "id": "6ad6afe58cebe1e48cea4ee3",
      "name": "Online coaching"
    }
  ],
  "dateOfBirth": "1991-04-18",
  "sex": "male",
  "heightCm": 178,
  "timezone": "America/New_York",
  "preferredUnits": {
    "weight": "lb",
    "length": "inch"
  },
  "coachingPeriod": {
    "startDate": "2026-03-02",
    "endDate": "2027-03-01"
  },
  "lastCheckInAt": "2026-10-26T14:32:05.000Z",
  "lastActiveAt": "2026-10-27T07:42:10.000Z",
  "createdAt": "2026-03-02T15:04:11.000Z"
}
```

## List clients

`GET https://api.hubfit.com/v1/clients`

Clients you can reach, newest first. Team members with the Standard role only see their assigned clients. Deleted clients are never listed, and archived ones only when you ask for them with `status`. Requires `clients:read`.

### Query parameters

- `search` (string): Case-insensitive match on part of a name or email.
- `email` (string): Only the client with exactly this email, ignoring case. Use it to find one specific client; `search` also matches partial emails.
- `tagId` (string): Only clients with this tag. An id from `GET /tags`.
- `status` (enum): `active` (the default) for current clients, `archived` for archived ones, `all` for both. An archived client is only ever listed: anything else about them answers `409 client_archived` until you unarchive them in HubFit. One of `active`, `archived`, `all`. Default `active`.
- `limit` (integer): How many results to return, from 1 to 100. Default `25`.
- `cursor` (string): The `nextCursor` from the previous page.

### Returns

A page of clients.

### Example request

cURL:

```bash
curl -G https://api.hubfit.com/v1/clients \
  -H "Authorization: Bearer $HUBFIT_API_KEY" \
  -d search=jordan
```

Node.js:

```javascript
const response = await fetch("https://api.hubfit.com/v1/clients?search=jordan", {
  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/clients",
    headers={"Authorization": f"Bearer {os.environ['HUBFIT_API_KEY']}"},
    params={
        "search": "jordan",
    },
)

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

### Example response (200 OK)

```json
{
  "data": [
    {
      "id": "6ad6af41d3199442d31b2743",
      "name": "Jordan Miller",
      "email": "jordan.miller@example.com",
      "status": "active",
      "tags": [
        {
          "id": "6ad6afe58cebe1e48cea4ee3",
          "name": "Online coaching"
        }
      ],
      "dateOfBirth": "1991-04-18",
      "sex": "male",
      "heightCm": 178,
      "timezone": "America/New_York",
      "preferredUnits": {
        "weight": "lb",
        "length": "inch"
      },
      "coachingPeriod": {
        "startDate": "2026-03-02",
        "endDate": "2027-03-01"
      },
      "lastCheckInAt": "2026-10-26T14:32:05.000Z",
      "lastActiveAt": "2026-10-27T07:42:10.000Z",
      "createdAt": "2026-03-02T15:04:11.000Z"
    }
  ],
  "nextCursor": "eyJpZCI6IjZhZDZhZjNmMjljNTk3ZjE1In0",
  "totalCount": 48
}
```

## Create a client

`POST https://api.hubfit.com/v1/clients`

Adds a client to your workspace, exactly as adding one in the app does: it counts toward your plan's client limit, and a team member who adds a client is assigned to them. With `sendLoginInstructions` (the default), the client is emailed their login instructions straight away.

A client's email is unique within your workspace, so adding an email that's already a client returns `409 client_exists` (with the existing `clientId` when you can reach that client) instead of a second client. That makes retries safe even without an `Idempotency-Key`. If the existing client is archived and you can reach them, it's `409 client_archived` instead: unarchive them in HubFit.

With `onboardingFlowId`, the flow runs for the new client once they're added, as adding a client with a flow does in the app: they get its programs, nutrition plans, check-ins, habits, metrics and the rest, and its team members are assigned them. A flow that isn't your workspace's is a 404, and no client is added. A client that already exists (`409`) gets nothing. Requires `clients:create`.

### Headers

- `Idempotency-Key` (string): Any unique string, such as a UUID, up to 255 characters. Retrying with the same key within 24 hours returns the first response instead of repeating the write. See [Idempotency](https://hubfit.com/developers/idempotency).

### Body parameters

- `name` (string, required): The client's full name. Can't contain `@`.
- `email` (string, required)
- `sendLoginInstructions` (boolean): Email the client their login instructions now. Default `true`.
- `onboardingFlowId` (string): An onboarding flow to run for the new client, by an `id` from `GET /onboarding-flows`.

### Returns

The new client.

### Example request

cURL:

```bash
curl -X POST https://api.hubfit.com/v1/clients \
  -H "Authorization: Bearer $HUBFIT_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Jordan Miller",
    "email": "jordan.miller@example.com",
    "sendLoginInstructions": true,
    "onboardingFlowId": "6ad6affacef0fafbcef28df8"
  }'
```

Node.js:

```javascript
const response = await fetch("https://api.hubfit.com/v1/clients", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.HUBFIT_API_KEY}`,
    "Content-Type": "application/json",
    "Idempotency-Key": crypto.randomUUID(),
  },
  body: JSON.stringify({
    name: "Jordan Miller",
    email: "jordan.miller@example.com",
    sendLoginInstructions: true,
    onboardingFlowId: "6ad6affacef0fafbcef28df8",
  }),
});

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

Python:

```python
import os
import uuid
import requests

response = requests.post(
    "https://api.hubfit.com/v1/clients",
    headers={"Authorization": f"Bearer {os.environ['HUBFIT_API_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
    json={
        "name": "Jordan Miller",
        "email": "jordan.miller@example.com",
        "sendLoginInstructions": True,
        "onboardingFlowId": "6ad6affacef0fafbcef28df8",
    },
)

data = response.json()["data"]
```

### Example response (201 Created)

```json
{
  "data": {
    "id": "6ad6af41d3199442d31b2743",
    "name": "Jordan Miller",
    "email": "jordan.miller@example.com",
    "status": "active",
    "tags": [
      {
        "id": "6ad6afe58cebe1e48cea4ee3",
        "name": "Online coaching"
      }
    ],
    "dateOfBirth": "1991-04-18",
    "sex": "male",
    "heightCm": 178,
    "timezone": "America/New_York",
    "preferredUnits": {
      "weight": "lb",
      "length": "inch"
    },
    "coachingPeriod": {
      "startDate": "2026-03-02",
      "endDate": "2027-03-01"
    },
    "lastCheckInAt": "2026-10-26T14:32:05.000Z",
    "lastActiveAt": "2026-10-27T07:42:10.000Z",
    "createdAt": "2026-03-02T15:04:11.000Z"
  }
}
```

## Get a client

`GET https://api.hubfit.com/v1/clients/{clientId}`

One client, the same object the list returns. Requires `clients:read`.

### Path parameters

- `clientId` (string, required): The client's `id`.

### Returns

The client.

### Example request

cURL:

```bash
curl https://api.hubfit.com/v1/clients/6ad6af41d3199442d31b2743 \
  -H "Authorization: Bearer $HUBFIT_API_KEY"
```

Node.js:

```javascript
const response = await fetch("https://api.hubfit.com/v1/clients/6ad6af41d3199442d31b2743", {
  headers: {
    Authorization: `Bearer ${process.env.HUBFIT_API_KEY}`,
  },
});

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

Python:

```python
import os
import requests

response = requests.get(
    "https://api.hubfit.com/v1/clients/6ad6af41d3199442d31b2743",
    headers={"Authorization": f"Bearer {os.environ['HUBFIT_API_KEY']}"},
)

data = response.json()["data"]
```

### Example response (200 OK)

```json
{
  "data": {
    "id": "6ad6af41d3199442d31b2743",
    "name": "Jordan Miller",
    "email": "jordan.miller@example.com",
    "status": "active",
    "tags": [
      {
        "id": "6ad6afe58cebe1e48cea4ee3",
        "name": "Online coaching"
      }
    ],
    "dateOfBirth": "1991-04-18",
    "sex": "male",
    "heightCm": 178,
    "timezone": "America/New_York",
    "preferredUnits": {
      "weight": "lb",
      "length": "inch"
    },
    "coachingPeriod": {
      "startDate": "2026-03-02",
      "endDate": "2027-03-01"
    },
    "lastCheckInAt": "2026-10-26T14:32:05.000Z",
    "lastActiveAt": "2026-10-27T07:42:10.000Z",
    "createdAt": "2026-03-02T15:04:11.000Z"
  }
}
```

## Webhook events

- `client.created`: A client was added. Sent when a client is added, however they were added (in the app, through the API, by a package purchase or by Zapier). Fetch them with `GET /clients/{clientId}`.

An event carries the record's `id` and its `clientId`, not the record. See [Webhooks](https://hubfit.com/developers/webhooks).
