Skip to main content
Restricted API

All FinOps endpoints require ANALYTICS_CORE_POLICY gating and tenant authentication. Only users with the platform_admin or sre role may access these endpoints. Accessible via the API gateway at /v1/finops/*.

FinOps Dashboard API

Manage infrastructure costs, predict cash drawer needs, generate dispute evidence, and detect ghost inventory.

Overview

The FinOps Dashboard API provides financial operations tooling across two domains: infrastructure cost management (GCP billing analysis powered by ClickHouse) and restaurant financial operations (cash prediction, dispute handling, inventory verification).

FeatureDescription
Cost Anomaly DetectionAnalyze GCP billing data against a 7-day baseline (20% threshold)
Cost SummaryAggregated cost breakdown by GCP service for up to 90 days
Cash PredictionPredict cash drawer and change order needs from 30 days of sales history
Dispute EvidenceAI-powered evidence package generation for payment disputes
Ghost InventoryVision AI comparison of physical shelf counts vs system inventory
Health CheckVerify ClickHouse connectivity status

Related Issues: #583 (Cost Anomaly Detection), Epic #819 (Cash Prediction), Epic #1475 (ClickHouse Migration)


Authentication and Authorization

All endpoints on the /finops router share two layers of protection:

LayerMechanismDetails
Gating PolicyANALYTICS_CORE_POLICYChecked via require_gating_policy dependency
Tenant AuthJWT Bearer tokenChecked via require_tenant_auth with scope="global"
RBAC Rolesplatform_admin, sreOnly these roles are permitted access

All requests must include a valid JWT:

Authorization: Bearer {access_token}

Detect Cost Anomalies

Trigger cost anomaly detection for a specific date. Analyzes GCP billing data and compares daily costs to the 7-day rolling baseline. Services with costs exceeding 20% of baseline are flagged as anomalies. This endpoint can be called by Cloud Scheduler (daily cron) or manually by SRE/platform admins.

Request

POST /api/v1/finops/cost-anomalies/detect
Authorization: Bearer {access_token}
Content-Type: application/json
{
"target_date": "2026-02-18",
"send_alerts": true
}

Request Body

FieldTypeRequiredDefaultDescription
target_datedate (ISO 8601)NoYesterdayDate to analyze
send_alertsbooleanNotrueWhether to send alerts for detected anomalies

Response (200)

{
"target_date": "2026-02-18",
"anomalies_found": 2,
"critical_count": 1,
"anomalies": [
{
"service": "Cloud Run",
"date": "2026-02-18",
"daily_cost": 184.50,
"baseline_cost": 120.00,
"percentage_increase": 53.8,
"severity": "critical"
},
{
"service": "Cloud Spanner",
"date": "2026-02-18",
"daily_cost": 95.20,
"baseline_cost": 78.00,
"percentage_increase": 22.1,
"severity": "warning"
}
],
"alerts_sent": true
}

Response Fields

FieldTypeDescription
target_datestringDate that was analyzed (ISO format)
anomalies_foundintegerTotal number of anomalies detected
critical_countintegerNumber of critical-severity anomalies
anomaliesarrayList of CostAnomalyResponse objects
alerts_sentbooleanWhether alerts were dispatched

Anomaly Severity Levels

SeverityThresholdDescription
warning20-49% above baselineCost increase worth investigating
critical50%+ above baselineRequires immediate attention

Get Cost Summary

Get aggregated cost summary by GCP service for a date range. Returns total costs, average daily costs, and min/max costs per service.

Request

GET /api/v1/finops/cost-summary?
start_date=2026-01-01&
end_date=2026-01-31
Authorization: Bearer {access_token}

Query Parameters

ParameterTypeRequiredDescription
start_datedateYesStart date for analysis (ISO 8601)
end_datedateYesEnd date for analysis (ISO 8601)

Constraints:

  • end_date must be greater than or equal to start_date
  • Date range cannot exceed 90 days

Response (200)

{
"start_date": "2026-01-01",
"end_date": "2026-01-31",
"total_cost": 4825.60,
"services": [
{
"service": "Cloud Run",
"total_cost": 2100.00,
"avg_daily_cost": 67.74,
"min_daily_cost": 45.20,
"max_daily_cost": 125.80,
"percentage_of_total": 43.5
},
{
"service": "Cloud Spanner",
"total_cost": 1450.30,
"avg_daily_cost": 46.78,
"min_daily_cost": 42.00,
"max_daily_cost": 55.10,
"percentage_of_total": 30.1
},
{
"service": "Cloud Storage",
"total_cost": 625.30,
"avg_daily_cost": 20.17,
"min_daily_cost": 18.50,
"max_daily_cost": 22.40,
"percentage_of_total": 13.0
},
{
"service": "Pub/Sub",
"total_cost": 350.00,
"avg_daily_cost": 11.29,
"min_daily_cost": 8.00,
"max_daily_cost": 18.50,
"percentage_of_total": 7.3
},
{
"service": "Cloud Logging",
"total_cost": 300.00,
"avg_daily_cost": 9.68,
"min_daily_cost": 7.50,
"max_daily_cost": 14.20,
"percentage_of_total": 6.2
}
]
}

Response Fields

FieldTypeDescription
start_datestringStart date of the analysis period
end_datestringEnd date of the analysis period
total_costfloatTotal cost in USD across all services
servicesarrayCost breakdown per GCP service

Health Check

Check if the FinOps service is healthy and ClickHouse is accessible. This endpoint verifies the ClickHouse connection used by cost anomaly detection (Epic #1475: ClickHouse Cloud replaces BigQuery for analytics).

Request

GET /api/v1/finops/health
Authorization: Bearer {access_token}

Response -- Healthy (200)

{
"status": "healthy",
"clickhouse": "connected"
}

Response -- Degraded (200)

{
"status": "degraded",
"clickhouse": "unavailable",
"message": "ClickHouse client not installed or configured"
}

Response -- Unhealthy (200)

{
"status": "unhealthy",
"clickhouse": "error",
"message": "Internal error occurred. Check logs for details."
}

Status Values

StatusMeaning
healthyClickHouse is connected and responding
degradedClickHouse client is not installed or configured; cost features unavailable
unhealthyConnection attempt failed; check service logs

Predict Cash Needs

Predict cash drawer float and change order needs for a location based on the last 30 days of historical sales data (Epic #819). Uses HQ Analytics Service to fetch daily sales metrics, then applies a prediction model to recommend drawer setup.

Request

POST /api/v1/finops/cash/predict
Authorization: Bearer {access_token}
Content-Type: application/json
{
"tenant_id": "550e8400-e29b-41d4-a716-446655449100",
"location_id": "550e8400-e29b-41d4-a716-446655449110"
}

Request Body

FieldTypeRequiredDescription
tenant_idstringYesTenant UUID
location_idstringYesLocation UUID

Response (200)

{
"recommended_float": 200.00,
"change_order_suggestion": {
"ones": 55,
"fives": 22,
"pennies": 50
},
"predicted_cash_sales": 550.00,
"confidence": 0.85
}

Response Fields

FieldTypeDescription
recommended_floatfloatRecommended starting cash drawer float in USD
change_order_suggestionobjectSuggested denomination breakdown (key = denomination, value = count)
predicted_cash_salesfloatPredicted total cash sales for the upcoming period in USD
confidencefloatModel confidence score (0.0 to 1.0). Returns 0.0 when no historical data is available

Generate Dispute Evidence

Generate an AI-powered evidence package for a payment dispute. This endpoint runs a LangGraph agent workflow that fetches transaction details from Stripe/PaymentService, retrieves audit logs from Spanner, analyzes win probability using AI, and produces a PDF evidence brief.

Request

POST /api/v1/finops/disputes/{dispute_id}/generate-evidence?
tenant_id=550e8400-e29b-41d4-a716-446655449100
Authorization: Bearer {access_token}

Path Parameters

ParameterTypeDescription
dispute_idstringThe dispute or payment ID to generate evidence for

Query Parameters

ParameterTypeRequiredDescription
tenant_idstringYesTenant UUID

Response (200)

{
"tenant_id": "550e8400-e29b-41d4-a716-446655449100",
"dispute_id": "dp_1234567890",
"transaction_data": {
"amount": 4599,
"currency": "usd",
"status": "succeeded",
"payment_method_details": {
"card": {
"brand": "visa",
"last4": "4242",
"present": true,
"emv_auth_data": "8A023030"
}
},
"created": "2026-02-10T14:30:00Z"
},
"audit_logs": [
{
"timestamp": "2026-02-10T14:29:55Z",
"action": "order_created",
"user_id": "550e8400-e29b-41d4-a716-446655449122"
},
{
"timestamp": "2026-02-10T14:30:00Z",
"action": "payment_captured",
"user_id": "550e8400-e29b-41d4-a716-446655449122"
}
],
"analysis": "Win Probability: High. Evidence: Card was present during transaction. EMV Chip was read (Liability Shift applies).",
"evidence_pdf_url": "https://storage.googleapis.com/olympus-disputes/dp_1234567890/evidence.pdf"
}

Response Fields

FieldTypeDescription
tenant_idstringTenant UUID
dispute_idstringDispute ID
transaction_dataobjectPayment transaction details fetched from Stripe
audit_logsarrayAudit log entries from Spanner for the transaction timeline
analysisstringAI-generated analysis including win probability and evidence summary
evidence_pdf_urlstringURL to the generated PDF evidence brief (GCS signed URL)

Agent Workflow

The dispute evidence generation follows a LangGraph state machine:

fetch_data --> analyze --> END
  1. fetch_data -- Retrieves payment details from Stripe/PaymentService
  2. analyze -- Evaluates card presence, EMV chip data, and liability shift rules to determine win probability (High, Medium, Low)

Detect Ghost Inventory

Detect discrepancies between system inventory records and physical counts using Vision AI. Captures a frame from a specified camera, runs shelf analysis via the Vision AI edge inference pipeline, and compares the count against the Commerce service inventory record.

Request

POST /api/v1/finops/ghost-inventory/detect?
tenant_id=550e8400-e29b-41d4-a716-446655449100&
camera_id=cam-kitchen-01&
item_type=coke_bottle
Authorization: Bearer {access_token}

Query Parameters

ParameterTypeRequiredDescription
tenant_idstringYesTenant UUID
camera_idstringYesCamera identifier to capture the frame from
item_typestringYesItem type to count (e.g., coke_bottle, cup_16oz)

Response (200)

{
"camera_id": "cam-kitchen-01",
"item_type": "coke_bottle",
"vision_count": 18,
"system_count": 24,
"discrepancy": 6,
"alert": true,
"timestamp": "2026-02-20T10:15:30Z"
}

Response Fields

FieldTypeDescription
camera_idstringCamera that was analyzed
item_typestringItem type that was counted
vision_countintegerNumber of items detected by Vision AI
system_countintegerNumber of items recorded in the system inventory
discrepancyintegerDifference: system_count - vision_count. Positive values indicate ghost inventory
alertbooleantrue if discrepancy exceeds the threshold (currently 2 units)
timestampstringTimestamp of the vision analysis

Error Cases

If the camera is not found or no frame is available, the endpoint returns:

{
"error": "Camera not found",
"camera_id": "cam-unknown"
}
{
"error": "No frame available",
"camera_id": "cam-kitchen-01"
}

Error Responses

All FinOps endpoints follow consistent error handling patterns.

Invalid Date Range (400)

{
"detail": "end_date must be greater than or equal to start_date"
}

Date Range Too Large (400)

{
"detail": "Date range cannot exceed 90 days"
}

ClickHouse Unavailable (503)

Returned when the ClickHouse backend is not available (Epic #1475). Cost anomaly detection and cost summary endpoints depend on ClickHouse connectivity.

{
"detail": "ClickHouse client not available. Ensure clickhouse-connect is installed."
}

Internal Server Error (500)

Internal errors are logged with full details but sanitized messages are returned to clients.

{
"detail": "Failed to detect anomalies. Please contact support if the issue persists."
}

Authorization Denied (403)

Returned when the caller does not have the platform_admin or sre role, or the tenant fails the ANALYTICS_CORE_POLICY gating check.

{
"detail": "Forbidden: insufficient permissions"
}

Data Models Reference

DetectAnomaliesRequest

FieldTypeRequiredDefaultDescription
target_datedateNoYesterdayDate to analyze (ISO 8601)
send_alertsbooleanNotrueSend alerts for detected anomalies

CostAnomalyResponse

FieldTypeDescription
servicestringGCP service name (e.g., "Cloud Run", "Cloud Spanner")
datestringDate of the anomaly (ISO format)
daily_costfloatActual daily cost in USD
baseline_costfloatExpected cost based on 7-day rolling baseline
percentage_increasefloatPercentage increase from baseline
severitystringAnomaly severity: warning or critical

CostSummaryResponse

FieldTypeDescription
start_datestringStart date of analysis
end_datestringEnd date of analysis
total_costfloatTotal cost in USD
servicesarrayCost breakdown by GCP service

CashPredictionRequest

FieldTypeRequiredDescription
tenant_idstringYesTenant UUID
location_idstringYesLocation UUID

CashPrediction (Response)

FieldTypeDescription
recommended_floatfloatRecommended starting drawer float (USD)
change_order_suggestionobjectDenomination breakdown (e.g., {"ones": 50, "fives": 20})
predicted_cash_salesfloatPredicted cash sales for the period (USD)
confidencefloatModel confidence (0.0 to 1.0)