# Clients (hotels) — tool reference

Generated from the OpenAPI document (`https://maison-labs.com/api/v1/openapi.json`). Field types are JSON Schema types; GET/DELETE inputs travel as path or query, other methods as a JSON body.

## `create_client` — Create a client

Provision a hotel in one call: creates the client on its feature plan, links its website as the main knowledge source, seeds the default hotel configuration and chatbot tone, queues the first website scrape (or property discovery for a multi-property group), and deploys the demo preview site. The plan: `planTemplateId` puts the client on a plan template with optional `featureOverrides` winning over its defaults; `noTemplate: true` grants exactly `features`; neither gives the baseline set. A website without a scheme is stored as https. 409 when a client with the same name exists; 404 for an unknown plan template. Returns the new client record.

- REST: `POST https://maison-labs.com/api/v1/client`
- MCP tool / A2A skill: `create_client`
- Needs: clients WRITE (global)

Inputs:

| Field | Where | Type | Required | Notes |
| --- | --- | --- | --- | --- |
| `name` | body | string | yes | Hotel name |
| `website` | body | string | yes | Public website URL, e.g. https://example-hotel.com (https:// is added if missing) |
| `scrapeWebsite` | body | boolean | no | Queue the first scrape immediately (ignored for multi-property, which always runs discovery); default true |
| `scrapeLanguage` | body | string \| null | no | Language the scraper writes in, e.g. English; default null |
| `multiProperty` | body | boolean | no | The website is a group/brand site with several properties — never scraped whole; default false |
| `demoClient` | body | boolean | no | default false |
| `hotelConfig` | body | object | no | Extra hotelConfig fields merged on top of name + website (address, phone, …) |
| `planTemplateId` | body | string | no | Plan template to put the client on (see `list_plan_templates`); format uuid |
| `featureOverrides` | body | array of object | no | With `planTemplateId`: features switched on or off against the plan |
| `noTemplate` | body | boolean | no | No plan template: the client gets exactly `features` |
| `features` | body | array of string | no | With `noTemplate: true`: the features the client is entitled to |

## `deploy_preview_site` — Deploy the demo preview site

Create or recreate the hosted demo page that embeds the client's chat widget, and return its URL. `name` and `website` override the client's stored values for the page (a website without a scheme gets https://). 503 when this environment has no preview-site hosting. Safe to repeat.

- REST: `POST https://maison-labs.com/api/v1/client/{clientId}/previewsite`
- MCP tool / A2A skill: `deploy_preview_site`
- Needs: clients EXECUTE (client); client plan must include `update-client`

Inputs:

| Field | Where | Type | Required | Notes |
| --- | --- | --- | --- | --- |
| `clientId` | path | string | yes | Client (hotel) id; format uuid |
| `name` | body | string | no | Name shown on the demo page |
| `website` | body | string | no | Website the page links to |

## `disable_client` — Disable a client

Switch a hotel off as if its account were deleted; nothing is deleted. Its chat widget no longer appears and its chats stop answering; its Instagram, Messenger, WhatsApp and email channels and its guest MCP listing go silent; its agents, scheduled reports, website syncs and every other job stop; incoming webhooks for it are refused; and the public API refuses every call for it except `get_client`, `enable_client` and `disable_client`. Staff keep their logins but lose the hotel (within ten minutes at most). Payments already in flight still settle. Calling it again re-applies the switch. Reverse with `enable_client`.

- REST: `POST https://maison-labs.com/api/v1/client/{clientId}/disable`
- MCP tool / A2A skill: `disable_client`
- Needs: clients WRITE (global)
- Destructive — confirm with the user first.

Inputs:

| Field | Where | Type | Required | Notes |
| --- | --- | --- | --- | --- |
| `clientId` | path | string | yes | Client (hotel) id; format uuid |

## `enable_client` — Re-enable a client

Switch a disabled hotel back on: its chat widget, chats, channels, agents, jobs, webhooks and public API access resume, and it appears in active listings again. Guests routed to it from a shared brand channel choose again. Calling it again re-applies the switch.

- REST: `POST https://maison-labs.com/api/v1/client/{clientId}/enable`
- MCP tool / A2A skill: `enable_client`
- Needs: clients WRITE (global)

Inputs:

| Field | Where | Type | Required | Notes |
| --- | --- | --- | --- | --- |
| `clientId` | path | string | yes | Client (hotel) id; format uuid |

## `get_client` — Get a client

The full client record (settings, website, scrape state, schedules, IANA timezone, computed flags) and its automatic live status: `live_status` (LIVE = the chat widget loaded on the hotel's own website in the last 7 days; CHURN_RISK = no load for 14 days; NOT_LIVE; MANUAL_NOT_LIVE = the override in Settings), `live_since`, `live_last_seen_at`, `live_last_seen_host`, `live_manual_not_live`. 404 when the id is unknown or disabled-and-hidden.

- REST: `GET https://maison-labs.com/api/v1/client/{clientId}`
- MCP tool / A2A skill: `get_client`
- Needs: clients READ (client)
- Read-only.

Inputs:

| Field | Where | Type | Required | Notes |
| --- | --- | --- | --- | --- |
| `clientId` | path | string | yes | Client (hotel) id; format uuid |

## `get_client_activity` — Client activity feed

The audit/activity timeline for a hotel (knowledge, configuration, brand, connections, access, reports, account, health, notes), newest first, with cursor paging (`direction: newer` pages towards the present) and filters: one category or all but one (`excludeCategory`), failed only, a date range, one knowledge source (`source`), or one event by its `MX-…` support reference. Requires the client-activity entitlement.

- REST: `GET https://maison-labs.com/api/v1/client/{clientId}/activity`
- MCP tool / A2A skill: `get_client_activity`
- Needs: client-activity READ (client); client plan must include `client-activity`
- Read-only.

Inputs:

| Field | Where | Type | Required | Notes |
| --- | --- | --- | --- | --- |
| `clientId` | path | string | yes | Client (hotel) id; format uuid |
| `limit` | query | integer | no | default 50 |
| `cursor` | query | string | no |  |
| `direction` | query | enum: older \| newer | no | Page towards older events (default) or newer ones from the cursor; default "older" |
| `category` | query | enum: knowledge \| configuration \| brand \| connections \| access \| reports \| account \| health \| notes | no |  |
| `excludeCategory` | query | enum: knowledge \| configuration \| brand \| connections \| access \| reports \| account \| health \| notes | no | Hide one category |
| `failedOnly` | query | boolean | no | default false |
| `from` | query | string \| string | no | Inclusive lower bound: ISO date or date-time |
| `to` | query | string \| string | no | Exclusive upper bound: ISO date or date-time |
| `source` | query | string | no | Only events of this knowledge source link; format uuid |
| `reference` | query | string | no | A support reference (MX-…) to resolve to its event |

## `get_client_metrics` — Client metrics

Headline numbers for one hotel: conversations, knowledge size, last scrape, channel counts. For time-series analytics use `get_portfolio_overview`.

- REST: `GET https://maison-labs.com/api/v1/client/{clientId}/metrics`
- MCP tool / A2A skill: `get_client_metrics`
- Needs: clients READ (client)
- Read-only.

Inputs:

| Field | Where | Type | Required | Notes |
| --- | --- | --- | --- | --- |
| `clientId` | path | string | yes | Client (hotel) id; format uuid |

## `get_client_overview` — Client overview

The client workspace Overview in one read: identity (name, website, demo site), setup progress, scheduled and recent jobs, knowledge, people, group (parent/children), latest activity, latest note and a timeline. A section the client is not entitled to or the caller cannot read is omitted; a section that failed alone is `{ error: true }`. For headline counts only use `get_client_metrics`.

- REST: `GET https://maison-labs.com/api/v1/client/{clientId}/overview`
- MCP tool / A2A skill: `get_client_overview`
- Needs: clients READ (client)
- Read-only.

Inputs:

| Field | Where | Type | Required | Notes |
| --- | --- | --- | --- | --- |
| `clientId` | path | string | yes | Client (hotel) id; format uuid |

## `get_clients_summary` — Clients summary

Counts of active, disabled, demo and recently created clients across the caller's portfolio. Use for a dashboard headline; use `list_clients` for rows.

- REST: `GET https://maison-labs.com/api/v1/clients/summary`
- MCP tool / A2A skill: `get_clients_summary`
- Needs: clients READ (any)
- Read-only.

Inputs:

_No inputs._

## `get_live_clients_report` — Live clients report

For one month (`YYYY-MM`, UTC), the clients that were LIVE at any point in it and how many were still LIVE at month end, optionally limited to the clients under one hierarchy node (`nodeId`: every descendant in `client_hierarchy`, the node itself excluded). LIVE = the chat widget loaded on the client's own website (never a Maison host) in the last 7 days, recomputed daily; derived from the recorded `live_status_changed` transitions and the current status. Use it for rep-co invoices (live member hotels per month). 404 when `nodeId` is unknown.

- REST: `GET https://maison-labs.com/api/v1/clients/livereport`
- MCP tool / A2A skill: `get_live_clients_report`
- Needs: clients READ (global)
- Read-only.

Inputs:

| Field | Where | Type | Required | Notes |
| --- | --- | --- | --- | --- |
| `month` | query | string | yes | The month, e.g. "2026-10" |
| `nodeId` | query | string | no | A hierarchy node (group client): only its descendants are counted; format uuid |

## `list_client_jobs` — List running jobs

Pipeline jobs (scrapes, ingests, reports) currently running for a hotel, with task ids usable by `stop_client_job`. Maison staff only.

- REST: `GET https://maison-labs.com/api/v1/client/{clientId}/jobs`
- MCP tool / A2A skill: `list_client_jobs`
- Needs: jobs EXECUTE (global)
- Read-only.

Inputs:

| Field | Where | Type | Required | Notes |
| --- | --- | --- | --- | --- |
| `clientId` | path | string | yes | Client (hotel) id; format uuid |

## `list_clients` — List clients

Page through the hotels the caller can see, with search, status filter and sort. Returns only clients the key's user holds `clients` READ on (or all, with a global grant). Each row carries its automatic live status (`live_status`: LIVE, NOT_LIVE, CHURN_RISK or MANUAL_NOT_LIVE; `live_since`, `live_last_seen_at`, `live_last_seen_host`). Use `get_client` for one hotel's full record. Filter server-side instead of paging the portfolio: `liveStatus` (live | not_live) and `activity` (none | some = conversations in the last `activityDays` days, default 30; widget loads never count) — e.g. live hotels without conversations = `liveStatus: live, activity: none`; `total` is the full count, so answer with it and the first page. With an activity filter or `orderBy: last_activity_date`, rows also carry `conversations_in_window` and `last_activity_date` (last day with a conversation).

- REST: `GET https://maison-labs.com/api/v1/clients`
- MCP tool / A2A skill: `list_clients`
- Needs: clients READ (any)
- Read-only.

Inputs:

| Field | Where | Type | Required | Notes |
| --- | --- | --- | --- | --- |
| `limit` | query | integer | no | Page size (1–100); default 20 |
| `after` | query | string | no | Opaque cursor from the previous page's `nextCursor`; omit for the first page |
| `search` | query | string | no | Case-insensitive match on name or website |
| `status` | query | enum: active \| disabled \| all | no | default "active" |
| `orderBy` | query | enum: name \| created_date \| demo_client \| last_scraped_date \| primary_scrape_status \| scrape_schedule \| ai_visibility_schedule \| last_activity_date | no | default "name" |
| `sort` | query | enum: ASC \| DESC | no | default "DESC" |
| `liveStatus` | query | enum: live \| not_live \| any | no | `live` = live_status LIVE; `not_live` = any other status; omit or `any` for all |
| `activity` | query | enum: none \| some \| any | no | Conversations in the last `activityDays` days: `none` = zero, `some` = at least one; omit or `any` for all |
| `activityDays` | query | integer | no | Window of the `activity` filter and `conversations_in_window`, in days (default 30) |

## `rescrape_client_website` — Rescrape the main website

Queue a fresh scrape of the client's main website into its knowledge base. `force` re-ingests pages even when unchanged. Progress is visible in `list_client_jobs` and `get_client_activity`.

- REST: `POST https://maison-labs.com/api/v1/client/{clientId}/rescrape`
- MCP tool / A2A skill: `rescrape_client_website`
- Needs: document-source EXECUTE (client)

Inputs:

| Field | Where | Type | Required | Notes |
| --- | --- | --- | --- | --- |
| `clientId` | path | string | yes | Client (hotel) id; format uuid |
| `language` | body | string \| null | no | default null |
| `force` | body | boolean | no | default false |

## `stop_client_job` — Stop a running job

Stop one running pipeline job for a hotel (a stopped scrape is marked canceled). A task belonging to another client is reported as not found. Recorded in the activity feed. Maison staff only.

- REST: `DELETE https://maison-labs.com/api/v1/client/{clientId}/job/{taskId}`
- MCP tool / A2A skill: `stop_client_job`
- Needs: jobs EXECUTE (global)
- Destructive — confirm with the user first.

Inputs:

| Field | Where | Type | Required | Notes |
| --- | --- | --- | --- | --- |
| `clientId` | path | string | yes | Client (hotel) id; format uuid |
| `taskId` | path | string | yes | ECS task id (32 lowercase hex) |

## `update_client` — Update a client

Partial update of the client record: name, description, demo flag, website, scrape language, manual-knowledge and multi-property flags, report schedules, and the hotel's IANA timezone (400 `invalid_timezone` for a zone outside the runtime's Intl list). Only the fields sent are changed. Changing a schedule also needs the Maison-only `schedules` WRITE grant (403 otherwise). Recorded in the activity feed. Hotel configuration (address, hours, …) lives in `update_hotel_config`.

- REST: `PUT https://maison-labs.com/api/v1/client/{clientId}`
- MCP tool / A2A skill: `update_client`
- Needs: update-client WRITE (client); client plan must include `update-client`

Inputs:

| Field | Where | Type | Required | Notes |
| --- | --- | --- | --- | --- |
| `clientId` | path | string | yes | Client (hotel) id; format uuid |
| `name` | body | string | no |  |
| `description` | body | string \| null | no |  |
| `demoClient` | body | boolean | no |  |
| `websiteId` | body | string | no | Website record the client is linked to; format uuid |
| `scrapeLanguage` | body | string \| null | no |  |
| `manualKnowledge` | body | boolean | no | True = the knowledge base is curated by hand, never scraped |
| `multiProperty` | body | boolean | no | The website is a multi-property group/brand site |
| `chatLogsAnalyticsSchedule` | body | enum: NONE \| DAILY \| WEEKLY \| BI_WEEKLY \| MONTHLY | no | Needs the `schedules` WRITE grant |
| `aiVisibilitySchedule` | body | enum: NONE \| DAILY \| WEEKLY \| BI_WEEKLY \| MONTHLY | no | Needs the `schedules` WRITE grant |
| `timezone` | body | string \| null | no | The hotel's IANA timezone, e.g. "Europe/Paris"; every time the console shows for this client is in it. null clears it. |
