# User Statistics API Documentation ## Overview The User Statistics API provides comprehensive analytics about user growth, engagement, activity, and content distribution. All statistics support flexible time intervals and are optimized for dashboard visualizations. **Base URL**: `/api/stats` **Authentication**: All endpoints require API key authentication via Bearer token. --- ## Authentication Include your API key in the `Authorization` header: ```bash Authorization: Bearer YOUR_STATS_API_KEY ``` Set the API key via the `STATS_API_KEY` environment variable. --- ## Base Endpoint ``` GET /api/stats ``` All statistics are accessed through this single endpoint using the `type` query parameter to specify the stat type. --- ## Query Parameters | Parameter | Type | Required | Description | Valid Values | | ------------------- | ------- | -------- | ------------------------------------------ | ----------------------------------------------- | | `type` | string | Yes | Type of statistics to retrieve | `growth`, `engagement`, `activity`, `breakdown` | | `interval` | string | No | Time interval for aggregation | `day`, `week`, `month` (default: `day`) | | `limit` | number | No | Number of intervals to return | 1-365 (default: 30) | | `includeTimeSeries` | boolean | No | Include time series data (engagement only) | `true`, `false` (default: `false`) | --- ## Stat Types ### 1. Growth Statistics **Description**: Track user sign-ups over time with cumulative totals and period-over-period growth. **Query Parameters**: - `type=growth` (required) - `interval` (optional, default: `day`) - `limit` (optional, default: 30) **Request Example**: ```bash curl -X GET "http://localhost:3000/api/stats?type=growth&interval=day&limit=30" \ -H "Authorization: Bearer YOUR_STATS_API_KEY" ``` **Response Schema**: ```typescript { dataPoints: Array<{ date: string; // ISO date string totalUsers: number; // Cumulative total users up to this date newUsers: number; // New users added in this period }>; currentTotal: number; // Total users as of now periodStart: string; // ISO date string of first data point periodEnd: string; // ISO date string of last data point } ``` **Example Response**: ```json { "dataPoints": [ { "date": "2026-03-11T00:00:00.000Z", "totalUsers": 100, "newUsers": 15 }, { "date": "2026-03-12T00:00:00.000Z", "totalUsers": 112, "newUsers": 12 }, { "date": "2026-03-13T00:00:00.000Z", "totalUsers": 125, "newUsers": 13 } ], "currentTotal": 125, "periodStart": "2026-03-11T00:00:00.000Z", "periodEnd": "2026-03-13T00:00:00.000Z" } ``` --- ### 2. Engagement Statistics **Description**: Track active vs inactive users with detailed content breakdown. Supports optional time series data. **Note**: Only counts URL cards (excludes NOTE and HIGHLIGHT cards). **Query Parameters**: - `type=engagement` (required) - `interval` (optional, default: `day`, used if `includeTimeSeries=true`) - `limit` (optional, default: 30, used if `includeTimeSeries=true`) - `includeTimeSeries` (optional, default: `false`) **Request Example (Snapshot)**: ```bash curl -X GET "http://localhost:3000/api/stats?type=engagement" \ -H "Authorization: Bearer YOUR_STATS_API_KEY" ``` **Request Example (With Time Series)**: ```bash curl -X GET "http://localhost:3000/api/stats?type=engagement&includeTimeSeries=true&interval=week&limit=12" \ -H "Authorization: Bearer YOUR_STATS_API_KEY" ``` **Response Schema**: ```typescript { // Snapshot data (always included) totalUsers: number; // Total registered users activeUsers: number; // Users who created any content inactiveUsers: number; // Users who signed in but created nothing // Activity breakdown usersWithCards: number; // Users who created URL cards usersWithCollections: number; // Users who created collections usersWithConnections: number; // Users who created connections usersWithFollows: number; // Users who followed targets usersWithContributions: number; // Users who added cards to others' collections // Engagement metrics activationRate: number; // activeUsers / totalUsers avgActionsPerActiveUser: number; // Average actions per active user // Optional time series data (only if includeTimeSeries=true) dataPoints?: Array<{ date: string; // ISO date string activeUsers: number; // Users activated in this period newlyActivatedUsers: number; // Previously inactive users who became active cumulativeActiveUsers: number; // Total active users up to this date }>; } ``` **Example Response (Snapshot)**: ```json { "totalUsers": 500, "activeUsers": 320, "inactiveUsers": 180, "usersWithCards": 280, "usersWithCollections": 150, "usersWithConnections": 90, "usersWithFollows": 200, "usersWithContributions": 45, "activationRate": 0.64, "avgActionsPerActiveUser": 12.5 } ``` **Example Response (With Time Series)**: ```json { "totalUsers": 500, "activeUsers": 320, "inactiveUsers": 180, "usersWithCards": 280, "usersWithCollections": 150, "usersWithConnections": 90, "usersWithFollows": 200, "usersWithContributions": 45, "activationRate": 0.64, "avgActionsPerActiveUser": 12.5, "dataPoints": [ { "date": "2026-03-01T00:00:00.000Z", "activeUsers": 25, "newlyActivatedUsers": 25, "cumulativeActiveUsers": 275 }, { "date": "2026-03-08T00:00:00.000Z", "activeUsers": 30, "newlyActivatedUsers": 30, "cumulativeActiveUsers": 305 }, { "date": "2026-03-15T00:00:00.000Z", "activeUsers": 15, "newlyActivatedUsers": 15, "cumulativeActiveUsers": 320 } ] } ``` --- ### 3. Activity Statistics **Description**: Track daily content creation volume across all content types. **Note**: Only counts URL cards (excludes NOTE and HIGHLIGHT cards). **Query Parameters**: - `type=activity` (required) - `interval` (optional, default: `day`) - `limit` (optional, default: 30) **Request Example**: ```bash curl -X GET "http://localhost:3000/api/stats?type=activity&interval=day&limit=7" \ -H "Authorization: Bearer YOUR_STATS_API_KEY" ``` **Response Schema**: ```typescript { dataPoints: Array<{ date: string; // ISO date string cardsCreated: number; // URL cards created in this period collectionsCreated: number; // Collections created in this period connectionsCreated: number; // Connections created in this period followsCreated: number; // Follows created in this period totalActions: number; // Sum of all above }>; totals: { cardsCreated: number; // Total across all periods collectionsCreated: number; // Total across all periods connectionsCreated: number; // Total across all periods followsCreated: number; // Total across all periods totalActions: number; // Sum of all totals } periodStart: string; // ISO date string of first data point periodEnd: string; // ISO date string of last data point } ``` **Example Response**: ```json { "dataPoints": [ { "date": "2026-04-08T00:00:00.000Z", "cardsCreated": 45, "collectionsCreated": 12, "connectionsCreated": 8, "followsCreated": 23, "totalActions": 88 }, { "date": "2026-04-09T00:00:00.000Z", "cardsCreated": 52, "collectionsCreated": 15, "connectionsCreated": 10, "followsCreated": 28, "totalActions": 105 }, { "date": "2026-04-10T00:00:00.000Z", "cardsCreated": 38, "collectionsCreated": 9, "connectionsCreated": 6, "followsCreated": 19, "totalActions": 72 } ], "totals": { "cardsCreated": 135, "collectionsCreated": 36, "connectionsCreated": 24, "followsCreated": 70, "totalActions": 265 }, "periodStart": "2026-04-08T00:00:00.000Z", "periodEnd": "2026-04-10T00:00:00.000Z" } ``` --- ### 4. Breakdown Statistics **Description**: Track content distribution by subtypes over time. Shows cumulative growth of different content categories. **Breakdowns**: - URL cards by `urlType` (article, video, tool, etc.) - Collections by `accessType` (OPEN, CLOSED) - Connections by `connectionType` (SUPPORTS, OPPOSES, unspecified) **Note**: Only counts URL cards (excludes NOTE and HIGHLIGHT cards). **Query Parameters**: - `type=breakdown` (required) - `interval` (optional, default: `day`) - `limit` (optional, default: 30) **Request Example**: ```bash curl -X GET "http://localhost:3000/api/stats?type=breakdown&interval=week&limit=4" \ -H "Authorization: Bearer YOUR_STATS_API_KEY" ``` **Response Schema**: ```typescript { dataPoints: Array<{ date: string; // ISO date string urlCards: { total: number; // Total URL cards at this date byType: Record; // Breakdown by urlType }; collections: { total: number; // Total collections at this date byAccessType: Record; // Breakdown by accessType }; connections: { total: number; // Total connections at this date byType: Record; // Breakdown by connectionType }; }>; currentTotals: { urlCards: { total: number; // Current total URL cards byType: Record; // Current breakdown by urlType } collections: { total: number; // Current total collections byAccessType: Record; // Current breakdown by accessType } connections: { total: number; // Current total connections byType: Record; // Current breakdown by connectionType } } periodStart: string; // ISO date string of first data point periodEnd: string; // ISO date string of last data point } ``` **Example Response**: ```json { "dataPoints": [ { "date": "2026-03-17T00:00:00.000Z", "urlCards": { "total": 450, "byType": { "article": 180, "video": 120, "tool": 90, "unspecified": 60 } }, "collections": { "total": 85, "byAccessType": { "OPEN": 60, "CLOSED": 25 } }, "connections": { "total": 120, "byType": { "SUPPORTS": 70, "OPPOSES": 30, "unspecified": 20 } } }, { "date": "2026-03-24T00:00:00.000Z", "urlCards": { "total": 520, "byType": { "article": 210, "video": 140, "tool": 105, "unspecified": 65 } }, "collections": { "total": 98, "byAccessType": { "OPEN": 72, "CLOSED": 26 } }, "connections": { "total": 145, "byType": { "SUPPORTS": 85, "OPPOSES": 38, "unspecified": 22 } } } ], "currentTotals": { "urlCards": { "total": 520, "byType": { "article": 210, "video": 140, "tool": 105, "unspecified": 65 } }, "collections": { "total": 98, "byAccessType": { "OPEN": 72, "CLOSED": 26 } }, "connections": { "total": 145, "byType": { "SUPPORTS": 85, "OPPOSES": 38, "unspecified": 22 } } }, "periodStart": "2026-03-17T00:00:00.000Z", "periodEnd": "2026-03-24T00:00:00.000Z" } ``` --- ## Error Responses All endpoints return standard error responses: **Validation Error** (400): ```json { "error": "Stat type is required" } ``` **Authentication Error** (401): ```json { "error": "Unauthorized" } ``` **Server Error** (500): ```json { "error": "Failed to retrieve user stats: " } ``` --- ## Implementation Notes ### Card Counting - **Important**: All card counts refer exclusively to URL cards - NOTE cards and HIGHLIGHT cards are excluded from all statistics - This applies to: engagement stats, activity stats, and breakdown stats ### Time Intervals - `day`: Data aggregated by calendar day - `week`: Data aggregated by calendar week (starts Monday) - `month`: Data aggregated by calendar month ### Data Points Ordering - All time series data is returned in **chronological order** (oldest to newest) - This makes it easy to render charts and track trends over time ### Performance - Queries are optimized with indexes on relevant columns - Large date ranges (limit > 100) may take longer to compute - Breakdown stats execute three queries in parallel for better performance ### Null Handling - Null values in `urlType` and `connectionType` are mapped to `"unspecified"` - This ensures consistent data structure in breakdown responses --- ## Common Use Cases ### Dashboard Overview Get current engagement snapshot: ```bash GET /api/stats?type=engagement ``` ### Growth Chart Get 90 days of user growth by week: ```bash GET /api/stats?type=growth&interval=week&limit=13 ``` ### Activity Heatmap Get daily activity for the past month: ```bash GET /api/stats?type=activity&interval=day&limit=30 ``` ### Content Distribution Trends Track content type growth over 6 months: ```bash GET /api/stats?type=breakdown&interval=month&limit=6 ``` ### Activation Funnel Get engagement with time series to track activation trends: ```bash GET /api/stats?type=engagement&includeTimeSeries=true&interval=week&limit=12 ```