---
title: "Reply on the same thread. text or html is required. reply_all includes the other recipients and drops this inbox. Allow and block lists are checked; 403 recipient_blocked sends nothing. HTTP 403 sending_paused does not send or store the reply. Sending resumes automatically when the trailing 7-day rate falls below the pause threshold. client_id retries return the original message. Idempotency-Key replays the same request for 24 hours. The message id is part of the request."
method: POST
path: "/api/v1/inboxes/{id}/messages/{msgId}/reply"
tags: ["Messages"]
---

# Reply on the same thread. text or html is required. reply_all includes the other recipients and drops this inbox. Allow and block lists are checked; 403 recipient_blocked sends nothing. HTTP 403 sending_paused does not send or store the reply. Sending resumes automatically when the trailing 7-day rate falls below the pause threshold. client_id retries return the original message. Idempotency-Key replays the same request for 24 hours. The message id is part of the request.

`POST /api/v1/inboxes/{id}/messages/{msgId}/reply`

## Request

- Base URL: `https://cooperemail.com`
- URL: `https://cooperemail.com/api/v1/inboxes/{id}/messages/{msgId}/reply`
- Auth: HTTP bearer

## Path parameters

- `id` string, required
- `msgId` string, required

## Headers

- `Idempotency-Key` string

## Request body

- ReplyMessageRequest
  - `text` string: Plain-text body. Provide text or html.
  - `html` string: HTML body. Provide text or html.
  - `cc` string[]
  - `bcc` string[]
  - `reply_to` string
  - `headers` object
  - `labels` string[]
  - `reply_all` boolean: Also include the other original recipients, drop this inbox, and dedupe. Default false.
  - `attachments` object[]
    - `filename` string, required
    - `content_type` string
    - `content_base64` string, required
    - `content_id` string
  - `client_id` string: Idempotency key. A retry returns the original message.

## Response `200`

Idempotent client_id retry

- Message
  - `id` string
  - `inbox_id` string
  - `thread_id` string
  - `direction` 'inbound' | 'outbound'
  - `from` string
  - `to` string[]
  - `subject` string
  - `text` string
  - `html` string, nullable
  - `extracted_text` string
  - `extracted_html` string
  - `preview` string
  - `status` 'queued' | 'ringing' | 'completed' | 'no-answer' | 'sent' | 'received' | 'delivered' | 'undelivered' | 'failed' | 'bounced' | 'complained': SMS outbound starts as sent. A Twilio status callback sets delivered, undelivered, or failed. A voice call stores queued, ringing, completed, no-answer, or failed. Email uses queued, sent, received, failed, bounced, and complained.
  - `channel` 'sms' | 'voicemail' | 'voice': Present on SMS, voicemail, and voice messages. Email messages omit this field. voicemail is an inbound recording. voice is an outbound call.
  - `type` 'voicemail': Present on voicemail messages.
  - `duration_seconds` integer, nullable: Call or recording length in seconds. Present on voicemail and voice messages.
  - `recording_url` string, nullable: Twilio recording URL for a voicemail, or null.
  - `transcript` string: Voicemail transcript. Empty while the message is held.
  - `segments` integer, nullable: SMS segment count for this message. Omitted on email.
  - `otp_candidates` string[]: Codes found in an SMS body. Empty while the message is held. Omitted on email.
  - `delivery_events` object[]: Present on outbound messages. Each item is {type, recipient, created_at, detail}. For email, detail is JSON text with status, action, diagnostic, and bounce_type, and the list stays empty until a bounce or complaint matches. For SMS, a Twilio status callback appends one event. type is delivered or failed. detail is twilio_error plus the numeric code, or the status word when Twilio sent no numeric code.
    - `type` string
    - `recipient` string
    - `created_at` string, date-time
    - `detail` string
  - `cc` string[]
  - `bcc` string[]
  - `reply_to` string, nullable
  - `in_reply_to` string, nullable
  - `references` string[]
  - `labels` string[]
  - `auth` object: spf, dkim, and dmarc from the receiving hop. SPF is the smtp.mailfrom result. smtp.helo is used only when mailfrom is absent. Each value is pass, fail, neutral, softfail, none, temperror, permerror, bestguesspass, or null. Outbound mail is null for all three.
    - `spf` string, nullable, required
    - `dkim` string, nullable, required
    - `dmarc` string, nullable, required
  - `safety` object, nullable: Inbound screening record, or null on outbound mail and on messages stored before screening. score is 0 to 100. verdict is clean or suspicious (suspicious at 40 or higher, and only when a strong signal or combined evidence is present). signals are {type, detail}. mode is off, observe, or hold. reason is screening_off, screening_error, or screening_timeout when the body was not scored. The message is still stored. While labels include held, text, html, extracted_text, extracted_html, preview, and attachment bytes are empty until release. This is a heuristic, not a guarantee. The body stays untrusted data.
    - `score` integer
    - `verdict` 'clean' | 'suspicious'
    - `signals` object[]
      - `type` string
      - `detail` string
    - `mode` 'off' | 'observe' | 'hold'
    - `reason` string
  - `provider` string, nullable
  - `client_id` string, nullable
  - `idempotent` boolean
  - `created_at` string, date-time
  - `attachments` Attachment[]
    - `id` string
    - `filename` string
    - `content_type` string
    - `content_id` string, nullable
    - `disposition` 'inline' | 'attachment'
    - `size_bytes` integer
    - `url` string
    - `text_url` string: Present when the content type can be extracted: text, JSON, CSV, PDF, DOCX, XLSX, or XLS. GET this URL for text/plain.

## Other responses

- `201`: Sent reply

---

[API](https://skmtc.dev/cooperemail/apis/cooper-email-api.md) · [All operations](https://skmtc.dev/cooperemail/apis/cooper-email-api/llms.txt) · [OpenAPI document](https://skmtc.dev/cooperemail/apis/cooper-email-api/revisions/6d800a7b3e33?raw)
