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

# Send Message

> Send an email or LinkedIn message in an existing Unibox thread.

**CLI:**

```bash theme={null}
puffle thread message send --id <id> --body-text <body-text>
puffle thread message send --id <id> --body-text <body-text> --body-html <body-html> --subject <subject> --account-id <account-id> --cc <cc> --bcc <bcc> --threading-mode <threading-mode>
```

## Overview

Sends a message in an existing Unibox thread.

For a new one-off email, first call [Create thread](/api-reference/unibox/create-thread), then call this endpoint with `threading_mode: "new_thread"`. For an existing email or LinkedIn conversation, call this endpoint on the existing thread to reply from the connected sender.

## Path Parameters

| Parameter | Type   | Description                                                               |
| --------- | ------ | ------------------------------------------------------------------------- |
| `id`      | string | Thread ID returned by `POST /api/threads` or any thread listing endpoint. |

## Request Body

| Field            | Type                        | Required                                                               | Description                                                                                                                                           |
| ---------------- | --------------------------- | ---------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| `body_text`      | string                      | Yes                                                                    | Plain-text message body. Empty strings are rejected.                                                                                                  |
| `body_html`      | string                      | Optional                                                               | HTML body. For email, if omitted, Puffle derives HTML from `body_text`.                                                                               |
| `subject`        | string                      | Required for new email threads unless the thread already has a subject | Email subject. Ignored by LinkedIn sends.                                                                                                             |
| `account_id`     | string                      | Required for email when the thread has no sender                       | Email sender account ID. The account must belong to the workspace and be ready to send.                                                               |
| `threading_mode` | `"new_thread"` or `"reply"` | Optional                                                               | Email threading behavior. Use `"new_thread"` for a one-off outbound email. If omitted, Puffle replies to the most recent inbound email when possible. |
| `cc`             | string                      | Optional                                                               | Comma-separated CC recipients for email.                                                                                                              |
| `bcc`            | string                      | Optional                                                               | Comma-separated BCC recipients for email.                                                                                                             |
| `attachments`    | array                       | Dashboard only                                                         | Attachment metadata uploaded through the dashboard. Bearer API-key requests that include this field return `403`.                                     |

Attachment uploads are available only to authenticated dashboard sessions. Public API and CLI callers must omit `attachments`.

## Send a One-Off Email

```bash theme={null}
curl -X POST "https://app.puffle.ai/api/threads/3d986dd1-9d70-45b7-8e36-5d5b8b1c9337/messages" \
  -H "Authorization: Bearer $PUFFLE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "account_id": "8a2f0c7a-9d1e-4d8f-9d7d-6a8b8e8f4a11",
    "subject": "Quick question",
    "body_text": "Hi Alex, I had a quick question about your outbound workflow.",
    "threading_mode": "new_thread"
  }'
```

On success, the response includes the saved outbound `message` and the refreshed `thread`. A one-off outbound email appears in Unibox with `thread.inbox_state` set to `sent_one_off`.

```json theme={null}
{
  "message": {
    "id": "6d54211c-7e24-4eb9-85fc-7388c8d89f2f",
    "conversation_id": "3d986dd1-9d70-45b7-8e36-5d5b8b1c9337",
    "direction": "outbound",
    "subject": "Quick question",
    "body_text": "Hi Alex, I had a quick question about your outbound workflow."
  },
  "thread": {
    "id": "3d986dd1-9d70-45b7-8e36-5d5b8b1c9337",
    "channel": "email",
    "status": "active",
    "inbox_state": "sent_one_off",
    "outbound_message_count": 1,
    "has_one_off_message": true
  }
}
```

## Error Notes

| Status | When it happens                                                                                                                                                                                       |
| ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `400`  | `body_text` is missing or empty, `threading_mode` is invalid, or attachment metadata is invalid.                                                                                                      |
| `403`  | An API-key request includes dashboard-only `attachments`.                                                                                                                                             |
| `404`  | The thread does not exist or does not belong to the workspace.                                                                                                                                        |
| `422`  | The thread cannot send on the requested channel, the recipient email is missing, or the sender account is not ready.                                                                                  |
| `429`  | The email provider rate-limited the send.                                                                                                                                                             |
| `500`  | The message may have been sent externally but failed to save locally. If the response says the message was sent but could not be saved, do **not** retry; the recipient may already have received it. |
| `502`  | The provider failed to send the message.                                                                                                                                                              |

## AI agent notes

For a brand-new one-off email, create the thread first and send with `threading_mode: "new_thread"`. Do not retry a `500` response that says the message was sent but could not be saved, because the recipient may already have received it.


## OpenAPI

````yaml post /api/threads/{id}/messages
openapi: 3.0.3
info:
  title: Puffle API
  version: 1.0.0
  description: >-
    HTTP API for the Puffle GTM platform - Feed and Lead Finder search
    preparation, campaign-backed Outbound execution, Puffle Agent runs, sender
    management, and Unibox reply workflows. Designed for operation by both
    humans and autonomous AI agents. Agents should start at the [Agent
    Playbook](/guides/agent-playbook) which prescribes a workspace-context check
    (`GET /api/context`) and core user journeys with exact call ordering.
  contact:
    name: Puffle Support
    url: https://puffle.ai
servers:
  - url: https://app.puffle.ai
    description: Production
security:
  - bearerAuth: []
tags:
  - name: Campaigns
    description: >-
      Campaign-backed Outbound execution. These endpoints manage draft,
      launching, active, paused, and completed Outbound runs with sequence
      nodes, contacts, and sender accounts.
  - name: Accounts
    description: Signed-in user account, settings, and workspace context endpoints.
  - name: Billing
    description: Billing customer portal and account billing endpoints.
  - name: Senders
    description: >-
      Connected sender accounts, email inboxes, sending domains, DNS
      verification, warmup, and sender capacity.
  - name: Socials
    description: >-
      Read connected LinkedIn and X accounts, review current and archived posts,
      and reconcile publication status. Creating, editing, scheduling,
      publishing, OAuth connection, analytics, and mentions remain
      dashboard-managed workflows and are not part of the public Bearer-token
      API.
paths:
  /api/threads/{id}/messages:
    post:
      tags:
        - Unibox
      summary: Send Message
      description: Send Message
      operationId: sendThreadMessage
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            description: Thread (`conversations.id`) UUID.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                body_text:
                  type: string
                  minLength: 1
                  description: Plain-text message body.
                body_html:
                  description: Optional HTML message body.
                  type: string
                subject:
                  description: Email subject.
                  type: string
                account_id:
                  description: Email sender account ID.
                  type: string
                cc:
                  description: Email CC recipients.
                  type: string
                bcc:
                  description: Email BCC recipients.
                  type: string
                threading_mode:
                  description: Email threading behavior.
                  type: string
                  enum:
                    - new_thread
                    - reply
                attachments:
                  description: Uploaded attachment metadata.
                  type: array
                  items:
                    type: object
                    properties:
                      name:
                        type: string
                        minLength: 1
                        description: Attachment file name.
                      url:
                        description: Attachment URL.
                        type: string
                        minLength: 1
                      bucket:
                        type: string
                        minLength: 1
                        description: Storage bucket containing the attachment.
                      path:
                        type: string
                        minLength: 1
                        description: Attachment path within the storage bucket.
                      mime_type:
                        type: string
                        minLength: 1
                      size:
                        type: number
                        minimum: 0
                      content_id:
                        type: string
                        minLength: 1
                      content_disposition:
                        type: string
                        enum:
                          - attachment
                          - inline
                    required:
                      - name
                      - bucket
                      - path
                    additionalProperties: false
                  nullable: true
              required:
                - body_text
              additionalProperties: false
      responses:
        '200':
          description: Successful response.
        '400':
          description: Bad request.
        '401':
          description: Unauthorized.
        '403':
          description: Forbidden.
        '404':
          description: Not found.
        '500':
          description: Internal server error.
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: pk_live_...

````