> ## 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.

# Conversation control and delivery

> Conversation control and delivery — Visito M2M API

All paths below are relative to `/m2m/v1`. Send `Authorization: Bearer <key>`. Tenant identity comes from the key.

## Receive, read, reply, track

If your integration owns replies, enable manual mode before processing callbacks. Receiving a webhook does not pause Visito AI; otherwise both systems may reply.

1. Subscribe to `message.created` with `webhooks:write` and `conversations:read`.
2. Process only `data.direction=inbound` when automatically replying. Outbound replies also generate events.
3. Read `GET /conversations/{conversationId}/messages` with `conversations:read`; paginate to the supplied `messageId` if necessary. Webhooks do not carry message text.
4. Reply through existing `POST /conversations/{conversationId}/reply`, with `conversations:write` and a stable `Idempotency-Key` derived from the inbound event.
5. Use the returned `requestEventId` at `GET /message-requests/{requestEventId}/status` with `messages:read`. Subscribe to `message.delivery.updated` for subsequent changes.

A queued acknowledgement is not proof of delivery. Status values include `queued`, `sent`, `delivered`, `read`, `failed`, `blocked`, `partial_sent`, and `unknown`. Individual message lookup uses `GET /messages/{messageId}/status`. Multi-message requests return individual `messages`; inspect these if the aggregate is `unknown`.

## AI and human ownership

| Method | Route                                 | Scope                            |
| ------ | ------------------------------------- | -------------------------------- |
| GET    | `/conversations/{id}/policy`          | `conversations:read`             |
| PATCH  | `/conversations/{id}/policy`          | `conversations:policy:write`     |
| GET    | `/conversations/assignable-operators` | `conversations:assignment:read`  |
| PUT    | `/conversations/{id}/assignment`      | `conversations:assignment:write` |
| GET    | `/conversations/{id}/handoffs`        | `conversations:read`             |
| POST   | `/conversations/{id}/handoff/resolve` | `conversations:handoffs:write`   |

Pause AI with `{"manualEnabled":true}`; resume with `{"manualEnabled":false}`. Policy also accepts `statusAction` (`archive`, `unarchive`, `block`, `unblock`), `freezeForMinutes`, and `unfreeze`. A freeze and `unfreeze:true` cannot be combined. Unresolved handoffs lock policy changes. Other channel and conversation gates still apply after resuming.

Assignment accepts `{"operatorId":"operator_id"}` or `{"operatorId":null}` to clear. The operator must belong to the same tenant. Resolving a handoff accepts optional `resolutionNote` and returns the conversation to AI mode; it does not resolve a separate pending reply obligation.

Normal replies target an existing conversation. To initiate WhatsApp outreach, use the existing approved-template send endpoint.
