# zenoti

**Category:** 💻 Developer Tools  
**Repository:** https://github.com/tacit-code/zenoti-mcp-server  
**npm Downloads (last month):** 6  
**Views:** 0  
**Installs:** 0  
**Upvotes:** 0  
**Directory Page:** https://allmcps.com/mcp/zenoti

## Description
MCP server for Zenoti spa/wellness/medspa — guests, appointments, bookings, invoices

## Claude Desktop Quick Installation
Heuristic fallback — verify the package name and runner against the repository README before running it. Uses `npx` (confidence: low):

```json
"mcpServers": {
  "zenoti": {
    "command": "npx",
    "args": ["-y","zenoti"]
  }
}
```

## Documentation & README

# Zenoti MCP Server

A Model Context Protocol (MCP) server for the [Zenoti](https://www.zenoti.com/) spa/wellness/medspa management platform. Exposes appointments, guests, service booking, invoices, catalog, and forms as tools an AI agent can call.

### Hosted version available

Do not want to manage credentials, hosting, and updates yourself? [DOCK](https://dockhq.vercel.app) is the managed version of this server: encrypted per-practice auth, audit logs, draft-first write actions, and a workflow library. Founding practices lock lifetime pricing: Front Desk $49/mo (Zenoti), Billing Desk $99/mo (Tebra, BAA included), Full Practice $129/mo (both). https://dockhq.vercel.app

## Installation

```bash
npm install -g zenoti-mcp-server
```

Or run from source:

```bash
git clone https://github.com/tacit-code/zenoti-mcp-server.git
cd zenoti-mcp-server
npm install
npm run build
```

## Configuration

| Variable | Required | Description |
|---|---|---|
| `ZENOTI_API_KEY` | yes | API key from Zenoti Admin → Settings → Apps (create a backend app) |
| `ZENOTI_API_URL` | no | Base URL, default `https://api.zenoti.com` (with or without `/v1`) |
| `ZENOTI_CENTER_ID` | recommended | Default center GUID; tools accept `center_id` to override per call |

Claude Desktop / Claude Code config:

```json
{
  "mcpServers": {
    "zenoti": {
      "command": "npx",
      "args": ["-y", "zenoti-mcp-server"],
      "env": {
        "ZENOTI_API_KEY": "your_api_key",
        "ZENOTI_CENTER_ID": "your_center_guid"
      }
    }
  }
}
```

The server starts even without credentials and returns a readable configuration error on each tool call, so a misconfigured client shows the problem instead of crash-looping.

## Tools

### Catalog
| Tool | Purpose |
|---|---|
| `zenoti-centers-list` | List organization centers (find center GUIDs) |
| `zenoti-services-list` | Services of a center (compact by default, `verbose` for raw) |
| `zenoti-services-get` | Full service details |
| `zenoti-therapists-list` | Therapists of a center, optionally filtered to a service |
| `zenoti-employee-schedules` | Who is on shift for a date range (date-scoped staffing) |

### Guests
| Tool | Purpose |
|---|---|
| `zenoti-guests-search` | Search by name/email/phone/code/tags (≥1 criterion required) |
| `zenoti-guests-create` | Create a guest profile |
| `zenoti-guests-get` | Guest details by GUID |
| `zenoti-guests-update` | Update fields — does a safe read-merge-write (Zenoti replaces the whole object on update) |
| `zenoti-guests-appointments` | Appointment history for a guest |
| `zenoti-guests-notes-list` / `zenoti-guests-notes-add` | Guest notes and profile alerts |
| `zenoti-guests-memberships` | Guest's memberships (status, credits, dues) |
| `zenoti-guests-packages` | Guest's packages/series with remaining redemptions |

### Appointments
| Tool | Purpose |
|---|---|
| `zenoti-appointments-list` | Center appointments for a date range (compact by default) |
| `zenoti-appointments-get` | Appointment details (`appointment_id`) |
| `zenoti-appointments-checkin` / `zenoti-appointments-undo-checkin` | Check-in state (`appointment_group_id`) |
| `zenoti-appointments-noshow` | Mark no-show (`appointment_group_id`) |
| `zenoti-appointments-progress` | Start/open/complete service (`appointment_id`) |
| `zenoti-appointments-cancel` | Cancel a booking (by `invoice_id`) |
| `zenoti-appointments-reschedule` | Start a reschedule (creates a booking draft tied to the invoice) |

### Booking flow
1. `zenoti-availability-slots` — creates a booking draft for guest+service+date and returns `booking_id` plus open slots
2. `zenoti-booking-reserve` — hold a chosen slot (holds are short-lived)
3. `zenoti-booking-confirm` — finalize; the response includes the invoice

### Invoices
| Tool | Purpose |
|---|---|
| `zenoti-invoices-get` | Invoice with line items, payments, and optional dues/fees |
| `zenoti-invoices-pay-custom` | Record a cash/custom payment (financial action) |
| `zenoti-invoices-pay-card` | Charge the guest's card on file (financial action) |
| `zenoti-invoices-close` | Close a fully-paid invoice |
| `zenoti-invoices-email` | Email the receipt/invoice to the guest |
| `zenoti-invoices-confirm-visit` | Confirm (or undo-confirm) the visit — a scheduling status, despite living on the invoice |

### Reports
| Tool | Purpose |
|---|---|
| `zenoti-reports-sales` | What was sold over a date range |
| `zenoti-reports-collections` | Money received over a date range |

### Forms & feedback
| Tool | Purpose |
|---|---|
| `zenoti-forms-list` / `zenoti-forms-get` | Forms and submitted form data of an appointment |
| `zenoti-guest-forms-list` | Forms on a guest profile |
| `zenoti-feedback-submit` | Insert externally collected guest feedback |

## Zenoti API gotchas this server handles

- **Three identifiers in one workflow.** Check-in/no-show/feedback take `appointment_group_id`; details/progress/forms take `appointment_id`; cancel and payments take `invoice_id`. Tool schemas name the exact one required.
- **Guest updates replace the whole object.** The update tool fetches the current profile and merges your changes; a naive partial `PUT` would erase fields.
- **Rate limit is 60 calls/minute** (org-wide). The HTTP layer honors `Retry-After` on 429. Reads also retry on 5xx/network failures/timeouts; writes retry **only** on 429 (a rate-limit rejection was never processed, so retrying can't duplicate a booking — any other write failure surfaces immediately).
- **Pagination caps at `size=100`**; larger values are rejected by Zenoti with a 422.
- **Webhooks have no subscription API** — they are configured in the Zenoti web UI (Admin → Webhooks) and require the Zenoti API package. This server intentionally has no webhook tool.
- **Undocumented numeric enums.** Gender and appointment-progress codes aren't in Zenoti's public docs; the mappings used here are documented in the tool descriptions and can be overridden (`progress_code`).

## Development

```bash
npm run dev        # run from source (tsx)
npm test           # unit + end-to-end tests (mock Zenoti API; no real credentials needed)
npm run typecheck  # tsc --noEmit
npm run build      # emit dist/
```

The e2e suite spawns the real server over stdio via the MCP SDK client and asserts every tool's method, path, query, and body against Zenoti's documented endpoints.

## License

MIT

