{"openapi":"3.1.0","info":{"title":"Hotline LMS API","version":"2.0","description":"The same operations AI assistants use through MCP (https:\/\/your-workspace.hotlinelms.com\/mcp). Every workspace has its own address. Authenticate as a person with OAuth 2.1 (PKCE), or as a system with a service key. Generated from the live operation list."},"servers":[{"url":"https:\/\/your-workspace.hotlinelms.com"}],"security":[{"oauth2":[]},{"serviceKey":[]}],"paths":{"\/api\/v2\/me":{"get":{"operationId":"me_get","summary":"Who am I","description":"The signed-in person (name, email, role, organisation), the workspace, the permissions they hold and the tools available to them. Call this first.","tags":["Me"],"security":[{"oauth2":["profile"]},{"serviceKey":[]}],"x-mcp-tool":"me_get","x-scope":"profile","x-permissions":[],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}}}}},"\/api\/v2\/users":{"get":{"operationId":"users_list","summary":"List people","description":"People in the workspace that you can see (admins: everyone; organisation managers: their companies). Search by name or email, filter by organisation, role or status. Paged.","tags":["People & companies"],"security":[{"oauth2":["people:read"]},{"serviceKey":[]}],"x-mcp-tool":"users_list","x-scope":"people:read","x-permissions":["users.view_all","users.view_org"],"parameters":[{"name":"q","in":"query","required":false,"description":"Part of a name or email.","schema":{"type":"string","maxLength":120,"description":"Part of a name or email."}},{"name":"organisation_id","in":"query","required":false,"description":"","schema":{"type":"integer"}},{"name":"role","in":"query","required":false,"description":"","schema":{"type":"string","enum":["tenant_admin","training_admin","org_manager","instructor","author","learner"]}},{"name":"status","in":"query","required":false,"description":"","schema":{"type":"string","enum":["active","invited","suspended","pending_approval"]}},{"name":"page","in":"query","required":false,"description":"Page number, from 1.","schema":{"type":"integer","minimum":1,"description":"Page number, from 1."}},{"name":"per_page","in":"query","required":false,"description":"Rows per page (default 25, at most 100).","schema":{"type":"integer","minimum":1,"maximum":100,"description":"Rows per page (default 25, at most 100)."}}],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}}}},"post":{"operationId":"users_create","summary":"Add a person","description":"Add a member and (by default) email them an activation link to set their own password. Same rules as Add member: plan and company limits; organisation managers can only add learners to their own company. Staff roles (tenant_admin, training_admin) cannot be given through an AI assistant (MCP). Preview first, then confirm.\n\nConfirm-first: call without confirm_token to preview; call again with the same arguments and the confirm_token to carry it out.","tags":["People & companies"],"security":[{"oauth2":["people:write"]},{"serviceKey":[]}],"x-mcp-tool":"users_create","x-scope":"people:write","x-permissions":["users.create"],"x-effects":["email","webhook"],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","properties":{"first_name":{"type":"string","maxLength":100},"last_name":{"type":"string","maxLength":100},"email":{"type":"string","format":"email","maxLength":190},"role":{"type":"string","enum":["learner","instructor","author","org_manager","training_admin","tenant_admin"]},"organisation_id":{"type":"integer"},"manager_id":{"type":"integer","description":"Who they report to (someone in the same organisation)."},"send_invite":{"type":"boolean","description":"Email the activation link (default true). If false they can be invited later with users_resend_invite."},"confirm_token":{"type":"string","description":"From the preview. Leave out to preview."}},"required":["first_name","last_name","email","role"]}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string. Repeating the request with the same key within 24 hours returns the first reply instead of running again.","schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"A preview (data.preview, data.confirm_token) or the result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}},"201":{"description":"Created.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}}}}},"\/api\/v2\/users\/{user}":{"get":{"operationId":"users_get","summary":"Get a person","description":"One person with their organisation, who they report to, their enrolments (status, progress, deadline) and certificates.","tags":["People & companies"],"security":[{"oauth2":["people:read"]},{"serviceKey":[]}],"x-mcp-tool":"users_get","x-scope":"people:read","x-permissions":["users.view_all","users.view_org"],"parameters":[{"name":"user","in":"path","required":true,"description":"Their id or uuid (from users_list).","schema":{"type":"string"}}],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}}}},"patch":{"operationId":"users_update","summary":"Update a person","description":"Change name, email, organisation, who they report to, role (admins only; staff roles not through an AI assistant) or status (active \/ suspended). Only send the fields to change. Preview shows before and after.\n\nConfirm-first: call without confirm_token to preview; call again with the same arguments and the confirm_token to carry it out.","tags":["People & companies"],"security":[{"oauth2":["people:write"]},{"serviceKey":[]}],"x-mcp-tool":"users_update","x-scope":"people:write","x-permissions":["users.edit"],"requestBody":{"required":false,"content":{"application\/json":{"schema":{"type":"object","properties":{"first_name":{"type":"string","maxLength":100},"last_name":{"type":"string","maxLength":100},"email":{"type":"string","format":"email","maxLength":190},"organisation_id":{"type":"integer"},"manager_id":{"type":"integer"},"role":{"type":"string","enum":["learner","instructor","author","org_manager","training_admin","tenant_admin"]},"status":{"type":"string","enum":["active","suspended"]},"confirm_token":{"type":"string","description":"From the preview. Leave out to preview."}}}}}},"parameters":[{"name":"user","in":"path","required":true,"description":"Their id or uuid.","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string. Repeating the request with the same key within 24 hours returns the first reply instead of running again.","schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"A preview (data.preview, data.confirm_token) or the result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}}}}},"\/api\/v2\/organisations":{"get":{"operationId":"orgs_list","summary":"List organisations","description":"Customer companies (organisations) with member counts, parent company and manager. Organisation managers see the companies they manage.","tags":["People & companies"],"security":[{"oauth2":["people:read"]},{"serviceKey":[]}],"x-mcp-tool":"orgs_list","x-scope":"people:read","x-permissions":["organisations.edit","organisations.create","users.view_org"],"parameters":[{"name":"q","in":"query","required":false,"description":"Part of the name.","schema":{"type":"string","maxLength":120,"description":"Part of the name."}}],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}}}},"post":{"operationId":"orgs_create","summary":"Create a company","description":"Add a company (organisation): a name, optionally a parent company (to make it a sub-company), managers and a member limit. Managers need the organisation manager role to manage it; you are warned if they don't have it. Nobody is emailed.","tags":["People & companies"],"security":[{"oauth2":["people:write"]},{"serviceKey":[]}],"x-mcp-tool":"orgs_create","x-scope":"people:write","x-permissions":["organisations.create"],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":255},"parent_id":{"type":"integer","minimum":0,"description":"Parent company id (orgs_list). Leave out for a top-level company."},"managers":{"type":"array","maxItems":20,"items":{"type":"string"},"description":"Person ids or uuids; the first is the main manager."},"member_limit":{"type":"integer","minimum":0,"description":"Most members it may have; 0 or leave out for no limit."}},"required":["name"]}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string. Repeating the request with the same key within 24 hours returns the first reply instead of running again.","schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}},"201":{"description":"Created.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}}}}},"\/api\/v2\/organisations\/{organisation_id}":{"get":{"operationId":"orgs_get","summary":"Get an organisation","description":"One company: status, access expiry, member limit, managers, sub-companies and members (first 100).","tags":["People & companies"],"security":[{"oauth2":["people:read"]},{"serviceKey":[]}],"x-mcp-tool":"orgs_get","x-scope":"people:read","x-permissions":["organisations.edit","organisations.create","users.view_org"],"parameters":[{"name":"organisation_id","in":"path","required":true,"description":"","schema":{"type":"string"}}],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}}}},"patch":{"operationId":"orgs_update","summary":"Update a company","description":"Rename a company, move it under another company (parent_id; 0 makes it top level), replace its managers (the whole list; [] removes them all) or change its member limit (0 = no limit). Only what you give changes. Preview first: it shows before and after. Deactivating or deleting a company is done in the web app.\n\nConfirm-first: call without confirm_token to preview; call again with the same arguments and the confirm_token to carry it out.","tags":["People & companies"],"security":[{"oauth2":["people:write"]},{"serviceKey":[]}],"x-mcp-tool":"orgs_update","x-scope":"people:write","x-permissions":["organisations.edit"],"requestBody":{"required":false,"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":255},"parent_id":{"type":"integer","minimum":0,"description":"New parent company id; 0 makes it top level."},"managers":{"type":"array","maxItems":20,"items":{"type":"string"},"description":"The full list of person ids or uuids (replaces the current managers; the first is the main manager)."},"member_limit":{"type":"integer","minimum":0,"description":"0 = no limit."},"confirm_token":{"type":"string","description":"From the preview. Leave out to preview."}}}}}},"parameters":[{"name":"organisation_id","in":"path","required":true,"description":"","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string. Repeating the request with the same key within 24 hours returns the first reply instead of running again.","schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"A preview (data.preview, data.confirm_token) or the result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}}}}},"\/api\/v2\/my\/learning":{"get":{"operationId":"my_learning_list","summary":"List my courses","description":"The signed-in person's own courses: progress, deadline, whether it is mandatory or overdue, and completion. status: current (default: in progress), completed, or all. To open one, use my_open_link.","tags":["Me"],"security":[{"oauth2":["learning"]},{"serviceKey":[]}],"x-mcp-tool":"my_learning_list","x-scope":"learning","x-permissions":[],"parameters":[{"name":"status","in":"query","required":false,"description":"","schema":{"type":"string","enum":["current","completed","all"]}}],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}}}}},"\/api\/v2\/my\/certificates":{"get":{"operationId":"my_certificates_list","summary":"List my certificates","description":"The signed-in person's own current certificates: when each was issued and expires (valid, expiring within 90 days, expired) and a public link to check it.","tags":["Me"],"security":[{"oauth2":["learning"]},{"serviceKey":[]}],"x-mcp-tool":"my_certificates_list","x-scope":"learning","x-permissions":[],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}}}}},"\/api\/v2\/my\/course-dates":{"get":{"operationId":"my_bookings_list","summary":"List my course dates","description":"Face-to-face course dates the signed-in person is booked on that haven't finished yet: when (local time), where and the booking status.","tags":["Me"],"security":[{"oauth2":["learning"]},{"serviceKey":[]}],"x-mcp-tool":"my_bookings_list","x-scope":"learning","x-permissions":[],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}}}}},"\/api\/v2\/my\/catalogue":{"get":{"operationId":"my_catalogue_search","summary":"Find courses I can take","description":"Courses in the catalogue the signed-in person can see, searched by words in the title or description (q), with whether they are already on each. Free ones can be started with my_enrol; priced ones are bought on the website.","tags":["Me"],"security":[{"oauth2":["learning"]},{"serviceKey":[]}],"x-mcp-tool":"my_catalogue_search","x-scope":"learning","x-permissions":["courses.view_catalogue"],"parameters":[{"name":"q","in":"query","required":false,"description":"Words to search for.","schema":{"type":"string","maxLength":100,"description":"Words to search for."}}],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}}}}},"\/api\/v2\/my\/open-link":{"post":{"operationId":"my_open_link","summary":"Get a link to open my course","description":"A direct link (URL) to open, start, continue or resume one of the person's own courses (course), download one of their certificates (certificate: id or number), or open My learning (neither). Use this whenever they ask for a link to a course or certificate. The link signs them straight in: it works once, within 5 minutes, and only reaches their learning (anything else asks for their password). Give it to the person to click; never reuse or share it.","tags":["Me"],"security":[{"oauth2":["learning"]},{"serviceKey":[]}],"x-mcp-tool":"my_open_link","x-scope":"learning","x-permissions":[],"requestBody":{"required":false,"content":{"application\/json":{"schema":{"type":"object","properties":{"course":{"type":"string","description":"Course id, uuid or slug (my_learning_list)."},"certificate":{"type":"string","description":"Certificate id or number (my_certificates_list)."}}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string. Repeating the request with the same key within 24 hours returns the first reply instead of running again.","schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}},"201":{"description":"Created.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}}}}},"\/api\/v2\/my\/enrolments":{"post":{"operationId":"my_enrol","summary":"Enrol myself on a course","description":"Enrol the signed-in person on a free course from the catalogue, with the same rules as the website (open for enrolment, prerequisites done, not hidden from them). No email is sent. Then my_open_link opens it.","tags":["Me"],"security":[{"oauth2":["learning"]},{"serviceKey":[]}],"x-mcp-tool":"my_enrol","x-scope":"learning","x-permissions":["courses.enrol_self"],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","properties":{"course":{"type":"string","description":"Course id, uuid or slug (my_catalogue_search)."}},"required":["course"]}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string. Repeating the request with the same key within 24 hours returns the first reply instead of running again.","schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}},"201":{"description":"Created.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}}}}},"\/api\/v2\/users\/{user}\/training-record":{"get":{"operationId":"users_training_record","summary":"Get a person's training record","description":"Everything about one person's training: their courses with progress and completion, their certificates with expiry (add include_history for superseded ones too), and the course dates they were booked on. Certificates come with a public check link and a PDF link (which needs signing in).","tags":["People & companies"],"security":[{"oauth2":["people:read"]},{"serviceKey":[]}],"x-mcp-tool":"users_training_record","x-scope":"people:read","x-permissions":["users.view_all","users.view_org","analytics.view_all","analytics.view_org"],"parameters":[{"name":"user","in":"path","required":true,"description":"Their id or uuid (from users_list).","schema":{"type":"string"}},{"name":"include_history","in":"query","required":false,"description":"Also list certificates that were replaced by a newer one.","schema":{"type":"boolean","description":"Also list certificates that were replaced by a newer one."}}],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}}}}},"\/api\/v2\/users\/{user}\/password-reset":{"post":{"operationId":"users_send_password_reset","summary":"Send a password reset","description":"Email someone a link to choose a new password (the same as \"Forgot password\"; it works for an hour). For someone who hasn't activated their account yet, resend the invite instead. Managers can do this for learners in their companies. Preview first.\n\nConfirm-first: call without confirm_token to preview; call again with the same arguments and the confirm_token to carry it out.","tags":["People & companies"],"security":[{"oauth2":["people:write"]},{"serviceKey":[]}],"x-mcp-tool":"users_send_password_reset","x-scope":"people:write","x-permissions":["users.edit"],"x-effects":["email"],"requestBody":{"required":false,"content":{"application\/json":{"schema":{"type":"object","properties":{"confirm_token":{"type":"string","description":"From the preview. Leave out to preview."}}}}}},"parameters":[{"name":"user","in":"path","required":true,"description":"Their id or uuid.","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string. Repeating the request with the same key within 24 hours returns the first reply instead of running again.","schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"A preview (data.preview, data.confirm_token) or the result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}},"201":{"description":"Created.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}}}}},"\/api\/v2\/enrolments":{"get":{"operationId":"enrolments_list","summary":"List enrolments","description":"Course enrolments for people you can see: status, progress, deadline, completion. Filter by person, course, status or organisation, or only overdue ones. Paged.","tags":["Enrolments & certificates"],"security":[{"oauth2":["people:read"]},{"serviceKey":[]}],"x-mcp-tool":"enrolments_list","x-scope":"people:read","x-permissions":["enrolments.assign","users.view_all","users.view_org","analytics.view_all","analytics.view_org"],"parameters":[{"name":"user","in":"query","required":false,"description":"Person id or uuid.","schema":{"type":"string","description":"Person id or uuid."}},{"name":"course","in":"query","required":false,"description":"Course id, uuid or slug.","schema":{"type":"string","description":"Course id, uuid or slug."}},{"name":"status","in":"query","required":false,"description":"","schema":{"type":"string","enum":["active","awaiting_exam","completed","expired","dropped","cancelled"]}},{"name":"organisation_id","in":"query","required":false,"description":"","schema":{"type":"integer"}},{"name":"overdue","in":"query","required":false,"description":"Only enrolments past their deadline and not finished.","schema":{"type":"boolean","description":"Only enrolments past their deadline and not finished."}},{"name":"page","in":"query","required":false,"description":"Page number, from 1.","schema":{"type":"integer","minimum":1,"description":"Page number, from 1."}},{"name":"per_page","in":"query","required":false,"description":"Rows per page (default 25, at most 100).","schema":{"type":"integer","minimum":1,"maximum":100,"description":"Rows per page (default 25, at most 100)."}}],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}}}},"post":{"operationId":"enrolments_assign","summary":"Assign courses","description":"Assign one or more courses to one or more people (up to 200 people and 50 courses). The preview lists, per person and course, what will happen: enrolled, fresh run, already in progress, already completed, or not available, and how many course-assigned emails will go out. Same rules as Assign Courses.\n\nConfirm-first: call without confirm_token to preview; call again with the same arguments and the confirm_token to carry it out.","tags":["Enrolments & certificates"],"security":[{"oauth2":["people:write"]},{"serviceKey":[]}],"x-mcp-tool":"enrolments_assign","x-scope":"people:write","x-permissions":["enrolments.assign"],"x-effects":["email","webhook"],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","properties":{"users":{"type":"array","maxItems":200,"items":{"type":"string"},"description":"Person ids or uuids."},"courses":{"type":"array","maxItems":50,"items":{"type":"string"},"description":"Course ids, uuids or slugs."},"deadline":{"type":"string","format":"date","description":"Complete by (YYYY-MM-DD)."},"mandatory":{"type":"boolean","description":"Counts towards compliance (overdue reports)."},"renew_completed":{"type":"boolean","description":"Start a fresh run for people who already completed the course (e.g. a refresher)."},"force":{"type":"boolean","description":"Admins only: assign even where curation hides the course from them."},"notify":{"type":"boolean","description":"Tell them (in-app, and by email if the workspace sends course-assigned emails). Default true."},"confirm_token":{"type":"string","description":"From the preview. Leave out to preview."}},"required":["users","courses"]}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string. Repeating the request with the same key within 24 hours returns the first reply instead of running again.","schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"A preview (data.preview, data.confirm_token) or the result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}},"201":{"description":"Created.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}}}}},"\/api\/v2\/certificates":{"get":{"operationId":"certificates_list","summary":"List certificates","description":"Current certificates for people you can see, with issue and expiry dates. Filter by person or course, by expiring within N days, or expired. Paged.","tags":["Enrolments & certificates"],"security":[{"oauth2":["people:read"]},{"serviceKey":[]}],"x-mcp-tool":"certificates_list","x-scope":"people:read","x-permissions":["courses.view_all","analytics.view_all","analytics.view_org","users.view_all","users.view_org"],"parameters":[{"name":"user","in":"query","required":false,"description":"","schema":{"type":"string"}},{"name":"course","in":"query","required":false,"description":"","schema":{"type":"string"}},{"name":"expiring_within_days","in":"query","required":false,"description":"","schema":{"type":"integer","minimum":1,"maximum":730}},{"name":"expired","in":"query","required":false,"description":"","schema":{"type":"boolean"}},{"name":"include_superseded","in":"query","required":false,"description":"Also show certificates replaced by a later one.","schema":{"type":"boolean","description":"Also show certificates replaced by a later one."}},{"name":"page","in":"query","required":false,"description":"Page number, from 1.","schema":{"type":"integer","minimum":1,"description":"Page number, from 1."}},{"name":"per_page","in":"query","required":false,"description":"Rows per page (default 25, at most 100).","schema":{"type":"integer","minimum":1,"maximum":100,"description":"Rows per page (default 25, at most 100)."}}],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}}}}},"\/api\/v2\/recertification":{"get":{"operationId":"recert_matrix","summary":"Recertification status","description":"Who needs recertifying: each person and course with expiry date, days left and state (valid, expiring, grace, expired), plus the next course date to rebook onto. Use for questions like who needs recertifying this quarter.","tags":["Enrolments & certificates"],"security":[{"oauth2":["people:read"]},{"serviceKey":[]}],"x-mcp-tool":"recert_matrix","x-scope":"people:read","x-permissions":["tms.bookings.manage","analytics.view_all","analytics.view_org"],"parameters":[{"name":"organisation_id","in":"query","required":false,"description":"","schema":{"type":"integer"}},{"name":"course","in":"query","required":false,"description":"","schema":{"type":"string"}},{"name":"state","in":"query","required":false,"description":"","schema":{"type":"string","enum":["valid","expiring","grace","expired"]}},{"name":"limit","in":"query","required":false,"description":"","schema":{"type":"integer","minimum":1,"maximum":1000}}],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}}}}},"\/api\/v2\/completions":{"get":{"operationId":"completions_feed","summary":"Completions since","description":"Course completions (with certificate number and expiry) since a date\/time, oldest first, for syncing a training matrix or HR system. Pass meta.next_cursor as cursor to continue.","tags":["Enrolments & certificates"],"security":[{"oauth2":["people:read"]},{"serviceKey":[]}],"x-mcp-tool":"completions_feed","x-scope":"people:read","x-permissions":["analytics.view_all","analytics.view_org"],"parameters":[{"name":"since","in":"query","required":false,"description":"ISO 8601 date\/time, e.g. 2026-09-01T00:00:00Z.","schema":{"type":"string","description":"ISO 8601 date\/time, e.g. 2026-09-01T00:00:00Z."}},{"name":"cursor","in":"query","required":false,"description":"meta.next_cursor from the previous call.","schema":{"type":"string","description":"meta.next_cursor from the previous call."}},{"name":"limit","in":"query","required":false,"description":"","schema":{"type":"integer","minimum":1,"maximum":500}}],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}}}}},"\/api\/v2\/team\/snapshot":{"get":{"operationId":"team_snapshot","summary":"My team at a glance","description":"For organisation managers: each person in your companies with courses enrolled, completed, in progress, overdue, last active and next booking, plus a per-course summary.","tags":["People & companies"],"security":[{"oauth2":["people:read"]},{"serviceKey":[]}],"x-mcp-tool":"team_snapshot","x-scope":"people:read","x-permissions":["analytics.view_org"],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}}}}},"\/api\/v2\/courses":{"get":{"operationId":"courses_list","summary":"List courses","description":"Courses you can see (admins: all; instructors and authors: their own; organisation managers: published courses available to their company). Search, filter by status or category. Paged.","tags":["Courses"],"security":[{"oauth2":["courses:read"]},{"serviceKey":[]}],"x-mcp-tool":"courses_list","x-scope":"courses:read","x-permissions":["courses.view_all","courses.create"],"parameters":[{"name":"q","in":"query","required":false,"description":"","schema":{"type":"string","maxLength":120}},{"name":"status","in":"query","required":false,"description":"","schema":{"type":"string","enum":["draft","published","archived"]}},{"name":"category_id","in":"query","required":false,"description":"","schema":{"type":"integer"}},{"name":"page","in":"query","required":false,"description":"Page number, from 1.","schema":{"type":"integer","minimum":1,"description":"Page number, from 1."}},{"name":"per_page","in":"query","required":false,"description":"Rows per page (default 25, at most 100).","schema":{"type":"integer","minimum":1,"maximum":100,"description":"Rows per page (default 25, at most 100)."}}],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}}}}},"\/api\/v2\/courses\/{course}":{"get":{"operationId":"courses_get","summary":"Get a course","description":"One course: details, certificate rules, course rules (lesson_order, exam_access, completion_rule, exam_release, and exam_unlock_mode for its classroom dates), outline (modules, lesson titles and each lesson's requirement: required, optional or after_exam), course page sections, accreditations and enrolment counts.","tags":["Courses"],"security":[{"oauth2":["courses:read"]},{"serviceKey":[]}],"x-mcp-tool":"courses_get","x-scope":"courses:read","x-permissions":["courses.view_all","courses.create"],"parameters":[{"name":"course","in":"path","required":true,"description":"Course id, uuid or slug.","schema":{"type":"string"}}],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}}}},"patch":{"operationId":"courses_update","summary":"Change a course's rules","description":"Change how a course runs. lesson_order: free (learners choose the order) or sequential (each required lesson unlocks the next). exam_access: after_content (the exam opens once the required lessons are done) or any_time. completion_rule: content_and_exam (required lessons and the exam pass) or exam_only (the exam pass alone, a test-out). exam_release: automatic (the exam opens by the rules above) or trainer (as well as those rules, a trainer opens it for each learner, on the course page). exam_access, completion_rule and exam_release only for a course whose certificate policy is on_exam_pass. Only what you give changes. Preview first: it shows before and after, and any warnings. Other course settings are changed in the web app.\n\nConfirm-first: call without confirm_token to preview; call again with the same arguments and the confirm_token to carry it out.","tags":["Courses"],"security":[{"oauth2":["courses:write"]},{"serviceKey":[]}],"x-mcp-tool":"courses_update","x-scope":"courses:write","x-permissions":["courses.edit"],"requestBody":{"required":false,"content":{"application\/json":{"schema":{"type":"object","properties":{"lesson_order":{"type":"string","enum":["free","sequential"]},"exam_access":{"type":"string","enum":["after_content","any_time"]},"completion_rule":{"type":"string","enum":["content_and_exam","exam_only"]},"exam_release":{"type":"string","enum":["automatic","trainer"]},"confirm_token":{"type":"string","description":"From the preview. Leave out to preview."}}}}}},"parameters":[{"name":"course","in":"path","required":true,"description":"Course id, uuid or slug.","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string. Repeating the request with the same key within 24 hours returns the first reply instead of running again.","schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"A preview (data.preview, data.confirm_token) or the result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}}}}},"\/api\/v2\/reports":{"get":{"operationId":"reports_list","summary":"List reports","description":"The reports you can run (compliance, rosters, activity, exams, certificates, paths, engagement), with their filters and columns.","tags":["Reports"],"security":[{"oauth2":["reports:read"]},{"serviceKey":[]}],"x-mcp-tool":"reports_list","x-scope":"reports:read","x-permissions":["analytics.view_all","analytics.view_org","analytics.view_assigned","authoring.view_own_reports"],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}}}}},"\/api\/v2\/reports\/{report}":{"get":{"operationId":"reports_run","summary":"Run a report","description":"Run one report from reports_list and get its rows (up to 1000). Some reports need a course filter. course-feedback also returns a summary: per survey question the counts, average and % agree, and the written answers (names left out where the survey hides them).","tags":["Reports"],"security":[{"oauth2":["reports:read"]},{"serviceKey":[]}],"x-mcp-tool":"reports_run","x-scope":"reports:read","x-permissions":["analytics.view_all","analytics.view_org","analytics.view_assigned","authoring.view_own_reports"],"parameters":[{"name":"report","in":"path","required":true,"description":"Report id from reports_list.","schema":{"type":"string"}},{"name":"filters","in":"query","required":false,"description":"For example {\"course\": 12, \"org\": 3, \"include_optional\": 1, \"dormant_days\": 30}. course-feedback takes \"survey\": \"lesson_id:block_id\" (the course's first survey when left out).","schema":{"type":"object","description":"For example {\"course\": 12, \"org\": 3, \"include_optional\": 1, \"dormant_days\": 30}. course-feedback takes \"survey\": \"lesson_id:block_id\" (the course's first survey when left out)."}},{"name":"limit","in":"query","required":false,"description":"","schema":{"type":"integer","minimum":1,"maximum":1000}}],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}}}}},"\/api\/v2\/tms\/events":{"get":{"operationId":"tms_events_list","summary":"List course dates","description":"Face-to-face course dates in a date range (default: today to 60 days ahead) with status, venue, trainers, capacity, booked and places left. Staff see every date; trainers see the dates they teach. Filter by status, course, venue or trainer.","tags":["Course dates"],"security":[{"oauth2":["training:read"]},{"serviceKey":[]}],"x-mcp-tool":"tms_events_list","x-scope":"training:read","x-permissions":["tms.schedule.manage","tms.bookings.manage","tms.trainer.self"],"parameters":[{"name":"from","in":"query","required":false,"description":"ISO date or date\/time (UTC). Default today.","schema":{"type":"string","description":"ISO date or date\/time (UTC). Default today."}},{"name":"to","in":"query","required":false,"description":"ISO date or date\/time (UTC); a date on its own includes that whole day. Default 60 days ahead.","schema":{"type":"string","description":"ISO date or date\/time (UTC); a date on its own includes that whole day. Default 60 days ahead."}},{"name":"status","in":"query","required":false,"description":"","schema":{"type":"string","enum":["draft","published","confirmed","running","completed","cancelled"]}},{"name":"course","in":"query","required":false,"description":"Course id, uuid or slug.","schema":{"type":"string","description":"Course id, uuid or slug."}},{"name":"venue_id","in":"query","required":false,"description":"","schema":{"type":"integer"}},{"name":"trainer_id","in":"query","required":false,"description":"Trainer id from tms_resources_list.","schema":{"type":"integer","description":"Trainer id from tms_resources_list."}}],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}}}},"post":{"operationId":"tms_events_create","summary":"Create a course date","description":"Create a draft course date for a face-to-face course: sessions in the date's own local time, venue\/room, capacity, price (blank = course price). Or give an event template and first_date to fill in the pattern, tasks and settings. Nobody is emailed until it is published. A room already in use is left off with a warning.","tags":["Course dates"],"security":[{"oauth2":["training:write"]},{"serviceKey":[]}],"x-mcp-tool":"tms_events_create","x-scope":"training:write","x-permissions":["tms.schedule.manage"],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","properties":{"course":{"type":"string","description":"Course id, uuid or slug (a face-to-face course)."},"template":{"type":"string","description":"Event template uuid (optional)."},"first_date":{"type":"string","format":"date","description":"With a template: day 1 (YYYY-MM-DD); the pattern fills the other days."},"sessions":{"type":"array","maxItems":30,"items":{"type":"object","properties":{"date":{"type":"string","format":"date"},"start_time":{"type":"string","maxLength":5,"description":"HH:MM local"},"end_time":{"type":"string","maxLength":5},"title":{"type":"string","maxLength":150}}}},"timezone":{"type":"string","description":"IANA zone, default Europe\/London."},"title":{"type":"string","maxLength":255,"description":"Optional name instead of the course title."},"delivery_mode":{"type":"string","enum":["in_person","virtual","blended"]},"venue_id":{"type":"integer"},"room_id":{"type":"integer"},"capacity_max":{"type":"integer","minimum":1},"capacity_min":{"type":"integer","minimum":0},"price":{"type":"number","description":"Per place, in major units (e.g. 295.00). Leave out for the course price."},"currency":{"type":"string","maxLength":3},"is_private":{"type":"boolean"},"restricted_org_id":{"type":"integer","description":"Only this company can see and book it."},"virtual_join_url":{"type":"string","maxLength":500},"notes":{"type":"string","maxLength":5000},"booking_cutoff_hours":{"type":"integer","minimum":0,"description":"Online booking closes this many hours before the start."},"exam_unlock_mode":{"type":"string","enum":["inherit","auto","manual","time","time_or_manual","attendance"]},"booking_form":{"type":"string","description":"Booking questions: empty = follow the course, \"none\", or a form uuid."},"override_reason":{"type":"string","maxLength":255,"description":"Book the room even if it is in use (audited)."}},"required":["course"]}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string. Repeating the request with the same key within 24 hours returns the first reply instead of running again.","schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}},"201":{"description":"Created.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}}}}},"\/api\/v2\/tms\/events\/{event}":{"get":{"operationId":"tms_events_get","summary":"Get a course date","description":"One course date: sessions (UTC and local times), trainers, rooms and kit assigned, capacity, booked, booking cut-off, joining link.","tags":["Course dates"],"security":[{"oauth2":["training:read"]},{"serviceKey":[]}],"x-mcp-tool":"tms_events_get","x-scope":"training:read","x-permissions":["tms.schedule.manage","tms.bookings.manage","tms.trainer.self"],"parameters":[{"name":"event","in":"path","required":true,"description":"Course date uuid (from tms_events_list).","schema":{"type":"string"}}],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}}}},"patch":{"operationId":"tms_events_update","summary":"Change a course date","description":"Change settings and\/or sessions. Send only what changes; sessions, if sent, replace them all. The preview lists the changes and who will be told. A trainer or room clash comes back as conflict: call again with override_reason to force it.\n\nConfirm-first: call without confirm_token to preview; call again with the same arguments and the confirm_token to carry it out.","tags":["Course dates"],"security":[{"oauth2":["training:write"]},{"serviceKey":[]}],"x-mcp-tool":"tms_events_update","x-scope":"training:write","x-permissions":["tms.schedule.manage"],"x-effects":["email"],"requestBody":{"required":false,"content":{"application\/json":{"schema":{"type":"object","properties":{"sessions":{"type":"array","maxItems":30,"items":{"type":"object","properties":{"date":{"type":"string","format":"date"},"start_time":{"type":"string","maxLength":5},"end_time":{"type":"string","maxLength":5},"title":{"type":"string","maxLength":150}}}},"timezone":{"type":"string"},"title":{"type":"string","maxLength":255},"delivery_mode":{"type":"string","enum":["in_person","virtual","blended"]},"venue_id":{"type":"integer"},"room_id":{"type":"integer"},"capacity_max":{"type":"integer","minimum":1},"capacity_min":{"type":"integer","minimum":0},"price":{"type":"number"},"currency":{"type":"string","maxLength":3},"is_private":{"type":"boolean"},"restricted_org_id":{"type":"integer"},"virtual_join_url":{"type":"string","maxLength":500},"notes":{"type":"string","maxLength":5000},"booking_cutoff_hours":{"type":"integer","minimum":0},"exam_unlock_mode":{"type":"string","enum":["inherit","auto","manual","time","time_or_manual","attendance"]},"booking_form":{"type":"string"},"override_reason":{"type":"string","maxLength":255},"confirm_token":{"type":"string","description":"From the preview. Leave out to preview."}}}}}},"parameters":[{"name":"event","in":"path","required":true,"description":"","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string. Repeating the request with the same key within 24 hours returns the first reply instead of running again.","schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"A preview (data.preview, data.confirm_token) or the result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}}}}},"\/api\/v2\/tms\/events\/{event}\/overview":{"get":{"operationId":"tms_events_overview","summary":"Course date overview","description":"Everything about one course date on one page: delegates and their status, registration checklists, booking answers (including dietary and access needs), photo ID, joining instructions sent, comms log and tasks.","tags":["Course dates"],"security":[{"oauth2":["training:read"]},{"serviceKey":[]}],"x-mcp-tool":"tms_events_overview","x-scope":"training:read","x-permissions":["tms.schedule.manage","tms.bookings.manage"],"parameters":[{"name":"event","in":"path","required":true,"description":"","schema":{"type":"string"}}],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}}}}},"\/api\/v2\/tms\/events\/{event}\/bookings":{"get":{"operationId":"tms_bookings_list","summary":"List bookings on a date","description":"The booking sheet for one course date: each delegate (or unnamed place), status, approval, payment mode, company, PO and when they booked. Registration only applies to company places (registration_needed); for those, registered_at is when the person confirmed their details. Direct bookings never register, so an empty registered_at on them means nothing is outstanding.","tags":["Bookings"],"security":[{"oauth2":["training:read"]},{"serviceKey":[]}],"x-mcp-tool":"tms_bookings_list","x-scope":"training:read","x-permissions":["tms.schedule.manage","tms.bookings.manage"],"parameters":[{"name":"event","in":"path","required":true,"description":"","schema":{"type":"string"}},{"name":"include_cancelled","in":"query","required":false,"description":"","schema":{"type":"boolean"}}],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}}}},"post":{"operationId":"tms_bookings_create","summary":"Book people onto a course date","description":"One order of places on a published date, like the booking desk: named delegates (an email that matches an account books that person) and\/or places to name later. Confirmed bookings email joining instructions to each named delegate; provisional ones wait for tms_bookings_confirm. The preview shows places left, who has an account, prerequisite warnings and every email.\n\nConfirm-first: call without confirm_token to preview; call again with the same arguments and the confirm_token to carry it out.","tags":["Bookings"],"security":[{"oauth2":["training:write"]},{"serviceKey":[]}],"x-mcp-tool":"tms_bookings_create","x-scope":"training:write","x-permissions":["tms.bookings.manage"],"x-effects":["email","webhook"],"requestBody":{"required":false,"content":{"application\/json":{"schema":{"type":"object","properties":{"delegates":{"type":"array","maxItems":50,"items":{"type":"object","properties":{"name":{"type":"string","maxLength":150},"email":{"type":"string","maxLength":254}}}},"placeholders":{"type":"integer","minimum":0,"maximum":50,"description":"Extra places to name later (tms_bookings_fill)."},"payment_mode":{"type":"string","enum":["invoice","comp"],"description":"invoice (default) or comp (complimentary)."},"status":{"type":"string","enum":["confirmed","provisional"],"description":"confirmed (default) or provisional."},"po_number":{"type":"string","maxLength":80},"organisation_id":{"type":"integer","description":"The customer company the places are for."},"confirm_token":{"type":"string","description":"From the preview. Leave out to preview."}}}}}},"parameters":[{"name":"event","in":"path","required":true,"description":"Course date uuid.","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string. Repeating the request with the same key within 24 hours returns the first reply instead of running again.","schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"A preview (data.preview, data.confirm_token) or the result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}},"201":{"description":"Created.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}}}}},"\/api\/v2\/tms\/teaching":{"get":{"operationId":"tms_my_teaching","summary":"What am I teaching","description":"For trainers: the course dates you are teaching in a range (default the next 14 days), with sessions in local time, venue and number booked.","tags":["Teaching"],"security":[{"oauth2":["training:read"]},{"serviceKey":[]}],"x-mcp-tool":"tms_my_teaching","x-scope":"training:read","x-permissions":["tms.trainer.self"],"parameters":[{"name":"from","in":"query","required":false,"description":"","schema":{"type":"string"}},{"name":"to","in":"query","required":false,"description":"ISO date or date\/time (UTC); a date on its own includes that whole day. Default 14 days ahead.","schema":{"type":"string","description":"ISO date or date\/time (UTC); a date on its own includes that whole day. Default 14 days ahead."}}],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}}}}},"\/api\/v2\/tms\/events\/{event}\/register":{"get":{"operationId":"tms_register_get","summary":"Get the register","description":"The register for one course date: delegates, attendance per session (present, absent, late or not yet marked) and exam unlock status.","tags":["Teaching"],"security":[{"oauth2":["training:read"]},{"serviceKey":[]}],"x-mcp-tool":"tms_register_get","x-scope":"training:read","x-permissions":["tms.trainer.self","tms.attendance.mark","tms.schedule.manage"],"parameters":[{"name":"event","in":"path","required":true,"description":"","schema":{"type":"string"}}],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}}}}},"\/api\/v2\/tms\/dashboard":{"get":{"operationId":"tms_ops_dashboard","summary":"Training operations dashboard","description":"The next 30 days of course dates with fill and what needs attention (not published, no trainer, below minimum, unconfirmed places, IDs to check), action counts (approvals, held places, waitlist), certificate expiry counts and recent bookings.","tags":["Course dates"],"security":[{"oauth2":["training:read"]},{"serviceKey":[]}],"x-mcp-tool":"tms_ops_dashboard","x-scope":"training:read","x-permissions":["tms.schedule.manage","tms.bookings.manage"],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}}}}},"\/api\/v2\/tms\/approvals":{"get":{"operationId":"tms_approvals_list","summary":"Bookings waiting for approval","description":"Orders waiting for approval: booking-desk staff see all; organisation managers see requests from their own staff.","tags":["Bookings"],"security":[{"oauth2":["training:read"]},{"serviceKey":[]}],"x-mcp-tool":"tms_approvals_list","x-scope":"training:read","x-permissions":["tms.bookings.manage","enrolments.assign"],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}}}}},"\/api\/v2\/tms\/places":{"get":{"operationId":"tms_places_list","summary":"Company places","description":"Places held for companies on upcoming dates: how many held, unnamed and confirmed, release terms and who pays. Managers see their own companies.","tags":["Company places"],"security":[{"oauth2":["training:read"]},{"serviceKey":[]}],"x-mcp-tool":"tms_places_list","x-scope":"training:read","x-permissions":["tms.bookings.manage","enrolments.assign"],"parameters":[{"name":"organisation_id","in":"query","required":false,"description":"","schema":{"type":"integer"}}],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}}}}},"\/api\/v2\/tms\/resources":{"get":{"operationId":"tms_resources_list","summary":"Trainers, venues and kit","description":"Trainers (with ids for filters and availability checks), venues with their rooms, and equipment.","tags":["Course dates"],"security":[{"oauth2":["training:read"]},{"serviceKey":[]}],"x-mcp-tool":"tms_resources_list","x-scope":"training:read","x-permissions":["tms.schedule.manage","tms.resources.manage"],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}}}}},"\/api\/v2\/tms\/availability":{"get":{"operationId":"tms_availability_check","summary":"Check availability","description":"Is a trainer, room or piece of equipment free between two times? Checks working hours and time off, and lists course dates already using it.","tags":["Course dates"],"security":[{"oauth2":["training:read"]},{"serviceKey":[]}],"x-mcp-tool":"tms_availability_check","x-scope":"training:read","x-permissions":["tms.schedule.manage","tms.resources.manage"],"parameters":[{"name":"resource_type","in":"query","required":true,"description":"","schema":{"type":"string","enum":["trainer","room","equipment"]}},{"name":"resource_id","in":"query","required":true,"description":"Id from tms_resources_list.","schema":{"type":"integer","description":"Id from tms_resources_list."}},{"name":"from","in":"query","required":true,"description":"ISO date\/time, e.g. 2026-10-14T09:00:00+01:00.","schema":{"type":"string","description":"ISO date\/time, e.g. 2026-10-14T09:00:00+01:00."}},{"name":"to","in":"query","required":true,"description":"","schema":{"type":"string"}}],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}}}}},"\/api\/v2\/users\/{user}\/status":{"post":{"operationId":"users_set_status","summary":"Suspend, reactivate or deactivate a person","description":"active, suspended (cannot sign in) or deleted (deactivated: cannot sign in and disappears from lists). Preview first.\n\nConfirm-first: call without confirm_token to preview; call again with the same arguments and the confirm_token to carry it out.","tags":["People & companies"],"security":[{"oauth2":["people:write"]},{"serviceKey":[]}],"x-mcp-tool":"users_set_status","x-scope":"people:write","x-permissions":["users.delete"],"x-effects":["webhook"],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["active","suspended","deleted"]},"confirm_token":{"type":"string","description":"From the preview. Leave out to preview."}},"required":["status"]}}}},"parameters":[{"name":"user","in":"path","required":true,"description":"","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string. Repeating the request with the same key within 24 hours returns the first reply instead of running again.","schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"A preview (data.preview, data.confirm_token) or the result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}},"201":{"description":"Created.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}}}}},"\/api\/v2\/users\/{user}\/resend-invite":{"post":{"operationId":"users_resend_invite","summary":"Resend the account set-up email","description":"Email a fresh activation link. If they had already set a password it is wiped, so the link is the only way back in (use this to help someone locked out). Preview first.\n\nConfirm-first: call without confirm_token to preview; call again with the same arguments and the confirm_token to carry it out.","tags":["People & companies"],"security":[{"oauth2":["people:write"]},{"serviceKey":[]}],"x-mcp-tool":"users_resend_invite","x-scope":"people:write","x-permissions":["users.invite"],"x-effects":["email"],"requestBody":{"required":false,"content":{"application\/json":{"schema":{"type":"object","properties":{"confirm_token":{"type":"string","description":"From the preview. Leave out to preview."}}}}}},"parameters":[{"name":"user","in":"path","required":true,"description":"","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string. Repeating the request with the same key within 24 hours returns the first reply instead of running again.","schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"A preview (data.preview, data.confirm_token) or the result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}},"201":{"description":"Created.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}}}}},"\/api\/v2\/users\/{user}\/resend-welcome":{"post":{"operationId":"users_resend_welcome","summary":"Resend the welcome email","description":"Email the welcome message again. Does not change their password. Preview first.\n\nConfirm-first: call without confirm_token to preview; call again with the same arguments and the confirm_token to carry it out.","tags":["People & companies"],"security":[{"oauth2":["people:write"]},{"serviceKey":[]}],"x-mcp-tool":"users_resend_welcome","x-scope":"people:write","x-permissions":["users.edit"],"x-effects":["email"],"requestBody":{"required":false,"content":{"application\/json":{"schema":{"type":"object","properties":{"confirm_token":{"type":"string","description":"From the preview. Leave out to preview."}}}}}},"parameters":[{"name":"user","in":"path","required":true,"description":"","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string. Repeating the request with the same key within 24 hours returns the first reply instead of running again.","schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"A preview (data.preview, data.confirm_token) or the result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}},"201":{"description":"Created.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}}}}},"\/api\/v2\/users\/{user}\/mfa\/reset":{"post":{"operationId":"users_mfa_reset","summary":"Reset a person's two-factor sign-in","description":"For someone who has lost or replaced the phone with their authenticator app: removes their two-factor (authenticator link and backup codes) so they can set it up again, and emails them. If the workspace requires two-factor for their role they must set up a new authenticator at their next sign-in. Tenant admins only; not your own account, not someone more senior. Preview first: check the request really came from them.\n\nConfirm-first: call without confirm_token to preview; call again with the same arguments and the confirm_token to carry it out.","tags":["People & companies"],"security":[{"oauth2":["people:write"]},{"serviceKey":[]}],"x-mcp-tool":"users_mfa_reset","x-scope":"people:write","x-permissions":["settings.security"],"x-effects":["email"],"requestBody":{"required":false,"content":{"application\/json":{"schema":{"type":"object","properties":{"confirm_token":{"type":"string","description":"From the preview. Leave out to preview."}}}}}},"parameters":[{"name":"user","in":"path","required":true,"description":"Their id or uuid.","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string. Repeating the request with the same key within 24 hours returns the first reply instead of running again.","schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"A preview (data.preview, data.confirm_token) or the result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}},"201":{"description":"Created.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}}}}},"\/api\/v2\/enrolments\/{enrolment_id}":{"patch":{"operationId":"enrolments_update","summary":"Change an enrolment","description":"Set or clear the deadline (YYYY-MM-DD, or empty to clear) or the mandatory flag.","tags":["Enrolments & certificates"],"security":[{"oauth2":["people:write"]},{"serviceKey":[]}],"x-mcp-tool":"enrolments_update","x-scope":"people:write","x-permissions":["enrolments.assign"],"requestBody":{"required":false,"content":{"application\/json":{"schema":{"type":"object","properties":{"deadline":{"type":"string","maxLength":10},"mandatory":{"type":"boolean"}}}}}},"parameters":[{"name":"enrolment_id","in":"path","required":true,"description":"","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string. Repeating the request with the same key within 24 hours returns the first reply instead of running again.","schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}}}},"delete":{"operationId":"enrolments_drop","summary":"Remove an enrolment","description":"Take a course away from someone: they lose access (their progress is kept). Preview first.\n\nConfirm-first: call without confirm_token to preview; call again with the same arguments and the confirm_token to carry it out.","tags":["Enrolments & certificates"],"security":[{"oauth2":["people:write"]},{"serviceKey":[]}],"x-mcp-tool":"enrolments_drop","x-scope":"people:write","x-permissions":["enrolments.remove"],"requestBody":{"required":false,"content":{"application\/json":{"schema":{"type":"object","properties":{"confirm_token":{"type":"string","description":"From the preview. Leave out to preview."}}}}}},"parameters":[{"name":"enrolment_id","in":"path","required":true,"description":"","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string. Repeating the request with the same key within 24 hours returns the first reply instead of running again.","schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"A preview (data.preview, data.confirm_token) or the result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}}}}},"\/api\/v2\/tms\/events\/{event}\/publish":{"post":{"operationId":"tms_events_publish","summary":"Publish a course date","description":"Make a draft bookable (on your training pages and widgets unless private). Assigned trainers are told if trainer notices are on. Preview first.\n\nConfirm-first: call without confirm_token to preview; call again with the same arguments and the confirm_token to carry it out.","tags":["Course dates"],"security":[{"oauth2":["training:write"]},{"serviceKey":[]}],"x-mcp-tool":"tms_events_publish","x-scope":"training:write","x-permissions":["tms.schedule.manage"],"x-effects":["email","webhook"],"requestBody":{"required":false,"content":{"application\/json":{"schema":{"type":"object","properties":{"confirm_token":{"type":"string","description":"From the preview. Leave out to preview."}}}}}},"parameters":[{"name":"event","in":"path","required":true,"description":"","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string. Repeating the request with the same key within 24 hours returns the first reply instead of running again.","schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"A preview (data.preview, data.confirm_token) or the result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}},"201":{"description":"Created.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}}}}},"\/api\/v2\/tms\/events\/{event}\/status":{"post":{"operationId":"tms_events_set_status","summary":"Mark a course date confirmed, running or completed","description":"Move a published date on: confirmed (going ahead), running, completed. Dates also become running when their first session starts and completed when their last ends, automatically; use this to confirm a date or move it early. Status only: completion and certificates come from the register and exams.","tags":["Course dates"],"security":[{"oauth2":["training:write"]},{"serviceKey":[]}],"x-mcp-tool":"tms_events_set_status","x-scope":"training:write","x-permissions":["tms.schedule.manage"],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["confirmed","running","completed"]}},"required":["status"]}}}},"parameters":[{"name":"event","in":"path","required":true,"description":"","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string. Repeating the request with the same key within 24 hours returns the first reply instead of running again.","schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}},"201":{"description":"Created.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}}}}},"\/api\/v2\/tms\/my\/tasks":{"get":{"operationId":"tms_tasks_mine","summary":"List my tasks","description":"Course-date tasks that are overdue or due in the next two weeks: yours and the team's (unassigned), with the date they belong to. Tick one off with tms_tasks_set_done.","tags":["Course dates"],"security":[{"oauth2":["training:read"]},{"serviceKey":[]}],"x-mcp-tool":"tms_tasks_mine","x-scope":"training:read","x-permissions":["tms.schedule.manage","tms.bookings.manage","tms.trainer.self"],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}}}}},"\/api\/v2\/tms\/my\/availability":{"get":{"operationId":"tms_my_availability_list","summary":"List my time off and working hours","description":"For a trainer: their booked time off (today onwards) and their regular working hours.","tags":["Teaching"],"security":[{"oauth2":["training:read"]},{"serviceKey":[]}],"x-mcp-tool":"tms_my_availability_list","x-scope":"training:read","x-permissions":["tms.trainer.self"],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}}}}},"\/api\/v2\/tms\/my\/time-off":{"post":{"operationId":"tms_my_time_off_add","summary":"Book my time off","description":"For a trainer: book time off (from and to, whole days) so they aren't scheduled. If it clashes with dates they are teaching, it is refused with the clashes named; ask the person, and only then send save_despite_teaching = true (those dates still need another trainer).","tags":["Teaching"],"security":[{"oauth2":["training:write"]},{"serviceKey":[]}],"x-mcp-tool":"tms_my_time_off_add","x-scope":"training:write","x-permissions":["tms.trainer.self"],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","properties":{"from":{"type":"string","format":"date"},"to":{"type":"string","format":"date"},"reason":{"type":"string","enum":["holiday","meeting","other"]},"note":{"type":"string","maxLength":255},"save_despite_teaching":{"type":"boolean"}},"required":["from","to"]}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string. Repeating the request with the same key within 24 hours returns the first reply instead of running again.","schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}},"201":{"description":"Created.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}}}}},"\/api\/v2\/tms\/my\/time-off\/{id}":{"delete":{"operationId":"tms_my_time_off_remove","summary":"Remove my time off","description":"For a trainer: take back time off they booked (id from tms_my_availability_list).","tags":["Teaching"],"security":[{"oauth2":["training:write"]},{"serviceKey":[]}],"x-mcp-tool":"tms_my_time_off_remove","x-scope":"training:write","x-permissions":["tms.trainer.self"],"requestBody":{"required":false,"content":{"application\/json":{"schema":{"type":"object","properties":{}}}}},"parameters":[{"name":"id","in":"path","required":true,"description":"","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string. Repeating the request with the same key within 24 hours returns the first reply instead of running again.","schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}}}}},"\/api\/v2\/audit":{"get":{"operationId":"audit_list","summary":"Search the audit log","description":"What happened in the workspace and who did it, newest first: sign-ins, people and course changes, bookings, settings and everything done through an AI assistant or the API (via = claude for any AI assistant over MCP, api, any_app or web; a service key shows as \"Name (service)\"). Filter by date range, person, exact action or part of an action name (e.g. booking), and the record changed. Kept for 42 days unless the platform keeps more.","tags":["Reports"],"security":[{"oauth2":["reports:read"]},{"serviceKey":[]}],"x-mcp-tool":"audit_list","x-scope":"reports:read","x-permissions":["audit.view"],"parameters":[{"name":"from","in":"query","required":false,"description":"ISO date or date\/time (UTC).","schema":{"type":"string","description":"ISO date or date\/time (UTC)."}},{"name":"to","in":"query","required":false,"description":"ISO date or date\/time (UTC); a date on its own includes that whole day.","schema":{"type":"string","description":"ISO date or date\/time (UTC); a date on its own includes that whole day."}},{"name":"person","in":"query","required":false,"description":"Who did it: person id or uuid.","schema":{"type":"string","description":"Who did it: person id or uuid."}},{"name":"action","in":"query","required":false,"description":"An exact action, e.g. tms_booking_cancelled.","schema":{"type":"string","maxLength":100,"description":"An exact action, e.g. tms_booking_cancelled."}},{"name":"action_contains","in":"query","required":false,"description":"Part of an action name, e.g. booking, user, course.","schema":{"type":"string","maxLength":50,"description":"Part of an action name, e.g. booking, user, course."}},{"name":"via","in":"query","required":false,"description":"","schema":{"type":"string","enum":["claude","api","any_app","web"]}},{"name":"entity_type","in":"query","required":false,"description":"The kind of record, e.g. user, course, event, organisation.","schema":{"type":"string","maxLength":50,"description":"The kind of record, e.g. user, course, event, organisation."}},{"name":"entity_id","in":"query","required":false,"description":"","schema":{"type":"integer"}},{"name":"page","in":"query","required":false,"description":"Page number, from 1.","schema":{"type":"integer","minimum":1,"description":"Page number, from 1."}},{"name":"per_page","in":"query","required":false,"description":"Rows per page (default 50, at most 100).","schema":{"type":"integer","minimum":1,"maximum":100,"description":"Rows per page (default 50, at most 100)."}}],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}}}}},"\/api\/v2\/tms\/events\/{event}\/message":{"post":{"operationId":"tms_events_message","summary":"Message everyone on a course date","description":"Email a one-off message (plain text) to every named delegate on a date, and its trainers if include_trainers is true: a venue change, what to bring, a parking note. Sent in the workspace's branded email with the course, dates and venue underneath, and logged in the date's comms log. Unnamed company places get nothing. Preview first: it lists every recipient and repeats the message, so show it to the person word for word before confirming.\n\nConfirm-first: call without confirm_token to preview; call again with the same arguments and the confirm_token to carry it out.","tags":["Course dates"],"security":[{"oauth2":["training:write"]},{"serviceKey":[]}],"x-mcp-tool":"tms_events_message","x-scope":"training:write","x-permissions":["tms.bookings.manage","tms.schedule.manage"],"x-effects":["email"],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","properties":{"subject":{"type":"string","maxLength":150},"message":{"type":"string","maxLength":5000,"description":"Plain text; line breaks are kept."},"include_trainers":{"type":"boolean","description":"Also send it to the trainers on the date. Default false."},"confirm_token":{"type":"string","description":"From the preview. Leave out to preview."}},"required":["subject","message"]}}}},"parameters":[{"name":"event","in":"path","required":true,"description":"Course date uuid.","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string. Repeating the request with the same key within 24 hours returns the first reply instead of running again.","schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"A preview (data.preview, data.confirm_token) or the result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}},"201":{"description":"Created.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}}}}},"\/api\/v2\/tms\/events\/{event}\/cancel":{"post":{"operationId":"tms_events_cancel","summary":"Cancel a course date","description":"Cancel the date: every booking is cancelled and each delegate is emailed a cancellation notice; trainers, rooms and kit are freed. No refunds are made: paid or invoiced places are listed under Refunds to check (tms_refunds_list). The preview names everyone who will be emailed.\n\nConfirm-first: call without confirm_token to preview; call again with the same arguments and the confirm_token to carry it out.","tags":["Course dates"],"security":[{"oauth2":["training:write"]},{"serviceKey":[]}],"x-mcp-tool":"tms_events_cancel","x-scope":"training:write","x-permissions":["tms.schedule.manage"],"x-effects":["email"],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","maxLength":255},"confirm_token":{"type":"string","description":"From the preview. Leave out to preview."}},"required":["reason"]}}}},"parameters":[{"name":"event","in":"path","required":true,"description":"","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string. Repeating the request with the same key within 24 hours returns the first reply instead of running again.","schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"A preview (data.preview, data.confirm_token) or the result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}},"201":{"description":"Created.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}}}}},"\/api\/v2\/tms\/events\/{event}\/duplicate":{"post":{"operationId":"tms_events_duplicate","summary":"Duplicate a course date","description":"Copy a date as a new draft with the same times, settings, booking questions and tasks (trainers and rooms are not copied). Then move it with tms_events_reschedule or tms_events_update.","tags":["Course dates"],"security":[{"oauth2":["training:write"]},{"serviceKey":[]}],"x-mcp-tool":"tms_events_duplicate","x-scope":"training:write","x-permissions":["tms.schedule.manage"],"requestBody":{"required":false,"content":{"application\/json":{"schema":{"type":"object","properties":{}}}}},"parameters":[{"name":"event","in":"path","required":true,"description":"","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string. Repeating the request with the same key within 24 hours returns the first reply instead of running again.","schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}},"201":{"description":"Created.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}}}}},"\/api\/v2\/tms\/events\/{event}\/reschedule":{"post":{"operationId":"tms_events_reschedule","summary":"Move a course date by days","description":"Move every session by a whole number of days (same local times). Trainers, rooms and kit move with it; tasks follow; trainers are told. Clashes come back as conflict (use override_reason to force).\n\nConfirm-first: call without confirm_token to preview; call again with the same arguments and the confirm_token to carry it out.","tags":["Course dates"],"security":[{"oauth2":["training:write"]},{"serviceKey":[]}],"x-mcp-tool":"tms_events_reschedule","x-scope":"training:write","x-permissions":["tms.schedule.manage"],"x-effects":["email"],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","properties":{"delta_days":{"type":"integer","minimum":-370,"maximum":370},"override_reason":{"type":"string","maxLength":255},"confirm_token":{"type":"string","description":"From the preview. Leave out to preview."}},"required":["delta_days"]}}}},"parameters":[{"name":"event","in":"path","required":true,"description":"","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string. Repeating the request with the same key within 24 hours returns the first reply instead of running again.","schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"A preview (data.preview, data.confirm_token) or the result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}},"201":{"description":"Created.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}}}}},"\/api\/v2\/tms\/events\/{event}\/notes":{"put":{"operationId":"tms_events_notes_set","summary":"Set internal notes","description":"Replace the internal notes on a course date (staff only; not shown to delegates).","tags":["Course dates"],"security":[{"oauth2":["training:write"]},{"serviceKey":[]}],"x-mcp-tool":"tms_events_notes_set","x-scope":"training:write","x-permissions":["tms.schedule.manage","tms.bookings.manage"],"requestBody":{"required":false,"content":{"application\/json":{"schema":{"type":"object","properties":{"notes":{"type":"string","maxLength":5000}}}}}},"parameters":[{"name":"event","in":"path","required":true,"description":"","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string. Repeating the request with the same key within 24 hours returns the first reply instead of running again.","schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}}}}},"\/api\/v2\/tms\/events\/{event}\/assignments":{"post":{"operationId":"tms_assignments_create","summary":"Assign a trainer, room or kit","description":"Put a trainer, room or piece of equipment on a course date (or one session). The preview shows clashes with other dates, time off and working-hours warnings first; a clash needs override_reason.\n\nConfirm-first: call without confirm_token to preview; call again with the same arguments and the confirm_token to carry it out.","tags":["Course dates"],"security":[{"oauth2":["training:write"]},{"serviceKey":[]}],"x-mcp-tool":"tms_assignments_create","x-scope":"training:write","x-permissions":["tms.schedule.manage"],"x-effects":["email"],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","properties":{"resource_type":{"type":"string","enum":["trainer","room","equipment"]},"resource_id":{"type":"integer","description":"Id from tms_resources_list."},"session_id":{"type":"integer","description":"Just one session (from tms_events_get); leave out for the whole date."},"role":{"type":"string","maxLength":60},"override_reason":{"type":"string","maxLength":255},"confirm_token":{"type":"string","description":"From the preview. Leave out to preview."}},"required":["resource_type","resource_id"]}}}},"parameters":[{"name":"event","in":"path","required":true,"description":"","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string. Repeating the request with the same key within 24 hours returns the first reply instead of running again.","schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"A preview (data.preview, data.confirm_token) or the result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}},"201":{"description":"Created.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}}}}},"\/api\/v2\/tms\/events\/{event}\/assignments\/{assignment_id}":{"delete":{"operationId":"tms_assignments_release","summary":"Remove a trainer, room or kit","description":"Take an assignment off a course date and free the time. A trainer is told if trainer notices are on. Preview first.\n\nConfirm-first: call without confirm_token to preview; call again with the same arguments and the confirm_token to carry it out.","tags":["Course dates"],"security":[{"oauth2":["training:write"]},{"serviceKey":[]}],"x-mcp-tool":"tms_assignments_release","x-scope":"training:write","x-permissions":["tms.schedule.manage"],"x-effects":["email"],"requestBody":{"required":false,"content":{"application\/json":{"schema":{"type":"object","properties":{"confirm_token":{"type":"string","description":"From the preview. Leave out to preview."}}}}}},"parameters":[{"name":"event","in":"path","required":true,"description":"","schema":{"type":"string"}},{"name":"assignment_id","in":"path","required":true,"description":"From tms_events_get assignments.","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string. Repeating the request with the same key within 24 hours returns the first reply instead of running again.","schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"A preview (data.preview, data.confirm_token) or the result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}}}}},"\/api\/v2\/tms\/events\/{event}\/tasks":{"post":{"operationId":"tms_tasks_add","summary":"Add a task to a course date","description":"A to-do on the date (e.g. \"order certificates\"), due on a date, for a member of staff or the team.","tags":["Course dates"],"security":[{"oauth2":["training:write"]},{"serviceKey":[]}],"x-mcp-tool":"tms_tasks_add","x-scope":"training:write","x-permissions":["tms.schedule.manage","tms.bookings.manage"],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","properties":{"title":{"type":"string","maxLength":200},"due_on":{"type":"string","format":"date"},"assignee_id":{"type":"integer","description":"A staff member's id; leave out for the team."}},"required":["title","due_on"]}}}},"parameters":[{"name":"event","in":"path","required":true,"description":"","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string. Repeating the request with the same key within 24 hours returns the first reply instead of running again.","schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}},"201":{"description":"Created.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}}}}},"\/api\/v2\/tms\/events\/{event}\/tasks\/{task}\/done":{"post":{"operationId":"tms_tasks_set_done","summary":"Tick off a task","description":"Mark a course-date task done (or open again with done=false).","tags":["Course dates"],"security":[{"oauth2":["training:write"]},{"serviceKey":[]}],"x-mcp-tool":"tms_tasks_set_done","x-scope":"training:write","x-permissions":["tms.schedule.manage","tms.bookings.manage"],"requestBody":{"required":false,"content":{"application\/json":{"schema":{"type":"object","properties":{"done":{"type":"boolean"}}}}}},"parameters":[{"name":"event","in":"path","required":true,"description":"","schema":{"type":"string"}},{"name":"task","in":"path","required":true,"description":"Task uuid (from tms_events_overview tasks).","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string. Repeating the request with the same key within 24 hours returns the first reply instead of running again.","schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}},"201":{"description":"Created.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}}}}},"\/api\/v2\/tms\/events\/{event}\/tasks\/{task}":{"delete":{"operationId":"tms_tasks_remove","summary":"Remove a task","description":"Delete a task from a course date.","tags":["Course dates"],"security":[{"oauth2":["training:write"]},{"serviceKey":[]}],"x-mcp-tool":"tms_tasks_remove","x-scope":"training:write","x-permissions":["tms.schedule.manage","tms.bookings.manage"],"requestBody":{"required":false,"content":{"application\/json":{"schema":{"type":"object","properties":{}}}}},"parameters":[{"name":"event","in":"path","required":true,"description":"","schema":{"type":"string"}},{"name":"task","in":"path","required":true,"description":"","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string. Repeating the request with the same key within 24 hours returns the first reply instead of running again.","schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}}}}},"\/api\/v2\/tms\/events\/{event}\/bookings\/{booking_id}\/confirm":{"post":{"operationId":"tms_bookings_confirm","summary":"Confirm a provisional booking","description":"Confirm a provisional place (payment received or approved). The delegate is emailed their joining instructions.\n\nConfirm-first: call without confirm_token to preview; call again with the same arguments and the confirm_token to carry it out.","tags":["Bookings"],"security":[{"oauth2":["training:write"]},{"serviceKey":[]}],"x-mcp-tool":"tms_bookings_confirm","x-scope":"training:write","x-permissions":["tms.bookings.manage"],"x-effects":["email"],"requestBody":{"required":false,"content":{"application\/json":{"schema":{"type":"object","properties":{"confirm_token":{"type":"string","description":"From the preview. Leave out to preview."}}}}}},"parameters":[{"name":"event","in":"path","required":true,"description":"","schema":{"type":"string"}},{"name":"booking_id","in":"path","required":true,"description":"From tms_bookings_list.","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string. Repeating the request with the same key within 24 hours returns the first reply instead of running again.","schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"A preview (data.preview, data.confirm_token) or the result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}},"201":{"description":"Created.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}}}}},"\/api\/v2\/tms\/events\/{event}\/bookings\/{booking_id}\/cancel":{"post":{"operationId":"tms_bookings_cancel","summary":"Cancel a booking","description":"Cancel one place: the seat is freed and offered to the waitlist. The delegate is not emailed and nothing is refunded; a paid or invoiced place is listed under Refunds to check (tms_refunds_list).\n\nConfirm-first: call without confirm_token to preview; call again with the same arguments and the confirm_token to carry it out.","tags":["Bookings"],"security":[{"oauth2":["training:write"]},{"serviceKey":[]}],"x-mcp-tool":"tms_bookings_cancel","x-scope":"training:write","x-permissions":["tms.bookings.manage"],"x-effects":["webhook"],"requestBody":{"required":false,"content":{"application\/json":{"schema":{"type":"object","properties":{"confirm_token":{"type":"string","description":"From the preview. Leave out to preview."}}}}}},"parameters":[{"name":"event","in":"path","required":true,"description":"","schema":{"type":"string"}},{"name":"booking_id","in":"path","required":true,"description":"","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string. Repeating the request with the same key within 24 hours returns the first reply instead of running again.","schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"A preview (data.preview, data.confirm_token) or the result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}},"201":{"description":"Created.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}}}}},"\/api\/v2\/tms\/events\/{event}\/bookings\/{booking_id}\/delegate":{"post":{"operationId":"tms_bookings_fill","summary":"Name a place","description":"Put a person on an unnamed place, or correct a guest's details. An email that matches an account links that person (and enrols them on the course). On a confirmed place the new person is emailed joining instructions.\n\nConfirm-first: call without confirm_token to preview; call again with the same arguments and the confirm_token to carry it out.","tags":["Bookings"],"security":[{"oauth2":["training:write"]},{"serviceKey":[]}],"x-mcp-tool":"tms_bookings_fill","x-scope":"training:write","x-permissions":["tms.bookings.manage"],"x-effects":["email"],"requestBody":{"required":false,"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":150},"email":{"type":"string","maxLength":254},"confirm_token":{"type":"string","description":"From the preview. Leave out to preview."}}}}}},"parameters":[{"name":"event","in":"path","required":true,"description":"","schema":{"type":"string"}},{"name":"booking_id","in":"path","required":true,"description":"","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string. Repeating the request with the same key within 24 hours returns the first reply instead of running again.","schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"A preview (data.preview, data.confirm_token) or the result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}},"201":{"description":"Created.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}}}}},"\/api\/v2\/tms\/events\/{event}\/bookings\/{booking_id}\/substitute":{"post":{"operationId":"tms_bookings_substitute","summary":"Substitute a delegate","description":"Someone else takes this place (same date, same payment). On a confirmed place the new person is emailed joining instructions.\n\nConfirm-first: call without confirm_token to preview; call again with the same arguments and the confirm_token to carry it out.","tags":["Bookings"],"security":[{"oauth2":["training:write"]},{"serviceKey":[]}],"x-mcp-tool":"tms_bookings_substitute","x-scope":"training:write","x-permissions":["tms.bookings.manage"],"x-effects":["email"],"requestBody":{"required":false,"content":{"application\/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":150},"email":{"type":"string","maxLength":254},"confirm_token":{"type":"string","description":"From the preview. Leave out to preview."}}}}}},"parameters":[{"name":"event","in":"path","required":true,"description":"","schema":{"type":"string"}},{"name":"booking_id","in":"path","required":true,"description":"","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string. Repeating the request with the same key within 24 hours returns the first reply instead of running again.","schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"A preview (data.preview, data.confirm_token) or the result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}},"201":{"description":"Created.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}}}}},"\/api\/v2\/tms\/events\/{event}\/bookings\/{booking_id}\/transfer-quote":{"get":{"operationId":"tms_bookings_transfer_quote","summary":"Quote a transfer","description":"Before moving a booking to another date: places left on the new date, the price difference per seat and the ways it can be settled (delta_actions). Changes nothing.","tags":["Bookings"],"security":[{"oauth2":["training:read"]},{"serviceKey":[]}],"x-mcp-tool":"tms_bookings_transfer_quote","x-scope":"training:read","x-permissions":["tms.bookings.transfer","tms.bookings.manage"],"parameters":[{"name":"event","in":"path","required":true,"description":"","schema":{"type":"string"}},{"name":"booking_id","in":"path","required":true,"description":"","schema":{"type":"string"}},{"name":"to_event","in":"query","required":true,"description":"The date to move to (uuid).","schema":{"type":"string","description":"The date to move to (uuid)."}}],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}}}}},"\/api\/v2\/tms\/events\/{event}\/bookings\/{booking_id}\/transfer":{"post":{"operationId":"tms_bookings_transfer","summary":"Transfer a booking to another date","description":"Move one place to another published date. Quote first (tms_bookings_transfer_quote) and pass a delta_action it allows: none (same price), charged (raises an order for the difference), waived, refunded (card payments) or credited. The delegate is emailed joining instructions for the new date.\n\nConfirm-first: call without confirm_token to preview; call again with the same arguments and the confirm_token to carry it out.","tags":["Bookings"],"security":[{"oauth2":["training:write"]},{"serviceKey":[]}],"x-mcp-tool":"tms_bookings_transfer","x-scope":"training:write","x-permissions":["tms.bookings.transfer","tms.bookings.manage"],"x-effects":["email","money"],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","properties":{"to_event":{"type":"string"},"reason":{"type":"string","maxLength":255},"delta_action":{"type":"string","enum":["none","charged","waived","refunded","credited"]},"confirm_token":{"type":"string","description":"From the preview. Leave out to preview."}},"required":["to_event","reason"]}}}},"parameters":[{"name":"event","in":"path","required":true,"description":"","schema":{"type":"string"}},{"name":"booking_id","in":"path","required":true,"description":"","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string. Repeating the request with the same key within 24 hours returns the first reply instead of running again.","schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"A preview (data.preview, data.confirm_token) or the result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}},"201":{"description":"Created.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}}}}},"\/api\/v2\/tms\/events\/{event}\/waitlist":{"get":{"operationId":"tms_waitlist_list","summary":"Waitlist for a date","description":"Everyone queued for a course date, in order, with any open offer and when it lapses.","tags":["Bookings"],"security":[{"oauth2":["training:read"]},{"serviceKey":[]}],"x-mcp-tool":"tms_waitlist_list","x-scope":"training:read","x-permissions":["tms.bookings.manage"],"parameters":[{"name":"event","in":"path","required":true,"description":"","schema":{"type":"string"}}],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}}}}},"\/api\/v2\/tms\/events\/{event}\/waitlist\/{entry_id}\/offer":{"post":{"operationId":"tms_waitlist_offer","summary":"Offer a waitlisted person a place","description":"Email the person an offer of a place now, held for 72 hours.\n\nConfirm-first: call without confirm_token to preview; call again with the same arguments and the confirm_token to carry it out.","tags":["Bookings"],"security":[{"oauth2":["training:write"]},{"serviceKey":[]}],"x-mcp-tool":"tms_waitlist_offer","x-scope":"training:write","x-permissions":["tms.bookings.manage"],"x-effects":["email"],"requestBody":{"required":false,"content":{"application\/json":{"schema":{"type":"object","properties":{"confirm_token":{"type":"string","description":"From the preview. Leave out to preview."}}}}}},"parameters":[{"name":"event","in":"path","required":true,"description":"","schema":{"type":"string"}},{"name":"entry_id","in":"path","required":true,"description":"From tms_waitlist_list.","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string. Repeating the request with the same key within 24 hours returns the first reply instead of running again.","schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"A preview (data.preview, data.confirm_token) or the result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}},"201":{"description":"Created.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}}}}},"\/api\/v2\/tms\/events\/{event}\/waitlist\/{entry_id}":{"delete":{"operationId":"tms_waitlist_remove","summary":"Take someone off a waitlist","description":"Remove a person from the waitlist. They are not emailed.","tags":["Bookings"],"security":[{"oauth2":["training:write"]},{"serviceKey":[]}],"x-mcp-tool":"tms_waitlist_remove","x-scope":"training:write","x-permissions":["tms.bookings.manage"],"requestBody":{"required":false,"content":{"application\/json":{"schema":{"type":"object","properties":{}}}}},"parameters":[{"name":"event","in":"path","required":true,"description":"","schema":{"type":"string"}},{"name":"entry_id","in":"path","required":true,"description":"","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string. Repeating the request with the same key within 24 hours returns the first reply instead of running again.","schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}}}}},"\/api\/v2\/tms\/approvals\/{order_id}":{"post":{"operationId":"tms_approvals_decide","summary":"Approve or decline a booking","description":"Decide an order waiting for approval (from tms_approvals_list). Approving confirms every place and emails joining instructions; declining frees the places and emails the booker, with your reason if given. Booking-desk staff decide any order; organisation managers decide training requests from their own staff.\n\nConfirm-first: call without confirm_token to preview; call again with the same arguments and the confirm_token to carry it out.","tags":["Bookings"],"security":[{"oauth2":["training:write"]},{"serviceKey":[]}],"x-mcp-tool":"tms_approvals_decide","x-scope":"training:write","x-permissions":["tms.bookings.manage","enrolments.assign"],"x-effects":["email"],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","properties":{"decision":{"type":"string","enum":["approve","decline"]},"reason":{"type":"string","maxLength":255,"description":"Told to the booker when declining."},"confirm_token":{"type":"string","description":"From the preview. Leave out to preview."}},"required":["decision"]}}}},"parameters":[{"name":"order_id","in":"path","required":true,"description":"","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string. Repeating the request with the same key within 24 hours returns the first reply instead of running again.","schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"A preview (data.preview, data.confirm_token) or the result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}},"201":{"description":"Created.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}}}}},"\/api\/v2\/tms\/places\/{places}":{"get":{"operationId":"tms_places_get","summary":"Get company places","description":"One company's places on a course date: each place (unnamed, or who is on it), where each person is with registering (details, questions, ID, pre-work, payment), who pays, release terms and what will be charged. Managers see their own companies only.","tags":["Company places"],"security":[{"oauth2":["training:read"]},{"serviceKey":[]}],"x-mcp-tool":"tms_places_get","x-scope":"training:read","x-permissions":["tms.bookings.manage","enrolments.assign"],"parameters":[{"name":"places","in":"path","required":true,"description":"The company places uuid (from tms_places_list).","schema":{"type":"string"}}],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}}}},"patch":{"operationId":"tms_places_set_terms","summary":"Change company place terms","description":"Change release terms, who pays, what is charged, PO number or notes. Send only what changes.","tags":["Company places"],"security":[{"oauth2":["training:write"]},{"serviceKey":[]}],"x-mcp-tool":"tms_places_set_terms","x-scope":"training:write","x-permissions":["tms.bookings.manage"],"requestBody":{"required":false,"content":{"application\/json":{"schema":{"type":"object","properties":{"release_policy":{"type":"string","enum":["days_before","never"]},"release_days_before":{"type":"integer","minimum":1,"maximum":90},"warn_days_before_release":{"type":"integer","minimum":0,"maximum":30},"pay_mode":{"type":"string","enum":["account","card","free"]},"charge_mode":{"type":"string","enum":["used","reserved"]},"po_number":{"type":"string","maxLength":80},"notes":{"type":"string","maxLength":500}}}}}},"parameters":[{"name":"places","in":"path","required":true,"description":"","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string. Repeating the request with the same key within 24 hours returns the first reply instead of running again.","schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}}}}},"\/api\/v2\/tms\/events\/{event}\/places":{"post":{"operationId":"tms_places_reserve","summary":"Hold places for a company","description":"Hold unnamed places on a course date for a customer company; their managers can then name people. Nobody is emailed. Release terms: places not named by release_days_before are given back (never if left out close to the date).","tags":["Company places"],"security":[{"oauth2":["training:write"]},{"serviceKey":[]}],"x-mcp-tool":"tms_places_reserve","x-scope":"training:write","x-permissions":["tms.bookings.manage"],"x-effects":["webhook"],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","properties":{"organisation_id":{"type":"integer"},"places":{"type":"integer","minimum":1,"maximum":500},"release_policy":{"type":"string","enum":["days_before","never"]},"release_days_before":{"type":"integer","minimum":1,"maximum":90},"warn_days_before_release":{"type":"integer","minimum":0,"maximum":30,"description":"Warn the managers this many days before; 0 = no warning."},"pay_mode":{"type":"string","enum":["account","card","free"],"description":"Who pays by default: the company account, each person by card, or free."},"charge_mode":{"type":"string","enum":["used","reserved"],"description":"Charge for places used (default) or every place held."},"po_number":{"type":"string","maxLength":80},"notes":{"type":"string","maxLength":500}},"required":["organisation_id","places"]}}}},"parameters":[{"name":"event","in":"path","required":true,"description":"","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string. Repeating the request with the same key within 24 hours returns the first reply instead of running again.","schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}},"201":{"description":"Created.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}}}}},"\/api\/v2\/tms\/places\/{places}\/add":{"post":{"operationId":"tms_places_add","summary":"Hold more places for a company","description":"Add unnamed places to a company's existing hold on a date.","tags":["Company places"],"security":[{"oauth2":["training:write"]},{"serviceKey":[]}],"x-mcp-tool":"tms_places_add","x-scope":"training:write","x-permissions":["tms.bookings.manage"],"x-effects":["webhook"],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","properties":{"count":{"type":"integer","minimum":1,"maximum":500}},"required":["count"]}}}},"parameters":[{"name":"places","in":"path","required":true,"description":"","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string. Repeating the request with the same key within 24 hours returns the first reply instead of running again.","schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}},"201":{"description":"Created.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}}}}},"\/api\/v2\/tms\/places\/{places}\/fill":{"post":{"operationId":"tms_places_fill","summary":"Name people on company places","description":"Put people on unnamed places: a user_id, or a name and email (an email that matches an account links it). Each person is emailed a link to register (details, questions, ID, pre-work); the place is confirmed when they finish. Managers can only name people in their own team. The preview lists who will be emailed.\n\nConfirm-first: call without confirm_token to preview; call again with the same arguments and the confirm_token to carry it out.","tags":["Company places"],"security":[{"oauth2":["training:write"]},{"serviceKey":[]}],"x-mcp-tool":"tms_places_fill","x-scope":"training:write","x-permissions":["tms.bookings.manage","enrolments.assign"],"x-effects":["email"],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","properties":{"people":{"type":"array","maxItems":100,"items":{"type":"object","properties":{"user_id":{"type":"integer"},"name":{"type":"string","maxLength":150},"email":{"type":"string","maxLength":254}}}},"create_accounts":{"type":"boolean","description":"No longer needed: anyone without an account always gets one in the company when their place is named. Accepted and ignored."},"confirm_token":{"type":"string","description":"From the preview. Leave out to preview."}},"required":["people"]}}}},"parameters":[{"name":"places","in":"path","required":true,"description":"","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string. Repeating the request with the same key within 24 hours returns the first reply instead of running again.","schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"A preview (data.preview, data.confirm_token) or the result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}},"201":{"description":"Created.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}}}}},"\/api\/v2\/tms\/places\/{places}\/people\/{booking_id}\/unfill":{"post":{"operationId":"tms_places_unfill","summary":"Take someone off a company place","description":"Free a named place that person hasn't registered for yet; their link stops working. They are not emailed.","tags":["Company places"],"security":[{"oauth2":["training:write"]},{"serviceKey":[]}],"x-mcp-tool":"tms_places_unfill","x-scope":"training:write","x-permissions":["tms.bookings.manage","enrolments.assign"],"requestBody":{"required":false,"content":{"application\/json":{"schema":{"type":"object","properties":{}}}}},"parameters":[{"name":"places","in":"path","required":true,"description":"","schema":{"type":"string"}},{"name":"booking_id","in":"path","required":true,"description":"From tms_places_get people.","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string. Repeating the request with the same key within 24 hours returns the first reply instead of running again.","schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}},"201":{"description":"Created.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}}}}},"\/api\/v2\/tms\/places\/{places}\/people\/{booking_id}\/payer":{"post":{"operationId":"tms_places_set_payer","summary":"Change who pays for a place","description":"For a named place not yet confirmed: the company account, the person by card, or free (staff only). Switching away from card can finish their registration, which confirms the place and emails joining instructions.\n\nConfirm-first: call without confirm_token to preview; call again with the same arguments and the confirm_token to carry it out.","tags":["Company places"],"security":[{"oauth2":["training:write"]},{"serviceKey":[]}],"x-mcp-tool":"tms_places_set_payer","x-scope":"training:write","x-permissions":["tms.bookings.manage","enrolments.assign"],"x-effects":["email","money"],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","properties":{"payer":{"type":"string","enum":["account","card","free"]},"confirm_token":{"type":"string","description":"From the preview. Leave out to preview."}},"required":["payer"]}}}},"parameters":[{"name":"places","in":"path","required":true,"description":"","schema":{"type":"string"}},{"name":"booking_id","in":"path","required":true,"description":"","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string. Repeating the request with the same key within 24 hours returns the first reply instead of running again.","schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"A preview (data.preview, data.confirm_token) or the result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}},"201":{"description":"Created.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}}}}},"\/api\/v2\/tms\/places\/{places}\/people\/{booking_id}\/resend":{"post":{"operationId":"tms_places_resend_link","summary":"Send a registration link again","description":"Email someone on a company place their registration link again.\n\nConfirm-first: call without confirm_token to preview; call again with the same arguments and the confirm_token to carry it out.","tags":["Company places"],"security":[{"oauth2":["training:write"]},{"serviceKey":[]}],"x-mcp-tool":"tms_places_resend_link","x-scope":"training:write","x-permissions":["tms.bookings.manage","enrolments.assign"],"x-effects":["email"],"requestBody":{"required":false,"content":{"application\/json":{"schema":{"type":"object","properties":{"confirm_token":{"type":"string","description":"From the preview. Leave out to preview."}}}}}},"parameters":[{"name":"places","in":"path","required":true,"description":"","schema":{"type":"string"}},{"name":"booking_id","in":"path","required":true,"description":"","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string. Repeating the request with the same key within 24 hours returns the first reply instead of running again.","schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"A preview (data.preview, data.confirm_token) or the result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}},"201":{"description":"Created.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}}}}},"\/api\/v2\/tms\/places\/{places}\/remind":{"post":{"operationId":"tms_places_remind","summary":"Remind a company to name its places","description":"Email the managers of a company that holds unnamed places on a date, asking them to choose who is going (or give places back), with a link to name people. The same reminder goes out automatically before a release date; this sends it now. Staff only. Preview first: it names the managers.\n\nConfirm-first: call without confirm_token to preview; call again with the same arguments and the confirm_token to carry it out.","tags":["Company places"],"security":[{"oauth2":["training:write"]},{"serviceKey":[]}],"x-mcp-tool":"tms_places_remind","x-scope":"training:write","x-permissions":["tms.bookings.manage"],"x-effects":["email"],"requestBody":{"required":false,"content":{"application\/json":{"schema":{"type":"object","properties":{"confirm_token":{"type":"string","description":"From the preview. Leave out to preview."}}}}}},"parameters":[{"name":"places","in":"path","required":true,"description":"Company places uuid (tms_places_list).","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string. Repeating the request with the same key within 24 hours returns the first reply instead of running again.","schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"A preview (data.preview, data.confirm_token) or the result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}},"201":{"description":"Created.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}}}}},"\/api\/v2\/tms\/places\/{places}\/hand-back":{"post":{"operationId":"tms_places_hand_back","summary":"Give company places back","description":"Give unnamed places back for sale; anyone on the waitlist is offered them. Named people keep their places.\n\nConfirm-first: call without confirm_token to preview; call again with the same arguments and the confirm_token to carry it out.","tags":["Company places"],"security":[{"oauth2":["training:write"]},{"serviceKey":[]}],"x-mcp-tool":"tms_places_hand_back","x-scope":"training:write","x-permissions":["tms.bookings.manage","enrolments.assign"],"x-effects":["email"],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","properties":{"count":{"type":"integer","minimum":1,"maximum":500},"confirm_token":{"type":"string","description":"From the preview. Leave out to preview."}},"required":["count"]}}}},"parameters":[{"name":"places","in":"path","required":true,"description":"","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string. Repeating the request with the same key within 24 hours returns the first reply instead of running again.","schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"A preview (data.preview, data.confirm_token) or the result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}},"201":{"description":"Created.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}}}}},"\/api\/v2\/tms\/events\/{event}\/sessions\/{session_id}\/attendance":{"post":{"operationId":"tms_attendance_mark","summary":"Mark the register","description":"Mark delegates present, late or absent for one session (session ids and booking ids from tms_register_get). Only changes are saved. On the last session of a classroom course, present or late delegates complete the course and their exam opens; where the exam opens on attendance, marking present opens it.\n\nConfirm-first: call without confirm_token to preview; call again with the same arguments and the confirm_token to carry it out.","tags":["Teaching"],"security":[{"oauth2":["training:write"]},{"serviceKey":[]}],"x-mcp-tool":"tms_attendance_mark","x-scope":"training:write","x-permissions":["tms.trainer.self","tms.attendance.mark","tms.schedule.manage"],"x-effects":["email","webhook"],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","properties":{"marks":{"type":"array","maxItems":200,"items":{"type":"object","properties":{"booking_id":{"type":"integer"},"state":{"type":"string","enum":["present","late","absent"]}},"required":["booking_id","state"]}},"confirm_token":{"type":"string","description":"From the preview. Leave out to preview."}},"required":["marks"]}}}},"parameters":[{"name":"event","in":"path","required":true,"description":"","schema":{"type":"string"}},{"name":"session_id","in":"path","required":true,"description":"","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string. Repeating the request with the same key within 24 hours returns the first reply instead of running again.","schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"A preview (data.preview, data.confirm_token) or the result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}},"201":{"description":"Created.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}}}}},"\/api\/v2\/tms\/events\/{event}\/exam\/unlock":{"post":{"operationId":"tms_exam_unlock","summary":"Unlock the exam","description":"Open the exam for everyone on the date, or one delegate (booking_id), optionally for a number of minutes only.","tags":["Teaching"],"security":[{"oauth2":["training:write"]},{"serviceKey":[]}],"x-mcp-tool":"tms_exam_unlock","x-scope":"training:write","x-permissions":["tms.exam.unlock","tms.trainer.self"],"requestBody":{"required":false,"content":{"application\/json":{"schema":{"type":"object","properties":{"booking_id":{"type":"integer","description":"Leave out for everyone on the date."},"window_minutes":{"type":"integer","minimum":1,"maximum":10080},"note":{"type":"string","maxLength":255}}}}}},"parameters":[{"name":"event","in":"path","required":true,"description":"","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string. Repeating the request with the same key within 24 hours returns the first reply instead of running again.","schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}},"201":{"description":"Created.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}}}}},"\/api\/v2\/tms\/events\/{event}\/exam\/relock":{"post":{"operationId":"tms_exam_relock","summary":"Re-lock the exam","description":"Close an exam unlock for everyone on the date, or one delegate.","tags":["Teaching"],"security":[{"oauth2":["training:write"]},{"serviceKey":[]}],"x-mcp-tool":"tms_exam_relock","x-scope":"training:write","x-permissions":["tms.exam.unlock","tms.trainer.self"],"requestBody":{"required":false,"content":{"application\/json":{"schema":{"type":"object","properties":{"booking_id":{"type":"integer"}}}}}},"parameters":[{"name":"event","in":"path","required":true,"description":"","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string. Repeating the request with the same key within 24 hours returns the first reply instead of running again.","schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}},"201":{"description":"Created.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}}}}},"\/api\/v2\/tms\/events\/{event}\/bookings\/{booking_id}\/result":{"post":{"operationId":"tms_exam_record_result","summary":"Record a result by hand","description":"Pass a delegate without a digital exam attempt (paper exam, practical, assessor decision). A reason is required. Completes their course and issues the certificate if the course gives one; cannot be undone here.\n\nConfirm-first: call without confirm_token to preview; call again with the same arguments and the confirm_token to carry it out.","tags":["Teaching"],"security":[{"oauth2":["training:write"]},{"serviceKey":[]}],"x-mcp-tool":"tms_exam_record_result","x-scope":"training:write","x-permissions":["tms.exam.unlock","tms.trainer.self"],"x-effects":["email","webhook"],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","maxLength":255},"score":{"type":"number","minimum":0,"maximum":100,"description":"Percent, optional."},"confirm_token":{"type":"string","description":"From the preview. Leave out to preview."}},"required":["reason"]}}}},"parameters":[{"name":"event","in":"path","required":true,"description":"","schema":{"type":"string"}},{"name":"booking_id","in":"path","required":true,"description":"","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string. Repeating the request with the same key within 24 hours returns the first reply instead of running again.","schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"A preview (data.preview, data.confirm_token) or the result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}},"201":{"description":"Created.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}}}}},"\/api\/v2\/tms\/refunds":{"get":{"operationId":"tms_refunds_list","summary":"Refunds to check","description":"Cancelled places that were paid for or invoiced (a booking cancelled, or a whole course date). Refunds are manual: each says how it was paid and what to do (refund in Stripe, cancel or credit the invoice, or make sure an on-account place isn't invoiced). show=handled lists the ones already dealt with.","tags":["Bookings"],"security":[{"oauth2":["training:read"]},{"serviceKey":[]}],"x-mcp-tool":"tms_refunds_list","x-scope":"training:read","x-permissions":["tms.bookings.manage"],"parameters":[{"name":"show","in":"query","required":false,"description":"","schema":{"type":"string","enum":["open","handled"]}}],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}}}}},"\/api\/v2\/tms\/refunds\/{refund_id}":{"post":{"operationId":"tms_refunds_resolve","summary":"Mark a refund check done","description":"Record that a cancelled place was refunded, or needs no refund. This only records it; it moves no money and emails nobody.","tags":["Bookings"],"security":[{"oauth2":["training:write"]},{"serviceKey":[]}],"x-mcp-tool":"tms_refunds_resolve","x-scope":"training:write","x-permissions":["tms.bookings.manage"],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","properties":{"outcome":{"type":"string","enum":["refunded","not_needed"]},"note":{"type":"string","maxLength":255}},"required":["outcome"]}}}},"parameters":[{"name":"refund_id","in":"path","required":true,"description":"","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string. Repeating the request with the same key within 24 hours returns the first reply instead of running again.","schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}},"201":{"description":"Created.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}}}}},"\/api\/v2\/public\/courses":{"get":{"operationId":"public_courses_search","summary":"Find courses","description":"Courses on this training provider's website, best match first: what each covers, how it is delivered, duration, price and the next few dates with availability and booking links. query: words such as a subject, qualification or course name (leave out to list everything). category and delivery narrow it. Use the ref with public_course_get for the full details.","tags":["Website assistant"],"security":[{"serviceKey":[]}],"x-mcp-tool":"public_courses_search","x-scope":"public","x-permissions":[],"parameters":[{"name":"query","in":"query","required":false,"description":"What the visitor is looking for, e.g. \"IOSH\", \"first aid\", \"lifting operations\".","schema":{"type":"string","maxLength":200,"description":"What the visitor is looking for, e.g. \"IOSH\", \"first aid\", \"lifting operations\"."}},{"name":"category","in":"query","required":false,"description":"A category name (or part of one).","schema":{"type":"string","maxLength":100,"description":"A category name (or part of one)."}},{"name":"delivery","in":"query","required":false,"description":"classroom (at a venue), online (live online), blended.","schema":{"type":"string","enum":["classroom","online","blended"],"description":"classroom (at a venue), online (live online), blended."}},{"name":"limit","in":"query","required":false,"description":"At most this many courses (default 10).","schema":{"type":"integer","minimum":1,"maximum":25,"description":"At most this many courses (default 10)."}}],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}}}}},"\/api\/v2\/public\/courses\/{course}":{"get":{"operationId":"public_course_get","summary":"Course details and dates","description":"Everything about one course on the website: summary, full description, key facts, what it covers (sections), accreditations, duration, price, how to book, and every upcoming date with venue, availability, price and a booking link. course: the ref from public_courses_search, a course code, or the course title.","tags":["Website assistant"],"security":[{"serviceKey":[]}],"x-mcp-tool":"public_course_get","x-scope":"public","x-permissions":[],"parameters":[{"name":"course","in":"path","required":true,"description":"","schema":{"type":"string"}}],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}}}}},"\/api\/v2\/public\/dates":{"get":{"operationId":"public_dates_list","summary":"Upcoming course dates","description":"Upcoming dates in date order, for one course or across all courses: date and times, venue, town and postcode, delivery, availability (available, few_left or full; places_left too when the provider shows numbers), price and a booking link. Narrow by course, category, delivery, a date window (from \/ to, YYYY-MM-DD), a town or venue (location), or only dates with places (available_only). There is no distance search: for the nearest dates to a place, list them and compare the postcodes.","tags":["Website assistant"],"security":[{"serviceKey":[]}],"x-mcp-tool":"public_dates_list","x-scope":"public","x-permissions":[],"parameters":[{"name":"course","in":"query","required":false,"description":"A course ref, code or title.","schema":{"type":"string","maxLength":200,"description":"A course ref, code or title."}},{"name":"category","in":"query","required":false,"description":"","schema":{"type":"string","maxLength":100}},{"name":"delivery","in":"query","required":false,"description":"","schema":{"type":"string","enum":["classroom","online","blended"]}},{"name":"from","in":"query","required":false,"description":"","schema":{"type":"string","format":"date"}},{"name":"to","in":"query","required":false,"description":"","schema":{"type":"string","format":"date"}},{"name":"location","in":"query","required":false,"description":"A town, city or venue name.","schema":{"type":"string","maxLength":100,"description":"A town, city or venue name."}},{"name":"available_only","in":"query","required":false,"description":"Only dates with places left.","schema":{"type":"boolean","description":"Only dates with places left."}},{"name":"limit","in":"query","required":false,"description":"At most this many dates (default 15).","schema":{"type":"integer","minimum":1,"maximum":50,"description":"At most this many dates (default 15)."}}],"responses":{"200":{"description":"The result.","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Reply"}}}},"default":{"description":"An error (see the error codes).","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}}}}}},"components":{"securitySchemes":{"oauth2":{"type":"oauth2","description":"Acts as the person who approved the app. Discovery: \/.well-known\/oauth-authorization-server; dynamic client registration at \/oauth\/register.","flows":{"authorizationCode":{"authorizationUrl":"https:\/\/your-workspace.hotlinelms.com\/oauth\/authorize","tokenUrl":"https:\/\/your-workspace.hotlinelms.com\/oauth\/token","refreshUrl":"https:\/\/your-workspace.hotlinelms.com\/oauth\/token","scopes":{"profile":"See your name, role and what you can do","people:read":"See people, companies, enrolments and certificates you can already see","people:write":"Add and update people, assign and remove courses","courses:read":"See courses and course details","courses:write":"Change the rules of courses you can edit","reports:read":"Run reports and see dashboards","training:read":"See course dates, the schedule, bookings and your teaching","training:write":"Create and change course dates and bookings, approvals and company places","learning":"See your own courses, certificates and course dates, enrol yourself and open your courses"}}}},"serviceKey":{"type":"http","scheme":"bearer","bearerFormat":"hls_ service key","description":"A service connection made by a workspace admin in Settings → AI assistants. Acts with that admin's permissions and the scopes chosen for it. A website assistant key (hlw_) reaches only the public course tools (scope public): what the public training pages show."}},"schemas":{"Reply":{"type":"object","properties":{"data":{"description":"The result."},"meta":{"type":"object","description":"Paging (page, per_page, total, total_pages), practice_mode, replayed and notes."}}},"Error":{"type":"object","properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","enum":["unauthorized","invalid_token","plan_upgrade_required","forbidden","insufficient_scope","module_disabled","not_found","conflict","confirm_token_invalid","in_progress","invalid_input","too_many_recipients","rate_limited","temporarily_unavailable","internal_error"]},"message":{"type":"string"},"details":{"type":"object","description":"For invalid_input: a message per field."}}}}}}}}