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

# Send replies

> Send customer replies, inspect delivery, schedule email, and cancel pending sends.

## Record or send

Use `POST /conversations/{conversationId}/messages` (`messages:write`) to record or import a message without customer delivery. Use `POST /conversations/{conversationId}/send` (`messages:send`) to send an agent reply on the conversation's existing channel. The sender, channel, and delivery metadata are set by the server.

A key or OAuth connection with only `messages:write` cannot send customer replies. Add the separate send permission explicitly.

## Send a reply

The conversation must belong to the connected workspace and have the intended customer and channel. Email and WhatsApp require configured channel credentials and a recipient. Chat replies appear in the visitor stream. A test-mode API key still operates on real workspace data.

```bash theme={null}
curl --fail-with-body 'https://api.protodesk.io/v1/conversations/CONVERSATION_ID/send' \
  -H "Authorization: Bearer $PROTODESK_API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: reply-order-123-v1' \
  --data '{"body":"Your order is ready."}'
```

The response contains `message`, `queued`, `undoMsec`, and, for scheduled email, `scheduledFor`. Email and WhatsApp delivery jobs are committed in the same database transaction as the message. A queue failure rolls back the message.

Reuse the exact request and idempotency key after an uncertain response. A replay returns the original result with `Idempotency-Replayed: true`. Changing the request under the same key returns 409. Request idempotency does not promise exactly-once delivery by an external provider.

## Check delivery

Read `GET /messages/{messageId}` with `conversations:read`. For a reply created by the send endpoint, inspect `metadata.deliveryStatus`:

| State | Meaning |
| - | - |
| `queued` | A durable delivery job is waiting |
| `scheduled` | Delivery is scheduled for a future time |
| `sent` | The provider accepted the send |
| `delivered` | A provider delivery receipt was received |
| `failed` or `bounced` | Inspect delivery error details before deciding what to do |
| `canceled` | Pending delivery was canceled |
| `test` | A test-thread reply stayed in Protodesk |

A queued response is not delivery confirmation. Some delivery failures are retried by the worker; do not create another message merely because a retry is in progress.

## Schedule or cancel

Email replies can include `sendAt`, an RFC3339 timestamp in the future and at most 30 days ahead. Scheduling is not supported for internal notes, test threads, or other channels.

Normal provider sends have a five-second undo window. Call `POST /messages/{messageId}/cancel-send` with `messages:send` while the delivery job is pending. Scheduled sends can also be canceled before the worker claims them. Success returns 204. Once claimed, cancellation returns 409; it cannot recall an in-flight provider request.

## Internal notes and attachments

Set `internal: true` to add an internal note without contacting the customer. Test-thread replies also stay inside Protodesk.

Send attachments must use durable `/api/media/WORKSPACE_ID/...` references owned by that workspace. Arbitrary external URLs are not fetched or silently treated as delivered attachments. Channel/provider limits still apply.

## MCP equivalents

Use `send_message`, `get_message`, and `cancel_message_send`. Reads require `conversations:read`; sends and cancellation require `messages:send`. Call `workspace_context` first, supply its ID as `expectedWorkspaceId` on writes, and supply an `idempotencyKey` for sending.

```json theme={null}
{
  "conversationId": "CONVERSATION_ID",
  "expectedWorkspaceId": "WORKSPACE_ID",
  "idempotencyKey": "reply-order-123-v1",
  "body": { "body": "Your order is ready." }
}
```

See the [send endpoint](/api-reference/messages/sendMessage) for the full request contract.


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