Cobre: calendarios, event types, reservas (listar/detalhe/mudar estado/reenviar confirmacao), actividade, disponibilidade, reports, definicoes gerais, anfitrioes, estado do plugin/licenca Pro. 15 tools via REST API real com Application Password (nao SSH/SQL como mcp-bit-social - o FluentBooking regista register_rest_route com permission_callback por capability). Testado ponta-a-ponta em producao 19-08-2026, incluindo escrita sem mutar dados reais (422 'No changes found' do proprio plugin). references/api-reference.md com os endpoints/filtros/enums confirmados e references/diagnostics.md com o playbook de uso (agenda, cancelamento, health check).
5.7 KiB
FluentBooking — referência da REST API (confirmado em produção, 2026-08-19)
Namespace: fluent-booking/v2 (WP REST API real, wp-json/fluent-booking/v2/...). Auth: Basic
Auth com Application Password — o permission_callback de cada rota é uma Policy que verifica
current_user_can()/PermissionManager, não nonce de sessão. 100 rotas registadas entre free e
Pro; este ficheiro documenta só as usadas pelo MCP.
Calendários (/calendars)
GET /calendars — lista todos, cada um com slots[] (event types) aninhados, incluindo
settings.weekly_schedules completo por dia. GET /calendars/{id} — um só, mesma forma.
Campos relevantes de um calendar: id, title, slug, status (active/…), type
(simple/…), visibility (public/…), author_timezone, public_url
(https://descomplicar.pt/?fluent-booking=calendar&host=<slug>), author_profile (nome, avatar,
telefone).
Event types (/events/{event_id}, aninhado em calendars[].slots[])
GET /events/{event_id} → {calendar_event: {...}}. Campos: id, calendar_id, duration
(minutos), title, slug, description (HTML), settings.schedule_type
(weekly_schedules/…), settings.weekly_schedules.<dia>.{enabled, slots:[{start,end}]}.
Gotcha de nomes: GET /calendars/event-lists (sem id) devolve sempre
{"code":"plugin_exception", ...} em produção — não é um bug do MCP, o controller
CalendarController@getCalendarEventLists está partido standalone nesta instalação. Não usar
este endpoint; listar event types via fb_list_calendars/fb_get_calendar (já vêm aninhados).
Reservas (/schedules)
GET /schedules — parâmetros via filters[...] (bracket notation, o MCP trata isto
automaticamente a partir de campos planos no input schema):
| Filtro | Valores | Nota |
|---|---|---|
filters[period] |
upcoming (omissão), completed, cancelled, pending, no_show, latest_bookings, all |
Valor fora da lista cai silenciosamente para upcoming |
filters[author] |
id numérico do calendário, me, all |
Sem permissão "ver todas as reservas", o utilizador só vê as suas mesmo que peça all |
filters[event] |
id numérico do event type | |
filters[event_type] |
single/group/… |
|
filters[email] |
email do convidado | |
filters[range] |
[date_from, date_to] |
Filtra por created_at, não pela hora da reunião |
search |
texto livre | nome/email do convidado |
page |
inteiro | paginação Laravel-style |
Forma de uma reserva (schedules.data[]): id, hash, calendar_id, event_id, group_id
(agrupa reservas de grupo), host_user_id, start_time/end_time (timezone do site),
first_name/last_name/email/phone/message, location_details
({type, online_meeting_link} ou presencial), status
(scheduled/completed/cancelled/rejected/no_show), payment_status, source_url
(página onde o convidado marcou), custom_form_data (campos custom do formulário de marcação,
por chave), calendar_event (event type completo aninhado, redundante mas presente sempre),
happening_status, booking_status_text, reschedule_url.
GET /schedules/{id} — mesma forma para uma reserva.
PUT /schedules/{id} (fb_update_booking_status) — body {column:"status", value:<estado>, cancel_reason?, reject_reason?, refund_payment?}. Colunas válidas no controller real:
internal_note, email, phone, first_name, last_name, status, payment_status — o MCP
só expõe status deliberadamente (as outras deixam editar dados do convidado sem justificação de
negócio clara; ver SKILL.md "Fora do âmbito"). Side-effects reais confirmados no código
(SchedulesController::patchBooking):
status=cancelled→Booking::cancelMeeting($reason, 'host', $userId)+ email de cancelamento.status=rejected→Booking::rejectMeeting($reason, $userId).status=scheduledcompayment_method+payment_orderassociados → marca a order comopaid.- Valor igual ao actual →
422 {"message":"No changes found"}(não é um bug, é a validação do próprio plugin — útil para testar o caminho de escrita sem mutar nada).
POST /schedules/{id}/send-confirmation-email (fb_send_confirmation_email) — sem body, envia
email real.
Actividade (/schedules/{id}/activities, /reports/activities)
Mesma forma nos dois: {id, booking_id, parent_id, created_by, status, type, title, description, created_at, updated_at}. /reports/activities é o log do site inteiro (todas as reservas);
/schedules/{id}/activities filtra a uma só.
Disponibilidade (/availability)
GET /availability — lista templates reutilizáveis ({id, host_name, title, usage_count, settings:{timezone, date_overrides[], weekly_schedules}}). GET /availability/{id} — um só,
envelope {schedule: {...}} em vez de {availabilities: {data:[...]}}.
Reports (/reports, /reports/graph-reports)
GET /reports → {overview: [{title, period?, number, content, stat}], latest_books: [...]}.
Métricas confirmadas: Total Bookings, Completed Bookings, Cancelled Bookings, Total Guests.
GET /reports/graph-reports?date_range[0]=YYYY-MM-DD&date_range[1]=YYYY-MM-DD →
{booked_stats, completed_stats, cancelled_stats}, cada um {"YYYY-MM-DD": count}. Sem
date_range, o controller usa uma janela por omissão (~7 dias, granularidade adaptada ao
intervalo — dia/semana/mês).
Definições e equipa
GET /settings/general → {payments, emailing, administration} (moeda, remetente/rodapé de
email, auto_cancel_timing, dia de início da semana). GET /admin/all-hosts →
{hosts: [{id, name, label, avatar, calendar_id, deleted_user}]}. GET /settings/license (Pro)
→ {status, variation_title, expires, is_expired, activation_hash, renew_url, purchase_url}.