> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fitsociety.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Reports

> Read aggregate attendance, revenue, and retention summaries through the FITsociety Public API.

Report endpoints return aggregate summaries only. They are intended for
dashboards and synchronization checks, not row-level data export.

The authenticated company is always derived from the Bearer token. Requests must
not include `companyId`, and report DTOs do not expose individual clients,
bookings, invoices, payment IDs, coach IDs, or provider payloads.

## Scopes

| Scope                       | Allows                                                       |
| :-------------------------- | :----------------------------------------------------------- |
| `attendance_summaries:read` | Read aggregate booking attendance counts.                    |
| `revenue_summaries:read`    | Read aggregate invoice revenue totals.                       |
| `retention_summaries:read`  | Read aggregate client relationship and portal status counts. |

## Attendance summary

```http theme={null}
GET /public/v1/reports/attendance-summary?dateFrom=2026-07-01T00:00:00.000Z&dateTo=2026-07-31T23:59:59.999Z
Authorization: Bearer <access_token>
```

Required scope: `attendance_summaries:read`

Validation:

| Parameter  | Type          | Required | Rule                                                              |
| :--------- | :------------ | :------- | :---------------------------------------------------------------- |
| `dateFrom` | ISO date-time | no       | Optional range start. Must be paired with `dateTo` when supplied. |
| `dateTo`   | ISO date-time | no       | Optional range end. Must be after `dateFrom`.                     |

Default range: last 30 days. Maximum range: 366 days.

Response fields:

| Field                                             | Type    | Nullable | Description                                       |
| :------------------------------------------------ | :------ | :------- | :------------------------------------------------ |
| `data.attendanceSummary.dateFrom`                 | string  | no       | Parsed UTC range start.                           |
| `data.attendanceSummary.dateTo`                   | string  | no       | Parsed UTC range end.                             |
| `data.attendanceSummary.totals.bookings`          | integer | no       | Total booking rows in range.                      |
| `data.attendanceSummary.totals.persons`           | integer | no       | Sum of counted persons.                           |
| `data.attendanceSummary.totals.confirmedBookings` | integer | no       | `Planned` and `Completed` bookings.               |
| `data.attendanceSummary.totals.confirmedPersons`  | integer | no       | Persons for `Planned` and `Completed` bookings.   |
| `data.attendanceSummary.totals.waitingBookings`   | integer | no       | Waiting-list bookings.                            |
| `data.attendanceSummary.totals.pendingBookings`   | integer | no       | Pending booking requests.                         |
| `data.attendanceSummary.totals.cancelledBookings` | integer | no       | Bookings with a status starting with `Cancelled`. |
| `data.attendanceSummary.byStatus[].status`        | string  | no       | Booking status bucket.                            |
| `data.attendanceSummary.byStatus[].bookings`      | integer | no       | Booking count in the bucket.                      |
| `data.attendanceSummary.byStatus[].persons`       | integer | no       | Counted persons in the bucket.                    |

<CodeGroup>
  ```bash cURL theme={null}
  curl -H "Authorization: Bearer $FITSOCIETY_ACCESS_TOKEN" \
    "https://api.fitsociety.io/public/v1/reports/attendance-summary?dateFrom=2026-07-01T00:00:00.000Z&dateTo=2026-07-31T23:59:59.999Z"
  ```

  ```javascript JavaScript theme={null}
  const query = new URLSearchParams({
    dateFrom: "2026-07-01T00:00:00.000Z",
    dateTo: "2026-07-31T23:59:59.999Z",
  });

  const response = await fetch(
    `https://api.fitsociety.io/public/v1/reports/attendance-summary?${query}`,
    {
      headers: {
        Authorization: `Bearer ${process.env.FITSOCIETY_ACCESS_TOKEN}`,
      },
    },
  );

  const body = await response.json();
  console.log(body.data.attendanceSummary.totals);
  ```

  ```python Python theme={null}
  import os
  import requests

  response = requests.get(
      "https://api.fitsociety.io/public/v1/reports/attendance-summary",
      headers={"Authorization": f"Bearer {os.environ['FITSOCIETY_ACCESS_TOKEN']}"},
      params={
          "dateFrom": "2026-07-01T00:00:00.000Z",
          "dateTo": "2026-07-31T23:59:59.999Z",
      },
  )
  response.raise_for_status()

  body = response.json()
  print(body["data"]["attendanceSummary"]["totals"])
  ```
</CodeGroup>

Response:

```json theme={null}
{
  "data": {
    "attendanceSummary": {
      "dateFrom": "2026-07-01T00:00:00.000Z",
      "dateTo": "2026-07-31T23:59:59.999Z",
      "totals": {
        "bookings": 248,
        "persons": 312,
        "confirmedBookings": 231,
        "confirmedPersons": 290,
        "waitingBookings": 6,
        "pendingBookings": 3,
        "cancelledBookings": 8
      },
      "byStatus": [
        { "status": "Completed", "bookings": 205, "persons": 259 },
        { "status": "Planned", "bookings": 26, "persons": 31 },
        { "status": "CancelledByClient", "bookings": 8, "persons": 10 }
      ]
    }
  },
  "meta": {
    "requestId": "req_0123456789abcdef",
    "rateLimit": { "limit": 10, "remaining": 9, "resetSeconds": 1 }
  }
}
```

## Revenue summary

```http theme={null}
GET /public/v1/reports/revenue-summary?dateFrom=2026-07-01T00:00:00.000Z&dateTo=2026-07-31T23:59:59.999Z
Authorization: Bearer <access_token>
```

Required scope: `revenue_summaries:read`

Validation:

| Parameter  | Type          | Required | Rule                                                              |
| :--------- | :------------ | :------- | :---------------------------------------------------------------- |
| `dateFrom` | ISO date-time | no       | Optional range start. Must be paired with `dateTo` when supplied. |
| `dateTo`   | ISO date-time | no       | Optional range end. Must be after `dateFrom`.                     |

Default range: last 30 days. Maximum range: 366 days. Only `Invoice` documents
are included; credit notes are excluded.

Response fields:

| Field                                         | Type    | Nullable | Description                         |
| :-------------------------------------------- | :------ | :------- | :---------------------------------- |
| `data.revenueSummary.dateFrom`                | string  | no       | Parsed UTC range start.             |
| `data.revenueSummary.dateTo`                  | string  | no       | Parsed UTC range end.               |
| `data.revenueSummary.currency`                | string  | no       | Currency code used for the summary. |
| `data.revenueSummary.totals.invoiceCount`     | integer | no       | Total invoice count.                |
| `data.revenueSummary.totals.totalPrice`       | number  | no       | Sum of invoice totals.              |
| `data.revenueSummary.totals.totalVat`         | number  | no       | Sum of VAT totals.                  |
| `data.revenueSummary.totals.paidTotal`        | number  | no       | Sum for `Paid` invoices.            |
| `data.revenueSummary.totals.openTotal`        | number  | no       | Sum for `Pending` invoices.         |
| `data.revenueSummary.totals.chargebackTotal`  | number  | no       | Sum for `Chargeback` invoices.      |
| `data.revenueSummary.byStatus[].status`       | string  | no       | Invoice status bucket.              |
| `data.revenueSummary.byStatus[].invoiceCount` | integer | no       | Invoice count in the bucket.        |
| `data.revenueSummary.byStatus[].totalPrice`   | number  | no       | Total price in the bucket.          |
| `data.revenueSummary.byStatus[].totalVat`     | number  | no       | VAT total in the bucket.            |

Not exposed: invoice numbers, client IDs, payment IDs, payment-provider
payloads, line items, PDFs, billing-profile snapshots, or email history.

<CodeGroup>
  ```bash cURL theme={null}
  curl -H "Authorization: Bearer $FITSOCIETY_ACCESS_TOKEN" \
    "https://api.fitsociety.io/public/v1/reports/revenue-summary?dateFrom=2026-07-01T00:00:00.000Z&dateTo=2026-07-31T23:59:59.999Z"
  ```

  ```javascript JavaScript theme={null}
  const query = new URLSearchParams({
    dateFrom: "2026-07-01T00:00:00.000Z",
    dateTo: "2026-07-31T23:59:59.999Z",
  });

  const response = await fetch(
    `https://api.fitsociety.io/public/v1/reports/revenue-summary?${query}`,
    {
      headers: {
        Authorization: `Bearer ${process.env.FITSOCIETY_ACCESS_TOKEN}`,
      },
    },
  );

  const body = await response.json();
  console.log(body.data.revenueSummary.totals);
  ```

  ```python Python theme={null}
  import os
  import requests

  response = requests.get(
      "https://api.fitsociety.io/public/v1/reports/revenue-summary",
      headers={"Authorization": f"Bearer {os.environ['FITSOCIETY_ACCESS_TOKEN']}"},
      params={
          "dateFrom": "2026-07-01T00:00:00.000Z",
          "dateTo": "2026-07-31T23:59:59.999Z",
      },
  )
  response.raise_for_status()

  body = response.json()
  print(body["data"]["revenueSummary"]["totals"])
  ```
</CodeGroup>

Response:

```json theme={null}
{
  "data": {
    "revenueSummary": {
      "dateFrom": "2026-07-01T00:00:00.000Z",
      "dateTo": "2026-07-31T23:59:59.999Z",
      "currency": "EUR",
      "totals": {
        "invoiceCount": 132,
        "totalPrice": 11840.6,
        "totalVat": 2054.9,
        "paidTotal": 10920.75,
        "openTotal": 819.9,
        "chargebackTotal": 99.95
      },
      "byStatus": [
        {
          "status": "Paid",
          "invoiceCount": 121,
          "totalPrice": 10920.75,
          "totalVat": 1895.3
        },
        {
          "status": "Pending",
          "invoiceCount": 10,
          "totalPrice": 819.9,
          "totalVat": 142.25
        },
        {
          "status": "Chargeback",
          "invoiceCount": 1,
          "totalPrice": 99.95,
          "totalVat": 17.35
        }
      ]
    }
  },
  "meta": {
    "requestId": "req_0123456789abcdef",
    "rateLimit": { "limit": 10, "remaining": 8, "resetSeconds": 1 }
  }
}
```

## Retention summary

```http theme={null}
GET /public/v1/reports/retention-summary
Authorization: Bearer <access_token>
```

Required scope: `retention_summaries:read`

Response fields:

| Field                                                | Type    | Nullable | Description                             |
| :--------------------------------------------------- | :------ | :------- | :-------------------------------------- |
| `data.retentionSummary.generatedAt`                  | string  | no       | Summary generation timestamp.           |
| `data.retentionSummary.totals.relationships`         | integer | no       | Total company-client relationship rows. |
| `data.retentionSummary.totals.activeRelationships`   | integer | no       | Relationships with `active` status.     |
| `data.retentionSummary.totals.pendingApproval`       | integer | no       | Relationships pending approval.         |
| `data.retentionSummary.totals.archivedRelationships` | integer | no       | Archived relationships.                 |
| `data.retentionSummary.totals.rejectedRelationships` | integer | no       | Rejected relationships.                 |
| `data.retentionSummary.relationshipStatuses`         | object  | no       | Counts keyed by relationship status.    |
| `data.retentionSummary.memberStatuses`               | object  | no       | Counts keyed by member status.          |
| `data.retentionSummary.portalAccessStatuses`         | object  | no       | Counts keyed by portal access status.   |

Not exposed: client identity, email, phone, assigned coach, exact lifecycle
timeline, archive reasons, deletion metadata, or private notes.

## Rate limits

Report endpoints use the standard Public API client rate limit: 10 requests per
second per OAuth client. Responses include the standard `RateLimit-*` and
`X-RateLimit-*` headers documented in [Contracts](/public-api/contracts).
