Semestra

Imports

POST
/imports/uploads

Authorization

cookiesemestra_session<token>

Set by the sign-in endpoints for the web app. Requests other than GET, HEAD and OPTIONS also need the X-Semestra-CSRF header set to the semestra_csrf cookie.

Request Body

multipart/form-data
  1. body
file*File

Response Body

Successful Response

application/json
  1. response
id*Id
filename*Filename
mime_type*Mime Type
size_bytes*Size Bytes
Example Request
curl -X POST 'https://example.com/imports/uploads' \  -F 'file=string'
Example Response
{  "id": "string",  "filename": "string",  "mime_type": "string",  "size_bytes": 0}
GET
/imports/uploads/{upload_id}/content

Authorization

cookiesemestra_session<token>

Set by the sign-in endpoints for the web app. Requests other than GET, HEAD and OPTIONS also need the X-Semestra-CSRF header set to the semestra_csrf cookie.

Path Parameters

upload_id*Upload Id
Length1 <= length <= 64

Response Body

Successful Response

application/octet-stream
Example Request
curl -X GET 'https://example.com/imports/uploads/string/content'
Example Response
Empty
POST
/imports/{session_id}/items:decide

E.g. reject every item with import.duplicate_assessment. Give at least one filter; they combine (an item must match all given). Rejecting a course item also rejects the items that belong to it (its meetings, assessments, categories, events and tasks), so leaving a course out takes only its id. The assistant gets changed and the session's summary, without its items.

Authorization

cookiesemestra_session<token>

Set by the sign-in endpoints for the web app. Requests other than GET, HEAD and OPTIONS also need the X-Semestra-CSRF header set to the semestra_csrf cookie.

Path Parameters

session_id*Session Id

Import id, from imports.session.create or imports.session.list

Request Body

application/json
  1. body
decision*Decision

Decision to apply

Value in"accept""reject"
types?array<>|

Only items of these types

issue_codes?array<string>|

Only items with one of these issues

item_ids?array<>|

Only these items (items[].id of imports.session.get)

Response Body

Successful Response

application/json
  1. response
changed*Changed
session*
Example Request
curl -X POST 'https://example.com/imports/string/items:decide' \  -H 'Content-Type: application/json' \  -d '{  "decision": "accept"}'
Example Response
{  "changed": 0,  "session": {    "id": "string",    "program_id": "string",    "source_kind": "ics",    "target": {      "kind": "term_wizard",      "term_id": "string",      "course_id": "string",      "start_date": "2019-08-24",      "end_date": "2019-08-24"    },    "status": "extracting",    "job_id": "string",    "source_refs": [      {        "upload_id": "string",        "file_item_id": "string",        "filename": "string",        "lms_course_id": "string",        "status": "pending",        "error_code": "string",        "warning_code": "string"      }    ],    "source_meta": {},    "summary": {      "counts": {        "property1": 0,        "property2": 0      },      "accepted": {        "property1": 0,        "property2": 0      },      "issues": {        "property1": 0,        "property2": 0      },      "weights": [        {          "course_ref": "string",          "total": 0,          "existing": 0,          "ok": true        }      ],      "category_weights": [        {          "item_id": "string",          "expected": 0,          "total": 0,          "ok": true        }      ],      "created": 0,      "updated": 0,      "failed": 0    },    "error_code": "string",    "created_at": "2019-08-24T14:15:22Z",    "updated_at": "2019-08-24T14:15:22Z",    "committed_at": "2019-08-24T14:15:22Z",    "items": [      {        "id": "string",        "session_id": "string",        "type": "course",        "data": {},        "evidence": {          "property1": {            "upload_id": "string",            "file_item_id": "string",            "page": 0,            "quote": "string"          },          "property2": {            "upload_id": "string",            "file_item_id": "string",            "page": 0,            "quote": "string"          }        },        "confidence": {          "property1": "high",          "property2": "high"        },        "decision": "accept",        "issues": [          {            "code": "string",            "params": {}          }        ],        "depends_on": [          "string"        ],        "result": {          "created_id": "string",          "updated_id": "string",          "reused": false,          "error_code": "string",          "error_params": {},          "skipped_exceptions": [            {              "date": "string",              "code": "string"            }          ]        },        "position": 0      }    ],    "next_cursor": "string"  }}
PATCH
/imports/{session_id}/items/{item_id}

data is merged into the item (send null to clear a field); fields the item's type does not have are refused. The item's issues are checked again afterwards. The assistant (and an HTTP caller with only_touched) gets the session's summary with only the items this change touched: the edited one and those whose decision or issues changed with it.

Authorization

cookiesemestra_session<token>

Set by the sign-in endpoints for the web app. Requests other than GET, HEAD and OPTIONS also need the X-Semestra-CSRF header set to the semestra_csrf cookie.

Path Parameters

session_id*Session Id

Import id, from imports.session.create or imports.session.list

item_id*Item Id

Item id (items[].id of imports.session.get)

Request Body

application/json
  1. body
data?|

Fields to change; merged into the item's data

decision?|

accept, reject or pending

type?|

Turn an assessment item into a task or back

only_touched?Only Touched

Return only the items this change touched instead of all of them

Defaultfalse

Response Body

Successful Response

application/json
  1. response
id*Id
program_id*Program Id
source_kind*Source Kind
Value in"ics""syllabus""timetable_image""lms""text""agent"
target*
status*Status
Value in"extracting""ready""committing""committed""failed""discarded"
job_id*string|null
source_refs*array<>
source_meta*
summary*
error_code*string|null
created_at*Created At
Formatdate-time
updated_at*Updated At
Formatdate-time
committed_at*|null
items*array<>
next_cursor?|

More items: pass it as cursor to imports.session.get

Example Request
curl -X PATCH 'https://example.com/imports/string/items/string' \  -H 'Content-Type: application/json' \  -d '{}'
Example Response
{  "id": "string",  "program_id": "string",  "source_kind": "ics",  "target": {    "kind": "term_wizard",    "term_id": "string",    "course_id": "string",    "start_date": "2019-08-24",    "end_date": "2019-08-24"  },  "status": "extracting",  "job_id": "string",  "source_refs": [    {      "upload_id": "string",      "file_item_id": "string",      "filename": "string",      "lms_course_id": "string",      "status": "pending",      "error_code": "string",      "warning_code": "string"    }  ],  "source_meta": {},  "summary": {    "counts": {      "property1": 0,      "property2": 0    },    "accepted": {      "property1": 0,      "property2": 0    },    "issues": {      "property1": 0,      "property2": 0    },    "weights": [      {        "course_ref": "string",        "total": 0,        "existing": 0,        "ok": true      }    ],    "category_weights": [      {        "item_id": "string",        "expected": 0,        "total": 0,        "ok": true      }    ],    "created": 0,    "updated": 0,    "failed": 0  },  "error_code": "string",  "created_at": "2019-08-24T14:15:22Z",  "updated_at": "2019-08-24T14:15:22Z",  "committed_at": "2019-08-24T14:15:22Z",  "items": [    {      "id": "string",      "session_id": "string",      "type": "course",      "data": {},      "evidence": {        "property1": {          "upload_id": "string",          "file_item_id": "string",          "page": 0,          "quote": "string"        },        "property2": {          "upload_id": "string",          "file_item_id": "string",          "page": 0,          "quote": "string"        }      },      "confidence": {        "property1": "high",        "property2": "high"      },      "decision": "accept",      "issues": [        {          "code": "string",          "params": {}        }      ],      "depends_on": [        "string"      ],      "result": {        "created_id": "string",        "updated_id": "string",        "reused": false,        "error_code": "string",        "error_params": {},        "skipped_exceptions": [          {            "date": "string",            "code": "string"          }        ]      },      "position": 0    }  ],  "next_cursor": "string"}
POST
/imports/{session_id}:commit

The user reviews the import on its confirmation card; summarise it first. Writes in dependency order; one item failing does not undo the others (see each item's result). Repeating it only retries the items that have not been written. The assistant gets the counts and the items that failed.

Authorization

cookiesemestra_session<token>

Set by the sign-in endpoints for the web app. Requests other than GET, HEAD and OPTIONS also need the X-Semestra-CSRF header set to the semestra_csrf cookie.

Path Parameters

session_id*Session Id

Import id, from imports.session.create or imports.session.list

Request Body

application/json
  1. body
wizard_courses?array<>|

Term wizard: the courses it created from the session's course items

item_ids?array<>|

Retry only these items (failed ones, items[].id of imports.session.get); default: all accepted

Response Body

Successful Response

application/json
  1. response
session*
created*Created
updated*Updated
failed*Failed
Example Request
curl -X POST 'https://example.com/imports/string:commit' \  -H 'Content-Type: application/json' \  -d '{}'
Example Response
{  "session": {    "id": "string",    "program_id": "string",    "source_kind": "ics",    "target": {      "kind": "term_wizard",      "term_id": "string",      "course_id": "string",      "start_date": "2019-08-24",      "end_date": "2019-08-24"    },    "status": "extracting",    "job_id": "string",    "source_refs": [      {        "upload_id": "string",        "file_item_id": "string",        "filename": "string",        "lms_course_id": "string",        "status": "pending",        "error_code": "string",        "warning_code": "string"      }    ],    "source_meta": {},    "summary": {      "counts": {        "property1": 0,        "property2": 0      },      "accepted": {        "property1": 0,        "property2": 0      },      "issues": {        "property1": 0,        "property2": 0      },      "weights": [        {          "course_ref": "string",          "total": 0,          "existing": 0,          "ok": true        }      ],      "category_weights": [        {          "item_id": "string",          "expected": 0,          "total": 0,          "ok": true        }      ],      "created": 0,      "updated": 0,      "failed": 0    },    "error_code": "string",    "created_at": "2019-08-24T14:15:22Z",    "updated_at": "2019-08-24T14:15:22Z",    "committed_at": "2019-08-24T14:15:22Z",    "items": [      {        "id": "string",        "session_id": "string",        "type": "course",        "data": {},        "evidence": {          "property1": {            "upload_id": "string",            "file_item_id": "string",            "page": 0,            "quote": "string"          },          "property2": {            "upload_id": "string",            "file_item_id": "string",            "page": 0,            "quote": "string"          }        },        "confidence": {          "property1": "high",          "property2": "high"        },        "decision": "accept",        "issues": [          {            "code": "string",            "params": {}          }        ],        "depends_on": [          "string"        ],        "result": {          "created_id": "string",          "updated_id": "string",          "reused": false,          "error_code": "string",          "error_params": {},          "skipped_exceptions": [            {              "date": "string",              "code": "string"            }          ]        },        "position": 0      }    ],    "next_cursor": "string"  },  "created": 0,  "updated": 0,  "failed": 0}
GET
/programs/{program_id}/imports

Each import says where it came from and its state (extracting, ready, committed, failed, discarded). Open one with imports.session.get. Closed imports are kept for 30 days.

Authorization

cookiesemestra_session<token>

Set by the sign-in endpoints for the web app. Requests other than GET, HEAD and OPTIONS also need the X-Semestra-CSRF header set to the semestra_csrf cookie.

Path Parameters

program_id*Program Id

Program id

Query Parameters

cursor?|

next_cursor of the previous page

limit?Limit

Page size

Default50

Response Body

Successful Response

application/json
  1. response
items*array<>
next_cursor*string|null
Example Request
curl -X GET 'https://example.com/programs/string/imports'
Example Response
{  "items": [    {      "id": "string",      "program_id": "string",      "source_kind": "ics",      "target": {        "kind": "term_wizard",        "term_id": "string",        "course_id": "string",        "start_date": "2019-08-24",        "end_date": "2019-08-24"      },      "status": "extracting",      "job_id": "string",      "source_refs": [        {          "upload_id": "string",          "file_item_id": "string",          "filename": "string",          "lms_course_id": "string",          "status": "pending",          "error_code": "string",          "warning_code": "string"        }      ],      "source_meta": {},      "summary": {        "counts": {          "property1": 0,          "property2": 0        },        "accepted": {          "property1": 0,          "property2": 0        },        "issues": {          "property1": 0,          "property2": 0        },        "weights": [          {            "course_ref": "string",            "total": 0,            "existing": 0,            "ok": true          }        ],        "category_weights": [          {            "item_id": "string",            "expected": 0,            "total": 0,            "ok": true          }        ],        "created": 0,        "updated": 0,        "failed": 0      },      "error_code": "string",      "created_at": "2019-08-24T14:15:22Z",      "updated_at": "2019-08-24T14:15:22Z",      "committed_at": "2019-08-24T14:15:22Z"    }  ],  "next_cursor": "string"}
POST
/programs/{program_id}/imports

Use when the user shares a syllabus, timetable, ICS file or other document to bring into the app ("import this", "set up my courses from this syllabus"). Creates a draft the user reviews before anything is written. Pass the files themselves: attachment_ids for files attached to the conversation, file_item_ids for course files (the app passes upload_ids), or text. An import never creates terms: the target term must exist (academics.term.create first). ICS is parsed at once (status ready); the other sources are extracted in the background (status extracting → ready): call imports.session.get with wait_seconds to wait for it. Never write a document's contents with the modules' own create capabilities instead of importing it. The assistant gets summary and the first 25 items; read the rest with imports.session.get.

Authorization

cookiesemestra_session<token>

Set by the sign-in endpoints for the web app. Requests other than GET, HEAD and OPTIONS also need the X-Semestra-CSRF header set to the semestra_csrf cookie.

Path Parameters

program_id*Program Id

Program id

Request Body

application/json
  1. body
source_kind*Source Kind

ics, syllabus, timetable_image, text, or agent for items you add yourself with imports.item.add_many

Value in"ics""syllabus""timetable_image""lms""text""agent"
target*

A term or a course; agents cannot use the wizard

upload_ids?array<>

Files uploaded in the app; agents use attachment_ids or file_item_ids

Itemsitems <= 20
file_item_ids?array<>

Course files, from files.item.list

Itemsitems <= 20
attachment_ids?array<>

Files the user attached to the assistant conversation (the id of an block); the importer reads the original file

Itemsitems <= 10
text?|

Only for source_kind text: text the user pasted

source_meta?

Extra source info, e.g. {provider, connection_id}; {only: 'course_info'} keeps just the field changes of the target course; {keep_files: false} does not save an uploaded syllabus to the course files

Response Body

Successful Response

application/json
  1. response
id*Id
program_id*Program Id
source_kind*Source Kind
Value in"ics""syllabus""timetable_image""lms""text""agent"
target*
status*Status
Value in"extracting""ready""committing""committed""failed""discarded"
job_id*string|null
source_refs*array<>
source_meta*
summary*
error_code*string|null
created_at*Created At
Formatdate-time
updated_at*Updated At
Formatdate-time
committed_at*|null
items*array<>
next_cursor?|

More items: pass it as cursor to imports.session.get

Example Request
curl -X POST 'https://example.com/programs/string/imports' \  -H 'Content-Type: application/json' \  -d '{  "source_kind": "ics",  "target": {    "kind": "term_wizard"  }}'
Example Response
{  "id": "string",  "program_id": "string",  "source_kind": "ics",  "target": {    "kind": "term_wizard",    "term_id": "string",    "course_id": "string",    "start_date": "2019-08-24",    "end_date": "2019-08-24"  },  "status": "extracting",  "job_id": "string",  "source_refs": [    {      "upload_id": "string",      "file_item_id": "string",      "filename": "string",      "lms_course_id": "string",      "status": "pending",      "error_code": "string",      "warning_code": "string"    }  ],  "source_meta": {},  "summary": {    "counts": {      "property1": 0,      "property2": 0    },    "accepted": {      "property1": 0,      "property2": 0    },    "issues": {      "property1": 0,      "property2": 0    },    "weights": [      {        "course_ref": "string",        "total": 0,        "existing": 0,        "ok": true      }    ],    "category_weights": [      {        "item_id": "string",        "expected": 0,        "total": 0,        "ok": true      }    ],    "created": 0,    "updated": 0,    "failed": 0  },  "error_code": "string",  "created_at": "2019-08-24T14:15:22Z",  "updated_at": "2019-08-24T14:15:22Z",  "committed_at": "2019-08-24T14:15:22Z",  "items": [    {      "id": "string",      "session_id": "string",      "type": "course",      "data": {},      "evidence": {        "property1": {          "upload_id": "string",          "file_item_id": "string",          "page": 0,          "quote": "string"        },        "property2": {          "upload_id": "string",          "file_item_id": "string",          "page": 0,          "quote": "string"        }      },      "confidence": {        "property1": "high",        "property2": "high"      },      "decision": "accept",      "issues": [        {          "code": "string",          "params": {}        }      ],      "depends_on": [        "string"      ],      "result": {        "created_id": "string",        "updated_id": "string",        "reused": false,        "error_code": "string",        "error_params": {},        "skipped_exceptions": [          {            "date": "string",            "code": "string"          }        ]      },      "position": 0    }  ],  "next_cursor": "string"}
POST
/imports/{session_id}:discard

Use when the user does not want the import. Its uploaded files are deleted too.

Authorization

cookiesemestra_session<token>

Set by the sign-in endpoints for the web app. Requests other than GET, HEAD and OPTIONS also need the X-Semestra-CSRF header set to the semestra_csrf cookie.

Path Parameters

session_id*Session Id

Import id, from imports.session.create or imports.session.list

Response Body

Successful Response

application/json
  1. response
id*Id
program_id*Program Id
source_kind*Source Kind
Value in"ics""syllabus""timetable_image""lms""text""agent"
target*
status*Status
Value in"extracting""ready""committing""committed""failed""discarded"
job_id*string|null
source_refs*array<>
source_meta*
summary*
error_code*string|null
created_at*Created At
Formatdate-time
updated_at*Updated At
Formatdate-time
committed_at*|null
Example Request
curl -X POST 'https://example.com/imports/string:discard'
Example Response
{  "id": "string",  "program_id": "string",  "source_kind": "ics",  "target": {    "kind": "term_wizard",    "term_id": "string",    "course_id": "string",    "start_date": "2019-08-24",    "end_date": "2019-08-24"  },  "status": "extracting",  "job_id": "string",  "source_refs": [    {      "upload_id": "string",      "file_item_id": "string",      "filename": "string",      "lms_course_id": "string",      "status": "pending",      "error_code": "string",      "warning_code": "string"    }  ],  "source_meta": {},  "summary": {    "counts": {      "property1": 0,      "property2": 0    },    "accepted": {      "property1": 0,      "property2": 0    },    "issues": {      "property1": 0,      "property2": 0    },    "weights": [      {        "course_ref": "string",        "total": 0,        "existing": 0,        "ok": true      }    ],    "category_weights": [      {        "item_id": "string",        "expected": 0,        "total": 0,        "ok": true      }    ],    "created": 0,    "updated": 0,    "failed": 0  },  "error_code": "string",  "created_at": "2019-08-24T14:15:22Z",  "updated_at": "2019-08-24T14:15:22Z",  "committed_at": "2019-08-24T14:15:22Z"}
GET
/imports/{session_id}

Use to see what an import found (courses, assessments, meetings...) and what needs checking (issues: unresolved dates, weights not adding up to 100, duplicates). summary counts the items per type. Narrow it with item_ids (check one item after changing it), types and fields; items come 25 at a time, follow next_cursor for more. While it is extracting, pass wait_seconds (up to 25) to wait for the result in one call; if it is still extracting after that, tell the user and stop instead of calling again.

Authorization

cookiesemestra_session<token>

Set by the sign-in endpoints for the web app. Requests other than GET, HEAD and OPTIONS also need the X-Semestra-CSRF header set to the semestra_csrf cookie.

Path Parameters

session_id*Session Id

Import id, from imports.session.create or imports.session.list

Query Parameters

item_ids?array<>|

Only these items (items[].id of imports.session.get)

types?array<>|

Only items of these types

fields?array<>|

Agent/MCP only: return just these fields of each item (and its id); by default type, data, decision, issues and result

cursor?|

next_cursor of the previous page

limit?|

Items per page (agent/MCP default 25; HTTP: all)

wait_seconds?Wait Seconds

While the import is still extracting, wait up to this long for it to finish before answering

Default0

Response Body

Successful Response

application/json
  1. response
id*Id
program_id*Program Id
source_kind*Source Kind
Value in"ics""syllabus""timetable_image""lms""text""agent"
target*
status*Status
Value in"extracting""ready""committing""committed""failed""discarded"
job_id*string|null
source_refs*array<>
source_meta*
summary*
error_code*string|null
created_at*Created At
Formatdate-time
updated_at*Updated At
Formatdate-time
committed_at*|null
items*array<>
next_cursor?|

More items: pass it as cursor to imports.session.get

Example Request
curl -X GET 'https://example.com/imports/string'
Example Response
{  "id": "string",  "program_id": "string",  "source_kind": "ics",  "target": {    "kind": "term_wizard",    "term_id": "string",    "course_id": "string",    "start_date": "2019-08-24",    "end_date": "2019-08-24"  },  "status": "extracting",  "job_id": "string",  "source_refs": [    {      "upload_id": "string",      "file_item_id": "string",      "filename": "string",      "lms_course_id": "string",      "status": "pending",      "error_code": "string",      "warning_code": "string"    }  ],  "source_meta": {},  "summary": {    "counts": {      "property1": 0,      "property2": 0    },    "accepted": {      "property1": 0,      "property2": 0    },    "issues": {      "property1": 0,      "property2": 0    },    "weights": [      {        "course_ref": "string",        "total": 0,        "existing": 0,        "ok": true      }    ],    "category_weights": [      {        "item_id": "string",        "expected": 0,        "total": 0,        "ok": true      }    ],    "created": 0,    "updated": 0,    "failed": 0  },  "error_code": "string",  "created_at": "2019-08-24T14:15:22Z",  "updated_at": "2019-08-24T14:15:22Z",  "committed_at": "2019-08-24T14:15:22Z",  "items": [    {      "id": "string",      "session_id": "string",      "type": "course",      "data": {},      "evidence": {        "property1": {          "upload_id": "string",          "file_item_id": "string",          "page": 0,          "quote": "string"        },        "property2": {          "upload_id": "string",          "file_item_id": "string",          "page": 0,          "quote": "string"        }      },      "confidence": {        "property1": "high",        "property2": "high"      },      "decision": "accept",      "issues": [        {          "code": "string",          "params": {}        }      ],      "depends_on": [        "string"      ],      "result": {        "created_id": "string",        "updated_id": "string",        "reused": false,        "error_code": "string",        "error_params": {},        "skipped_exceptions": [          {            "date": "string",            "code": "string"          }        ]      },      "position": 0    }  ],  "next_cursor": "string"}