API
API¶
This project provides a FastAPI-based HTTP interface so the solver can be used without the CLI.
Web Frontend
A full-featured web application that consumes this API is available: StaffSchedulingWeb. It provides a graphical interface for all API operations described below, including real-time solver progress monitoring and interactive solution inspection. See Web Interface for details.
Start the API¶
uv run staff-scheduling-api
By default the API runs on:
http://127.0.0.1:8000
Interactive API docs:
- Swagger UI:
http://127.0.0.1:8000/docs - ReDoc:
http://127.0.0.1:8000/redoc
Endpoints¶
GET /status¶
Returns the current solver state. This endpoint is useful for monitoring progress from a frontend or another automation script without blocking on the solver request.
The phase field reflects the internal solver step which helps
present a progress bar. The strings are emitted directly from the
solver and should be interpreted as follows:
idle– no solver is runningphase_1_upper_bound– first pass to compute an upper bound on hidden employees (fast, relaxes staffing constraints)phase_2_tight_bound– second pass tuning hidden-employee counts to a tight boundphase_3_optimizing– main optimization/search phase (respects thetimeoutparameter)
Example response:
{
"is_solving": false,
"phase": "idle",
"timeout_set_for_phase_3": 0
}
Additional properties during a multi-solve run:
weight_id– index of the current weight configurationtotal_weights– number of iterations planned
POST /fetch¶
Exports planning data from TimeOffice to local case JSON files.
Request body:
{
"planning_unit": 77,
"from_date": "2024-11-01",
"till_date": "2024-11-30"
}
Response:
{
"success": true,
"log": "...captured log output...",
"stdout": "...captured console output...",
"console_output": "...combined stdout+log..."
}
success is always true when the request completes without errors; any
failure will raise an HTTP 500 error with a message.
POST /solve¶
Runs one solver execution for the given planning period.
The response now includes the full processed solution dictionary, which
is needed by the frontend and may be passed back later to /insert or
/delete.
Request body:
{
"unit": 77,
"start_date": "2024-11-01",
"end_date": "2024-11-30",
"timeout": 300
}
Response:
{
"success": true,
"status": "OPTIMAL",
"solution_data": { /* huge JSON object generated by process_solution */ },
"log": "...captured log output...",
"stdout": "...captured console output...",
"console_output": "...combined stdout+log..."
}
success is true when the solver returns FEASIBLE or OPTIMAL;
otherwise it is false and status holds the actual OR-Tools return code
(e.g. INFEASIBLE, UNKNOWN). The solution_data field is null if no
solution was produced.
The console_output field concatenates both stdout and log streams for
simpler consumption by the frontend (especially when displaying the raw
solver debug output).
POST /solve-multiple¶
Runs three solver executions with different weight presets. Each run now returns its own status and (when available) the processed solution data.
Request body:
{
"unit": 77,
"start_date": "2024-11-01",
"end_date": "2024-11-30",
"timeout": 300
}
Response:
{
"success": true,
"results": [
{
"weight_id": 0,
"status": "OPTIMAL",
"solution_data": { /* dict */ }
},
{
"weight_id": 1,
"status": "FEASIBLE",
"solution_data": { /* dict */ }
},
{
"weight_id": 2,
"status": "INFEASIBLE",
"solution_data": null
}
],
"log": "...captured log output...",
"stdout": "...captured console output...",
"console_output": "...combined stdout+log..."
}
Each object in results contains:
weight_id– zero-based index of the weight configurationstatus– OR-Tools return code for that iterationsolution_data– full processed solution dict ornullif the run produced no valid solution
success becomes true if any of the iterations returned
FEASIBLE or OPTIMAL. The console_output field is the concatenated
text from both stdout and log streams.
POST /insert¶
Inserts a previously generated solution into the TimeOffice database. The
body may include solution_data obtained from a previous /solve or
/solve-multiple call; when provided the API will use that payload directly
instead of reading files from disk.
Request body:
{
"planning_unit": 77,
"from_date": "2024-11-01",
"till_date": "2024-11-30",
"solution_data": { /* optional dict from solver */ }
}
Response:
{
"success": true,
"log": "...captured log output...",
"stdout": "...captured console output...",
"console_output": "...combined stdout+log..."
}
solution_data can be omitted; when present the import will bypass the
filesystem entirely. success remains true on normal completion; errors
return HTTP 500.
POST /delete¶
Deletes a previously inserted solution from the TimeOffice database. Like
/insert, you may supply solution_data to perform the deletion without any
disk IO (useful for stateless frontend workflows).
Request body:
{
"planning_unit": 77,
"from_date": "2024-11-01",
"till_date": "2024-11-30",
"solution_data": { /* optional dict from solver */ }
}
Response:
{
"success": true,
"log": "...captured log output...",
"stdout": "...captured console output...",
"console_output": "...combined stdout+log..."
}
Typical API Workflow¶
POST /fetchPOST /solveorPOST /solve-multiple- Poll
GET /statuswhile solving POST /insertto write the selected solution to TimeOffice- Optional:
POST /deleteto revert inserted solution data
Using the Web Interface
All of these steps can be performed through the StaffSchedulingWeb graphical interface, which handles API calls, status polling, and result display automatically.