--- method: GET path: /api/stats/summary auth: jwt area: stats --- # Get Reading Summary The `/stats` page's complete payload: totals, zero-filled daily arrays, streaks, most-active day, top books, and per-library/per-device breakdowns for a time range. All day boundaries and buckets are computed in the **requesting user's timezone**. ## Query Parameters | Parameter | Type | Required | Description | | --------- | ------ | -------- | -------------------------------------------------- | | range | string | No | `7` (default), `30`, `90`, or `year` (days window) | Invalid `range` values return **400**. ## Example Request ```http GET /api/stats/summary?range=30 Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... ``` ## Example response ```json example-response { "range": "30", "days": 30, "start_date": "2026-09-24", "end_date": "2026-10-24", "total_minutes": 1250, "total_audio_minutes": 1100, "total_pages": 412, "session_count": 96, "books_with_activity": 7, "books_finished": 2, "completion_rate": 0.29, "average_session_minutes": 13.0, "daily": [ { "date": "2026-09-24", "minutes": 42, "pages": 15, "sessions": 3, "audio_minutes": 42 } ], "streak": { "current": 5, "longest": 12 }, "most_active_weekday": "Saturday", "most_active_day": "2026-10-17", "most_active_day_minutes": 87, "top_books": [ { "media_item_id": "550e8400-e29b-41d4-a716-446655440000", "title": "Gardens of the Moon", "author": "Steven Erikson", "minutes": 610, "pages": 0 } ], "library_breakdown": [ { "library_id": "8c8d0cee-1cca-4def-9a37-edad3a4d438b", "name": "Audiobooks", "minutes": 1100, "pages": 0, "sessions": 84, "books": 5 } ], "device_breakdown": [ { "device_id": "", "name": "Web", "type": "web", "minutes": 150 }, { "device_id": "660e8400-e29b-41d4-a716-446655440001", "name": "Pixel 9", "type": "android", "minutes": 1100 } ] } ``` ## Response fields | Field | Type | Notes | | ---------------- | ------- | --------------------------------------------------------------------- | | total_audio_minutes | int | listening minutes inside `total_minutes` (mode-aware wording surface) | | daily | array | zero-filled across the whole range — every day present | | streak | object | `current` / `longest` day streaks | | most_active_weekday | string | `""` when the range has no sessions | | device_breakdown | array | `device_id` is `""` for the web bucket (pushes with no device credential) | ## Errors | Status | Body | When | | ------ | -------------------------- | ----------------------- | | 400 | `invalid range ...` | unknown range key | | 401 | `invalid user` | no user in JWT context |