HTTP API
The solver contract, version 0.2.0: every operation of the solver service with its request and response bodies. Generated from the published OpenAPI contract.
Preview
POST /api/v1/feasibility/check#
Run the manifest's pre-solve checks through the solve contract. The same function the embedded runtime's ``check_feasibility`` calls. ``feasible`` is false exactly when a declared check fails; the failed checks are named in ``issues`` with the demand, supply and deficit, and ``contract.suggestions`` gives the smallest changes they prove necessary. Problem types with no declared checks are a typed 422.
Request body: FeasibilityCheckRequest
| Status | Meaning | Body |
200 | Successful Response | FeasibilityCheckResponse |
422 | The request cannot be solved as submitted: missing inputs (missing_problem_data), an option the solve contract does not accept (unsupported_option), a problem type it has no answer for (unsupported_problem_type), a malformed repair request, or a structurally infeasible problem (rostering_structurally_infeasible, with named shortfalls and any ranked alternates). A body that is not a solve request at all returns the request-validation shape. | SolveFailureEnvelope | RequestValidationFailure |
503 | The solver engine or a dependency is unavailable (engine_unavailable: a requested engine is not installed in this deployment); retrying later may succeed. | SolveFailureEnvelope |
POST /api/v1/feasibility/check-quick#
The same checks as ``/feasibility/check``, in a compact answer (the body is the problem).
Request body: object
| Status | Meaning | Body |
200 | Successful Response | QuickFeasibilityResponse |
422 | The request cannot be solved as submitted: missing inputs (missing_problem_data), an option the solve contract does not accept (unsupported_option), a problem type it has no answer for (unsupported_problem_type), a malformed repair request, or a structurally infeasible problem (rostering_structurally_infeasible, with named shortfalls and any ranked alternates). A body that is not a solve request at all returns the request-validation shape. | SolveFailureEnvelope | RequestValidationFailure |
503 | The solver engine or a dependency is unavailable (engine_unavailable: a requested engine is not installed in this deployment); retrying later may succeed. | SolveFailureEnvelope |
GET /api/v1/health#
Shallow liveness for THIS process only. This endpoint used to call the GPU worker's /health on every request. It is public and it is polled, so each poll cold-started an L4 and Cloud Run then held it for ~15 minutes — meaning a liveness check kept an accelerator billing around the clock. Measured 2026-08-19: 100% of worker traffic was GET /health from this fan-out, ~1280 requests/day, holding the GPU 12+ hours/day for zero solves. A liveness probe must never wake an accelerator. Worker status now comes from the explicit deep check at /api/v1/health/gpu/aws-sqs-ec2, and even that is cached (see _worker_health).
| Status | Meaning | Body |
200 | Successful Response | object |
POST /api/v1/recommendations/{problem_type}#
Recommendations from the solver's own advice (``solve_contract.recommend``). ``parameters``: the smallest parameter changes the pre-solve checks prove necessary (empty when nothing fails). ``constraints``: each constraint's gate/hard/soft class and where it is enforced. ``data``: missing inputs and the declared defaults in effect.
| Parameter | In | Required | Type | Description |
problem_type | path | Yes | string | |
Request body: RecommendationRequest
| Status | Meaning | Body |
200 | Successful Response | RecommendationsResponse |
422 | The request cannot be solved as submitted: missing inputs (missing_problem_data), an option the solve contract does not accept (unsupported_option), a problem type it has no answer for (unsupported_problem_type), a malformed repair request, or a structurally infeasible problem (rostering_structurally_infeasible, with named shortfalls and any ranked alternates). A body that is not a solve request at all returns the request-validation shape. | SolveFailureEnvelope | RequestValidationFailure |
503 | The solver engine or a dependency is unavailable (engine_unavailable: a requested engine is not installed in this deployment); retrying later may succeed. | SolveFailureEnvelope |
GET /api/v1/recommendations/{problem_type}/types#
Recommendation Types
| Parameter | In | Required | Type | Description |
problem_type | path | Yes | string | |
GET /api/v1/solve/{job_id}#
Job Status
| Parameter | In | Required | Type | Description |
job_id | path | Yes | string | |
POST /api/v1/solve/{problem_type}#
Solve
| Parameter | In | Required | Type | Description |
problem_type | path | Yes | string | |
Request body: ApiSolveRequest
| Status | Meaning | Body |
200 | The solve result | HostedSolveResponse |
422 | The request cannot be solved as submitted: missing inputs (missing_problem_data), an option the solve contract does not accept (unsupported_option), a problem type it has no answer for (unsupported_problem_type), a malformed repair request, or a structurally infeasible problem (rostering_structurally_infeasible, with named shortfalls and any ranked alternates). A body that is not a solve request at all returns the request-validation shape. | SolveFailureEnvelope | RequestValidationFailure |
503 | The solver engine or a dependency is unavailable (engine_unavailable: a requested engine is not installed in this deployment); retrying later may succeed. | SolveFailureEnvelope |
GET /api/v1/version#
Version
| Status | Meaning | Body |
200 | Successful Response | object |
Schemas#
ApiSolveRequest#
| Field | Type | Required | Description |
context | object | null | No | Admitted invocation context (single-lane execution) |
options | object | No | |
problem | object | No | |
solver | object | No | |
FeasibilityCheckRequest#
Pre-solve check request. ``problem.problem_type`` names the problem type.
| Field | Type | Required | Description |
enabled_constraints | array of string | null | No | |
problem | object | Yes | The problem, with problem_type (vrp or rostering) |
FeasibilityCheckResponse#
Pre-solve checks computed by the solver's own code. ``feasible`` is false exactly when a fail-severity check fails; true means no declared check found a blocker, which does not prove a plan exists. ``contract`` is the typed report, identical in the embedded model.
| Field | Type | Required | Description |
analysis_time_ms | integer | Yes | |
analyzers_run | array of object | Yes | |
confidence | number | null | No | 1.0 when a failed check certifies infeasibility; null otherwise |
constraint_quality | object | Yes | |
contract | FeasibilityReport | Yes | |
feasible | boolean | Yes | |
issues | array of FeasibilityIssue | Yes | |
problem_type | string | Yes | |
summary | string | Yes | |
warnings | array of FeasibilityIssue | Yes | |
FeasibilityIssue#
| Field | Type | Required | Description |
code | string | Yes | |
details | object | No | |
message | string | Yes | |
severity | error | warning | Yes | |
FeasibilityReport#
Pre-solve checks. They are necessary conditions: passing proves no plan exists.
| Field | Type | Required | Description |
checks_run | integer | Yes | |
contract_version | string | No | |
findings | array of object | Yes | |
model | hosted | embedded | Yes | |
note | string | Yes | |
problem_type | string | Yes | |
shortfalls | array of object | Yes | |
skipped | array of object | Yes | |
structurally_infeasible | boolean | Yes | |
suggestions | array of object | Yes | |
totals | object | Yes | |
verdict | infeasible | no_blocker_found | Yes | |
HTTPValidationError#
HostedSolveResponse#
A completed or queued solve. ``contract`` is the solve-contract answer for contract problem types (vrp, rostering): the same shape the embedded model returns. Other fields are the service's legacy envelope.
| Field | Type | Required | Description |
contract | SolveOutcome | null | No | Solve-contract answer (verdict, plan only when feasible, shortfalls, alternates, certificate, metadata) |
job_id | string | null | No | |
objective_value | number | null | No | |
result | object | null | No | |
solution | object | null | No | The plan; null when the verdict is infeasible |
solver_used | string | null | No | |
status | string | Yes | completed, queued, running, or failed |
QuickFeasibilityResponse#
| Field | Type | Required | Description |
contract | FeasibilityReport | Yes | |
feasible | boolean | Yes | |
reason | string | Yes | |
suggestions | array of object | Yes | |
RecommendationRequest#
| Field | Type | Required | Description |
problem | object | null | No | The problem; the body itself is read as the problem when absent |
recommendation_type | parameters | constraints | data | No | |
RecommendationTypesResponse#
| Field | Type | Required | Description |
problem_type | string | Yes | |
supported | boolean | Yes | |
types | array of string | Yes | |
Recommendations#
Parameter changes the pre-solve checks prove necessary, and constraint classes.
| Field | Type | Required | Description |
contract_version | string | No | |
model | hosted | embedded | Yes | |
problem_type | string | Yes | |
recommendation_type | parameters | constraints | data | Yes | |
recommendations | array of object | Yes | |
source | string | Yes | |
RecommendationsResponse#
| Field | Type | Required | Description |
contract | Recommendations | Yes | |
metadata | object | Yes | |
recommendations | array of object | Yes | |
success | boolean | Yes | |
RequestValidationFailure#
FastAPI request-shape validation error (the body is not a solve request).
| Field | Type | Required | Description |
detail | array of object | Yes | |
RosteringShortfall#
One named shortfall found by the pre-solve marginal feasibility checks.
| Field | Type | Required | Description |
check_id | string | Yes | Declared feasibility check that failed |
check_type | string | null | No | Executor type of the check |
deficit_hours | number | null | No | demand_hours - supply_hours |
demand_hours | number | null | No | Hours of coverage the slice demands |
message | string | null | No | Human-readable explanation of the shortfall |
scope | string | null | No | What the check slices demand and supply by |
slice | object | No | The slice that cannot be staffed (e.g. a location, a day, a skill) |
supply_hours | number | null | No | Hours the eligible staff can supply to the slice |
SolveFailureEnvelope#
Typed failure body of a solve. Status tells the caller what kind of failure it is: * **422** - the request cannot be solved as submitted: inputs are missing (``missing_problem_data``, with ``missing_inputs``), a repair request is malformed, or the problem is structurally infeasible (``rostering_structurally_infeasible``, with the named ``shortfalls`` and any ranked ``alternates``). Retrying the same request fails the same way. * **503** - the engine or a dependency is unavailable (e.g. ``rostering_solver_unavailable``). Retrying later may succeed.
| Field | Type | Required | Description |
alternates | array of object | null | No | Ranked best-effort alternates, when an engine ran. Empty when the solve stopped before any engine ran (see alternates_unavailable_reason). |
alternates_unavailable_reason | string | null | No | Why alternates is empty |
detail | string | null | No | Human-readable failure description |
failure_code | string | Yes | Typed failure code |
missing_inputs | array of string | null | No | Input fields that are missing or invalid (missing_problem_data) |
problem_type | string | null | No | |
report | object | null | No | Full pre-solve feasibility report, when one produced the failure |
shortfalls | array of RosteringShortfall | null | No | Named shortfalls behind rostering_structurally_infeasible (fail-severity findings of the pre-solve checks) |
solver_used | string | null | No | |
solver_version | object | null | No | Build stamp of the solver that answered |
status | string | Yes | 'failed' or 'unsupported' |
Which model served the solve, which engine ran, and what it cost.
| Field | Type | Required | Description |
budget_seconds | number | null | Yes | |
contract_version | string | No | |
cost_unit | string | Yes | |
engine | string | null | Yes | Dotted name of the engine that produced the answer; None when no engine ran (the pre-solve checks certified the problem infeasible). |
engine_reason | string | Yes | |
engine_requested | string | Yes | |
final_cost | number | null | Yes | |
model | hosted | embedded | Yes | |
problem_type | string | Yes | |
seed | integer | null | Yes | |
seed_cost | number | null | Yes | Cost of the construction seed, for comparison. |
solvers_version | string | Yes | |
wall_seconds | number | Yes | |
SolveOutcome#
The answer to one solve, identical in shape in both models.
| Field | Type | Required | Description |
alternates | array of object | No | |
certificate | object | Yes | |
contract_version | string | No | |
cost | number | null | Yes | |
metadata | SolveMetadata | Yes | |
not_enforced | array of string | No | |
problem_type | string | Yes | |
shortfalls | array of object | No | |
solution | object | null | Yes | The plan (routes or roster). Present only when the verdict is feasible. |
verdict | feasible | infeasible | Yes | |
ValidationError#
| Field | Type | Required | Description |
loc | array of string | integer | Yes | |
msg | string | Yes | |
type | string | Yes | |