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

# Send Message

> Sends one or more text messages in a consultation, written in the first
person as the patient speaking.

A send must be made with the newest message in hand: pass
lastSeenMessageId, or read GET /api/consultations/{id} first. A stale
send is refused with status READ_REQUIRED and the latest conversation
state inline.

With waitForReply (the default) the response also carries whatever
happens next: the reply, a provider connecting, or the payment gate
when the send completed triage.




## OpenAPI

````yaml api-reference/openapi.yaml POST /api/consultations/{id}/messages
openapi: 3.1.0
info:
  title: Arlo Health MCP Server
  version: 1.0.0
  description: |
    Healthcare infrastructure for AI agents. Everything an agent needs
    to act in healthcare for its user.

    ## Overview

    This server exposes two interfaces:
    - **MCP** (Model Context Protocol) over streamable HTTP at `/` for AI agents
    - **REST API** at `/api/*` for bots, skills, and direct HTTP clients

    Both interfaces use the same tool handlers and authentication.

    ## Authentication

    OAuth 2.1 with PKCE. All `/api/*` endpoints require a Bearer token.

    Discovery endpoints (no auth required):
    - `/.well-known/oauth-protected-resource`
    - `/.well-known/oauth-authorization-server`
    - `/.well-known/mcp.json` (MCP Server Card)

    ## Service Regions

    Care is licensed by where the patient is physically located when they
    request it, so every conversation carries an ISO 3166-2 `region` code.
    Arlo currently serves California, United States (`US-CA`); an unsupported
    region is refused with `REGION_NOT_SUPPORTED`, whose payload names the
    regions Arlo serves at that moment.
  contact:
    name: Arlo Health
    url: https://arlohealth.ai
  license:
    name: Proprietary
    url: https://arlohealth.ai/tos
servers:
  - url: https://mcp.arlohealth.ai
    description: Production MCP Server
security:
  - oauth2:
      - openid
      - profile
      - email
      - offline_access
tags:
  - name: Discovery
    description: MCP and OAuth discovery endpoints (no auth required)
  - name: Profile
    description: User profile and patient information
  - name: Consultations
    description: Healthcare consultation management
  - name: Messaging
    description: Conversation messaging and media
  - name: Prescriptions
    description: Prescription and pharmacy management
  - name: Payment
    description: Billing and pay-per-use payment management
  - name: Webhooks
    description: Webhook registration and status
paths:
  /api/consultations/{id}/messages:
    post:
      tags:
        - Messaging
      summary: Send message in a consultation
      description: |
        Sends one or more text messages in a consultation, written in the first
        person as the patient speaking.

        A send must be made with the newest message in hand: pass
        lastSeenMessageId, or read GET /api/consultations/{id} first. A stale
        send is refused with status READ_REQUIRED and the latest conversation
        state inline.

        With waitForReply (the default) the response also carries whatever
        happens next: the reply, a provider connecting, or the payment gate
        when the send completed triage.
      operationId: sendMessage
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
          description: Consultation/conversation ID
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                messages:
                  type: array
                  items:
                    type: string
                  description: Array of message texts to send
                text:
                  type: string
                  description: Single message text (alternative to messages array)
                lastSeenMessageId:
                  type: string
                  description: |
                    Newest message id you have seen. Satisfies the read-first
                    gate without a separate read; a stale value is refused.
                waitForReply:
                  type: boolean
                  default: true
                  description: |
                    Wait up to ~55s for the next reply and return it inline.
                    On timeout the response carries stillWaiting - the message
                    is already sent, so never re-send.
      responses:
        '200':
          description: Message sent
          content:
            application/json:
              schema:
                type: object
                properties:
                  sent:
                    type: boolean
                    description: False on a READ_REQUIRED or PAYMENT_REQUIRED refusal
                  messagesSent:
                    type: integer
                  status:
                    type: string
                    description: >-
                      Conversation status, or READ_REQUIRED / PAYMENT_REQUIRED
                      on a refusal
                  reply:
                    $ref: '#/components/schemas/Message'
                  replies:
                    type: array
                    items:
                      $ref: '#/components/schemas/Message'
                  stillWaiting:
                    type: boolean
                    description: The wait timed out; the message is sent, keep waiting
                  connected:
                    type: boolean
                    description: A provider joined while waiting (status WITH_PROVIDER)
                  statusChanged:
                    type: string
                    description: The status the conversation moved to during the wait
                  paymentRequired:
                    type: boolean
                    description: >-
                      The send completed triage, so the patient must confirm
                      payment
                  paymentGate:
                    $ref: '#/components/schemas/PaymentGate'
                  latestMessageId:
                    type: string
                    description: On READ_REQUIRED, retry with this as lastSeenMessageId
                  conversation:
                    $ref: '#/components/schemas/ConsultationDetail'
                  userMessage:
                    type: string
                    description: Patient-facing wording to relay
                  agentInstructions:
                    type: array
                    items:
                      type: string
                  note:
                    type: string
                  nextStep:
                    type: string
                    description: Suggested follow-up call
                  nextStepArgs:
                    type: object
                    description: Arguments to pass to nextStep
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
components:
  schemas:
    Message:
      type: object
      description: A message in a consultation
      properties:
        id:
          type: string
        type:
          type: string
          enum:
            - text
            - triage
            - photo
            - video
            - file
            - join
            - prescription
            - lab_request
            - unknown
        content:
          type: string
        sender:
          type: string
          enum:
            - user
            - provider
            - ai
            - system
        timestamp:
          type: string
          format: date-time
        senderId:
          type: string
    PaymentGate:
      type: object
      description: Payment gate information when triage is complete
      properties:
        consultationSummary:
          type: string
          description: Markdown summary of what Arlo can help with
        ctaText:
          type: string
          description: Call-to-action button text
        gateType:
          type: string
          description: >-
            PAY_PER_USE = card on file, confirm to place the hold;
            PAYMENT_SETUP_REQUIRED = no card yet, run create_payment_setup first
          enum:
            - NONE
            - PAYMENT_SETUP_REQUIRED
            - PAY_PER_USE
        isLoading:
          type: boolean
          description: Whether summary is still being generated
        paymentType:
          type: string
          enum:
            - pay_per_use
            - payment_setup_required
    ConsultationDetail:
      type: object
      description: Full conversation details with messages
      properties:
        conversationId:
          type: string
        status:
          $ref: '#/components/schemas/ConsultationStatus'
        statusDescription:
          type: string
        region:
          type: string
          nullable: true
          description: ISO 3166-2 region this conversation is licensed for
        providerVisit:
          type: object
          nullable: true
          description: Present when a provider is in seat
          properties:
            active:
              type: boolean
            providerName:
              type: string
            consultId:
              type: string
        pastVisits:
          type: array
          description: Prior provider visits on this conversation
          items:
            type: object
            properties:
              consultId:
                type: string
              closedAt:
                type: string
              hasNotes:
                type: boolean
        messages:
          type: array
          description: |
            Windowed to the newest messages by default to keep long threads
            manageable; omittedOlderMessages reports how many older messages
            exist beyond the window.
          items:
            $ref: '#/components/schemas/Message'
        omittedOlderMessages:
          type: integer
          description: Present when the message window truncated older messages
        lastActivityAt:
          type: string
          format: date-time
          nullable: true
          description: Timestamp of the newest message
        updatedAt:
          type: string
          format: date-time
          nullable: true
          description: >-
            Timestamp of the last status or lifecycle change; messages do not
            move it
        informationNeed:
          type: array
          description: |
            While TRIAGING, the shortlist of what triage would most like to
            learn next. Gather the answers and send them in one message.
            Withheld when the patient's own message is newest on the thread.
          items:
            type: object
            properties:
              prompt:
                type: string
                description: The question to ask the patient
              why:
                type: string
                description: Why it helps triage
              priority:
                type: string
                enum:
                  - required
                  - helpful
              redFlagGate:
                type: boolean
                description: Safety-critical — answer these first
        informationNeedAsOfMessageId:
          type: string
          description: The AI message informationNeed was computed on
        paymentGate:
          $ref: '#/components/schemas/PaymentGate'
        nextSteps:
          type: array
          items:
            type: string
          description: Suggested actions based on current status
    ConsultationStatus:
      type: string
      enum:
        - IDLE
        - TRIAGING
        - PAYMENT_REQUIRED
        - MATCHING
        - WITH_PROVIDER
        - EMERGENCY
      description: >
        A conversation is a continuous thread — it never "closes." There is no

        terminal CLOSED/CANCELED status: a finished or canceled request simply

        leaves the conversation IDLE with its visit history intact.


        - IDLE: AI-only, nothing in progress. Re-engageable — sending a message
        re-runs triage

        - TRIAGING: AI is gathering symptom information on a live request

        - PAYMENT_REQUIRED: Triage complete, awaiting payment confirmation (or
        dismissal)

        - MATCHING: Being matched with a healthcare provider

        - WITH_PROVIDER: A provider is connected (messaging is asynchronous)

        - EMERGENCY: Urgent care advised — user should call 911 (not
        re-engageable)
    Error:
      type: object
      description: Error response
      properties:
        error:
          type: string
          description: Error code
        reason:
          type: string
          description: Human-readable explanation
        code:
          type: string
          description: Detailed error code
  responses:
    BadRequest:
      description: Invalid request
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Unauthorized:
      description: Missing or invalid authentication
      content:
        application/json:
          schema:
            type: object
            properties:
              error:
                type: string
              needsAuth:
                type: boolean
  securitySchemes:
    oauth2:
      type: oauth2
      description: OAuth 2.1 with PKCE
      flows:
        authorizationCode:
          authorizationUrl: /oauth/authorize
          tokenUrl: /oauth/token
          scopes:
            openid: OpenID Connect
            profile: User profile
            email: Email address
            offline_access: Refresh tokens

````