---
title: "Cancel Study"
method: POST
path: "/workspaces/{workspace_id}/studies/{study_id}/cancel"
tags: ["studies"]
---

# Cancel Study

`POST /workspaces/{workspace_id}/studies/{study_id}/cancel`

## Path parameters

- `study_id` string, uuid, required
- `workspace_id` string, uuid, required

## Response `200`

Successful Response

- StudyDetail — One immutable saved study, addressed by its study ID. Deliberately FLAT (A6's shape, extended in place — no reshape): every pipeline field is optional and absent until the lifecycle reaches it, so one model serves the canvas read, the 2 s pipeline poll, and the Report tab. Payload posture under the poll: `results` is bounded by the brief's question caps and `results.py`'s byte cap.
  - `id` string, uuid, required
  - `status` 'approved' | 'running' | 'reporting' | 'completed' | 'failed' | 'canceled', required
  - `title` string, nullable, required
  - `brief` Brief, required — The research brief document (the `studies.brief` jsonb). Donor `briefSchema` minus `audience` (KD4) and minus `status` — status is a column on the `studies` row, never a key inside the document.
    - `title` string, nullable
    - `business_problem` string, required
    - `action_standard` string, nullable — Pre-agreed decision rule — only when the research informs a decision: what result would make the user act. Absent for curiosity-driven studies.
    - `context` string, required
    - `assumptions` string[], required
    - `provenance` ProvenanceEntry[], required
      - `field` string, required
      - `source` 'assumed' | 'user_provided' | 'probed_confirmed', required
    - `research_objectives` ResearchObjective[], required
      - `id` string, required — Stable id: "R1", "R2", ...
      - `objective` string, required — What we must learn — often phrased as a question
      - `why_it_matters` string, required
    - `stimuli` union[], required
      - union
        - TextStimulus
          - `kind` 'text', required
          - `id` string, nullable — Stable id: "ST1", "ST2", ...
          - `label` string, required
          - `value` string, required
        - ImageStimulus
          - `kind` 'image', required
          - `id` string, nullable — Stable id: "ST1", "ST2", ...
          - `label` string, required
          - `asset_id` string, uuid, required
    - `stimulus_gap` string, nullable — Set when the business problem references an artifact the user could not provide
    - `survey_questions` SurveyQuestion[], required
      - `id` string, required — Stable id: "S1", "S2", ...
      - `text` string, required
      - `type` 'multiple_choice' | 'scale' | 'open_ended', required
      - `options` string[], nullable — Required for multiple_choice; exhaustive, ends with Other
      - `allow_multiple` boolean — multiple_choice only: may a respondent pick more than one option. Single-select is the common case, so it is the default
      - `scale` ScaleSpec — Mirrors the engine's `ScaleConfigInput` bounds exactly (`min`/`max`, not a point count), so `questions.py#_survey_config` passes them straight through. A count would have to be turned back into bounds somewhere, and that arithmetic is the kind of thing that silently pins every scale to 1.
        - `min` integer, required
        - `max` integer, required
        - `min_label` string, required
        - `max_label` string, required
      - `feeds` string[], required — Research objective ids this feeds — must list at least one (audited)
      - `stimulus` string, nullable — Stimulus id this question shows — the stimulus renders in this question's prompt only
      - `rationale` string, required
    - `qualitative_questions` QualitativeQuestion[], required
      - `id` string, required — Stable id: "Q1", "Q2", ...
      - `text` string, required — Phrased first-person, addressed to a respondent
      - `feeds` string[], required — Research objective ids this feeds — must list at least one (audited)
      - `stimulus` string, nullable — Stimulus id this question shows — the stimulus renders in this question's prompt only
    - `open_items` OpenItem[], required — Unresolved intake questions — this IS the question queue
      - `section` 'frame' | 'survey_questions' | 'qualitative_questions', required — The stage this question belongs to — frame covers title/goal/objectives
      - `question` string, required
  - `issues` AuditIssue[], required
    - `code` 'problem_missing' | 'problem_assumed' | 'coverage_gap' | 'unknown_feed' | 'unknown_stimulus' | 'unused_stimulus' | 'duplicate_stimulus_asset' | 'unfed_instrument' | 'mc_options' | 'mc_other' | 'scale_anchors' | 'status_premature' | 'population_missing' | 'objective_soft_cap' | 'survey_length' | 'qual_length' | 'duplicate_id' | 'open_items_out_of_order', required
    - `severity` 'error' | 'warning', required
    - `message` string, required
    - `path` string, nullable
  - `next_step` string, required
  - `approved_at` string, nullable, required
  - `created_at` string, required
  - `updated_at` string, required
  - `sample_plan` StudySamplePlan — What a run WOULD field, computed on read while the study is still pre-run (`draft`/`ready`/`approved`) — the numbers C8's confirm dialog restates, so no client does this math. `planned_personas` is the capped cohort-filtered count (`STUDY_MAX_PERSONAS`), `population_size` the population's whole persona count, `question_count` the brief's survey + qualitative questions (one fielded question each).
    - `planned_personas` integer, required
    - `population_size` integer, required
    - `question_count` integer, required
  - `started_at` string, nullable
  - `completed_at` string, nullable
  - `expected_response_count` integer, nullable
  - `response_count` integer, nullable
  - `failure_count` integer, nullable
  - `question_progress` StudyQuestionProgress[], nullable
    - `question_id` string, required
    - `response_count` integer, required
    - `failure_count` integer, required
  - `results` StudyQuestionResult[], nullable
    - `id` string, required
    - `text` string, required
    - `type` 'multiple_choice' | 'scale' | 'open_ended' | 'qualitative', required
    - `response_count` integer, required
    - `failure_count` integer, required
    - `aggregate` StudyResultAggregate — A choice/scale question's rollup (`results.py#question_aggregate`). The three list arms stay loosely typed exactly like the survey product's `SurveyConceptRollup` — same math, same wire shape.
      - `response_count` integer, required
      - `average_number` number, nullable
      - `numeric_percentiles` object[]
      - `number_distribution` object[]
      - `choice_counts` object[]
    - `rationales` string[]
    - `themes` StudyResultTheme[]
      - `title` string, required
      - `summary` string, required
      - `count` integer, required
      - `share` number, required
      - `example_answers` StudyResultExample[]
        - `persona` string, required
        - `text` string, required
    - `verbatims` StudyResultVerbatim[]
      - `persona` string, required
      - `answer` string, required
      - `theme` integer, nullable
    - `verbatims_omitted` string, nullable
  - `report_markdown` string, nullable
  - `failure_reason` 'below_success_gate' | 'canceled' | 'stranded' | 'internal_error', nullable
  - `population_id` string, uuid, nullable
  - `population_name` string, nullable
  - `cohort_filter` object, nullable
  - `can_run` boolean, required
  - `can_cancel` boolean, required
  - `can_delete` boolean, required
  - `stimulus_assets` object, nullable

## Other responses

- `422` — Validation Error

---

[API](https://skmtc.dev/useauxos/apis/auxos.md) · [All operations](https://skmtc.dev/useauxos/apis/auxos/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/useauxos/auxos/revisions/2f853c0b59f4/schema)
