Pages & Sites
Space MCP tools in the Pages & Sites scope (pages). Reach these with a wks_live_ key over space-mcp or space-api.
Tools in the pages scope, callable over space-mcp (tools/call) or space-api (REST) with a wks_live_* key that grants pages.
cancel_booking
Scope: pages:write
Cancel a booked appointment (status → cancelled). Get the booking_id from list_bookings. The linked calendar event is kept unless delete_calendar_event:true. The guest is NOT auto-notified — tell them if they should know.
| Parameter | Type | Required | Description |
|---|---|---|---|
booking_id | string | yes | |
delete_calendar_event | boolean | Also remove the linked calendar event (default false, matching the in-app cancel). |
create_blog_collection
Scope: pages:write
Create a blog (collection) — the REAL blog system, not a static page. To make it part of a website, pass site_id from create_site/list_sites. A blog holds the post layout (template_html with {{title}}/{{cover_image}}/{{excerpt}}/{{body}}/{{author}}/{{date}} tokens; a neutral default is used if omitted). Idempotent by base_slug per space. Then add posts with create_blog_post.
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | Blog name, e.g. "Acme Journal" (default "Blog"). | |
site_id | string | Attach to a site so the blog is part of one website (recommended). | |
base_slug | string | URL segment, default "blog". Unique per space. | |
template_html | string | Custom post layout HTML with the six tokens. Omit for a neutral responsive default. | |
index_page_id | string | Optional page that hosts the blog index/cards. |
create_blog_post
Scope: pages:write
Write a blog post into a collection. Provide body_html (HTML rendered into the blog template), plus optional excerpt, cover_image_url, and author. Defaults to a draft; pass status:'published' to publish immediately (live at /post/<id>). Requires create_blog_collection first.
| Parameter | Type | Required | Description |
|---|---|---|---|
collection_id | string | yes | From create_blog_collection / list_blog_collections. |
title | string | yes | |
body_html | string | Post body as HTML. | |
excerpt | string | ||
cover_image_url | string | Hosted cover image URL. | |
author | string | ||
slug | string | Preferred URL slug (a short suffix is appended to keep it unique). | |
status | draft | published | Default draft. |
create_booking_page
Scope: pages:write
Create a real Space booking page so visitors can schedule time. Returns { booking_page_id, slug }. Embed with <div data-wakato-booking="<booking_page_id>"> or link a CTA to /b/<slug>. Active immediately with default Mon–Fri 9–5 availability. Set meeting_location_type to "wakato_meet" so EVERY booking automatically creates a Wakato Meet video-call link.
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | yes | |
description | string | ||
booking_type | one_on_one | group | ||
duration_minutes | number | ||
timezone | string | ||
meeting_location_type | wakato_meet | in_person | phone_call | custom_link | Where meetings happen. "wakato_meet" auto-creates a Wakato Meet video link on every booking. | |
meeting_location_value | string | Address (in_person), phone/instructions (phone_call), or URL (custom_link). Leave empty for wakato_meet. | |
form_id | string | Attach a Space form (from list_forms/create_form) so guests answer extra questions when booking. Must belong to this space. |
create_page
Scope: pages:write
Create a new AI-designed web page. EVERY page is part of exactly one artifact — decide FIRST: (a) part of a browseable WEBSITE → create_site kind:"website" and pass site_id; (b) a step of a LANDING flow/funnel → create_site kind:"landing" and pass site_id (steps link FORWARD only, no nav); (c) a single standalone LANDING PAGE → no site_id (pass standalone:true if it's your 2nd+ within the hour). Pass layout_html (a complete HTML document) to build it in one call. Any <form> must use the binding <form data-wakato-form-id=\"<id>\"> and any calendar must use <div data-wakato-booking=\"<id>\"> (or a /b/<slug> link) referencing a real Space form/booking page — create those first with create_form/create_booking_page. Storefront sections: embed <div data-wakato-products></div> (live grid of every product listed on this space, optional data-limit="N") or <div data-wakato-product=\"<product_id>\"></div> (one product's card) — leave the container EMPTY; the platform fills live price/photos/stock with working Buy buttons at render time. Products must be listed on this space first (commerce scope: set_product_listing). Blog section: <div data-wakato-blog-index data-base=\"blog\"></div> fills with published post cards. Link sibling pages with /pg/<their slug> hrefs. Idempotent by title: a same-title page is filled if empty, otherwise returned untouched. ENFORCED: a 2nd+ standalone page within the hour is rejected unless standalone:true — scattering one website/funnel across loose pages is never allowed.\n\nPAGE_DESIGN_BRIEF
| Parameter | Type | Required | Description |
|---|---|---|---|
title | string | yes | |
description | string | ||
layout_html | string | Complete HTML document for the page body. | |
site_id | string | The artifact this page belongs to (from create_site/list_sites). REQUIRED for every website page and every landing-flow step; omit ONLY for a single standalone landing page. | |
standalone | boolean | Set true ONLY for an intentional separate single landing page unrelated to other recent pages. Required for a 2nd+ standalone page within an hour (otherwise rejected to prevent scattering one website/funnel as loose pages). |
create_site
Scope: pages:write
Create a web artifact and DECLARE what it is. kind:"website" = a browseable multi-page site (visitors roam freely via shared navigation). kind:"landing" = a landing page flow: forward-only steps toward ONE goal — opt-in → sales → thank-you etc. — with navigation disabled (when someone asks for a 'funnel', this is it; a single conversion page needs NO site — just create_page standalone). REQUIRED before any multi-page build: create the artifact FIRST, then pass its id as site_id on every create_page call (do NOT scatter pages standalone). Idempotent by title. The first page attached becomes the home page / step 1.
| Parameter | Type | Required | Description |
|---|---|---|---|
title | string | yes | Brand/offer name, e.g. "Acme Bike Co." or "Spring Sale Funnel". |
kind | website | landing | yes | website = browseable with shared nav · landing = forward-only step flow, nav disabled (a funnel when 2+ steps). |
description | string | ||
nav_layout | top | sidebar | none | Nav style for websites (default top). Ignored for kind:landing — landing flows never get a nav. | |
logo_url | string | Optional brand logo URL. |
delete_booking_page
Scope: pages:write
PERMANENTLY delete a booking page (its booking history is deleted with it). Refused while upcoming confirmed bookings exist — cancel those first with cancel_booking. Prefer update_booking_page status:"paused" to just stop new bookings.
| Parameter | Type | Required | Description |
|---|---|---|---|
booking_page_id | string | yes |
delete_page
Scope: pages:write
PERMANENTLY delete one page (a published page goes offline). To remove a WHOLE website or landing flow use delete_site instead — it removes the artifact and all its pages in one call. If the deleted page belonged to a site, run validate_site afterwards and fix any nav item that pointed at it.
| Parameter | Type | Required | Description |
|---|---|---|---|
page_id | string | yes |
delete_site
Scope: pages:write
PERMANENTLY delete a web artifact — the WHOLE website or landing flow: by default every page/step is deleted with it (published pages go offline). This is the correct way to remove a website or funnel; deleting its pages one by one leaves the shell behind. Pass keep_pages: true only if the pages should survive as standalone single landing pages (they lose the shared nav/flow).
| Parameter | Type | Required | Description |
|---|---|---|---|
site_id | string | yes | |
keep_pages | boolean | true = detach the site's pages as standalone instead of deleting them (default false). |
get_booking_page
Scope: pages:read
Get a Space booking page including its availability and timezone.
| Parameter | Type | Required | Description |
|---|---|---|---|
booking_page_id | string | yes |
get_page
Scope: pages:read
Get a single page including its layout_html (the full HTML document).
| Parameter | Type | Required | Description |
|---|---|---|---|
page_id | string | yes |
list_blog_collections
Scope: pages:read
List the space's blogs (collections). Each blog groups posts and may be attached to a site (site_id). Call before create_blog_collection to reuse an existing blog.
list_blog_posts
Scope: pages:read
List blog posts in the space. Optional collection_id, status (draft|published), limit.
| Parameter | Type | Required | Description |
|---|---|---|---|
collection_id | string | ||
status | draft | published | ||
limit | number |
list_booking_pages
Scope: pages:read
List Space booking pages (id, name, slug, status). Reuse an existing one before creating a new one.
list_bookings
Scope: pages:read
List actual booked appointments (guest name/email, start/end, status, attendee_status = whether the guest accepted/declined the calendar invite) across the space or one booking page. Use upcoming_only:true for the forward schedule, search to find a specific guest, status:"cancelled" for cancellations. Answers in the guest's attached form (if any) are in form_data.
| Parameter | Type | Required | Description |
|---|---|---|---|
booking_page_id | string | Restrict to one booking page (omit for all pages in the space). | |
status | confirmed | cancelled | ||
upcoming_only | boolean | Only bookings that start from now, soonest first. | |
from | string | ISO datetime lower bound on start_at. | |
to | string | ISO datetime upper bound on start_at. | |
search | string | Match on guest name or email. | |
limit | number | Max rows (default 50, max 200). |
list_pages
Scope: pages:read
List pages in the space.
list_sites
Scope: pages:read
List the space's web artifacts (sites). Each is EITHER kind:"website" (browseable multi-page site, shared brand + platform-injected navigation) OR kind:"landing" (a landing page flow — forward-only ordered steps toward one goal, no nav; 2+ steps = a funnel). Returns id, title, slug, kind, status, root_page_id. Call this before create_site to avoid duplicates.
present_page
Scope: pages:read
Show a Space Page live in the user's Space Computer panel (Apps & Pages tab). Call it when you start building or changing a page, or when the user asks to open/see one. Whiteboards and documents cannot be presented. UI-only signal — succeeds even if the panel is closed, and stores nothing.
| Parameter | Type | Required | Description |
|---|---|---|---|
page_id | string | yes |
preview_booking_page
Scope: pages:read
TEST a booking page the way a guest would: returns its full config, the attached form's questions (if any), and REAL bookable time slots computed with the same engine as the public /b/<slug> widget — plus a ready verdict and issues list. Each slot's label is complete — weekday, date, and time already rendered in the requested timezone (e.g. "Tuesday, July 14 at 10:30 AM"; quote verbatim — never pair a time with your own weekday/date or do timezone math) — plus an absolute start_at/end_at (UTC ISO). Use this right after create/update_booking_page to confirm it actually works. Pass a specific date (YYYY-MM-DD) to probe one day, or omit it to scan the next days (default 14) for the first open day.
| Parameter | Type | Required | Description |
|---|---|---|---|
booking_page_id | string | yes | |
date | string | Optional day to test, YYYY-MM-DD. Omit to scan forward for the next open day. | |
days | number | Days to scan when no date is given (default 14, max 60). | |
timezone | string | IANA timezone to render slot labels in (e.g. America/Los_Angeles). Defaults to the page's own timezone. |
preview_page
Scope: pages:run
SEE the live page: renders a PUBLISHED page headlessly, captures full-page screenshots (desktop 1440px + mobile 390px), saves them to Space Assets, and runs a vision QA critique (billed to the space wallet) reporting real visual problems — overlapping/clipped content, unreadable contrast, broken images, unstyled sections, empty product/blog containers, mobile overflow. THE QUALITY LOOP for website builds: publish_page → preview_page → fix every severity=error issue → republish → preview again until verdict is looks_good. Combine with validate_site (structure) for a complete check. Requires the page to be published first.
| Parameter | Type | Required | Description |
|---|---|---|---|
page_id | string | yes | |
viewports | string[] | Widths to capture (default both). | |
critique | boolean | Run the vision critique (default true). Set false for screenshots only. |
publish_blog_post
Scope: pages:run
Publish a blog post (live at /post/<id>), or pass publish:false to move it back to draft. Requires pages:run.
| Parameter | Type | Required | Description |
|---|---|---|---|
post_id | string | yes | |
publish | boolean | false to unpublish (default true). |
publish_page
Scope: pages:run
Publish a page so it's live at /pg/<published_slug>. Pass publish:false to unpublish. Requires pages:run. The result includes an automatic link lint (link_issues): severity=error entries are DEAD links/embeds visitors will hit — fix and republish, never leave them. Publishing is step 1 of the quality loop; ALWAYS follow with preview_page.
| Parameter | Type | Required | Description |
|---|---|---|---|
page_id | string | yes | |
published_slug | string | Optional custom slug; defaults to the page's slug. | |
publish | boolean | false to unpublish (default true). |
reorder_site_pages
Scope: pages:write
Set the display order of a site's pages (the order they appear in the site's page list and default navigation). Pass the site's page ids in the desired order; omitted pages sort after the listed ones.
| Parameter | Type | Required | Description |
|---|---|---|---|
site_id | string | yes | |
page_ids | string[] | yes | Page ids in the desired order (first = home position). |
reschedule_booking
Scope: pages:write
Move a confirmed booking to a new slot. Pass new_date (YYYY-MM-DD) + new_start (HH:MM) in the booking page's OWN timezone — find open slots with preview_booking_page first. The new slot is validated against real availability (the booking never conflicts with itself) and the linked calendar event moves with it. The guest is NOT auto-notified.
| Parameter | Type | Required | Description |
|---|---|---|---|
booking_id | string | yes | |
new_date | string | yes | YYYY-MM-DD in the page's timezone. |
new_start | string | yes | HH:MM in the page's timezone. |
new_end | string | HH:MM — derived from the page's duration when omitted. | |
skip_availability_check | boolean | Force the move even if the slot isn't in the page's open availability. |
update_blog_collection
Scope: pages:write
Edit a blog (collection): rename it, replace template_html to re-theme the post layout (keep the six tokens), or attach/detach a site_id / index_page_id (pass null to detach). The base_slug is fixed at creation.
| Parameter | Type | Required | Description |
|---|---|---|---|
collection_id | string | yes | |
name | string | ||
template_html | string | Replacement post layout HTML with the six tokens. | |
site_id | string,null | Attach to a site, or null to detach. | |
index_page_id | string,null | Set the blog index page, or null to clear. |
update_blog_post
Scope: pages:write
Edit a blog post's title, excerpt, cover_image_url, body_html, or author.
| Parameter | Type | Required | Description |
|---|---|---|---|
post_id | string | yes | |
title | string | ||
excerpt | string | ||
cover_image_url | string | ||
body_html | string | ||
author | string |
update_booking_page
Scope: pages:write
Edit an existing booking page. Pass booking_page_id + only the fields to change. Set meeting_location_type to "wakato_meet" so every booking auto-creates a Wakato Meet video-call link.
| Parameter | Type | Required | Description |
|---|---|---|---|
booking_page_id | string | yes | |
name | string | ||
description | string | ||
duration_minutes | number | ||
timezone | string | ||
status | draft | active | paused | ||
buffer_minutes | number | ||
min_notice_hours | number | ||
max_advance_days | number | ||
meeting_location_type | wakato_meet | in_person | phone_call | custom_link | ||
meeting_location_value | string | ||
form_id | string | Attach a Space form (id) so guests answer extra questions when booking, or null to detach. Must belong to this space. | |
confirmation_message | string | Text shown on-page after booking AND inside the default confirmation email. | |
confirmation_email_enabled | boolean | Send the guest a confirmation email with the .ics invite (default true). false = no email. | |
confirmation_email_subject | string | Custom confirmation email subject. Merge tags: {{guest_name}} {{guest_email}} {{page_name}} {{space_name}} {{meeting_time}} {{meeting_link}} {{meeting_location}}. | |
confirmation_email_body | string | Custom confirmation email body text — replaces the default greeting/intro; the meeting time, join link, and .ics invite are always included below it. Merge tags: {{guest_name}} {{guest_email}} {{page_name}} {{space_name}} {{meeting_time}} {{meeting_link}} {{meeting_location}}. |
update_page
Scope: pages:write
Update a page's title/description and/or rewrite its layout_html. Embedded form/booking/product references are re-validated against this space. Storefront containers (data-wakato-products / data-wakato-product="<id>") and the blog index (data-wakato-blog-index) are supported the same as create_page. If the page is already published the change goes LIVE immediately — run preview_page afterwards.\n\nPAGE_DESIGN_BRIEF
| Parameter | Type | Required | Description |
|---|---|---|---|
page_id | string | yes | |
title | string | ||
description | string | ||
layout_html | string | Replacement HTML document. |
update_site
Scope: pages:write
Update a web artifact after creation: title, description, nav_layout (top/sidebar/none), logo_url, root_page_id (the home page / step 1), and the managed nav_config. nav_config replaces the whole nav when provided: { enabled, items: [{label?, page_id? | url?}], cta: {label, page_id? | url?}, style: {sticky?, theme? (auto/light/dark), transparent_on_hero?, logo_position? (left/center), accent_color?} }. Page items must be pages of THIS site; item labels default to the live page title. WEBSITES ONLY for nav: landing pages are forward-only and any attempt to enable a nav on kind:landing is rejected — if visitors should browse freely, build a website instead.
| Parameter | Type | Required | Description |
|---|---|---|---|
site_id | string | yes | |
title | string | ||
description | string | ||
nav_layout | top | sidebar | none | ||
logo_url | string | Brand logo URL. Empty string removes the logo. | |
root_page_id | string | Page id to use as the site's home page. | |
nav_config | object | Managed navigation. items = ordered nav entries ({page_id} for site pages, {url} for external/public links like /f/<slug>); cta = optional highlighted button; style = bar appearance. |
validate_site
Scope: pages:read
Readiness lint for a site BEFORE (or after) publishing: reports dead links (/pg/, /f/, /b/, /pay/, /post/ that resolve to nothing), nav items pointing at deleted or draft pages, form/booking/product embeds that don't exist in this space, and unpublished pages. Run this after building a multi-page site and FIX every error it reports — a site with dead links is not done. Returns { ok, pages_total, pages_published, issues: [{severity, code, message, page_id?, detail?}] }.
| Parameter | Type | Required | Description |
|---|---|---|---|
site_id | string | yes |