Every change Wellknown observed on this MCP server, newest first, with what it was before and what it became. Tool-surface changes carry the definition diff. Nothing here is edited after the fact.
Changed the definition of "whoami"
Only numbers and dates differ: this server embeds live figures in the definition, so the text moves without the contract changing.
⟨614 unchanged words⟩ to the user — diagnostic only. [SURFACE_BUILD:0.20.80.20.9]
Added "call_tool" and "get_tool_schema"; removed "bookings_add_lead", "classes_add_course", "classes_commit_class" and 18 more; changed the definition of "bookings_copy_booking", "bookings_find", "classes_find_classes" and 7 more (37 tools before, 18 now)
⟨212 unchanged words⟩ , which Zooza charges on top of it. ANOTHER PROGRAMME IS ALLOWED. The target class may belong to a different programme than the booking (e.g. a free trial moving into a paid course). The preview then carries a `different_programme` warning: the booking is priced by the TARGET programme, no instalment plan is applied (payments_add_plan afterwards), and the old programme's booking-form answers are carried over — the target programme's own required questions are NOT asked. SIMPLE CASE ONLY. This tool cannot set up ⟨47 unchanged words⟩
⟨69 unchanged words⟩ (one exact booking by its id), `place_id` (venue), `status`, `payment_status`, or booking date with `created_from`/`created_to` ⟨25 unchanged words⟩ straight into comms_send_message (`audience.registration_id` / `audience.user_id`).Class/programmeEachNAMESbooking
Changed the definition of "bookings_find", "classes_commit_class", "classes_find_classes" and 2 more
⟨58 unchanged words⟩ `course_id`/`schedule_id` (resolve via classes_find_courses / classes_find_classes), `billing_period_id` (a term/season), `user_id`, `registration_id` (one exact booking by its ⟨77 unchanged words⟩
{"$schema":"http://json-schema.org/draft-07/schema#","additionalProperties":false,"properties":{"billing_period_id":{"description":"Bookings belonging to this billing period (term/season). Resolve the id with classes_find_resource (kind:'billing_period'); never guess it. To cover several periods, call once per period and merge the ids.","exclusiveMinimum":0,"type":"integer"},"company_id":{"description":"Zooza company id to ⟨459 unchanged words⟩
Certificate changed, valid to 2026-12-25
Added "bookings_copy_booking" and "sessions_cancel"; changed the definition of "whoami" (35 tools before, 37 now)
Only numbers and dates differ: this server embeds live figures in the definition, so the text moves without the contract changing.
⟨614 unchanged words⟩ to the user — diagnostic only. [SURFACE_BUILD:0.13.00.14.3]
Copy or move a booking to another class (preview, then apply) — Copy or move a client's existing booking into a different class. COPY creates a second booking and leaves the original in place — use it when the client is continuing into a new term or adding a class alongside their current one. MOVE relocates the booking itself, carrying its payment history and debt, and the client is no longer in the old class — use it when they are switching. TWO CALLS. First WITHOUT `token`: returns both class prices, what the client currently owes, free places in the target class, and any blockers, plus a single-use token. Show that to the operator — especially the `mo…
Certificate recorded, valid to 2026-10-26
Authorization not required
First tool surface recorded: 35 tools (server version 0.13.0)
Showing the latest 8 events. The API returns up to 500 and filters by kind: ?kind=tool_surface_changed
⟨5 unchanged words⟩ properties":{"billing_period_id":{"description":"Bookingsbelonging toin this billing period (term/season). Resolvethe id withvia classes_find_resource (kind:'billing_period');never guess it. To cover several periods, call once perone periodand merge theperids.call.","exclusiveMinimum":0,"type":"integer"} ⟨181 unchanged words⟩ per booking.","type":"boolean"},"include_inactiveinactive_only":{"description":"true → ONLY clients marked inactive (former clients). Defaultfalse.alreadySetincludestruethem; never set it toalsowiden.","type":"boolean"},"include_extra_fields":{"description":"trueinclude→inactiveeachcustomers.booking gets `extra_fields: [{field, label, value}]`: filled custom booking-form answers, labelled per programme. Not with `distinct`.","type":"boolean"},"name":{"description":"Enrolled person's name (substring, accent-insensitive).If it draws a blankBlank for a kids'class,class?tryTry `search` (alsomatches theaccount-holderparent too).","type":"string"},"page" ⟨49 unchanged words⟩ :"string"},"type":"array"},"registration_idplace_id":{"description":"Fetch ONE exact booking by its registration id.BookingsUseat thistovenue.confirmResolveaviaspecificclasses_find_resourceregistration(kind:'place').","exclusiveMinimum":0,"type":"integer"},"registration_id":{"description":"ONEexistsexactorbookingreadbywhoid,itwhateverisits—status (unlike `search`, which substring-matchesthe id (search: 45 alsomatcheshits 145, 450). An exact registration_id lookup returns that booking whatever its status (only truly deleted rows are hidden).","exclusiveMinimum":0,"type":"integer ⟨129 unchanged words⟩
⟨114 unchanged words⟩ classes inside one programme), `trainer_id`, `place_id`, `billing_period_id` (term block; one id or up to 10), `day` of week, `registration_type`, `in_trial: true` ( ⟨88 unchanged words⟩ registrations_count, sessions_count, status, in_trial, registration_url, billing_period_id, schedule_type}` — enough to disambiguate when several ⟨126 unchanged words⟩ bookable or the company has no registration widget).; its programme/venue/room params are rebuilt from the class's live values, so it stays correct after a class is moved. `billing_period_id` 0 = no billing period. Combine filters in ONE call — e.g. ` ⟨172 unchanged words⟩
⟨28 unchanged words⟩ classes too.","type":"boolean"},"billing_period_id":{"anyOf":[{"exclusiveMinimum":0,"type":"integer"},{"items":{"exclusiveMinimum":0,"type":"integer"},"maxItems":10,"minItems":1,"type":"array"}],"description":"Only classes in this billing period (term block) — or these. Resolve via classes_find_resource kind:'billing_period'."},"company_id":{"description":"Zooza company id to ⟨390 unchanged words⟩
⟨42 unchanged words⟩ ), registration-count cap, billing period, online-registration, trial lessons, status — and/or instructor, venue, or session ⟨202 unchanged words⟩
⟨28 unchanged words⟩ (billing period) this class belongs to. Resolve:withclasses_find_resourceclasses_find_billing_periods.kind:billing_period.","exclusiveMinimum":0,"type":"integer"} ⟨299 unchanged words⟩ ":"Venue (place) for the class. Resolve:withclasses_find_resourceclasses_find_places.kind:place. Must be changed together with room_id. CASCADE field ⟨91 unchanged words⟩ birthday party = 1 registration holding 7 seats), so this limits how many separate bookings exist, independent of seat count.. `0` =OFF,no limiton the number of registrations — this is(the normaldefault. Setting it to 1 restricts the class to a single registration; setting it todefault); N caps it at N registrations.It does NOT by itself stop registrations or reduce capacity, and it hasNOTHING to do withmake-up/replacementmake-up (náhrady) sessions —for thoseuse extra_capacity. Onlyset thisfor genuine multi-seat-per-registration scenarios.","minimum":0," ⟨37 unchanged words⟩ "description":"Instructor assigned to the class. Resolve:withclasses_find_resourcetrainers_find.kind:trainer. CASCADE field — changing it requires session_scope.", ⟨15 unchanged words⟩ is paid, not what clients pay). Resolve:withclasses_find_resourcetrainers_find_rate_types.kind:trainer_rate_type. CASCADE field — changing it requires session_scope.","minimum":0,"type":"integer"},"trial_enabled":{"description":"Whether this class accepts trial lessons. Only effective when the programme allows trials (classes_update_course_settings).","type":"boolean"},"unit_price":{"description":"Per-session price ⟨312 unchanged words⟩
⟨21 unchanged words⟩ ,"properties":{"active_only":{"description":"Only meaningfulWithwithwhole_companywhole_company.only. true (DEFAULT) =onlyclients with an ACTIVE(registered) booking — the safe choice.booking. false =literallyEVERYONE incl. cancelled/inactive/pastclients(spammy) —useonlywhenif the operatorhasexplicitlyaskedasks.forAskthat.whichWhentheywhole_companymean.","type":"boolean"},"billing_period_id":{"description":"Everyoneisbookedset,intoASKthisthebillingoperatorperiodwhich(termtheyblock).meanONEandidstate—plainlyclasses_find_resourcethatkind:'billing_period'.theCombinedefaultwithskipscourse_id/schedule_idcancelled/inactivetopeople.narrow; several periods = one message each.","exclusiveMinimum":0,"type":"booleaninteger"},"course_id":{"description":"Everyone registered ⟨38 unchanged words⟩ estimate).","type":"boolean"},"inactive_customersinactive_only":{"description":"Defaulttruefalse.→IncludeONLY clients marked inactiveregistrations.(former clients). Default already includes them.","type":"boolean"},"labels":{ ⟨41 unchanged words⟩ ":"array"}],"description":"One booking,or a LIST of bookings — pass a singleid oranaarrayLIST (e.g.the registration_ids froma bookings_find resultset,so you canto message an ad-hoc cohort like the unpaid roster ⟨40 unchanged words⟩ :{"description":"Broadcast to the ENTIRE company— every booking, one email perclient. The only audience needingclient; noid.id needed. ONLY for genuinely company-widesends.sendsFor— for a NAMED subset— the(unpaid roster,thewaitlist, one class— do NOT use this;) resolvethe cohortit with bookings_find andpass its registration_id list to registration_id instead. This can reach a LOT of people,usesoregistration_id. ALWAYS confirm scope with the operatorfirst, and make the all-vs-active choice explicit (see active_only) — do NOT silently email everyone.first;Pairpair with active_only.","type":"boolean"}}, ⟨387 unchanged words⟩
⟨171 unchanged words⟩ `reason` is required and is recorded for staffonly.only — it must be the operator's own words: if they did not say why, ASK before the first call; never invent a placeholder such as "cancelled by operator". `public_reason` is what clients read and is required ⟨168 unchanged words⟩
⟨259 unchanged words⟩ REQUIRED. Internal, staff-only; Zooza cannot clear it later. The operator's stated reason — ask, never invent.","minLength":1,"type":"string"} ⟨164 unchanged words⟩
⟨327 unchanged words⟩ To CHANGE any of this, use `trainers_add_helpers`. **Trainer pay (payroll).** `pay` = `{rate_type_id, rate_type, payout_percentage, minutes, main_trainer}`; each `additional_trainers[]` entry has its own `pay`. Each trainer's `{unit_amount, amount}` mirrors the Zooza trainer report: `amount = unit_amount × payout_percentage × minutes` (`fixed` rate type: no × minutes), where the RATE TYPE is the session's and `unit_amount` is that trainer's own rate for it (`null` → no rate set, amount 0). `payout_percentage` is a 0–1 fraction (cancelled sessions are 0). `pay` is null when the session has no rate type or rates are not readable for this caller. For one trainer's monthly cost, sum `pay.main_trainer.amount` ONLY on rows whose `trainer_id` is that trainer, plus `pay.amount` of THEIR entry in `additional_trainers[]` — the `trainer_id` filter also returns sessions they are merely linked to (substituted away, class roster), which pay them nothing. The roster (`class_additional_trainers`) carries no pay. **Critical: "my sessions" / "what am ⟨241 unchanged words⟩
⟨15 unchanged words⟩ or more billing periods (term blocks). Resolve:withclasses_find_resourceclasses_find_billing_periods.kind:billing_period."},"company_id":{"description":"Zooza company ⟨189 unchanged words⟩ at one or more venues (places). Resolve:withclasses_find_resourceclasses_find_places.kind:place."},"room_id":{"$ref":"#/properties/course_id", ⟨143 unchanged words⟩ is connected to (one or more). Resolve:withclasses_find_resourcetrainers_find.kind:trainer. See the trainer filter note above — this ⟨41 unchanged words⟩
⟨468 unchanged words⟩ setting `sessions_mark_attendance`'s `use_voucher=true` on a `going` write. - `additional_trainers` — who works THIS session alongside the main instructor, as `{trainer_id, trainer_name, role}` (`secondary` = "Secondary instructor", `assistant` = "Assistant", `helper` = "Assistant instructor", `trainer` = "Instructor"); `[]` = nobody. `trainer_name` null = lookup failed, not a missing trainer. For pay, use `sessions_find_events`. - `summary` block at the top level surfaces whether ⟨50 unchanged words⟩
⟨12 unchanged words⟩ to a class. Two modes, one tool. NOT for a change that holds from a date onward or for every session ("from next week Jana teaches the Monday class", "the class moves to Room B") — that is ONE classes_update call with session_scope ('upcoming' or 'all'), never a per-session edit of each date. EDIT-MODE — pass `event_ids` + `changes`: reschedule a ⟨194 unchanged words⟩ ", "give Friday's session to Jana").To change an attribute across ALL or all upcoming sessions of a class in one go, use classes_update with session_scope instead.To cancel sessions, use the cancellation tools ⟨6 unchanged words⟩
⟨28 unchanged words⟩ :"integer"},"place_id":{"description":"Move the session(s) to a different venue (place); must beNewsentvenue;togethersend with room_id. Resolvewithviaclasses_find_places.classes_find_resource kind:'place'.","exclusiveMinimum":0,"type":"integer"} ⟨22 unchanged words⟩ ":{"const":"set","description":"Reschedule mode: move the session(s) to an explicitExplicit date (and+ optional time).","type":"string"},"time":{"description":"New start time,HH:MM. Omitto→ keep each session'sexistingtime.","pattern":"^\\d{2}:\\d{2 ⟨12 unchanged words⟩ ":{"const":"unify_time","description":"Reschedule mode: set every selected session to the sameSame timeonforitsall,existingdatesdate.unchanged.","type":"string"},"time":{"description":"Start time,HH:MM,applied tofor every selected session.","pattern":"^\\d{2 ⟨12 unchanged words⟩ ,"properties":{"days":{"description":"Days to shift each session by;Days; negativemoves it= earlier.","type":"integer"},"minutes":{"description":"Minutes to shift each session's time by;Minutes; negativemoves it= earlier.","type":"integer"},"mode":{"const":"shift","description":"Reschedule mode: move each session by a relativeRelative offset (days and/or minutes).","type" ⟨3 unchanged words⟩ type":"object"}],"description":"Movethe selected session(s)to a newdate/time. Pick a modedate/time: set (explicit date), unify_time (same timeon, existing dates),or shift (relative offset)."},"room_id":{"description":"Room within the venuefor(0the=session(snone);must be sent togethersend with place_id.","minimum":0,"type": ⟨23 unchanged words⟩ to clear."},"trainer_id":{"description":"Reassign the session(s) to a differentNew instructor. Resolvewithviatrainers_find.classes_find_resource kind:'trainer'.","exclusiveMinimum":0,"type":"integer"},"trainer_rate_type_id":{"description":"Set the instructorInstructor pay-ratetype for the session(s).type. Resolvewithviatrainers_find_rate_types.classes_find_resource kind:'trainer_rate_type'.","minimum":0,"type":"integer"} ⟨119 unchanged words⟩ boolean"},"event_ids":{"description":"EDIT-MODE.Existing sessionSession ids tochange; pairchange, with`changes`.`changes`;Resolveresolvewithvia sessions_find_events. Not with schedule_id/sessions.","items":{" ⟨9 unchanged words⟩ description":"Default false. true emails enrolled clientsabout the change— confirmintentwith the operator first. Setiton the FIRSTcall; it iscall (frozen into theplan.plan).","type":"boolean"},"schedule_id":{ ⟨21 unchanged words⟩ "sessions":{"description":"ADD-MODE. New sessionsto createon`schedule_id`.`schedule_id`;Eacheach needs adate;date, time/duration default from the class.For\"oneOne more at the end\",:getthe date after the last sessionvia(sessions_find_eventsand pass the next date.).","items":{"additionalProperties":false,"properties" ⟨105 unchanged words⟩
Only numbers and dates differ: this server embeds live figures in the definition, so the text moves without the contract changing.
⟨614 unchanged words⟩ to the user — diagnostic only. [SURFACE_BUILD:0.15.00.20.8]
Call any Zooza tool by name — Runs a Zooza tool by name. Use it for every Zooza tool that is NOT in your tool list — these exist and work; never send the user to another app because a Zooza tool isn't listed. Call get_tool_schema(name) first for the arguments. Write tools behave exactly as when called directly: the first call previews and returns a token, the second (token + confirmed:true) applies. Tools reachable this way: - bookings_add_lead: Add a lead (minimal registration on a lead-collection schedule) - classes_add_course: Create a new programme (course) - classes_add_share_link: Create a private registration link …
Get a Zooza tool's input schema — Returns the description and exact input schema of a Zooza tool, including tools not in your tool list (call_tool lists them). Call it once per tool before that tool's first call_tool.
Add a lead (minimal registration on a lead-collection schedule) — Create a LEAD — a lightweight registration on a lead-collection schedule — for a prospective customer, from their name and email. Use this to capture an inbound enquiry as a trackable Zooza record you can later label, message, and check for conversion. It does NOT enrol the person in a real class, take payment, or email the customer (the server authenticates with an App-type key, which sends no customer communication). It works ONLY against schedules whose type is `lead_collection`; for a genuine class booking, or anything that should charge or notify the customer, do NOT use this tool. Not i…
Create a new programme (course) — Create a new programme (course) — the top-level container in Zooza that holds pricing, payment settings, and booking-form configuration. Classes and sessions are added inside it afterwards; a programme cannot accept bookings until it has at least one class. IMPORTANT routing rule: only create a programme for a genuinely NEW product or offering. If the user is re-running an existing programme — new term, new time slot, new venue, new instructor — do NOT create a programme; create a class inside the existing programme instead (classes_preview_schedule → classes_commit_class; the class inherits …
Commit a class (schedule + events) — Writes a class to api-v1 in one shot: creates the schedule, attaches any selected payment templates (bundled inline), and posts the assembled events array. Call this only after the user has confirmed the class shell (from `classes_preview_schedule`) and the full event list (accumulated from one or more `classes_preview_events` calls). For lead-collection classes, pass `events: []`. Returns the created schedule's id and url plus the list of created event ids. If api-v1 silently skips any events (a known quirk), the tool surfaces the mismatch as an error so the caller knows the partial state. …
List valid Zooza schedule patterns — Returns all valid field values for building class schedules and payment plans in Zooza. No Zooza API call — hardcoded from Events_Preview.php and Payment_Schedule.php. Call this BEFORE classes_preview_schedule or classes_commit_class to avoid validation errors. Critical: weekdays must be 3-letter lowercase (mon/tue/wed...), NOT 'monday' or '1'. Critical: until_date and count are mutually exclusive — sending both causes an API error. Examples: domain="event_generation" → cadences, weekdays, time format; domain="payment_schedule" → schedule types and billing frequencies; empty call → both secti…
Preview class session dates — Expands one or more recurrence patterns and/or ad-hoc dates into the concrete list of class sessions, honouring holiday-skip flags. Stateless — performs no writes. Call this once per pattern the user describes during class creation. Accumulate the returned sessions across multiple calls (Claude side) until the user says they're done, then pass the full list to `classes_commit_class`. Each block must carry EXACTLY ONE of `count` (stop after N sessions) or `until_date` (stop on a fixed date) — count mode is preferred when the user says "X sessions". A top-level `to_date` acts as a fallback `unt…
Preview a class schedule shell — Resolves a new class's *schedule shell* — the course, venue, trainer, capacity, prices, billing period, and default payment templates — and returns the result alongside any warnings. Performs no writes. Use this first in a class-creation flow to confirm the basic class settings with the user before collecting session dates via `classes_preview_events` and committing via `classes_commit_class`. Defaults are copied from the parent course where the caller hasn't specified them (capacity from `target_audience`, prices from the course's pricing fields). Always surface the `warnings[]` array to the…
Change programme settings (preview, then apply) — Change the settings of an existing programme (course) — pricing, online booking, make-up sessions, trial, auto-enrolment, attendance, feedback, basic info, or archiving. Works one section at a time, like the settings tiles in the Zooza app. TWO CALLS. First call WITHOUT `token`: returns a diff of current → proposed values, warnings, and a single-use token. Show that diff to the user and get their approval. Second call with `token` + `confirmed: true`: applies it. Send nothing else on the second call — the token already carries the change. The token expires in 15 minutes; if it is expired or …
Read inbound customer replies and set a reply's state — Read inbound replies a customer has sent back to Zooza emails, and optionally mark a reply handled. Use it to see whether a lead responded and what they said — filter by the lead's registration id, sender email, state (unread / todo / resolved), or date. To act on a reply, pass `mark_reply_id` + `mark_state` to flag it `todo` (needs a human) or `resolved` (handled), or `read`. Replies only appear here if the original email went out through Zooza tied to that registration. This does NOT send anything — use comms_send_message to reply. The idempotency pattern: read `unread` replies, act, then m…
List Zooza message merge variables — Returns all valid merge variables for Zooza message templates (email, SMS, WhatsApp). Format: *|VARIABLE_NAME|* (MailChimp-compatible). No Zooza API call — hardcoded from Merge_Vars::merge_vars() in api-v1. Use this BEFORE writing any message template to get correct variable names. Claude must not invent variable names — only variables listed here are valid. Examples: category="financial" → payment and balance vars; medium="sms" → SMS-safe vars with HTML warnings; empty call → full catalogue grouped by category.
List the company's automated email templates — Lists the automated email templates Zooza sends to this company's clients — registration confirmations, trial follow-ups, cancellation notices, session reminders, loyalty/discount emails, and custom templates. For each template returns its trigger `type`, subject line, and whether the company uses the stock Zooza default or has customized it. Use this to see which automated emails exist, check what has been customized, or look up a template's `type` before previewing or sending it (comms_send_message accepts that `type`). This tool only lists email templates — for the merge variables (*|FIRST…
Explain Zooza data model — Returns a structured description of Zooza's domain entities — hierarchy, roles, valid field values (enums), parent/child relationships, and disambiguation rules. No Zooza API call is made — purely hardcoded domain knowledge. Call this before any class-creation, booking, or attendance tool to avoid entity confusion. Examples: entity="programme" → registration_type enums; entity="booking" → status values; entity="credit" → make-up / replacement entitlements (the "unused/expired make-ups" and "credits" concept); empty call → full hierarchy with all entities.
Attach or detach a label on a course, schedule, or registration — Attach or detach a label (a named tag) on a Zooza course, schedule, or registration. Set `present: true` to attach (the label is created automatically if it doesn't exist yet — attach is idempotent), `present: false` to detach. Use it to tag records for grouping or pipeline state — e.g. mark a lead registration `converted`, or flag one `todo`. Works ONLY on courses, schedules, and registrations. NOTE: labels on a SCHEDULE can be customer-visible on the public booking widget (output flags this as `public_facing`); labels on courses and registrations are internal. Does not send anything.
Negotiate terminology — build a personalised vocabulary profile — Free tool — no Zooza API call, no company_id required. Two modes: "start" → returns the 8-question interview template for Claude to conduct conversationally. "build" → validates answers against the Zooza glossary, returns a TerminologyProfile JSON plus a /remember instruction so Claude saves the profile to memory. Run once per user. The saved profile is auto-loaded in every future Zooza session — no re-configuration needed. Call get_skill('negotiate-terminology') before starting the interview.
Apply a payment plan to a booking — Put a booking on a payment plan — the instalment calendar the client actually pays against. A plan attached to a programme or class is NOT inherited by bookings; each booking has to have it applied, and until then the client owes nothing and sees no payment schedule. TWO CALLS. First WITHOUT `token`: writes nothing and returns the TOTAL plus the instalment dates and how many sessions each one covers. Zooza's preview does not expose per-instalment amounts before the plan exists — divide the total by the instalment count when telling the user, and say it is the expected split. Show that to the…
Add a session summary — Write a post-session summary on one event. Two independent fields: - `public_summary` — visible to attendees / parents via their in-app Zooza feed. Use when the user says "write a summary for the parents," "send a recap," "note for the families," etc. After write, every attendee's Person_Feed gets a `SUMMARY_PUBLIC` entry — parents see it in their client portal. - `internal_summary` — admin / team only. Use when the user says "add a note for the team," "private note," "reminder for next week," etc. Not visible to parents. At least one of the two must be provided. Both can be written in one …
Create a payment plan template — Create a company-level payment plan template ("splátková šablóna") — the object that defines HOW a programme's price is collected: in how many instalments, how often, with what discount and rounding. A programme set to instalment collection produces NO instalment schedule until a template is attached, so this is the step that makes instalment billing actually happen. CRITICAL — the template does NOT carry the price. The amount always comes from the programme/class; the template only says how to split it. So "€200 in 4 × €50" is: programme price 200 (set via classes_add_course or classes_upda…
Set a programme's payment plan templates — Choose which payment plan templates a programme offers clients — attach new ones, and DETACH ones that should not be there. Detaching is the point: Zooza attaches templates by itself when a programme's price type or payment collection changes, and on a company with many templates that can silently put dozens of plans on a programme. This is how you clean that up. TWO CALLS. First WITHOUT `token`: writes nothing and returns what is attached now, what would be attached, and the exact attach/detach list. Show it to the operator. Then call again with `token` + `confirmed: true` to apply. `templ…
Submit feedback to engineering — Submit user feedback about the Zooza MCP integration to the engineering team. Two paths: - 'path: "github"' — returns a prefilled issue-creation URL on the **public** `zooza-dev/zooza-mcp-server` repo. The user opens it in their browser and files the issue themselves (no MCP-side auth). The body MUST be fully anonymized (no user_id, company_id, company name, user email/name, course/class/event names, customer/client identifiers). The server runs a safety-net regex and will reject the call if obvious identifiers (long numbers, emails) remain. - 'path: "internal"' — files an issue on the user'…
Create an operator to-do item — Create a to-do item for a Zooza operator — a task a human needs to action. Give it a `message` and the `to_user_id` of the person it's assigned to. Optionally link it to a record (`entity_type` + `entity_id`, e.g. a registration) so the operator can open the thing it's about, and set a `due_date`. Use this to escalate — e.g. a lead asked a question that needs a human reply. It creates an OPEN todo in Zooza's normal to-do list; it does not email anyone. There is no `inbound_reply` entity type — link a reply escalation to its registration instead.
Change the status of a to-do item — Change the status of a to-do item: `done` (completed), `cancelled` (won't do), or `open` (reopen). Only OPEN todos can be marked `done` or `cancelled`; a `done` or `cancelled` todo can only be reopened to `open`. Marking `done` stamps completion time automatically.
Add additional lecturers to classes and sessions — Register **additional lecturers** — a second instructor, assistant, or helper — on one or more classes, and control which of their sessions each one actually works. This is NOT how you set or change a class's main instructor (that is `classes_update`, or `sessions_update` for one-off substitutions); additional lecturers are extra people who work *alongside* the main instructor. By default a lecturer you add here works **every** session of the class — that is the normal arrangement. Restrict one to certain days by giving that assignment `weekdays` (1=Monday … 7=Sunday), or to hand-picked sessi…
⟨172 unchanged words⟩ templates to attach to the class. Omit tokeepattach every template thecourse'scourse offers (the same defaulttemplateclasses_preview_scheduleselectionmarksfromselected_by_default).classes_preview_schedule.Pass the ids explicitly to attach a subset.","items":{"exclusiveMinimum":0,"type" ⟨425 unchanged words⟩
⟨205 unchanged words⟩ time, trainer_id, trainer_name, place_id, place_name, room_id, duration_minutes, trainer_rate_type_id, capacity, registrations_count, sessions_count, status, in_trial, registration_url ⟨8 unchanged words⟩ classes share a name, never enough to mutate. When COPYING an existing class, pass its `room_id`, `duration_minutes` and `trainer_rate_type_id` into `classes_preview_schedule` explicitly — otherwise the preview falls back to no room, the 60-minute default and no pay rate. `room_id` 0 = no specific room; `trainer_rate_type_id` 0 = none set (or hidden from your role). `sessions_count` is the class's number of sessions ( ⟨253 unchanged words⟩
⟨225 unchanged words⟩ with a normal course fee; 'pay_as_you_go' is for recurring membership pricing. A template is NOT a class pass: a fixed bundle ("5 classes for €X, valid 6 weeks") cannot be modelled here — tell the operator it is not available through these tools rather than approximating it with a discount. Pass `course_id` to attach the template to a ⟨39 unchanged words⟩
Only numbers and dates differ: this server embeds live figures in the definition, so the text moves without the contract changing.
⟨614 unchanged words⟩ to the user — diagnostic only. [SURFACE_BUILD:0.14.30.15.0]
Cancel sessions (preview, then apply) — Cancel one or more scheduled SESSIONS of a class so they do not take place — "cancel Tuesday's sessions", "the pool is closed on Friday", "Martina is ill all week, cancel her classes". A cancelled session stays visible in Zooza with a cancelled status; it is NOT deleted. Scope the call to exactly ONE entity: `event_ids`, a single `date`, a single `trainer_id` with `from`/`to`, a single `schedule_id` with `from`/`to`, or a single `place_id` with a `date`. Two instructors or two classes in one call are refused by design — cancel them one at a time so each blast radius is reviewed on its own. A…