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

# Send a message

> Send a message as the authenticated contact. Requires an `Idempotency-Key` header of 8–255 characters; reusing the same key with the same request returns the original message. Pass `draft: true` (without parts) to open a streaming draft instead.




## OpenAPI

````yaml /api-reference/openapi.yaml post /v1/messages
openapi: 3.1.0
info:
  title: Relay developer API
  version: '0.1'
  description: >
    Give your agent a Relay contact, receive messages, and reply with plain
    HTTPS and JSON. Authenticate every request with an Agent Token unless the
    endpoint is marked public.
servers:
  - url: https://api.relayapp.im
    description: Production
  - url: http://localhost:8788
    description: Local development
security:
  - agentToken: []
tags:
  - name: Agent
  - name: Messages
  - name: Events
  - name: Webhook
  - name: Public
paths:
  /v1/messages:
    post:
      tags:
        - Messages
      summary: Send a message
      description: >
        Send a message as the authenticated contact. Requires an
        `Idempotency-Key` header of 8–255 characters; reusing the same key with
        the same request returns the original message. Pass `draft: true`
        (without parts) to open a streaming draft instead.
      operationId: sendMessage
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - conversation_id
              properties:
                conversation_id:
                  type: string
                  description: Conversation to send into, from `message.received`.
                  example: cnv_01JZC7K4RQ
                parts:
                  type: array
                  minItems: 1
                  maxItems: 32
                  description: Ordered message parts. Required unless `draft` is true.
                  items:
                    $ref: '#/components/schemas/PartInput'
                reply_to:
                  $ref: '#/components/schemas/ReplyRef'
                draft:
                  type: boolean
                  description: >-
                    Open a streaming draft; grow it with append and publish with
                    finalize.
      responses:
        '202':
          description: Message accepted and committed.
          content:
            application/json:
              schema:
                type: object
                required:
                  - message_id
                  - message
                properties:
                  message_id:
                    type: string
                    example: msg_01JZM4Q9VN
                  message:
                    $ref: '#/components/schemas/Message'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: >-
            The contact is not an active participant or is not installed for the
            user.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: The conversation does not exist.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '409':
          description: The idempotency key was already used with a different request.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: >-
            The key, conversation ID, parts, attachment reference, or reply
            target is invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
components:
  parameters:
    IdempotencyKey:
      name: Idempotency-Key
      in: header
      required: true
      schema:
        type: string
        minLength: 8
        maxLength: 255
      description: Deriving it from the triggering `event_id` makes a retry safe.
  schemas:
    PartInput:
      type: object
      required:
        - type
      properties:
        type:
          type: string
          enum:
            - text
            - link
            - data
            - media
            - voice
        text:
          type: string
          description: Content for `text` (≤ 8 KB) and the URL for `link`.
        payload:
          type: object
          description: Structured JSON for `data` (≤ 16 KB).
        attachment_id:
          type: string
          description: Existing attachment reference for `media` and `voice`.
      example:
        type: text
        text: Tomorrow at 2:00 PM works.
    ReplyRef:
      type:
        - object
        - 'null'
      properties:
        message_id:
          type: string
          example: msg_01JZM3T8AH
        part_index:
          type: integer
          example: 0
    Message:
      type: object
      required:
        - id
        - conversation_id
        - sequence
        - sender
        - parts
        - fallback_text
        - status
        - created_at
      properties:
        id:
          type: string
          example: msg_01JZM3T8AH
        conversation_id:
          type: string
          example: cnv_01JZC7K4RQ
        sequence:
          type: integer
          description: Order inside the conversation. Not the polling cursor.
        sender:
          $ref: '#/components/schemas/Sender'
        parts:
          type: array
          items:
            $ref: '#/components/schemas/Part'
        reply_to:
          $ref: '#/components/schemas/ReplyRef'
        fallback_text:
          type: string
          description: Plain-language representation used by notifications and search.
        status:
          type: string
          example: sent
        created_at:
          type: string
          format: date-time
    Error:
      type: object
      required:
        - error
      properties:
        error:
          type: object
          required:
            - code
            - message
          properties:
            code:
              type: string
              example: invalid_request
            message:
              type: string
              example: conversation_id is required
    Sender:
      type: object
      required:
        - kind
        - id
      properties:
        kind:
          type: string
          enum:
            - user
            - agent
        id:
          type: string
          example: usr_01JZU1F0BD
    Part:
      type: object
      required:
        - part_index
        - type
      properties:
        part_index:
          type: integer
        type:
          type: string
          enum:
            - text
            - link
            - data
            - media
            - voice
        text:
          type: string
        url:
          type: string
        attachment_id:
          type: string
        data:
          type: object
  responses:
    Unauthorized:
      description: Token is absent or invalid.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
  securitySchemes:
    agentToken:
      type: http
      scheme: bearer
      description: Agent Token (`relay_agt_live_…`), shown once at agent creation.

````