Add API Reference

2026-03-21 07:27:19 +00:00
parent 5091eea00b
commit 8a984b3e89

237
API-Reference.md Normal file

@@ -0,0 +1,237 @@
# API Reference
Base URL: `http://localhost:8080/api/v1`
All request and response bodies are JSON. All endpoints return `Content-Type: application/json`.
---
## Health
### `GET /health`
Returns 200 if the database is reachable.
**Response:**
```json
{"status": "ok"}
```
Returns 503 if the database ping fails.
---
## Reference Data
Reference data (departments and GL accounts) must be created before budget lines or actuals, as they are foreign-key parents.
---
### Departments
#### `POST /departments`
Create a department.
**Request body:**
```json
{
"code": "ENG",
"name": "Engineering"
}
```
#### `GET /departments`
List all departments.
**Response:**
```json
[
{"id": 1, "code": "ENG", "name": "Engineering"},
{"id": 2, "code": "MKT", "name": "Marketing"}
]
```
#### `DELETE /departments/{id}`
Delete a department by ID.
---
### GL Accounts
#### `POST /gl-accounts`
Create a GL account.
**Request body:**
```json
{
"code": "6100",
"description": "Salaries & Wages",
"type": "headcount",
"favour_high": false
}
```
`favour_high` drives the favourability logic. Set to `true` for revenue accounts (higher actual = good), `false` for cost accounts (lower actual = good).
**Account types:** `revenue`, `cogs`, `opex`, `capex`, `headcount`
#### `GET /gl-accounts`
List all GL accounts.
#### `DELETE /gl-accounts/{id}`
Delete a GL account by ID.
---
## Budgets
#### `POST /budgets`
Create a budget line.
**Request body:**
```json
{
"department_id": 1,
"gl_account_id": 3,
"fiscal_year": 2024,
"fiscal_period": 9,
"version": "original",
"amount": 4200000,
"currency": "DKK",
"notes": "Headcount plan P09"
}
```
**Budget versions:** `original`, `forecast1`, `forecast2`, `forecast3`
#### `PUT /budgets/{id}`
Update a budget line's amount or notes.
**Request body:**
```json
{
"amount": 4350000,
"notes": "Revised after headcount change"
}
```
#### `DELETE /budgets/{id}`
Delete a budget line by ID.
---
## Actuals
#### `POST /actuals/ingest`
Upsert an actual. Idempotent by `(fiscal_year, fiscal_period, department_id, gl_account_id)` — posting the same period twice updates the amount rather than creating a duplicate.
**Request body:**
```json
{
"department_id": 1,
"gl_account_id": 3,
"fiscal_year": 2024,
"fiscal_period": 9,
"amount": 4380000,
"currency": "DKK",
"source": "SAP_EXPORT"
}
```
Designed to accept bulk ERP export feeds. POST each line individually or build a batch wrapper around the endpoint.
---
## Variance
### Query Parameters (both variance endpoints)
| Parameter | Example | Description |
|---|---|---|
| `year` | `2024` | Fiscal year (required) |
| `period` | `9` | Fiscal period 112 (required) |
| `dept` | `ENG` | Department code — omit to return all departments |
| `version` | `original` | Budget version (defaults to `original`) |
---
#### `GET /variance`
Full variance report for the given filters.
**Example:**
```
GET /api/v1/variance?year=2024&period=9&dept=ENG
```
**Response:**
```json
{
"department": "ENG",
"fiscal_year": 2024,
"fiscal_period": 9,
"version": "original",
"currency": "DKK",
"total_budget": 6740000,
"total_actual": 7074600,
"total_variance": -334600,
"total_variance_pct": -4.97,
"lines": [
{
"gl_code": "6100",
"gl_description": "Salaries & Wages",
"gl_type": "headcount",
"budget": 4200000,
"actual": 4380000,
"variance_abs": -180000,
"variance_pct": -4.29,
"status": "unfavourable",
"currency": "DKK"
},
{
"gl_code": "5000",
"gl_description": "Cloud Infrastructure",
"gl_type": "cogs",
"budget": 850000,
"actual": 791000,
"variance_abs": 59000,
"variance_pct": 6.94,
"status": "favourable",
"currency": "DKK"
}
]
}
```
`variance_abs` = actual budget. Positive means over-budget for costs, under-budget for revenue.
`status` is `"favourable"` or `"unfavourable"` based on the account's `favour_high` flag — see [Finance Concepts](Finance-Concepts).
---
#### `GET /variance/alerts`
Returns only the GL lines where absolute variance percentage exceeds the threshold.
**Additional query parameter:**
| Parameter | Example | Description |
|---|---|---|
| `threshold` | `15` | Alert threshold as a percentage (default: `10`) |
**Example:**
```
GET /api/v1/variance/alerts?year=2024&period=9&threshold=15
```
Returns the same line-level structure as the full variance report, filtered to lines where `abs(variance_pct) > threshold`.