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

# Enviar un mensaje del visitante

> Registra un mensaje **entrante** — lo que escribió el visitante en tu sitio — y dispara la atención del equipo o del agente de IA según la configuración del canal.

**Primer mensaje:** omite `conversationId`, indica en `contact` quién escribe (al menos `id`, `email` o `phone`) y opcionalmente `channelId`. La respuesta trae el `conversationId` nuevo.

**Mensajes siguientes:** envía ese `conversationId`; `channelId` y `contact` se ignoran.

La identidad del visitante la afirma tu backend y Revem le cree: el contacto resuelto recibe el historial, los tickets y el contexto del agente. Autentica a tu usuario antes de llamar a esta ruta y nunca la expongas directamente desde el navegador.

Las respuestas del equipo o del agente llegan de forma asíncrona: léelas con `GET /webchat/conversations/{id}/messages`.



## OpenAPI

````yaml /openapi.json post /webchat/messages
openapi: 3.1.0
info:
  title: Revem API
  version: 1.0.0
  description: >-
    La API pública de Revem para integraciones de servidor a servidor:
    contactos, tickets y el canal de webchat. Se autentica con la API key de tu
    organización.
  contact:
    name: Soporte Revem
    email: soporte@revem.ai
    url: https://revem.ai
servers:
  - url: https://api.revem.ai
    description: Producción
security:
  - apiKey: []
tags:
  - name: Contactos
    description: >-
      Sincroniza tu base de clientes con Revem. Los contactos se identifican por
      teléfono al crearlos y por id después.
  - name: Tickets
    description: Lee y actualiza los tickets de tu embudo desde tu sistema de gestión.
  - name: Webchat
    description: >-
      Conecta el chat de tu sitio con Revem: registra lo que escribe el
      visitante y lee las respuestas del equipo o del agente.
paths:
  /webchat/messages:
    post:
      tags:
        - Webchat
      summary: Enviar un mensaje del visitante
      description: >-
        Registra un mensaje **entrante** — lo que escribió el visitante en tu
        sitio — y dispara la atención del equipo o del agente de IA según la
        configuración del canal.


        **Primer mensaje:** omite `conversationId`, indica en `contact` quién
        escribe (al menos `id`, `email` o `phone`) y opcionalmente `channelId`.
        La respuesta trae el `conversationId` nuevo.


        **Mensajes siguientes:** envía ese `conversationId`; `channelId` y
        `contact` se ignoran.


        La identidad del visitante la afirma tu backend y Revem le cree: el
        contacto resuelto recibe el historial, los tickets y el contexto del
        agente. Autentica a tu usuario antes de llamar a esta ruta y nunca la
        expongas directamente desde el navegador.


        Las respuestas del equipo o del agente llegan de forma asíncrona: léelas
        con `GET /webchat/conversations/{id}/messages`.
      operationId: sendWebchatMessage
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WebchatMessageBody'
            example:
              channelId: b7e3d2a1-4c5f-4e6d-9a8b-7c6d5e4f3a2b
              contact:
                email: camila@ejemplo.cl
                name: Camila Rojas
              body: Hola, ¿tienen horas disponibles esta semana?
      responses:
        '201':
          description: Mensaje guardado.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WebchatSent'
              example:
                conversationId: a1d2c3b4-e5f6-4a7b-8c9d-0e1f2a3b4c5d
                messageId: 482
        '400':
          description: >-
            El cuerpo no cumple el esquema, falta la identidad del contacto
            (`contact_identity_required`) o un adjunto no existe
            (`attachment_not_found`).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WebchatError'
              example:
                ok: false
                error: contact_identity_required
                message: >-
                  Para abrir una conversación hace falta un id de contacto, un
                  email o un teléfono.
        '401':
          description: Sin credencial, o la API key no existe o fue revocada.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AuthError'
              example:
                error: Unauthorized
                message: Invalid API key
        '403':
          description: >-
            La ruta es sólo para sistemas externos autenticados con API key
            (`inbound_requires_service_identity`).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WebchatError'
        '404':
          description: >-
            La conversación no existe (`conversation_not_found`), el canal no
            existe o el tenant no tiene webchat (`channel_not_found`), o
            `contact.id` no resuelve (`contact_not_found`).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WebchatError'
              example:
                ok: false
                error: channel_not_found
                message: El canal de webchat no existe.
        '409':
          description: >-
            El email o el teléfono ya pertenecen a otro contacto, posiblemente
            en la papelera (`contact_identity_conflict`).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WebchatError'
        '429':
          description: >-
            La key superó su límite de solicitudes por minuto. El header
            `retry-after` indica cuánto esperar.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RateLimitError'
              example:
                ok: false
                error: Too many requests. Retry in 1 minute.
          headers:
            retry-after:
              description: Segundos que esperar antes de reintentar.
              schema:
                type: integer
            x-ratelimit-limit:
              description: Solicitudes permitidas por minuto.
              schema:
                type: integer
            x-ratelimit-remaining:
              description: Solicitudes que quedan en la ventana actual.
              schema:
                type: integer
            x-ratelimit-reset:
              description: Segundos hasta que la ventana se reinicia.
              schema:
                type: integer
components:
  schemas:
    WebchatMessageBody:
      type: object
      properties:
        conversationId:
          type: string
          format: uuid
          description: >-
            Conversación existente en la que escribe el visitante. Es el valor
            que devolvió el primer mensaje. Cuando viene, `channelId` y
            `contact` se ignoran.
        channelId:
          type: string
          format: uuid
          description: >-
            Canal de webchat en el que abrir la conversación. Si se omite se usa
            el webchat más antiguo del tenant. Sólo se lee cuando no hay
            `conversationId`.
        contact:
          type: object
          properties:
            id:
              type: string
              format: uuid
            email:
              type: string
              maxLength: 255
              format: email
            phone:
              type: string
              minLength: 1
              maxLength: 50
            name:
              type: string
              minLength: 1
              maxLength: 255
          description: >-
            Quién escribe, para una conversación nueva. Hace falta al menos
            `id`, `email` o `phone`. Se prueban en ese orden: `id` manda y no
            crea contactos; `email` y `phone` buscan un contacto existente o lo
            crean.
        body:
          type: string
          minLength: 1
          maxLength: 4000
          description: >-
            Texto del mensaje, hasta 4000 caracteres. Obligatorio si no hay
            adjuntos.
        attachments:
          maxItems: 20
          type: array
          items:
            type: object
            properties:
              mediaId:
                type: string
                format: uuid
            required:
              - mediaId
          description: >-
            Adjuntos subidos previamente con `POST /webchat/media`, hasta 20 por
            mensaje. Obligatorio si no hay `body`.
      description: >-
        Un mensaje necesita `body`, `attachments` o ambos. Para abrir una
        conversación nueva se omite `conversationId` y se indica quién escribe
        en `contact`.
    WebchatSent:
      type: object
      properties:
        conversationId:
          type: string
          format: uuid
          description: >-
            La conversación del mensaje. En un primer mensaje es nueva; envíala
            en los siguientes y úsala para leer las respuestas.
        messageId:
          type: integer
          description: Identificador del mensaje guardado.
      required:
        - conversationId
        - messageId
      additionalProperties: false
    WebchatError:
      type: object
      properties:
        ok:
          type: boolean
          const: false
        error:
          type: string
          description: >-
            Código estable del error, por ejemplo `channel_not_found`,
            `contact_identity_required` o `unsupported_media_type`.
        message:
          type: string
          description: Explicación legible del problema.
      required:
        - ok
        - error
      additionalProperties: false
    AuthError:
      type: object
      properties:
        ok:
          type: boolean
          const: false
          description: Presente sólo en el `403`.
        error:
          type: string
        message:
          type: string
      required:
        - error
        - message
    RateLimitError:
      type: object
      properties:
        ok:
          type: boolean
          const: false
        error:
          type: string
          description: Incluye cuánto esperar antes de reintentar.
      required:
        - ok
        - error
  securitySchemes:
    apiKey:
      type: http
      scheme: bearer
      description: >-
        La API key de tu organización, con la forma `rvm_<prefijo>.<secreto>`,
        enviada como `Authorization: Bearer rvm_…`. Revem la emite y sólo se
        muestra una vez; si la pierdes se reemplaza, no se recupera.

````