# Send a message

> POST https://api.nabrah.ai/api/ext/omni_v2/conversation/conversation/{id}/messages

Group: Conversations. Page: https://www.nabrah.ai/en/docs/api-reference/conversations/send-a-message

Sends a new message into the conversation. The path `id` selects the conversation; the JSON body carries the message `content` and options. Set `private: true` to post an internal note that the contact cannot see, or `false` for an outgoing reply. Returns the created message object (with its assigned `id`, `created_at`, `status`, and any `attachments`). For replies that include a file, use the `messages_with_attachment` endpoint instead.

## Request body fields

Base your request on these fields (only `content` is typically required).

- **content**: The message text/body to send. Fields: `content`.
- **message_type**: Use `outgoing` (the default) for replies and for WhatsApp templates. `template` is not accepted and returns 422. Fields: `message_type`.
- **private**: When true the message is an internal note visible only to agents; when false it is delivered to the contact. Fields: `private`.
- **content_type / content_attributes**: Leave `content_type` as `text` and `content_attributes` empty. To show buttons, send an approved template that includes them. Fields: `content_type`, `content_attributes`.
- **template_params**: Sends an approved WhatsApp template instead of a free-form message. See WhatsApp templates below. `campaign_id` is not needed. Fields: `template_params`.

## WhatsApp templates

Templates are how you reach a customer outside the 24-hour window, for example to confirm or remind an appointment.

- **New numbers**: To message a number that has never written to you, first open a conversation with POST /api/ext/omni_v2/whatsapp and `contact_phone`, then post the template into it here. Sent this way, the template shows in the inbox and the customer's reply continues in the same conversation.
- **Shape** ("template_params": { "name", "language", "category", "processed_params" }): `name` and `language` must match a template that is approved for this WhatsApp number, for example `appointment_confirmation` and `en`. `category` is optional. Send these fields directly in `template_params`; WhatsApp's own `template` object and `components` list are not accepted. Fields: `template_params`.
- **Variables** ("processed_params": { "1": "Sara", "2": "12 Oct, 10:00" }): Values for `{{1}}`, `{{2}}`, … in the template body, as strings, keyed by position.
- **content**: Required. It is the text shown in the conversation history; the customer receives the template. Use the filled-in template text. Fields: `content`.
- **24-hour window**: Outside the 24-hour customer-service window only templates are delivered. A plain message sent outside it is accepted but is then marked `failed`.
- **Delivery status**: The response is the created message. Delivery to WhatsApp happens right after; read `status` (`sent`, `delivered`, `read` or `failed`) on the message from GET /api/ext/omni_v2/conversation/conversation/{id}/messages.
- **Errors**: A message that cannot be created returns 422 with the reason in `detail`, for example `Message rejected: Validation failed: Name is required` when `template_params` has no `name`. Nothing is sent in that case.

## Instagram and TikTok reply windows

Outgoing messages on Instagram and TikTok conversations are only delivered inside the platform's reply window.

- **409 reply_window_closed**: Returned when the window has closed: 24 hours after the customer's last message on Instagram, 48 hours on TikTok. Private notes are not affected. On Instagram, team members replying from the platform can still reply for up to 7 days; API sends cannot.
- **Not delivered**: If the platform refuses a message after it was accepted, a private note starting with "Not delivered" is added to the conversation.

## Authorization

- `X-API-Key` (string, header, required): your workspace API key.

## Path parameters

- `id` (integer, required): Integer id of the conversation to post the message into. From a list endpoint or `GET.../conversation/{id}`.

## Body (application/json)

### Example: Outgoing reply

Send a plain-text reply that is delivered to the contact.

```json
{
  "content": "Thanks for reaching out — we have shipped your replacement and it will arrive within 3 business days.",
  "message_type": "outgoing",
  "private": false,
  "content_type": "text",
  "content_attributes": {}
}
```

### Example: Private note

Post an internal note visible only to agents, not the contact.

```json
{
  "content": "Customer is a VIP — escalate any further issues to the success team.",
  "message_type": "outgoing",
  "private": true,
  "content_type": "text",
  "content_attributes": {}
}
```

### Example: WhatsApp template

Send an approved appointment-confirmation template with two variables.

```json
{
  "content": "Hi Sara, your appointment is confirmed for 12 Oct, 10:00.",
  "message_type": "outgoing",
  "template_params": {
    "name": "appointment_confirmation",
    "category": "UTILITY",
    "language": "en",
    "processed_params": {
      "1": "Sara",
      "2": "12 Oct, 10:00"
    }
  }
}
```

## Response

### 200 Successful Response

Content type: `application/json`

```json
{
  "content": "string",
  "content_attributes": {},
  "content_type": "string",
  "conversation_id": 0,
  "created_at": 0,
  "echo_id": "string",
  "id": 0,
  "inbox_id": 0,
  "message_type": 0,
  "private": false,
  "sender": {
    "id": 0,
    "name": "string",
    "available_name": "string",
    "avatar_url": "string",
    "type": "string"
  },
  "source_id": "string",
  "status": "string",
  "attachments": [
    {
      "id": 0,
      "account_id": 0,
      "message_id": 0,
      "thumb_url": "string",
      "data_url": "string",
      "file_size": 0,
      "file_type": "string",
      "extension": "string",
      "width": 0,
      "height": 0,
      "created_at": 0,
      "sender": {
        "id": 0,
        "name": "string",
        "available_name": "string",
        "avatar_url": "string",
        "type": "string",
        "availability_status": "string",
        "thumbnail": "string",
        "additional_attributes": {},
        "custom_attributes": {},
        "email": "string",
        "identifier": "string",
        "phone_number": "string",
        "blocked": false
      },
      "coordinates_lat": 0,
      "coordinates_lng": 0,
      "fallback_title": "string",
      "meta": {}
    }
  ]
}
```

### 422 Validation Error

Content type: `application/json`

```json
{
  "detail": [
    {
      "loc": [
        "string"
      ],
      "msg": "string",
      "type": "string"
    }
  ]
}
```

## Request examples

### cURL

```bash
curl --request POST \
  --url 'https://api.nabrah.ai/api/ext/omni_v2/conversation/conversation/<id>/messages' \
  --header 'X-API-Key: <your-api-key>' \
  --header 'Content-Type: application/json' \
  --data '{
  "content": "Thanks for reaching out — we have shipped your replacement and it will arrive within 3 business days.",
  "message_type": "outgoing",
  "private": false,
  "content_type": "text",
  "content_attributes": {}
}'
```

### Python

```python
import requests

url = "https://api.nabrah.ai/api/ext/omni_v2/conversation/conversation/<id>/messages"
headers = {
    "X-API-Key": "<your-api-key>",
}
payload = {
    "content": "Thanks for reaching out — we have shipped your replacement and it will arrive within 3 business days.",
    "message_type": "outgoing",
    "private": False,
    "content_type": "text",
    "content_attributes": {}
}

response = requests.post(url, headers=headers, json=payload)
response.raise_for_status()
print(response.json())
```

### JavaScript

```javascript
const response = await fetch("https://api.nabrah.ai/api/ext/omni_v2/conversation/conversation/<id>/messages", {
  method: "POST",
  headers: {
    "X-API-Key": "<your-api-key>",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "content": "Thanks for reaching out — we have shipped your replacement and it will arrive within 3 business days.",
    "message_type": "outgoing",
    "private": false,
    "content_type": "text",
    "content_attributes": {}
  }),
});

const data = await response.json();
console.log(data);
```

### Go

```go
package main

import (
	"fmt"
	"io"
	"net/http"
	"strings"
)

func main() {
	payload := strings.NewReader(`{
  "content": "Thanks for reaching out — we have shipped your replacement and it will arrive within 3 business days.",
  "message_type": "outgoing",
  "private": false,
  "content_type": "text",
  "content_attributes": {}
}`)

	req, _ := http.NewRequest("POST", "https://api.nabrah.ai/api/ext/omni_v2/conversation/conversation/<id>/messages", payload)
	req.Header.Set("X-API-Key", "<your-api-key>")
	req.Header.Set("Content-Type", "application/json")

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	out, _ := io.ReadAll(res.Body)
	fmt.Println(string(out))
}
```
