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

# Send a message

> Sends on the channel the customer last used (or the identity or channel uuid in `channel`), records it in the thread and fires the same message.* webhooks a dashboard reply does. Counted as a BOT send: it needs the workspace in good standing, never takes the conversation over, and gets the bot's messaging window. Refused with 422 (with a `reason`) when the contact is blocked or opted out, or the window is closed — send an approved template (`type: template`, `template_id`, `parameters`) to re-engage. Media (while inbox media is on) is sent by reference: `media.library` (an id from POST /media) or `media.source_message_id`; a URL is refused. Send an `Idempotency-Key` header to make a retried request one send.

**Required permission:** `salesbot:messages:send`



## OpenAPI

````yaml /api-reference/messaging.openapi.json post /messages
openapi: 3.1.0
info:
  title: Messaging API
  version: 1.0.0
  description: >-
    Contacts, conversations, messages, broadcasts, automations and media for one
    workspace. The workspace is selected by the API key, so no workspace ID
    appears in any URL.
servers:
  - url: https://{domain}/api/v1
    description: Your platform domain
    variables:
      domain:
        default: app.example.com
        description: The domain you sign in to, without https://
security:
  - bearerAuth: []
  - apiKeyHeader: []
tags:
  - name: Account
    description: >-
      The workspace is selected by the API key, so no workspace id appears in
      any /api/v1 URL.
  - name: Automations
    description: >-
      Read + activate/pause only. Authoring a node graph stays in the builder,
      which owns its own validation.
  - name: Broadcasts
    description: >-
      The send pipeline is never invoked directly: marking a broadcast scheduled
      is what lets the sweep's single Scheduled→Sending claim keep it
      un-double-sendable.
  - name: Channels
    description: >-
      Read-only: connecting a channel is an OAuth flow that must happen in the
      dashboard.
  - name: Contacts
    description: >-
      custom_fields is a flat {key: value} map. An empty map is returned as {}
      so client-side property access is always safe.
  - name: Conversations & Messages
    description: >-
      There is no Conversation model: a conversation is a Contact with messages,
      and the rollup fields are denormalised columns on it.
  - name: Media
    description: >-
      Upload requests are multipart, not JSON — do not set Content-Type:
      application/json on media.store.
  - name: Segments
    description: Segments are the audience type broadcasts target.
  - name: Tags
    description: >-
      Contacts are tagged by NAME (see contacts.tags.add), so tag names stay
      unique.
paths:
  /messages:
    post:
      tags:
        - Conversations & Messages
      summary: Send a message
      description: >-
        Sends on the channel the customer last used (or the identity or channel
        uuid in `channel`), records it in the thread and fires the same
        message.* webhooks a dashboard reply does. Counted as a BOT send: it
        needs the workspace in good standing, never takes the conversation over,
        and gets the bot's messaging window. Refused with 422 (with a `reason`)
        when the contact is blocked or opted out, or the window is closed — send
        an approved template (`type: template`, `template_id`, `parameters`) to
        re-engage. Media (while inbox media is on) is sent by reference:
        `media.library` (an id from POST /media) or `media.source_message_id`; a
        URL is refused. Send an `Idempotency-Key` header to make a retried
        request one send.


        **Required permission:** `salesbot:messages:send`
      operationId: messages.store
      parameters:
        - name: Idempotency-Key
          in: header
          required: false
          schema:
            type: string
          description: Makes a retried request a single send.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                contact_id:
                  type: string
                  format: uuid
                type:
                  type: string
                  example: text
                body:
                  type: string
                  example: Your order has shipped.
                kind:
                  type: string
                  example: dm
      responses:
        '201':
          description: Created
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: 'A workspace API key: `Authorization: Bearer osk_...`'
    apiKeyHeader:
      type: apiKey
      in: header
      name: x-api-key
      description: The same workspace API key in the `x-api-key` header.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.