---
title: "Create Proposal"
method: POST
path: "/admin/import-plans/{plan_id}/proposals"
tags: ["admin-import-plans"]
---

# Create Proposal

`POST /admin/import-plans/{plan_id}/proposals`

Store operations as a pending proposal (never applied here). Used by
the MCP (Claude for an admin) and the assistant.

## Path parameters

- `plan_id` string, required

## Request body

- ImportPlanProposalCreate
  - `operations` union[], required
    - union
      - AddSourceOpInput
        - `kind` 'add_source'
        - `source` PlanSourceInput, required
          - `id` string, required
          - `file_name` string, required
          - `kind` 'xlsx' | 'xls' | 'ods' | 'csv' | 'pdf' | 'text', required
          - `size_bytes` integer
          - `added_at` string, date-time, required
          - `added_by` PlanAuthor, required — Who did something: an admin, the page assistant or Claude through the MCP (both acting for an admin), the model reading a file, the system.
            - `kind` 'admin' | 'assistant' | 'mcp' | 'system' | 'model', required
            - `email` string, nullable
            - `name` string, nullable
          - `grid` FileGrid, required — One file: its sheets in workbook order (a CSV, a PDF or pasted text is a single sheet). `limits_hit` lists every cap that cut something, so a partial read is never mistaken for the whole file.
            - `file_name` string, required
            - `kind` 'xlsx' | 'xls' | 'ods' | 'csv' | 'pdf' | 'text', required
            - `size_bytes` integer
            - `sheets` SheetGrid[]
              - …
            - `warnings` string[]
            - `limits_hit` string[]
            - `error` string, nullable
      - RemoveSourceOp
        - `kind` 'remove_source'
        - `source_id` string, required
      - SetSheetMappingOpInput
        - `kind` 'set_sheet_mapping'
        - `mapping` SheetMappingInput, required
          - `source_id` string, required
          - `sheet` string, required
          - `ignored` boolean
          - `regions` SheetRegion[]
            - `role` 'students' | 'teachers' | 'division_teachers', required
            - `header_row` integer, nullable
            - `first_row` integer, required
            - `last_row` integer, nullable
            - `skip_rows` integer[]
            - `columns` ColumnMeaning[]
              - …
            - `group_name_from` CellSource — Where a value that is not in a column comes from: the sheet's name (a group per tab) or one cell (a title, a `Classe :` form field).
              - …
            - `division_from` CellSource — Where a value that is not in a column comes from: the sheet's name (a group per tab) or one cell (a title, a `Classe :` form field).
              - …
            - `teacher_from` CellSource — Where a value that is not in a column comes from: the sheet's name (a group per tab) or one cell (a title, a `Classe :` form field).
              - …
            - `teacher_subject` 'maths' | 'physique-chimie' | 'maths-complementaires' | 'maths-expertes', nullable
            - `region_subject` 'maths' | 'physique-chimie' | 'maths-complementaires' | 'maths-expertes', nullable
            - `level` 'sixieme' | 'cinquieme' | 'quatrieme' | 'troisieme' | 'seconde' | 'premiere' | 'terminale' | 'prepa', nullable
          - `population_filter` PopulationFilter — Only the rows with one of `values` in `column` enter the plan: "only the students with 1 in column Z" (the school's paid seats).
            - `column` string, required
            - `values` string[], required
          - `option_codes` object
          - `summary` string
          - `origin` 'model' | 'admin' | 'default'
      - SetMappingSummaryOp
        - `kind` 'set_mapping_summary'
        - `summary` string, required
      - SetColumnMeaningOp
        - `kind` 'set_column_meaning'
        - `source_id` string, required
        - `sheet` string, required
        - `column` string, required
        - `meaning` string, required
        - `subject` 'maths' | 'physique-chimie' | 'maths-complementaires' | 'maths-expertes', nullable
        - `region_index` integer
      - SetPopulationFilterOp
        - `kind` 'set_population_filter'
        - `source_id` string, required
        - `sheet` string, required
        - `column` string, nullable
        - `values` string[]
      - SplitGroupOp
        - `kind` 'split_group'
        - `group_id` string, required
        - `parts` GroupPart[], required
          - `name` string, required
          - `student_ids` string[]
          - `divisions` string[]
          - `teacher_ids` string[]
          - `group_id` string, nullable
        - `origin` 'file' | 'school_answer' | 'admin'
      - MergeGroupsOp
        - `kind` 'merge_groups'
        - `group_ids` string[], required
        - `name` string, nullable
        - `group_id` string, nullable
      - MoveStudentsOp
        - `kind` 'move_students'
        - `student_ids` string[], required
        - `from_group_id` string, nullable
        - `to_group_id` string, required
      - AddGroupOp
        - `kind` 'add_group'
        - `name` string, required
        - `subject` 'maths' | 'physique-chimie' | 'maths-complementaires' | 'maths-expertes', required
        - `grade` 'sixieme' | 'cinquieme' | 'quatrieme' | 'troisieme' | 'seconde' | 'premiere' | 'terminale' | 'prepa', nullable
        - `student_ids` string[]
        - `divisions` string[]
        - `teacher_ids` string[]
        - `group_id` string, nullable
        - `origin` 'file' | 'school_answer' | 'admin'
      - RemoveGroupOp
        - `kind` 'remove_group'
        - `group_id` string, required
      - RenameGroupOp
        - `kind` 'rename_group'
        - `group_id` string, required
        - `name` string, required
      - SetTeachersOp
        - `kind` 'set_teachers'
        - `group_id` string, required
        - `teacher_ids` string[], required
      - SetGroupStatusOp
        - `kind` 'set_group_status'
        - `group_id` string, required
        - `status` 'up_to_date' | 'to_create' | 'to_complete' | 'to_confirm' | 'waiting_school' | 'excluded', nullable
        - `reason` string
      - LinkExistingClassOp
        - `kind` 'link_existing_class'
        - `group_id` string, required
        - `class_id` string, nullable
      - ResolveTeacherOp
        - `kind` 'resolve_teacher'
        - `teacher_id` string, required
        - `status` 'account' | 'invitation' | 'to_invite' | 'ambiguous' | 'not_found' | 'out_of_scope', required
        - `candidate_id` string, nullable
      - InviteTeacherOp
        - `kind` 'invite_teacher'
        - `teacher_id` string, required
        - `email` string, required
      - AddTeacherOp
        - `kind` 'add_teacher'
        - `last_name` string, required
        - `first_name` string
        - `email` string, nullable
        - `subjects` string[]
        - `teacher_id` string, nullable
      - AddQuestionOp
        - `kind` 'add_question'
        - `text` string, required
        - `detail` string
        - `category` 'groups' | 'teachers' | 'students' | 'file'
        - `group_ids` string[]
        - `teacher_ids` string[]
        - `student_ids` string[]
        - `question_id` string, nullable
      - CloseQuestionOp
        - `kind` 'close_question'
        - `question_id` string, required
        - `answer` string
      - AddStudentOp
        - `kind` 'add_student'
        - `last_name` string, required
        - `first_name` string, required
        - `email` string, nullable
        - `division` string, nullable
        - `group_ids` string[]
        - `student_id` string, nullable
      - RemoveStudentOp
        - `kind` 'remove_student'
        - `student_id` string, required
      - EditStudentOp
        - `kind` 'edit_student'
        - `student_id` string, required
        - `first_name` string, nullable
        - `last_name` string, nullable
        - `email` string, nullable
        - `division` string, nullable
      - SetSchoolContactOp
        - `kind` 'set_school_contact'
        - `name` string, nullable
        - `email` string, nullable
      - MarkMessageSentOp
        - `kind` 'mark_message_sent'
      - ApplyGroupsOp
        - `kind` 'apply_groups'
        - `group_ids` string[]
        - `options` ApplyOptions
          - `send_student_invitations` boolean
          - `prepare_invited_teacher_classes` boolean
          - `invite_missing_teachers` boolean
        - `run_id` string, nullable
      - RefreshMatchingOpInput
        - `kind` 'refresh_matching'
        - `context` SchoolContextInput, required
          - `school_id` string, required
          - `school_name` string
          - `school_year` string
          - `fetched_at` string, date-time, nullable
          - `teachers` SchoolTeacherInput[]
            - `id` string, required
            - `kind` 'account' | 'invitation', required
            - `first_name` string, nullable
            - `last_name` string, nullable
            - `email` string
            - `subject` string, nullable
            - `in_school` boolean
            - `invited_at` string, date-time, nullable
          - `classes` SchoolClass[]
            - `id` string, required
            - `name` string, required
            - `code` string, nullable
            - `teacher_id` string, required
            - `teacher_kind` 'account' | 'invitation'
            - `teacher_name` string
            - `school_year` string, nullable
            - `grade` string, nullable
            - `subject` string, nullable
            - `roster` RosterEntry[]
              - …
          - `students` SchoolStudent[]
            - `user_id` string, required
            - `first_name` string
            - `last_name` string
            - `email` string
            - `class_ids` string[]
          - `outside_teachers` SchoolTeacherInput[]
            - `id` string, required
            - `kind` 'account' | 'invitation', required
            - `first_name` string, nullable
            - `last_name` string, nullable
            - `email` string
            - `subject` string, nullable
            - `in_school` boolean
            - `invited_at` string, date-time, nullable
      - RecordGroupAppliedOp
        - `kind` 'record_group_applied'
        - `run_id` string, required
        - `group_id` string, required
        - `results` AppliedClass[], required
          - `teacher_id` string, required
          - `class_id` string, nullable
          - `class_code` string, nullable
          - `class_name` string, nullable
          - `pending_class_id` string, nullable
          - `created` boolean
          - `completed` boolean
          - `students_added` integer
          - `students_skipped` integer
          - `invitations_sent` integer
          - `student_ids_sent` string[]
          - `skipped_reason` string, nullable
          - `error` string, nullable
          - `at` string, date-time, nullable
      - FinishApplyOp
        - `kind` 'finish_apply'
        - `run_id` string, required
        - `error` string, nullable
  - `title` string, required
  - `message` string
  - `source` 'assistant' | 'mcp'

## Response `200`

Successful Response

- ProposalCreateResponse
  - `proposal` ProposalResponse, required
    - `id` string, required
    - `title` string, required
    - `message` string
    - `author` PlanAuthor, required — Who did something: an admin, the page assistant or Claude through the MCP (both acting for an admin), the model reading a file, the system.
      - `kind` 'admin' | 'assistant' | 'mcp' | 'system' | 'model', required
      - `email` string, nullable
      - `name` string, nullable
    - `created_at` string, date-time, required
    - `base_revision` integer, required
    - `items` ProposalItem[]
      - `operation` union, required
        - AddSourceOpOutput
          - `kind` 'add_source'
          - `source` PlanSourceOutput, required
            - `id` string, required
            - `file_name` string, required
            - `kind` 'xlsx' | 'xls' | 'ods' | 'csv' | 'pdf' | 'text', required
            - `size_bytes` integer
            - `added_at` string, date-time, required
            - `added_by` PlanAuthor, required — Who did something: an admin, the page assistant or Claude through the MCP (both acting for an admin), the model reading a file, the system.
              - …
            - `grid` FileGrid, required — One file: its sheets in workbook order (a CSV, a PDF or pasted text is a single sheet). `limits_hit` lists every cap that cut something, so a partial read is never mistaken for the whole file.
              - …
        - RemoveSourceOp
          - `kind` 'remove_source'
          - `source_id` string, required
        - SetSheetMappingOpOutput
          - `kind` 'set_sheet_mapping'
          - `mapping` SheetMappingOutput, required
            - `source_id` string, required
            - `sheet` string, required
            - `ignored` boolean
            - `regions` SheetRegion[]
              - …
            - `population_filter` PopulationFilter — Only the rows with one of `values` in `column` enter the plan: "only the students with 1 in column Z" (the school's paid seats).
              - …
            - `option_codes` object
            - `summary` string
            - `origin` 'model' | 'admin' | 'default'
        - SetMappingSummaryOp
          - `kind` 'set_mapping_summary'
          - `summary` string, required
        - SetColumnMeaningOp
          - `kind` 'set_column_meaning'
          - `source_id` string, required
          - `sheet` string, required
          - `column` string, required
          - `meaning` string, required
          - `subject` 'maths' | 'physique-chimie' | 'maths-complementaires' | 'maths-expertes', nullable
          - `region_index` integer
        - SetPopulationFilterOp
          - `kind` 'set_population_filter'
          - `source_id` string, required
          - `sheet` string, required
          - `column` string, nullable
          - `values` string[]
        - SplitGroupOp
          - `kind` 'split_group'
          - `group_id` string, required
          - `parts` GroupPart[], required
            - `name` string, required
            - `student_ids` string[]
            - `divisions` string[]
            - `teacher_ids` string[]
            - `group_id` string, nullable
          - `origin` 'file' | 'school_answer' | 'admin'
        - MergeGroupsOp
          - `kind` 'merge_groups'
          - `group_ids` string[], required
          - `name` string, nullable
          - `group_id` string, nullable
        - MoveStudentsOp
          - `kind` 'move_students'
          - `student_ids` string[], required
          - `from_group_id` string, nullable
          - `to_group_id` string, required
        - AddGroupOp
          - `kind` 'add_group'
          - `name` string, required
          - `subject` 'maths' | 'physique-chimie' | 'maths-complementaires' | 'maths-expertes', required
          - `grade` 'sixieme' | 'cinquieme' | 'quatrieme' | 'troisieme' | 'seconde' | 'premiere' | 'terminale' | 'prepa', nullable
          - `student_ids` string[]
          - `divisions` string[]
          - `teacher_ids` string[]
          - `group_id` string, nullable
          - `origin` 'file' | 'school_answer' | 'admin'
        - RemoveGroupOp
          - `kind` 'remove_group'
          - `group_id` string, required
        - RenameGroupOp
          - `kind` 'rename_group'
          - `group_id` string, required
          - `name` string, required
        - SetTeachersOp
          - `kind` 'set_teachers'
          - `group_id` string, required
          - `teacher_ids` string[], required
        - SetGroupStatusOp
          - `kind` 'set_group_status'
          - `group_id` string, required
          - `status` 'up_to_date' | 'to_create' | 'to_complete' | 'to_confirm' | 'waiting_school' | 'excluded', nullable
          - `reason` string
        - LinkExistingClassOp
          - `kind` 'link_existing_class'
          - `group_id` string, required
          - `class_id` string, nullable
        - ResolveTeacherOp
          - `kind` 'resolve_teacher'
          - `teacher_id` string, required
          - `status` 'account' | 'invitation' | 'to_invite' | 'ambiguous' | 'not_found' | 'out_of_scope', required
          - `candidate_id` string, nullable
        - InviteTeacherOp
          - `kind` 'invite_teacher'
          - `teacher_id` string, required
          - `email` string, required
        - AddTeacherOp
          - `kind` 'add_teacher'
          - `last_name` string, required
          - `first_name` string
          - `email` string, nullable
          - `subjects` string[]
          - `teacher_id` string, nullable
        - AddQuestionOp
          - `kind` 'add_question'
          - `text` string, required
          - `detail` string
          - `category` 'groups' | 'teachers' | 'students' | 'file'
          - `group_ids` string[]
          - `teacher_ids` string[]
          - `student_ids` string[]
          - `question_id` string, nullable
        - CloseQuestionOp
          - `kind` 'close_question'
          - `question_id` string, required
          - `answer` string
        - AddStudentOp
          - `kind` 'add_student'
          - `last_name` string, required
          - `first_name` string, required
          - `email` string, nullable
          - `division` string, nullable
          - `group_ids` string[]
          - `student_id` string, nullable
        - RemoveStudentOp
          - `kind` 'remove_student'
          - `student_id` string, required
        - EditStudentOp
          - `kind` 'edit_student'
          - `student_id` string, required
          - `first_name` string, nullable
          - `last_name` string, nullable
          - `email` string, nullable
          - `division` string, nullable
        - SetSchoolContactOp
          - `kind` 'set_school_contact'
          - `name` string, nullable
          - `email` string, nullable
        - MarkMessageSentOp
          - `kind` 'mark_message_sent'
        - ApplyGroupsOp
          - `kind` 'apply_groups'
          - `group_ids` string[]
          - `options` ApplyOptions
            - `send_student_invitations` boolean
            - `prepare_invited_teacher_classes` boolean
            - `invite_missing_teachers` boolean
          - `run_id` string, nullable
        - RefreshMatchingOpOutput
          - `kind` 'refresh_matching'
          - `context` SchoolContextOutput, required
            - `school_id` string, required
            - `school_name` string
            - `school_year` string
            - `fetched_at` string, date-time, nullable
            - `teachers` DomainImportPlanMatchingSchoolTeacher[]
              - …
            - `classes` SchoolClass[]
              - …
            - `students` SchoolStudent[]
              - …
            - `outside_teachers` DomainImportPlanMatchingSchoolTeacher[]
              - …
        - RecordGroupAppliedOp
          - `kind` 'record_group_applied'
          - `run_id` string, required
          - `group_id` string, required
          - `results` AppliedClass[], required
            - `teacher_id` string, required
            - `class_id` string, nullable
            - `class_code` string, nullable
            - `class_name` string, nullable
            - `pending_class_id` string, nullable
            - `created` boolean
            - `completed` boolean
            - `students_added` integer
            - `students_skipped` integer
            - `invitations_sent` integer
            - `student_ids_sent` string[]
            - `skipped_reason` string, nullable
            - `error` string, nullable
            - `at` string, date-time, nullable
        - FinishApplyOp
          - `kind` 'finish_apply'
          - `run_id` string, required
          - `error` string, nullable
      - `label` LabelPart[]
        - `kind` 'text' | 'strong' | 'del' | 'ins'
        - `value` string, required
      - `status` 'pending' | 'applied' | 'refused' | 'failed'
      - `error` string, nullable
      - `applied_revision` integer, nullable
    - `status` 'pending' | 'applied' | 'partial' | 'refused'
    - `decided_by` PlanAuthor — Who did something: an admin, the page assistant or Claude through the MCP (both acting for an admin), the model reading a file, the system.
      - `kind` 'admin' | 'assistant' | 'mcp' | 'system' | 'model', required
      - `email` string, nullable
      - `name` string, nullable
    - `decided_at` string, date-time, nullable
    - `notes` string[]
    - `stale` object
  - `page_url` string, required

## Other responses

- `404` — Resource not found
- `409` — Business rule violated
- `422` — Validation Error

## Changes

> 30 revisions in range; 1 not diffed.

- **2026-10-02** `a0b4ce9a0d8f` — 1 info
  - endpoint added

[Change history](https://skmtc.dev/excellence-ai/apis/excellence-learning/changes/admin/import-plans/:plan_id/proposals/post.md)

---

[API](https://skmtc.dev/excellence-ai/apis/excellence-learning.md) · [All operations](https://skmtc.dev/excellence-ai/apis/excellence-learning/llms.txt) · [OpenAPI document](https://skmtc.dev/excellence-ai/apis/excellence-learning/revisions/a0b4ce9a0d8f?raw)
