Skip to content

Query endpoints

Query endpoints answer the four Advisory questions and a few related flavors. Each takes a state context (persisted via token, or supplied inline) plus a target, and returns an academic_result (or array thereof).

All are POST, all share the same overall request shape, all return the standard envelope.

State modes

Every query request includes a state_mode:

{
"state_mode": "persisted", // use the token's stored state
"targets": { ... }
}

or:

{
"state_mode": "supplied",
"student_state": { ... }, // inline state, not persisted
"targets": { ... }
}

persisted requires the Authorization header. supplied does not — useful for stateless exploration and the what-if flow.

The shared response shape

Each academic_result in the response carries:

{
"target": { "kind": "course", "course_code": "MATH 247" },
"status": "partial",
"completeness": "all_subrules_evaluated",
"explanation_tree": { ... },
"missing_options": [
{ "course_code": "MATH 137", "source_reference_id": "sref_..." }
],
"unknowns": [
{ "unknown_reason": "unparsed_requirement", "source_reference_id": "sref_..." }
],
"conflicts": [],
"assumptions": [],
"source_reference_ids": [ "sref_...", ... ]
}

Statuses are the six-state taxonomy. Engine native states (engine_unknown, engine_timeout, engine_unsat) are never present here — they’re mapped through ADR 0018.

Endpoint surface

POST /api/v1/query/course-unlock

“What am I missing to take this course?”

Targets: { "course_codes": ["MATH 247", ...] }. Returns one academic_result per requested course.

POST /api/v1/query/course-impact

“What does taking this course unlock?”

Targets: { "course_codes": [...] } plus the courses to evaluate against (typically your full Kanban). Returns the set of downstream courses and credentials whose status would change if the target were added.

POST /api/v1/query/credential-progress

“What am I missing for this credential?”

Targets: { "credential_ids": ["credential:math_minor", ...] }. Returns one academic_result per credential with the full requirement tree evaluated against state.

POST /api/v1/query/credential-gap-summary

A flatter variant of credential-progress. Returns just the missing courses and unresolved subrules per credential — useful when you want “how many courses am I short?” without the full explanation tree.

POST /api/v1/query/what-if

Evaluate an arbitrary hypothetical state change against a target, without mutating persisted state. The request body accepts inline state changes inside evaluation_problem:

{
"state_mode": "persisted",
"evaluation_problem": {
"added_courses": [{ "course_code": "CO 250", "status": "planned" }],
"removed_courses": []
},
"targets": { "course_codes": ["CO 351"] }
}

The hypothetical is a one-shot — your persisted state is unchanged.

POST /api/v1/query/advisory

The umbrella Advisory endpoint. Accepts a free-form request describing which of the four questions you want answered, against which target, under what bounds. Returns a structured aggregate of the four underlying queries.

The frontend widget uses this when the user types a question; it dispatches to the right underlying query based on intent.

Bounded enumeration

Endpoints that enumerate alternative paths (notably advisory and credential-gap-summary) are bounded. Truncation is reported via the graph_view_truncated-style warnings in the envelope. See Graph views for the bound numerics — they’re shared.

Concrete examples

Terminal window
# What am I missing for CO 351?
curl -X POST https://uwwoe.fyi/api/v1/query/course-unlock \
-H 'Authorization: Bearer <token>' \
-H 'Content-Type: application/json' \
-d '{"state_mode":"persisted","targets":{"course_codes":["CO 351"]}}'
# What would CO 250 unlock if I added it?
curl -X POST https://uwwoe.fyi/api/v1/query/what-if \
-H 'Authorization: Bearer <token>' \
-H 'Content-Type: application/json' \
-d '{
"state_mode":"persisted",
"evaluation_problem":{"added_courses":[{"course_code":"CO 250","status":"planned"}]},
"targets":{"course_codes":["CO 351","CO 367"]}
}'

Want more?