Add API Reference
237
API-Reference.md
Normal file
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 1–12 (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`.
|
||||||
Reference in New Issue
Block a user