> ## Documentation Index
> Fetch the complete documentation index at: https://docs.visitoai.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Daily operations API

> Find conversations, manage follow-ups and reviews, start WhatsApp conversations, and inspect reservations and guest messaging.

All paths below are relative to `/m2m/v1`. Use `Authorization: Bearer <API_KEY>`; the credential fixes the business. No tenant override is supported. Existing keys and OAuth grants do not automatically gain these new permissions. An administrator must explicitly grant the required scopes. The same operations are exposed as MCP tools when the MCP service is enabled.

## Endpoints and MCP tools

| Endpoint | Required scope | MCP tool |
| - | - | - |
| `GET /conversations/start/whatsapp-template-status` | `conversations:read` | `get_conversation_start_status` |
| `POST /conversations/start` | `conversations:start` | `start_conversation` |
| `POST /conversations/{conversationId}/read` | `conversations:triage:write` | `mark_conversation_read` |
| `POST /conversations/{conversationId}/needs-reply/resolve` | `conversations:triage:write` | `resolve_conversation_needs_reply` |
| `POST /conversations/{conversationId}/review` | `conversations:reviews:write` | `create_conversation_review` |
| `PUT /conversations/{conversationId}/review/assignment` | `conversations:reviews:write` | `assign_conversation_review` |
| `POST /conversations/{conversationId}/review/resolve` | `conversations:reviews:write` | `resolve_conversation_review` |
| `GET /crm/follow-ups` | `crm:followups:read` | `list_follow_ups` |
| `POST /crm/follow-ups` | `crm:followups:write` | `create_follow_up` |
| `PATCH /crm/follow-ups/{followUpId}` | `crm:followups:write` | `update_follow_up` |
| `POST /crm/follow-ups/{followUpId}/dismiss` | `crm:followups:write` | `dismiss_follow_up` |
| `POST /crm/follow-ups/{followUpId}/cancel` | `crm:followups:write` | `cancel_follow_up` |
| `POST /crm/follow-ups/{followUpId}/send` | `crm:followups:send` | `send_follow_up` |
| `GET /crm/follow-up-settings` | `crm:automation:read` | `get_follow_up_settings` |
| `PATCH /crm/follow-up-settings` | `crm:automation:write` | `update_follow_up_settings` |
| `GET /reservations` | `reservations:read` | `list_reservations` |
| `GET /conversations/{conversationId}/reservations` | `reservations:read` | `list_conversation_reservations` |
| `GET /reservations/readiness` | `reservations:read` | `get_reservation_readiness` |
| `GET /reservations/sync/receipts` | `reservations:read` | `list_reservation_sync_receipts` |
| `GET /reservations/lifecycle/attempts` | `reservations:read` | `list_reservation_message_attempts` |
| `GET /reservations/lifecycle/events` | `reservations:read` | `get_reservation_message_settings` |
| `PUT /reservations/lifecycle/integrations/{integrationId}/events/{eventType}` | `reservations:messaging:write` | `set_reservation_message_event` |
| `PUT /reservations/lifecycle/integrations/{integrationId}/sender` | `reservations:messaging:write` | `set_reservation_message_sender` |

## Find a conversation

`GET /conversations?contactQuery=Maria&channel=whatsapp&owner=OPERATOR_ID&limit=50`

`contactQuery` uses the dashboard's contact search, with 2–200 characters. `channel` accepts `all`, `whatsapp`, `instagram`, `messenger`, or `webchat`. `owner` is `all` or an active operator's 24-character ID in this business; `mine` is not supported for machine credentials. Discover operator IDs through `/conversations/assignable-operators` with `conversations:assignment:read`.

Pass `nextCursor` as `cursor` while `hasMore` is true, preserving every filter. Conversations remain a live list: new activity can move records between pages. Deduplicate by `conversationId` when combining pages. Filters also apply to returned inbox counts. Invalid cursors and unsupported filter values return 400; a foreign/inactive owner returns 404.

## Manage follow-ups

Find leads through existing sales opportunities; use their `leadId` and `conversationId` when creating a follow-up. List by status, mode, lead, conversation, or `dueAfter`. List pages default to 50, maximum 200; continue `nextCursor` while `hasMore` is true.

```json theme={null}
{"leadId":"LEAD_ID","conversationId":"CONVERSATION_ID","reason":"Guest requested a callback","messageDraft":"Hello, would you like to continue?","dueAt":"2026-10-01T15:00:00Z"}
```

Create returns 201. Creation is not idempotent: after an uncertain response, inspect the list before creating again. PATCH changes `messageDraft` or `dueAt`; `dueAt:null` clears the date. Dismiss/cancel accept an optional `feedbackReason`. A send accepts optional `messageText` and uses the follow-up's durable claim/send identity. An active or completed claim may return 409. Do not create another follow-up to retry a send.

Sending returns 202 with `followUp` and `reply`. Check `reply.requestEventId` using `/message-requests/{requestEventId}/status` with `messages:read`. If `crmStatusUpdateFailed:true`, the send was accepted but CRM completion failed: reconcile the receipt instead of sending again. Accepted is not delivered. Manual sends inherit the current business reply-pause setting.

## Configure automation

Read `/crm/follow-up-settings` before changing it. PATCH supports `followUpMode` (`off`, `draft`, `auto`), `followUpLevel` (`light`, `balanced`, `proactive`), `followUpInstructions` (at most 2,000 characters), and `quietHours` (`start`/`end`, distinct `HH:mm` values in the business timezone). Only supplied fields change; at least one field is required.

```json theme={null}
{"followUpMode":"draft","quietHours":{"start":"21:00","end":"09:00"}}
```

Changing to `auto` can trigger future eligible sends, including existing eligible follow-ups. Only change automation on explicit instruction. Creating or editing an individual follow-up never changes automation settings. Existing CRM eligibility and timing checks still apply.

## Complete inbox work

Mark read, resolve needs reply, review, and handoff resolution are separate operations. Review creation accepts `reasonCode` (defaults to `other`), optional `note` and `assignedOperatorId`. Reasons: `ai_response_issue`, `knowledge_gap`, `policy_compliance`, `guest_experience`, `booking_payment`, `other`. Notes are at most 2,000 characters. Creating a review returns 409 if a handoff or review is already open. Review assignment requires `operatorId`; use `null` to unassign. Resolution accepts optional `resolutionNote`.

These actions retain dashboard realtime updates and record the integration credential as the actor. Resolving needs reply does not close a handoff or resolve a review.

## Start a WhatsApp conversation

Read `/conversations/start/whatsapp-template-status?channelId=CHANNEL_ID`. This checks persisted readiness without provisioning or refreshing provider templates. `not_prepared` means template setup is still needed through the dashboard. Start requires an approved prepared locale, an available WhatsApp channel, recipient consent and no opt-out.

Send `POST /conversations/start` with a stable `Idempotency-Key` header:

```json theme={null}
{"channel":"whatsapp","targetChannelId":"CHANNEL_ID","phoneNumber":"+15551234567","locale":"en_US","messageText":"Following up on your request.","consentConfirmed":true}
```

Only `en_US` and `es_MX` are supported. `contactName` is optional; `messageText` is limited to 1,024 characters. Repeat a key only with identical input. Keys are scoped to business and target conversation; conflicting reuse returns 409. Legacy dashboard attempts without a request fingerprint preserve their previous replay behavior. The response includes `conversationId`, `replyId` and `requestEventId`; 202 means queued, not delivered. A previous failed attempt requires reconciliation before a new send.

## Reservations and guest messaging

`GET /reservations` reads mirrored provider records, not live availability. Filter by `integrationId`, `reservationId`, or status; sort by `booked_at` or `check_in_date`, ascending or descending. Pages contain at most 20 records. Continue `nextCursor` while `hasNext` is true, retaining filters and sorting. Receipt and attempt lists use the same 20-record pagination convention. Conversation-linked lookup returns at most five reservations using existing guest-phone matching.

Readiness and lifecycle settings identify available integrations, senders and event configuration. Writes currently support one Cloudbeds integration per request. Set an event with `{"enabled":false}` or select its sender with `{"channelId":"CHANNEL_ID"}`. Supported events: `booking_confirmed`, `pre_checkin`, `post_checkout_review`. The sender must be an available WhatsApp channel in the same business. Foreign or unsupported integrations return 404; invalid or unavailable senders return 400/404. Existing global feature gates remain enforced.

Enabling an event changes future guest messaging; it does not send immediately or guarantee delivery. Attempt results such as `would_send`, `deferred`, `skipped`, `invalid`, `duplicate` and `error` are diagnostics, not delivery receipts. Counts labelled sent in existing lifecycle summaries are not proof of provider delivery. No booking creation, cancellation, live availability, bulk campaign execution or business-wide event switch is exposed here.

## Errors and safe retries

Missing/invalid credentials return 401; missing scope returns 403; invalid input returns 400; missing or foreign resources return 404; state/idempotency conflicts return 409. Downstream failures can return 5xx. Read operations are safe to retry. For outbound operations, reconcile accepted receipts before retrying. Configuration PUTs set explicit values, so identical repeats do not toggle state.
