# SPECIFICATIONS/06_API/06_06_ANALYTICS_ENDPOINTS.md

**PURPOSE:** Specifies the financial analytics API surface.

> **Performance strategy and caching:** `../03_ARCHITECTURE/03_PERFORMANCE_STRATEGY.md`
> **Time filter rules:** `../01_BUSINESS_CONTEXT/03_BUSINESS_RULES.md` → BR-007-1

---

## GET /api/v1/Analytics/kpis

**Permission:** `analytics.view`

**Inputs (Query Params):**

| Field | Type | Required | Validation |
|:---|:---|:---|:---|
| `from_date` | date (Y-m-d) | Yes | — |
| `to_date` | date (Y-m-d) | Yes | after_or_equal:from_date |
| `comparison_from_date` | date (Y-m-d) | Yes | — |
| `comparison_to_date` | date (Y-m-d) | Yes | after_or_equal:comparison_from_date |

**Outputs:**
```json
{
    "success": true,
    "message": "string",
    "data": {
        "executive_kpis": [
            {
                "key": "contract_signing",
                "value": 12,
                "value_type": "number",
                "change_percentage": 15.5,
                "direction": "up",
                "status": "good",
                "sparkline": [
                    {
                        "date": "2024-01-15",
                        "value": 3,
                        "value_type": "number"
                    }
                ]
            }
        ],
        "operational_kpis": [
            {
                "key": "payments_within_7_days",
                "value": "45000.00",
                "value_type": "day"
            }
        ]
    }
}
```

**Behavior:**
- **Executive KPIs** include comparison data (change_percentage, direction, status) and sparkline data points
- **Operational KPIs** are point-in-time values without comparison
- Executive KPI keys: `contract_signing`, `active_investments_value`, `avg_days_late`
- Operational KPI keys: `payments_within_7_days`, `payments_within_15_days`, `payments_within_30_days`
- Data source for executive KPIs: `daily_contract_metrics`, `daily_investment_metrics`, `daily_collection_metrics` (up to 24 hours stale)
- Data source for operational KPIs: live query from `installments` table
- Results cached with TTL-based expiration

**Errors:**

| Condition | Key | HTTP |
|:---|:---|:---|
| Invalid date range | `errors/analytics.invalid_date_range` | 422 |

---

## GET /api/v1/Analytics/charts

**Permission:** `analytics.view`

**Inputs (Query Params):**

| Field | Type | Required | Validation |
|:---|:---|:---|:---|
| `from_date` | date (Y-m-d) | Yes | — |
| `to_date` | date (Y-m-d) | Yes | after_or_equal:from_date |

**Outputs:**
```json
{
    "success": true,
    "message": "string",
    "data": {
        "installments_status_distribution": [
            {
                "status": "pending",
                "percentage": 35.5,
                "amount": "15000.00"
            },
            {
                "status": "collected",
                "percentage": 40.0,
                "amount": "16900.00"
            },
            {
                "status": "overdue",
                "percentage": 24.5,
                "amount": "10350.00"
            }
        ],
        "overdue_aging": [
            {
                "bucket": "1-15",
                "amount": "5000.00"
            },
            {
                "bucket": "16-30",
                "amount": "3000.00"
            },
            {
                "bucket": ">60",
                "amount": "2350.00"
            }
        ],
        "collection_trend": [
            {
                "date": "2024-01-15",
                "collected_amount": "4200.00",
                "overdue_amount": "1500.00"
            },
            {
                "date": "2024-01-16",
                "collected_amount": "3800.00",
                "overdue_amount": "0.00"
            }
        ]
    }
}
```

**Behavior:**
- **installments_status_distribution:** Live query categorizing installment amounts into `pending`, `collected`, `overdue`, and `scheduled`. Percentages calculated relative to total. Zero-amount categories are excluded.
- **overdue_aging:** Live query grouping overdue installments into time buckets: `1-15`, `16-30`, `31-45`, `46-60`, `>60` days late.
- **collection_trend:** Reads from `daily_collection_metrics` snapshot table. Returns daily collected and newly overdue amounts. Days with zero values in both fields are excluded.
- No caching — all data computed per request

**Errors:**

| Condition | Key | HTTP |
|:---|:---|:---|
| Invalid date range | `errors/analytics.invalid_date_range` | 422 |