InfraNotes Financial Intelligence · v0
Welcome
Select a document from the sidebar to read it.
Financial Intelligence — Release 0 Canonical API
- Jira:
INFT-70 - Source of truth: this file. Frozen contract for the Release 0 frontend cutover.
- Owner:
infranotes-financial-intelligence - Gateway entitlements:
business_financial,business_accounting - Tenant-aware: yes
- Idempotency-Key required on POST/PUT/PATCH/DELETE per gateway manifest
Authentication contract
- Issuer:
https://iam.staging.infranotes.io(staging) - Audiences:
infranotes-gateway,infranotes-intelligence - JWKS:
https://iam.staging.infranotes.io/.well-known/jwks.json - Trust profile: B (gateway-forwarded headers in production, direct JWT validation in local dev)
- Role mapping: see
internal/middleware/scope_mapping.go. Canonical IAM role-template names frominfranotes-iam/docs/contracts/jwt-claims.mdcovered:tenant_admin,finance_manager,accountant,analyst,admin,manager,user,premium,readonly.
Canonical route surface (/api/v1/intelligence/*)
The full backend surface is implemented and stable. The frontend Release 0 cutover only needs the subset listed under "Frontend-consumed" below; the rest is available for future product increments.
Budgets (32 routes)
POST /budgets
GET /budgets
GET /budgets/active
GET /budgets/code/{code}/lookup
GET /budgets/{budgetId}
GET /budgets/{budgetId}/usage
GET /budgets/{budgetId}/vs-actual
GET /budgets/{budgetId}/children
GET /budgets/{budgetId}/categories
GET /budgets/{budgetId}/allocations
GET /budgets/{budgetId}/commitments
GET /budgets/{budgetId}/alerts
GET /budgets/{budgetId}/revisions
GET /budgets/{budgetId}/revisions/compare
PUT /budgets/{budgetId}
DELETE /budgets/{budgetId}
POST /budgets/{budgetId}/categories
PUT /budgets/{budgetId}/categories/{catId}
DELETE /budgets/{budgetId}/categories/{catId}
POST /budgets/{budgetId}/allocations
PUT /budgets/{budgetId}/allocations/{allocId}
DELETE /budgets/{budgetId}/allocations/{allocId}
POST /budgets/{budgetId}/revisions
PUT /budgets/{budgetId}/alerts/settings
POST /budgets/{budgetId}/alerts/{alertId}/acknowledge
POST /budgets/{budgetId}/request-approval
POST /budgets/{budgetId}/renew
POST /budgets/{budgetId}/reserve
POST /budgets/{budgetId}/availability
GET /budgets/reservations/{reservationId}
POST /budgets/reservations/{reservationId}/release
POST /budgets/reservations/{reservationId}/spend
Dashboard (2 routes)
GET /dashboard
GET /dashboard/summary
Analytics (11 routes)
GET /analytics/summary
GET /analytics/summary/compare
GET /analytics/summary/categories
GET /analytics/summary/vendors
GET /analytics/summary/departments
GET /analytics/trends
GET /analytics/trends/significant
GET /analytics/anomalies
GET /analytics/recurring
PUT /analytics/anomalies/{anomalyId}/resolve
POST /analytics/refresh
Forecasts (7 routes)
GET /forecasts
GET /forecasts/overall
GET /forecasts/category/{id}
GET /forecasts/vendor/{name}
GET /forecasts/department/{id}
GET /forecasts/accuracy
POST /forecasts/regenerate
Cash Flow (7 routes)
GET /cashflow/predictions
GET /cashflow/snapshot
GET /cashflow/alerts
GET /cashflow/recommendations
GET /cashflow/recurring
PUT /cashflow/alerts/{alertId}/acknowledge
PUT /cashflow/recommendations/{recId}/status
GET /cashflow/snapshot returns 200 with the canonical {data, meta} envelope. Tenants that have not generated a snapshot yet receive a zero-state payload — data.id == "00000000-0000-0000-0000-000000000000", data.current_balance == 0, projection fields omitted, data.tenant_id echoes the caller. Frontend cashflow callers can render a stable shape without branching on 404. Earlier behaviour returned 404 NOT_FOUND for this case; that contract was changed for Release 0 to align with how other FI list/aggregate endpoints serialize empty results.
Planning — Goals (10 routes)
POST /goals
GET /goals
GET /goals/{goalId}
PUT /goals/{goalId}
DELETE /goals/{goalId}
GET /goals/{goalId}/milestones
POST /goals/{goalId}/milestones
PUT /goals/{goalId}/milestones/{mid}
GET /goals/{goalId}/progress
POST /goals/{goalId}/contributions
Planning — Scenarios (13 routes)
POST /scenarios
GET /scenarios
GET /scenarios/compare
POST /scenarios/compare
GET /scenarios/{scenarioId}
PUT /scenarios/{scenarioId}
DELETE /scenarios/{scenarioId}
GET /scenarios/{scenarioId}/projections
GET /scenarios/{scenarioId}/risk
POST /scenarios/{scenarioId}/calculate
POST /scenarios/{scenarioId}/items
PUT /scenarios/{scenarioId}/items/{itemId}
DELETE /scenarios/{scenarioId}/items/{itemId}
Planning — Planned Expenses (6 routes)
POST /planned-expenses
GET /planned-expenses
PUT /planned-expenses/{expenseId}
DELETE /planned-expenses/{expenseId}
POST /planned-expenses/{expenseId}/reminders
GET /planned-expenses/{expenseId}/reminders
Suggestions (5 routes)
GET /suggestions
GET /suggestions/top
GET /suggestions/{suggestionId}
PUT /suggestions/{suggestionId}/status
POST /suggestions/generate
Frontend-consumed canonical paths (Release 0 critical surface)
The contract test in internal/handler/canonical_routes_test.go pins this list. Renaming or removing any of these paths requires updating the test, this doc, and the frontend handoff together.
GET /api/v1/intelligence/budgets
POST /api/v1/intelligence/budgets
GET /api/v1/intelligence/budgets/{budgetId}
PUT /api/v1/intelligence/budgets/{budgetId}
GET /api/v1/intelligence/budgets/{budgetId}/categories
POST /api/v1/intelligence/budgets/{budgetId}/categories
PUT /api/v1/intelligence/budgets/{budgetId}/categories/{catId}
GET /api/v1/intelligence/goals
POST /api/v1/intelligence/goals
GET /api/v1/intelligence/goals/{goalId}
PUT /api/v1/intelligence/goals/{goalId}
GET /api/v1/intelligence/goals/{goalId}/milestones
POST /api/v1/intelligence/goals/{goalId}/milestones
PUT /api/v1/intelligence/goals/{goalId}/milestones/{mid}
GET /api/v1/intelligence/planned-expenses
POST /api/v1/intelligence/planned-expenses
PUT /api/v1/intelligence/planned-expenses/{expenseId}
DELETE /api/v1/intelligence/planned-expenses/{expenseId}
GET /api/v1/intelligence/scenarios
POST /api/v1/intelligence/scenarios
GET /api/v1/intelligence/scenarios/{scenarioId}
PUT /api/v1/intelligence/scenarios/{scenarioId}
DELETE /api/v1/intelligence/scenarios/{scenarioId}
POST /api/v1/intelligence/scenarios/{scenarioId}/calculate
POST /api/v1/intelligence/scenarios/{scenarioId}/items
PUT /api/v1/intelligence/scenarios/{scenarioId}/items/{itemId}
DELETE /api/v1/intelligence/scenarios/{scenarioId}/items/{itemId}
GET /api/v1/intelligence/scenarios/compare
POST /api/v1/intelligence/scenarios/compare
GET /api/v1/intelligence/cashflow/predictions
GET /api/v1/intelligence/cashflow/snapshot
GET /api/v1/intelligence/cashflow/alerts
GET /api/v1/intelligence/cashflow/recommendations
GET /api/v1/intelligence/cashflow/recurring
PUT /api/v1/intelligence/cashflow/alerts/{alertId}/acknowledge
PUT /api/v1/intelligence/cashflow/recommendations/{recId}/status
Release 3 frontend-consumed addition
Working-capital intelligence was intentionally out of scope for the Release 0 cutover. Release 3 promotes this read surface into the frontend-consumed canonical contract and pins it in internal/handler/canonical_routes_test.go.
GET /api/v1/intelligence/working-capital/summary
The endpoint uses the standard {data, meta} envelope. Query parameters are optional: start_date and end_date use YYYY-MM-DD, and entity_id filters by UUID. Empty tenants receive zero AR/AP aging summaries, unavailable cash-conversion and forecast-variance states, and freshness rows showing missing source facts rather than an error response.
Release 4 dashboard freshness addition
The existing dashboard routes remain unchanged:
GET /api/v1/intelligence/dashboard
GET /api/v1/intelligence/dashboard/summary
Both responses now include first-class freshness metadata in data.freshness, plus data.degraded and data.degraded_reasons. Freshness rows use source, state, observed_count, latest_at, and age_seconds; state is fresh, stale, or missing. stale means the source's latest_at is older than 72 hours (age_seconds > 259200).
Release 5 migration-validation addition
Financial Intelligence exposes a read-only reconciliation surface for Release 5 migration validation dashboards:
GET /api/v1/intelligence/migration-validation/reconciliation
The endpoint uses the standard {data, meta} envelope and requires intelligence:analytics:view. Query parameters are optional: start_date and end_date use YYYY-MM-DD, and entity_id filters working-capital facts by UUID. data.facts contains decimal amount strings or integer counts for analytics, budget, cashflow, and working-capital sources. data.freshness, data.degraded, and data.degraded_reasons follow the Release 4 freshness semantics above.
Legacy frontend paths still in use (FE migration backlog)
The frontend currently calls these legacy paths in addition to the canonical ones above. The gateway manifest preserves them with a sunset of 2026-07-31. The frontend cutover (INFT-66) replaces them with the canonical equivalents listed above.
# Budgets — replace with canonical /api/v1/intelligence/budgets/*
GET /api/planning/budgets/active
GET /api/planning/budgets/{id}/progress
PUT /api/planning/budgets/{id}/progress/update
GET /api/planning/budgets/{budgetId}/categories/{categoryId}/progress
GET /api/planning/budgets/{id}/impact-projection
# Goals — replace with canonical /api/v1/intelligence/goals/*
GET /api/goals/active
GET /api/goals/{goalId}/contributions
GET /api/goals/{goalId}/analysis/progress
GET /api/goals/{goalId}/analysis/required-contribution
GET /api/goals/{goalId}/analysis/projected-completion
GET /api/goals/recommendations
# Planned expenses — replace with canonical /api/v1/intelligence/planned-expenses/*
PUT /api/planning/expenses/{id}/paid
GET /api/planning/expenses/upcoming
GET /api/planning/expenses/overdue
GET /api/planning/expenses/recurring
GET /api/planning/expenses/category/{categoryId}
GET /api/planning/expenses/statistics
GET /api/planning/expenses/notifications
# Scenarios — replace with canonical /api/v1/intelligence/scenarios/{id}/calculate
POST /api/planning/scenarios/{scenarioId}/calculate
# Cash flow — replace with canonical /api/v1/intelligence/cashflow/*
POST /api/cashflow/predictions/generate
GET /api/cashflow/predictions/{id}
POST /api/cashflow/alerts/generate
GET /api/cashflow/alerts/{id}
PUT /api/cashflow/alerts/{id}/resolve
POST /api/cashflow/recurring/detect
GET /api/cashflow/recurring/upcoming
GET /api/cashflow/recurring/{id}
GET /api/cashflow/rules
GET /api/cashflow/rules/{id}
PUT /api/cashflow/recommendations/{id}/dismiss
PUT /api/cashflow/recommendations/{id}/implement
POST /api/cashflow/snapshots/generate
GET /api/cashflow/snapshots/{date}
Out of scope for Release 0
- Working-capital intelligence, forecast-accuracy scoring depth, variance explanations, persona packs (per Jira INFT-70 scope: targeted at later release waves).
- Frontend implementation. The FI role of this document is to freeze the contract; FE migration is owned by
INFT-66. - Workload-token / signed gateway header hardening (Profile B follow-up, ADR-0003).
Acceptance evidence
Required gate checks for the Release 0 readiness slice:
- canonical IAM role
tenant_adminresolves to the full intelligence permission set (covered byinternal/middleware/scope_mapping_test.go). - one authenticated happy path against a frontend-consumed read endpoint via the gateway.
- one negative path: missing token returns
401. - contract test
TestCanonicalRoutesAreMountedpasses.
Evidence appended to the workspace TEST_LOG.md and RELEASE_0_HANDOFF_SUMMARY.md.