Skip to content

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 running
  • phase_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 bound
  • phase_3_optimizing – main optimization/search phase (respects the timeout parameter)

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 configuration
  • total_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 configuration
  • status – OR-Tools return code for that iteration
  • solution_data – full processed solution dict or null if 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

  1. POST /fetch
  2. POST /solve or POST /solve-multiple
  3. Poll GET /status while solving
  4. POST /insert to write the selected solution to TimeOffice
  5. Optional: POST /delete to 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.