LMS (Canvas)
semestra_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.
course_id*Course Idfile_id*File Iddownload?DownloadSend as an attachment
falsecheck?CheckOnly check that the file opens (204, or the same errors)
falseSuccessful Response
curl -X GET 'https://example.com/courses/string/lms/files/string/content'semestra_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.
course_id*Course IdCourse id (must be linked)
refresh?RefreshSkip the 5-minute cache and ask again
falsesince?|Only posted after this time
fields?array<>|Agent/MCP only: return just these fields of each item (and its external_id); default title, author, posted_at, unread. markdown (or html) is the body, as Markdown
Successful Response
application/json- response
items*array<>truncated*Truncatedcurl -X GET 'https://example.com/courses/string/lms/announcements'{ "items": [ { "external_id": "string", "web_url": "string", "raw_kind": "string", "external_course_id": "", "title": "string", "html": "string", "author": "string", "posted_at": "2019-08-24T14:15:22Z", "updated_at": "2019-08-24T14:15:22Z", "unread": false } ], "truncated": true}Only when the user allows Semestra to change things on the platform (account
setting lms.allow_writes), otherwise lms.writes_disabled. Not for agents.
semestra_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.
course_id*Course IdCourse id (must be linked)
announcement_id*Announcement IdExternal announcement id
Successful Response
application/json- response
announcement_id*Announcement Idunread*Unreadcurl -X POST 'https://example.com/courses/string/lms/announcements/string:read'{ "announcement_id": "string", "unread": true}For assignments whose imported_as.kind is task in lms.assignment.list: each
becomes an assessment and keeps its to-do. Saved at once when nothing needs a decision
(committed); otherwise commit it after the review (imports.session.commit).
semestra_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.
course_id*Course IdCourse id (must be linked)
application/json- body
external_ids*array<>Assignments (external_id of lms.assignment.list)
1 <= items <= 200Successful Response
application/json- response
session_id*Session Idprogram_id*Program Idcount*CountItems in the import
committed?CommittedSaved at once (nothing needed a decision); otherwise it waits for review
falsefailed?FailedItems that could not be saved, when committed (see the import)
0curl -X POST 'https://example.com/courses/string/lms/imports:gradebook' \ -H 'Content-Type: application/json' \ -d '{ "external_ids": [ "string" ]}'{ "session_id": "string", "program_id": "string", "count": 0, "committed": false, "failed": 0}Assignments worth points become assessments (each gets its task), the others
tasks; ones imported before are left out. Saved at once when nothing needs a decision
(committed); otherwise the user reviews it, then commit it like any import
(imports.session.commit).
semestra_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.
course_id*Course IdCourse id (must be linked)
application/json- body
external_ids*array<>Assignments (external_id of lms.assignment.list)
1 <= items <= 200Successful Response
application/json- response
session_id*Session Idprogram_id*Program Idcount*CountItems in the import
committed?CommittedSaved at once (nothing needed a decision); otherwise it waits for review
falsefailed?FailedItems that could not be saved, when committed (see the import)
0curl -X POST 'https://example.com/courses/string/lms/imports:assignments' \ -H 'Content-Type: application/json' \ -d '{ "external_ids": [ "string" ]}'{ "session_id": "string", "program_id": "string", "count": 0, "committed": false, "failed": 0}To add them to the gradebook or tasks use lms.assignment.import (and lms.assignment.add_to_gradebook for ones imported as tasks), never the gradebook or task capabilities directly.
semestra_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.
course_id*Course IdCourse id (must be linked)
refresh?RefreshSkip the 5-minute cache and ask again
falsefields?array<>|Agent/MCP only: return just these fields of each item (and its external_id); default name, due_at, points, group_name, submission, imported_as. markdown (or html) is the body, as Markdown
Successful Response
application/json- response
items*array<>new_ids*array<string>external_id of the new assignments: not imported and due later
truncated*Truncatedcurl -X GET 'https://example.com/courses/string/lms/assignments'{ "items": [ { "external_id": "string", "web_url": "string", "raw_kind": "string", "name": "string", "html": "string", "due_at": "2019-08-24T14:15:22Z", "unlock_at": "2019-08-24T14:15:22Z", "lock_at": "2019-08-24T14:15:22Z", "points": 0, "group_id": "string", "group_name": "string", "group_weight": 0, "submission_types": [ "string" ], "submission": { "state": "string", "submitted_at": "2019-08-24T14:15:22Z", "graded_at": "2019-08-24T14:15:22Z", "score": 0, "grade": "string", "late": false, "missing": false, "attempt": 0 }, "published": true, "updated_at": "2019-08-24T14:15:22Z", "locked": false, "lock_explanation": "string", "allowed_attempts": 0, "rubric": [ { "id": "string", "description": "", "long_description": "string", "points": 0, "ratings": [ { "id": "string", "description": "", "points": 0 } ] } ], "imported_as": { "kind": "assessment", "id": "string" } } ], "new_ids": [ "string" ], "truncated": true}Not for agents.
semestra_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.
Successful Response
application/json- response
items*array<>curl -X GET 'https://example.com/lms/connections'{ "items": [ { "id": "string", "provider": "string", "display_name": "string", "config": {}, "credentials_hint": { "property1": "string", "property2": "string" }, "has_credentials": true, "account_name": "string", "status": "connected", "last_checked_at": "2019-08-24T14:15:22Z", "last_error_code": "string", "program_ids": [ "string" ], "link_count": 0, "created_at": "2019-08-24T14:15:22Z", "updated_at": "2019-08-24T14:15:22Z" } ]}Credentials are stored encrypted and only ever shown masked. Not for agents.
semestra_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.
application/json- body
provider*ProviderProvider kind: canvas
length <= 32display_name?|Name shown in the app; defaults to the instance name
config*Provider settings, e.g. {base_url}
credentials?Provider credentials, e.g. {access_token}; stored encrypted
sign_in?|Instead of credentials: the address the platform's sign-in page ended on (lms.connection.sign_in.start)
Successful Response
application/json- response
id*Idprovider*Providerdisplay_name*Display Nameconfig*Non-secret settings, e.g. {base_url}
credentials_hint*Masked credentials, never the values
has_credentials*Has CredentialsFalse after a data import: enter them again
account_name*string|nullstatus*Status"connected""error"last_checked_at*|nulllast_error_code*string|nullprogram_ids*array<string>Programs bound to this connection
link_count*Link CountCourses linked through this connection
created_at*Created Atdate-timeupdated_at*Updated Atdate-timecurl -X POST 'https://example.com/lms/connections' \ -H 'Content-Type: application/json' \ -d '{ "provider": "string", "config": {}}'{ "id": "string", "provider": "string", "display_name": "string", "config": {}, "credentials_hint": { "property1": "string", "property2": "string" }, "has_credentials": true, "account_name": "string", "status": "connected", "last_checked_at": "2019-08-24T14:15:22Z", "last_error_code": "string", "program_ids": [ "string" ], "link_count": 0, "created_at": "2019-08-24T14:15:22Z", "updated_at": "2019-08-24T14:15:22Z"}New settings or credentials are checked before saving. Not for agents.
semestra_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.
id*IdConnection id
application/json- body
display_name?|New display name
config?|New provider settings
credentials?|New credentials (checked before saving)
sign_in?|Instead of credentials: a new sign-in on the platform's page
Successful Response
application/json- response
id*Idprovider*Providerdisplay_name*Display Nameconfig*Non-secret settings, e.g. {base_url}
credentials_hint*Masked credentials, never the values
has_credentials*Has CredentialsFalse after a data import: enter them again
account_name*string|nullstatus*Status"connected""error"last_checked_at*|nulllast_error_code*string|nullprogram_ids*array<string>Programs bound to this connection
link_count*Link CountCourses linked through this connection
created_at*Created Atdate-timeupdated_at*Updated Atdate-timecurl -X PATCH 'https://example.com/lms/connections/string' \ -H 'Content-Type: application/json' \ -d '{}'{ "id": "string", "provider": "string", "display_name": "string", "config": {}, "credentials_hint": { "property1": "string", "property2": "string" }, "has_credentials": true, "account_name": "string", "status": "connected", "last_checked_at": "2019-08-24T14:15:22Z", "last_error_code": "string", "program_ids": [ "string" ], "link_count": 0, "created_at": "2019-08-24T14:15:22Z", "updated_at": "2019-08-24T14:15:22Z"}Refused while Programs are bound to it (lms.connection_in_use) unless
detach_all, which also unbinds them and unlinks their courses; imported assessments, tasks
and files stay. Not for agents.
semestra_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.
id*IdConnection id
detach_all?Detach AllAlso unbind its Programs and unlink their courses (imports are kept)
falseSuccessful Response
application/json- response
id*Idunbound_programs*Unbound Programsunlinked_courses*Unlinked Coursescurl -X DELETE 'https://example.com/lms/connections/string'{ "id": "string", "unbound_programs": 0, "unlinked_courses": 0}Returns the address to open in the user's browser; the address that page ends
on goes to lms.connection.create (or update) as sign_in. Only where the server allows it
(providers with sign_in). Not for agents.
semestra_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.
application/json- body
provider*ProviderProvider kind: canvas
length <= 32config*Provider settings, e.g. {base_url}
Successful Response
application/json- response
authorize_url*Authorize UrlOpen in the user's browser to sign in
curl -X POST 'https://example.com/lms/connections:sign-in' \ -H 'Content-Type: application/json' \ -d '{ "provider": "string", "config": {}}'{ "authorize_url": "string"}A re-check records the connection's status. Not for agents.
semestra_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.
application/json- body
connection_id?|Check a saved connection; omitted fields use its stored values
provider?|Provider kind (new connection)
config?|Provider settings
credentials?|Credentials
Successful Response
application/json- response
ok*Okerror_code*string|nullerror_params?summary*|nullconnection*|The saved connection, when one was checked
curl -X POST 'https://example.com/lms/connections:validate' \ -H 'Content-Type: application/json' \ -d '{}'{ "ok": true, "error_code": "string", "error_params": {}, "summary": { "account_name": "string", "avatar_url": "string", "instance_name": "string" }, "connection": { "id": "string", "provider": "string", "display_name": "string", "config": {}, "credentials_hint": { "property1": "string", "property2": "string" }, "has_credentials": true, "account_name": "string", "status": "connected", "last_checked_at": "2019-08-24T14:15:22Z", "last_error_code": "string", "program_ids": [ "string" ], "link_count": 0, "created_at": "2019-08-24T14:15:22Z", "updated_at": "2019-08-24T14:15:22Z" }}A score change is a grade the gradebook does not have yet. Put them up for
the user's review with lms.course.queue_updates.
semestra_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.
course_id*Course IdCourse id (must be linked)
refresh?RefreshSkip the 5-minute cache and ask again
falseSuccessful Response
application/json- response
course_id*Course Idcount*Countitems*array<>curl -X GET 'https://example.com/courses/string/lms/updates'{ "course_id": "string", "count": 0, "items": [ { "external_id": "string", "name": "string", "target": { "kind": "assessment", "id": "string" }, "changes": { "property1": { "old": null, "new": null }, "property2": { "old": null, "new": null } } } ]}Creates an import the user reviews (imports.session.get); committing it creates the courses and links them to the LMS in one go.
semestra_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.
program_id*Program IdProgram id (must have a bound connection)
application/json- body
external_course_ids*array<>External courses to import (external_id of lms.course.list)
1 <= items <= 50term_id?|Term the courses go into; agents create the term first
term_wizard?Term WizardOnly for the app's new-term wizard (the term is created afterwards); agents cannot use it
falsestart_date?|App wizard only: first day of the term
end_date?|App wizard only: last day of the term
Successful Response
application/json- response
session_id*Session Idprogram_id*Program Idcount*CountItems in the import
committed?CommittedSaved at once (nothing needed a decision); otherwise it waits for review
falsefailed?FailedItems that could not be saved, when committed (see the import)
0curl -X POST 'https://example.com/programs/string/lms/imports:courses' \ -H 'Content-Type: application/json' \ -d '{ "external_course_ids": [ "string" ]}'{ "session_id": "string", "program_id": "string", "count": 0, "committed": false, "failed": 0}Also says which connection the course's Program is bound to. Check it before the lms.* read tools: they need a linked course (lms.course_not_linked otherwise). Link a course with lms.course.link.set.
semestra_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.
course_id*Course IdCourse id
Successful Response
application/json- response
course_id*Course Idlink*|nullprogram_connection_id*|Connection bound to the course's Program; null = bind one first
curl -X GET 'https://example.com/courses/string/lms-link'{ "course_id": "string", "link": { "id": "string", "course_id": "string", "program_id": "string", "connection_id": "string", "provider": "string", "external_course_id": "string", "external_code": "string", "external_name": "string", "external_term": "string", "web_url": "string", "sync_enabled": true, "last_synced_at": "2019-08-24T14:15:22Z", "last_error_code": "string", "created_at": "2019-08-24T14:15:22Z" }, "program_connection_id": "string"}Off: no calendar overlay and no update checks; reading still works. To remove the link altogether use lms.course.link.delete.
semestra_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.
course_id*Course IdCourse id
application/json- body
sync_enabled*Sync EnabledShow in the calendar, check updates
Successful Response
application/json- response
course_id*Course Idlink*|nullprogram_connection_id*|Connection bound to the course's Program; null = bind one first
curl -X PATCH 'https://example.com/courses/string/lms-link' \ -H 'Content-Type: application/json' \ -d '{ "sync_enabled": true}'{ "course_id": "string", "link": { "id": "string", "course_id": "string", "program_id": "string", "connection_id": "string", "provider": "string", "external_course_id": "string", "external_code": "string", "external_name": "string", "external_term": "string", "web_url": "string", "sync_enabled": true, "last_synced_at": "2019-08-24T14:15:22Z", "last_error_code": "string", "created_at": "2019-08-24T14:15:22Z" }, "program_connection_id": "string"}Imported assessments, tasks and files stay; LMS reads, calendar overlay and update checks stop for this course. Link it again with lms.course.link.set. To pause syncing but keep reading, use lms.course.link.update instead.
semestra_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.
course_id*Course IdCourse id
Successful Response
application/json- response
course_id*Course Idlink*|nullprogram_connection_id*|Connection bound to the course's Program; null = bind one first
curl -X DELETE 'https://example.com/courses/string/lms-link'{ "course_id": "string", "link": { "id": "string", "course_id": "string", "program_id": "string", "connection_id": "string", "provider": "string", "external_course_id": "string", "external_code": "string", "external_name": "string", "external_term": "string", "web_url": "string", "sync_enabled": true, "last_synced_at": "2019-08-24T14:15:22Z", "last_error_code": "string", "created_at": "2019-08-24T14:15:22Z" }, "program_connection_id": "string"}Uses the Program's bound connection (lms.program_not_configured without one). An external course can be linked to only one course of the Program (lms.course_already_linked). If the course is already linked to another external course this fails with lms.course_link_exists (naming that course) unless replace is true; replacing stops tracking what was imported through the old link.
semestra_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.
course_id*Course IdCourse id
application/json- body
external_course_id*External Course IdExternal course id (lms.course.list)
1 <= length <= 200sync_enabled?Sync EnabledShow in the calendar, check updates
truereplace?ReplaceReplace the course's link to another external course; only when the user asked to change it
falseSuccessful Response
application/json- response
course_id*Course Idlink*|nullprogram_connection_id*|Connection bound to the course's Program; null = bind one first
curl -X PUT 'https://example.com/courses/string/lms-link' \ -H 'Content-Type: application/json' \ -d '{ "external_course_id": "string"}'{ "course_id": "string", "link": { "id": "string", "course_id": "string", "program_id": "string", "connection_id": "string", "provider": "string", "external_course_id": "string", "external_code": "string", "external_name": "string", "external_term": "string", "web_url": "string", "sync_enabled": true, "last_synced_at": "2019-08-24T14:15:22Z", "last_error_code": "string", "created_at": "2019-08-24T14:15:22Z" }, "program_connection_id": "string"}Changes only the link, never the course itself. Use when the course was renamed or moved on the LMS and the link still shows the old code, name or term.
semestra_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.
course_id*Course IdCourse id
Successful Response
application/json- response
course_id*Course Idlink*|nullprogram_connection_id*|Connection bound to the course's Program; null = bind one first
curl -X POST 'https://example.com/courses/string/lms-link:sync'{ "course_id": "string", "link": { "id": "string", "course_id": "string", "program_id": "string", "connection_id": "string", "provider": "string", "external_course_id": "string", "external_code": "string", "external_name": "string", "external_term": "string", "web_url": "string", "sync_enabled": true, "last_synced_at": "2019-08-24T14:15:22Z", "last_error_code": "string", "created_at": "2019-08-24T14:15:22Z" }, "program_connection_id": "string"}Current-term courses by default; include_past for all of them.
semestra_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.
program_id*Program IdProgram id
include_past?Include PastAlso courses of past terms
falserefresh?RefreshSkip the 5-minute cache and ask again
falseSuccessful Response
application/json- response
connection_id*Connection Idprovider*Provideritems*array<>truncated*Truncatedcurl -X GET 'https://example.com/programs/string/lms/courses'{ "connection_id": "string", "provider": "string", "items": [ { "external_id": "string", "web_url": "string", "raw_kind": "string", "code": "string", "name": "string", "term": "string", "start_at": "2019-08-24T14:15:22Z", "end_at": "2019-08-24T14:15:22Z", "default_view": "string", "is_current": true, "linked_course_id": "string", "linked_course_name": "string" } ], "truncated": true}A read the platform does not support fails with lms.feature_unsupported.
semestra_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.
course_id*Course IdCourse id (must be linked)
refresh?RefreshSkip the 5-minute cache and ask again
falseSuccessful Response
application/json- response
link*provider*Providerprovider_name*Provider Namefeatures*array<>course*navigation*array<>default_view*string|nullfetched_at?|When the course was last read from the platform (cached)
truncated*Truncatedcurl -X GET 'https://example.com/courses/string/lms'{ "link": { "id": "string", "course_id": "string", "program_id": "string", "connection_id": "string", "provider": "string", "external_course_id": "string", "external_code": "string", "external_name": "string", "external_term": "string", "web_url": "string", "sync_enabled": true, "last_synced_at": "2019-08-24T14:15:22Z", "last_error_code": "string", "created_at": "2019-08-24T14:15:22Z" }, "provider": "string", "provider_name": "string", "features": [ "courses" ], "course": { "external_id": "string", "web_url": "string", "raw_kind": "string", "code": "string", "name": "string", "term": "string", "start_at": "2019-08-24T14:15:22Z", "end_at": "2019-08-24T14:15:22Z", "default_view": "string", "is_current": true }, "navigation": [ { "external_id": "string", "web_url": "string", "raw_kind": "string", "kind": "home", "label": "string", "position": 0, "hidden": false } ], "default_view": "string", "fetched_at": "2019-08-24T14:15:22Z", "truncated": true}Creates an import of the changes and changes nothing itself: they are written when the import is committed (imports.session.commit) after the user reviewed it.
semestra_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.
course_id*Course IdCourse id
Successful Response
application/json- response
session_id*Session Idprogram_id*Program Idcount*CountItems in the import
committed?CommittedSaved at once (nothing needed a decision); otherwise it waits for review
falsefailed?FailedItems that could not be saved, when committed (see the import)
0curl -X POST 'https://example.com/courses/string/lms/updates:review'{ "session_id": "string", "program_id": "string", "count": 0, "committed": false, "failed": 0}The Canvas tab's "Refresh". Reads with refresh do the same for one read.
Not for agents.
semestra_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.
course_id*Course IdCourse id
Successful Response
application/json- response
course_id*Course Idlink*|nullprogram_connection_id*|Connection bound to the course's Program; null = bind one first
curl -X POST 'https://example.com/courses/string/lms:refresh'{ "course_id": "string", "link": { "id": "string", "course_id": "string", "program_id": "string", "connection_id": "string", "provider": "string", "external_course_id": "string", "external_code": "string", "external_name": "string", "external_term": "string", "web_url": "string", "sync_enabled": true, "last_synced_at": "2019-08-24T14:15:22Z", "last_error_code": "string", "created_at": "2019-08-24T14:15:22Z" }, "program_connection_id": "string"}Read its text with lms.file.preview; to search or cite it, save it with lms.file.save_to_course.
semestra_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.
course_id*Course IdCourse id (must be linked)
file_id*File IdExternal file id: target.ref of a file in lms.module_item.list, or external_id of a file from lms.folder.get / lms.file.search
refresh?RefreshSkip the 5-minute cache and ask again
falseSuccessful Response
application/json- response
external_id*External Idweb_url?|Opens the item on the platform
raw_kind?|The platform's own type (debugging)
name*Namemime_type?string|nullsize_bytes?integer|nullupdated_at?|nulllocked?Lockedfalsecurl -X GET 'https://example.com/courses/string/lms/files/string'{ "external_id": "string", "web_url": "string", "raw_kind": "string", "name": "string", "mime_type": "string", "size_bytes": 0, "updated_at": "2019-08-24T14:15:22Z", "locked": false}Reads it without saving it. To search it or cite it, save it with lms.file.save_to_course instead.
semestra_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.
course_id*Course IdCourse id (must be linked)
file_id*File IdExternal file id: target.ref of a file in lms.module_item.list, or external_id of a file from lms.folder.get / lms.file.search
refresh?RefreshSkip the 5-minute cache and ask again
falseSuccessful Response
application/json- response
name*Namemime_type*Mime Typekind*Kindpdf, docx, pptx, xlsx, csv, html, text or markdown
pages*array<string>Markdown per page (slide, sheet, logical page)
truncated*TruncatedOnly the first pages are included
curl -X GET 'https://example.com/courses/string/lms/files/string/preview'{ "name": "string", "mime_type": "string", "kind": "string", "pages": [ "string" ], "truncated": true}It is then processed like an upload and can be searched and extracted.
semestra_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.
course_id*Course IdCourse id (must be linked)
file_id*File IdExternal file id: target.ref of a file in lms.module_item.list, or external_id of a file from lms.folder.get / lms.file.search
application/json- body
folder_id?|Course folder, default root
Successful Response
application/json- response
file_item_id*File Item Idname*Namecurl -X POST 'https://example.com/courses/string/lms/files/string:save' \ -H 'Content-Type: application/json' \ -d '{}'{ "file_item_id": "string", "name": "string"}Matches part of the file name, not its contents. Each result says its type, size, last change and whether it is locked. Browse by folder with lms.folder.get, open one with lms.file.preview, or copy it into the course's files with lms.file.save_to_course.
semestra_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.
course_id*Course IdCourse id (must be linked)
refresh?RefreshSkip the 5-minute cache and ask again
falseterm*TermPart of the file name
Successful Response
application/json- response
items*array<>truncated*Truncatedcurl -X GET 'https://example.com/courses/string/lms/files?term=string'{ "items": [ { "external_id": "string", "web_url": "string", "raw_kind": "string", "name": "string", "mime_type": "string", "size_bytes": 0, "updated_at": "2019-08-24T14:15:22Z", "locked": false } ], "truncated": true}Leave out folder_id for the root folder. Courses that hide their files from students fail with lms.forbidden; their files are still reachable through modules.
semestra_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.
course_id*Course IdCourse id (must be linked)
refresh?RefreshSkip the 5-minute cache and ask again
falsefolder_id?|External folder id; the course's root folder when left out
Successful Response
application/json- response
folder*trail*array<>From the root folder down to folder
folders*array<>files*array<>truncated?Truncatedfalsecurl -X GET 'https://example.com/courses/string/lms/folders'{ "folder": { "external_id": "string", "web_url": "string", "raw_kind": "string", "name": "string", "path": "string", "parent_id": "string", "files_count": 0, "folders_count": 0, "locked": false }, "trail": [ { "external_id": "string", "web_url": "string", "raw_kind": "string", "name": "string", "path": "string", "parent_id": "string", "files_count": 0, "folders_count": 0, "locked": false } ], "folders": [ { "external_id": "string", "web_url": "string", "raw_kind": "string", "name": "string", "path": "string", "parent_id": "string", "files_count": 0, "folders_count": 0, "locked": false } ], "files": [ { "external_id": "string", "web_url": "string", "raw_kind": "string", "name": "string", "mime_type": "string", "size_bytes": 0, "updated_at": "2019-08-24T14:15:22Z", "locked": false } ], "truncated": false}The course total first, then one row per assignment, with score, points possible and grade as the LMS shows them. The gradebook in this app is grading.gradebook.get; to add LMS assignments to it use lms.assignment.import.
semestra_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.
course_id*Course IdCourse id (must be linked)
refresh?RefreshSkip the 5-minute cache and ask again
falseSuccessful Response
application/json- response
items*array<>truncated*Truncatedcurl -X GET 'https://example.com/courses/string/lms/grades'{ "items": [ { "external_id": "string", "web_url": "string", "raw_kind": "string", "name": "string", "score": 0, "points_possible": 0, "grade": "string", "group_name": "string", "graded_at": "2019-08-24T14:15:22Z", "kind": "total" } ], "truncated": true}Modules are the instructor's outline of the course (weeks or units), in order, with their state, unlock date and item count. Items of a module: lms.module_item.list.
semestra_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.
course_id*Course IdCourse id (must be linked)
refresh?RefreshSkip the 5-minute cache and ask again
falseSuccessful Response
application/json- response
items*array<>truncated*Truncatedcurl -X GET 'https://example.com/courses/string/lms/modules'{ "items": [ { "external_id": "string", "web_url": "string", "raw_kind": "string", "name": "string", "position": 0, "state": "string", "unlock_at": "2019-08-24T14:15:22Z", "item_count": 0, "completed_at": "2019-08-24T14:15:22Z", "prerequisite_module_ids": [ "string" ], "require_sequential_progress": false, "items": [ { "external_id": "string", "web_url": "string", "raw_kind": "string", "title": "string", "kind": "page", "position": 0, "indent": 0, "target": { "kind": "page", "ref": "string" }, "external_url": "string", "completion": { "type": "string", "min_score": 0, "completed": false }, "locked": false, "lock_explanation": "string", "due_at": "2019-08-24T14:15:22Z", "points": 0 } ] } ], "truncated": true}Get module_id from lms.module.list. Each item has a kind (page, assignment, file,
quiz, link...) and an indent level. target says where an item opens in the app (page, assignment,
file...).
semestra_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.
course_id*Course IdCourse id (must be linked)
module_id*Module IdExternal module id, from lms.module.list
refresh?RefreshSkip the 5-minute cache and ask again
falseSuccessful Response
application/json- response
items*array<>truncated*Truncatedcurl -X GET 'https://example.com/courses/string/lms/modules/string/items'{ "items": [ { "external_id": "string", "web_url": "string", "raw_kind": "string", "title": "string", "kind": "page", "position": 0, "indent": 0, "target": { "kind": "page", "ref": "string" }, "external_url": "string", "completion": { "type": "string", "min_score": 0, "completed": false }, "locked": false, "lock_explanation": "string", "due_at": "2019-08-24T14:15:22Z", "points": 0 } ], "truncated": true}semestra_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.
course_id*Course IdCourse id (must be linked)
ref*RefPage ref from lms.page.list, or @front for the course's front page
refresh?RefreshSkip the 5-minute cache and ask again
falseSuccessful Response
application/json- response
external_id*External Idweb_url?|Opens the item on the platform
raw_kind?|The platform's own type (debugging)
ref*RefWhat page takes (Canvas: the page url slug)
title*Titleupdated_at?|nullfront_page?Front Pagefalsehtml?string|nulllocked?Lockedfalselock_explanation?|Why it is locked, as the platform says
curl -X GET 'https://example.com/courses/string/lms/pages/string'{ "external_id": "string", "web_url": "string", "raw_kind": "string", "ref": "string", "title": "string", "updated_at": "2019-08-24T14:15:22Z", "front_page": false, "html": "string", "locked": false, "lock_explanation": "string"}Titles and last change only; the course's front page is marked. Read one with lms.page.get. The syllabus has its own tool, lms.syllabus.get.
semestra_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.
course_id*Course IdCourse id (must be linked)
refresh?RefreshSkip the 5-minute cache and ask again
falseSuccessful Response
application/json- response
items*array<>truncated*Truncatedcurl -X GET 'https://example.com/courses/string/lms/pages'{ "items": [ { "external_id": "string", "web_url": "string", "raw_kind": "string", "ref": "string", "title": "string", "updated_at": "2019-08-24T14:15:22Z", "front_page": false } ], "truncated": true}Courses of the Program can only be linked through this connection. The user manages connections in settings.
semestra_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.
program_id*Program IdProgram id
Successful Response
application/json- response
program_id*Program Idconnection_id*string|nullconnection*|nulllink_count*Link CountCourses of the Program linked through it
curl -X GET 'https://example.com/programs/string/lms-binding'{ "program_id": "string", "connection_id": "string", "connection": { "id": "string", "provider": "string", "display_name": "string", "config": {}, "credentials_hint": { "property1": "string", "property2": "string" }, "has_credentials": true, "account_name": "string", "status": "connected", "last_checked_at": "2019-08-24T14:15:22Z", "last_error_code": "string", "program_ids": [ "string" ], "link_count": 0, "created_at": "2019-08-24T14:15:22Z", "updated_at": "2019-08-24T14:15:22Z" }, "link_count": 0}Refused while courses of the Program are linked (lms.program_has_links): unlink them with lms.course.link.delete first. The connection itself stays.
semestra_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.
program_id*Program IdProgram id
Successful Response
application/json- response
program_id*Program Idconnection_id*string|nullconnection*|nulllink_count*Link CountCourses of the Program linked through it
curl -X DELETE 'https://example.com/programs/string/lms-binding'{ "program_id": "string", "connection_id": "string", "connection": { "id": "string", "provider": "string", "display_name": "string", "config": {}, "credentials_hint": { "property1": "string", "property2": "string" }, "has_credentials": true, "account_name": "string", "status": "connected", "last_checked_at": "2019-08-24T14:15:22Z", "last_error_code": "string", "program_ids": [ "string" ], "link_count": 0, "created_at": "2019-08-24T14:15:22Z", "updated_at": "2019-08-24T14:15:22Z" }, "link_count": 0}Refused while courses of the Program are linked (lms.program_has_links). Afterwards link courses with lms.course.link.set.
semestra_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.
program_id*Program IdProgram id
application/json- body
connection_id*Connection IdConnection to bind (connection.id of lms.program.binding.get); the user adds connections in the settings
1 <= length <= 64Successful Response
application/json- response
program_id*Program Idconnection_id*string|nullconnection*|nulllink_count*Link CountCourses of the Program linked through it
curl -X PUT 'https://example.com/programs/string/lms-binding' \ -H 'Content-Type: application/json' \ -d '{ "connection_id": "string"}'{ "program_id": "string", "connection_id": "string", "connection": { "id": "string", "provider": "string", "display_name": "string", "config": {}, "credentials_hint": { "property1": "string", "property2": "string" }, "has_credentials": true, "account_name": "string", "status": "connected", "last_checked_at": "2019-08-24T14:15:22Z", "last_error_code": "string", "program_ids": [ "string" ], "link_count": 0, "created_at": "2019-08-24T14:15:22Z", "updated_at": "2019-08-24T14:15:22Z" }, "link_count": 0}Features the provider lacks are not offered for its connections.
semestra_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.
Successful Response
application/json- response
items*array<>curl -X GET 'https://example.com/lms/providers'{ "items": [ { "kind": "string", "display_name": "string", "features": [ "courses" ], "config_schema": {}, "credentials_schema": {}, "sign_in": false } ]}Due, unlock and lock dates, points and question count by default; ask for more
with fields. A quiz's score and attempts come with lms.assignment.list (its assignment_id);
questions are not available.
semestra_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.
course_id*Course IdCourse id (must be linked)
refresh?RefreshSkip the 5-minute cache and ask again
falsefields?array<>|Agent/MCP only: return just these fields of each item (and its external_id); default all but web_url and html. markdown (or html) is the body, as Markdown
Successful Response
application/json- response
items*array<>truncated*Truncatedcurl -X GET 'https://example.com/courses/string/lms/quizzes'{ "items": [ { "external_id": "string", "web_url": "string", "raw_kind": "string", "title": "string", "html": "string", "due_at": "2019-08-24T14:15:22Z", "unlock_at": "2019-08-24T14:15:22Z", "lock_at": "2019-08-24T14:15:22Z", "points": 0, "question_count": 0, "time_limit": 0, "allowed_attempts": 0, "locked": false, "lock_explanation": "string", "assignment_id": "string" } ], "truncated": true}Score, attempts, the teacher's comments and the rubric scores (match
rubric_scores.criterion_id with the assignment's rubric from lms.assignment.list).
semestra_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.
course_id*Course IdCourse id (must be linked)
assignment_id*Assignment IdExternal assignment id (external_id of lms.assignment.list)
refresh?RefreshSkip the 5-minute cache and ask again
falseSuccessful Response
application/json- response
The user's own submission of one assignment, with the teacher's feedback.
external_id*External Idweb_url?|Opens the item on the platform
raw_kind?|The platform's own type (debugging)
assignment_id*Assignment Idstate?string|nullsubmitted_at?|nullgraded_at?|nullscore?number|nullgrade?string|nullattempt?integer|nulllate?Latefalsemissing?Missingfalsecomments?array<>rubric_scores?array<>curl -X GET 'https://example.com/courses/string/lms/assignments/string/submission'{ "external_id": "string", "web_url": "string", "raw_kind": "string", "assignment_id": "string", "state": "string", "submitted_at": "2019-08-24T14:15:22Z", "graded_at": "2019-08-24T14:15:22Z", "score": 0, "grade": "string", "attempt": 0, "late": false, "missing": false, "comments": [ { "author": "string", "comment": "", "created_at": "2019-08-24T14:15:22Z" } ], "rubric_scores": [ { "criterion_id": "string", "points": 0, "rating_id": "string", "comments": "string" } ]}To extract its grading scheme use lms.syllabus.import.
semestra_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.
course_id*Course IdCourse id (must be linked)
refresh?RefreshSkip the 5-minute cache and ask again
falseSuccessful Response
application/json- response
html?string|nullweb_url?string|nullcurl -X GET 'https://example.com/courses/string/lms/syllabus'{ "html": "string", "web_url": "string"}Starts an AI extraction the user reviews; needs an AI model. Then wait for it and commit it like any import (imports.session.get, imports.session.commit).
semestra_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.
course_id*Course IdCourse id
Successful Response
application/json- response
session_id*Session Idprogram_id*Program Idcount*CountItems in the import
committed?CommittedSaved at once (nothing needed a decision); otherwise it waits for review
falsefailed?FailedItems that could not be saved, when committed (see the import)
0curl -X POST 'https://example.com/courses/string/lms/imports:syllabus'{ "session_id": "string", "program_id": "string", "count": 0, "committed": false, "failed": 0}One request per connection (the term board's card); each item names its
course_id. Not for agents: they read one course with lms.announcement.list.
semestra_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.
term_id*Term IdTerm id
refresh?RefreshSkip the 5-minute cache and ask again
falseSuccessful Response
application/json- response
items*array<>Newest first
linked_course_ids*array<string>The term's courses linked to an LMS
truncated*Truncatedcurl -X GET 'https://example.com/terms/string/lms/announcements'{ "items": [ { "external_id": "string", "web_url": "string", "raw_kind": "string", "external_course_id": "", "title": "string", "html": "string", "author": "string", "posted_at": "2019-08-24T14:15:22Z", "updated_at": "2019-08-24T14:15:22Z", "unread": false, "course_id": "string" } ], "linked_course_ids": [ "string" ], "truncated": true}From the cached lists, per course (the "today" page's prompt). Not for agents:
they read one course with lms.assignment.list (new_ids).
semestra_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.
term_id*Term IdTerm id
Successful Response
application/json- response
items*array<>Per linked course with new assignments
total*Totalunread?array<string>Synced linked courses whose assignments are not cached: read them with lms.assignment.list (its new_ids)
curl -X GET 'https://example.com/terms/string/lms/new-assignments'{ "items": [ { "course_id": "string", "external_ids": [ "string" ], "names": [ "string" ] } ], "total": 0, "unread": [ "string" ]}