nextmotion
nextmotion.
The Nextmotion clinics the API key's user belongs to — start here: every
setup & usage
⚠ your nextmotion api key
log in to the Nextmotion web app, then Settings → API Keys → generate a key and copy it: it is not shown again afterwards. paste it into your oto connector keys under nextmotion.
▸ calendar, catalogue, sales, leads, patients, statistics, stock and aggregates
start with nextmotion_clinic(): every other tool asks for a clinic_id.
nextmotion_practitioner(op="list", clinic_id=…)nextmotion_appointment(op="list", clinic_id=…, date="YYYY-MM-DD")nextmotion_availability(clinic_id=…, start_date=…, end_date=…)nextmotion_availability, then nextmotion_appointment(op="reschedule", appointment_id=…, visit_type_opening_hour_id=<slot id>, time_slot=<slot time_slot>)nextmotion_catalog(kind="visit_type"|"treatment_type"|"treatment_pricing"|…, clinic_id=…)nextmotion_quote(op="list", clinic_id=…), nextmotion_invoice(op="list", clinic_id=…)nextmotion_invoice(op="list", clinic_id=…, invoiced_from="2026-01-01", invoiced_to="2026-01-31")nextmotion_product(op="list", clinic_id=…, expiring_within_days=30) or stock_state="low"|"out"nextmotion_calendar(kind="room"|"device"|"opening_hour"|"absence", clinic_id=…) (show_all=True for the whole clinic, not only the key's user)nextmotion_calendar(kind="appointment_request", clinic_id=…, request_status="new")nextmotion_journey(clinic_id=…, start_date="YYYY-MM-DD", end_date="YYYY-MM-DD")nextmotion_catalog(kind="treatment_package"|"accounting_distribution"|"global_product", clinic_id=…); a package's treatments → op="items", a pricing's or package's per-practitioner distribution → op="distributions"nextmotion_payment(op="list", clinic_id=…) or invoice_id=… for one invoicenextmotion_statistics(kind="appointment_income"|"treatment_types"|"treatment_types_income", clinic_id=…, period_type="month")nextmotion_patient_stats(patient_id=…) with the id served by an appointment, a quote or an invoicenextmotion_lead(op="list", clinic_id=…), and the source or status labels → nextmotion_setting(kind="object_label", clinic_id=…, label_types=["lead_source"])nextmotion_patient_demographics(clinic_id=…, by=["department","age_band"]) — headcounts only; a municipality's socio-demographic profile (population, income) is read in open data: urba_socio(code_insee)nextmotion_device_usage(clinic_id=…, start_date=…, end_date=…, period_type="month") — 93 days at most per callnextmotion_setting(kind="feature"|"payment_medium"|"communication_template"|"document_template"|"survey_form"|"webhook", clinic_id=…)nextmotion_patient(op="get", patient_id=…) with the id served by an appointment, a quote, an invoice; "find Mrs X" → nextmotion_patient(op="list", clinic_id=…, search="X")nextmotion_patient(op="create", clinic_id=…, data={"email": …, "first_name": …, "last_name": …, "gender": …}) or op="update", patient_id=…nextmotion_calendar(kind=…, op="create", clinic_id=…, data={…}); edit / delete → op="update"|"delete", item_id=…nextmotion_appointment(op="update", appointment_id=…, data={"calendar_event": {"start_time": …, "end_time": …}})nextmotion_catalog(kind="treatment_type"|"treatment_package"|…, op="create"|"update", …, data={…}); a package's lines → op="add_item"|"set_items", per-practitioner distribution → op="set_distributions"nextmotion_catalog(kind="treatment_pricing", op="assign_distribution", data={"user": …, "accounting_distribution": …}, clinic_id=…, treatment_type_id=…), or data={"user": …, "items": [{"id": <pricing>, "accounting_distribution": …}, …]} when the split differs per line; remove with op="unassign_distribution"; audit a type first with op="distributions", clinic_id=…, treatment_type_id=…nextmotion_quote(op="validate", quote_id=…), nextmotion_invoice(op="pay", invoice_id=…, data={"card": "100.00"}), nextmotion_invoice(op="credit_note", clinic_id=…, data={"patient": …, "items": [...]})nextmotion_lead(op="create", clinic_id=…, data={…}), nextmotion_lead(op="convert", lead_id=…)nextmotion_communication(kind="call"|"message", clinic_id=…, data={…})· invoices by period: a complete, bounded walk
invoiced_time falls within the period, bounds includedmax_pages (20 by default, 100 at most); the response gives pages_lues, factures_parcourues and completcomplet: false = partial result: rerun with offset=<offset_suivant> and the same period to read the restlimit is refused and offset is the starting point of the walk· product stock: no link to invoices
nextmotion_product reads the clinic's stock (one batch per line: batch number, expiry, stock levels, unit price, product and brand); a batch can be created, edited (levels, expiry) and deleted· patient base and devices: aggregates, never a row
nextmotion_patient_demographics reads the whole patient list to count: by postal code, department, city, country, gender or age band; no row, no id, no name comes out, and a cell of fewer than 10 patients is masked (only the masked total is returned) — crossing many dimensions masks a lot: start broadnextmotion_device_usage counts, per device, the appointments held, their minutes and those not held, by reading the calendar day by day: it is the booked usage, not the machine's real usage (shots, actual duration), which Nextmotion does not know; no occupancy rate, the API does not give a device's capacity· health data: what is not served
fields=["*"] returns the default view, never the rawdoctor_comments is refused on writedry_run previews included); when the identity is useful, this id is resolved with nextmotion_patient(op="get", patient_id=…). nextmotion_patient_stats returns its financial totals and its visit dates· sales: full lines, statistics, settings
markup), VAT and its sub-pricings (subpricing: nature, price, VAT, accounting code, clinic or practitioner share)nextmotion_invoicetitle, labels, datasets); the API's meta block, undescribed, is not served· writes: a preview first
data, re-reads the targeted object and returns what would go out, without writing anything. pass dry_run=False to actdata, checked against the fields the Nextmotion spec accepts for THIS op: an unknown field is refused, by name, even in nested objects — never ignored; a missing required field toosub_visit_types, a treatment type's pricings, a package's op="set_items", op="set_distributions" — an omitted element is deletedop="assign_distribution" / "unassign_distribution" change ONE practitioner on up to 500 pricings or packages and rewrite every other practitioner as read: the preview lists each item's change (add, update, remove, unchanged), the write touches only the items that change, and an item that fails is listed in failed without stopping the othersnull value is not sent: a field cannot be emptied through this toolnextmotion_communication(kind="message") sends an email, SMS or WhatsApp to the patient, for a quote, an invoice or an administrative document only — never a prescription, a consent or a medical documentsend_appointment_modified_email|sms are true in the spec); the tool sends them as false unless you pass them as true, and the preview says who would be notified (notifie_le_patient)pay and credit_note validate the document by default on the Nextmotion side (do_validate: true); pass do_validate: false to keep a draft⚙ multiple comptes
this connector accepts multiple comptes: each stored credential becomes a named account (one name per compte), at your level, your team's or your org's.
_account="<name>" on the tool; list them: oto_identity(op='list', connector='nextmotion') (scope='org' or scope='group' for the org's or team's)oto_identity(op='set', connector='nextmotion', identity_id='<name>'); rename: op='rename' with new_name_account) and adding upoutils
chargement…
utilisation
claude code — installe le plugin oto —
claude plugin marketplace add otomata-tech/oto-plugin — mcp + skill configurés.cli —
pipx install oto-cli puis oto nextmotion …