Send a message
Sends a text message through the same writer every other client uses, so delivery, push and the conversation’s state update as they do there. A contact conversation sends email or SMS. A conversation the member cannot post to (a broadcast-only channel, an archived or closed conversation, or one the member has archived for themselves) returns 403.
A retry with the same client_message_id returns the message already sent, even when the
conversation has closed since. If that message was deleted, the response carries no text or
attachments.
curl --request POST \
--url https://api.fluid.app/api/member/v2026-10/messaging/conversations/{id}/messages \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"text": "See you at the kickoff.",
"client_message_id": "7f1c2b9e-launch"
}
'import requests
url = "https://api.fluid.app/api/member/v2026-10/messaging/conversations/{id}/messages"
payload = {
"text": "See you at the kickoff.",
"client_message_id": "7f1c2b9e-launch"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({text: 'See you at the kickoff.', client_message_id: '7f1c2b9e-launch'})
};
fetch('https://api.fluid.app/api/member/v2026-10/messaging/conversations/{id}/messages', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.fluid.app/api/member/v2026-10/messaging/conversations/{id}/messages",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'text' => 'See you at the kickoff.',
'client_message_id' => '7f1c2b9e-launch'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.fluid.app/api/member/v2026-10/messaging/conversations/{id}/messages"
payload := strings.NewReader("{\n \"text\": \"See you at the kickoff.\",\n \"client_message_id\": \"7f1c2b9e-launch\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.fluid.app/api/member/v2026-10/messaging/conversations/{id}/messages")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"text\": \"See you at the kickoff.\",\n \"client_message_id\": \"7f1c2b9e-launch\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.fluid.app/api/member/v2026-10/messaging/conversations/{id}/messages")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"text\": \"See you at the kickoff.\",\n \"client_message_id\": \"7f1c2b9e-launch\"\n}"
response = http.request(request)
puts response.read_body{
"status": 200,
"data": {
"id": "0199a1b2-c3d4-7e5f-8a9b-0c1d2e3f4a60",
"conversation_id": "0199a1b2-c3d4-7e5f-8a9b-0c1d2e3f4a5b",
"sender": {
"id": "01a08944-eff4-7a2a-be01-d699fa649966",
"kind": "member",
"name": "Nathan Rivera",
"avatar_url": null
},
"kind": "message",
"text": "See you at the kickoff.",
"event": null,
"attachments": [],
"reply_to": null,
"reactions": [
{
"emoji": "👍",
"count": 2,
"mine": true
}
],
"pinned": false,
"seen_by_count": 3,
"client_message_id": "7f1c2b9e-launch",
"sent_at": "2026-10-01T15:02:00Z",
"created_at": "2026-10-01T15:01:59Z",
"edited_at": null
},
"meta": {
"request_uuid": "01a0f4fe-de00-75b3-8d8a-b74b0cde8b07",
"timestamp": "2026-10-01T15:04:05Z"
}
}{
"status": 201,
"data": {
"id": "0199a1b2-c3d4-7e5f-8a9b-0c1d2e3f4a60",
"conversation_id": "0199a1b2-c3d4-7e5f-8a9b-0c1d2e3f4a5b",
"sender": {
"id": "01a08944-eff4-7a2a-be01-d699fa649966",
"kind": "member",
"name": "Nathan Rivera",
"avatar_url": null
},
"kind": "message",
"text": "See you at the kickoff.",
"event": null,
"attachments": [],
"reply_to": null,
"reactions": [
{
"emoji": "👍",
"count": 2,
"mine": true
}
],
"pinned": false,
"seen_by_count": 3,
"client_message_id": "7f1c2b9e-launch",
"sent_at": "2026-10-01T15:02:00Z",
"created_at": "2026-10-01T15:01:59Z",
"edited_at": null
},
"meta": {
"request_uuid": "01a0f4fe-de00-75b3-8d8a-b74b0cde8b07",
"timestamp": "2026-10-01T15:04:05Z"
}
}{
"status": 123,
"error": {
"message": "<string>",
"details": {}
},
"meta": {
"request_uuid": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"timestamp": "2023-11-07T05:31:56Z"
}
}{
"status": 123,
"error": {
"message": "<string>",
"details": {}
},
"meta": {
"request_uuid": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"timestamp": "2023-11-07T05:31:56Z"
}
}{
"status": 123,
"error": {
"message": "<string>",
"details": {}
},
"meta": {
"request_uuid": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"timestamp": "2023-11-07T05:31:56Z"
}
}{
"status": 123,
"error": {
"message": "<string>",
"details": {}
},
"meta": {
"request_uuid": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"timestamp": "2023-11-07T05:31:56Z"
}
}Authorizations
A member credential in the Authorization: Bearer header: a member
session JWT, a portal JWT whose login is linked to a membership in
that company, or a member token. The credential alone
identifies the member and company.
Path Parameters
Public id of a conversation the member can see.
Body
- Option 1
- Option 2
Required unless the message has attachments.
1 - 10000\SA message in this conversation the member can read.
An id the client chooses. A retry with the same id returns the message already sent, with 200, instead of sending it again.
1 - 100Files the client has uploaded, named by URL, as the legacy message endpoint takes them. The URL is not checked as an owned upload.
10Show child attributes
Show child attributes
Response
The message already sent with this client_message_id, without text or attachments if it was deleted.
curl --request POST \
--url https://api.fluid.app/api/member/v2026-10/messaging/conversations/{id}/messages \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"text": "See you at the kickoff.",
"client_message_id": "7f1c2b9e-launch"
}
'import requests
url = "https://api.fluid.app/api/member/v2026-10/messaging/conversations/{id}/messages"
payload = {
"text": "See you at the kickoff.",
"client_message_id": "7f1c2b9e-launch"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({text: 'See you at the kickoff.', client_message_id: '7f1c2b9e-launch'})
};
fetch('https://api.fluid.app/api/member/v2026-10/messaging/conversations/{id}/messages', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.fluid.app/api/member/v2026-10/messaging/conversations/{id}/messages",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'text' => 'See you at the kickoff.',
'client_message_id' => '7f1c2b9e-launch'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.fluid.app/api/member/v2026-10/messaging/conversations/{id}/messages"
payload := strings.NewReader("{\n \"text\": \"See you at the kickoff.\",\n \"client_message_id\": \"7f1c2b9e-launch\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.fluid.app/api/member/v2026-10/messaging/conversations/{id}/messages")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"text\": \"See you at the kickoff.\",\n \"client_message_id\": \"7f1c2b9e-launch\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.fluid.app/api/member/v2026-10/messaging/conversations/{id}/messages")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"text\": \"See you at the kickoff.\",\n \"client_message_id\": \"7f1c2b9e-launch\"\n}"
response = http.request(request)
puts response.read_body{
"status": 200,
"data": {
"id": "0199a1b2-c3d4-7e5f-8a9b-0c1d2e3f4a60",
"conversation_id": "0199a1b2-c3d4-7e5f-8a9b-0c1d2e3f4a5b",
"sender": {
"id": "01a08944-eff4-7a2a-be01-d699fa649966",
"kind": "member",
"name": "Nathan Rivera",
"avatar_url": null
},
"kind": "message",
"text": "See you at the kickoff.",
"event": null,
"attachments": [],
"reply_to": null,
"reactions": [
{
"emoji": "👍",
"count": 2,
"mine": true
}
],
"pinned": false,
"seen_by_count": 3,
"client_message_id": "7f1c2b9e-launch",
"sent_at": "2026-10-01T15:02:00Z",
"created_at": "2026-10-01T15:01:59Z",
"edited_at": null
},
"meta": {
"request_uuid": "01a0f4fe-de00-75b3-8d8a-b74b0cde8b07",
"timestamp": "2026-10-01T15:04:05Z"
}
}{
"status": 201,
"data": {
"id": "0199a1b2-c3d4-7e5f-8a9b-0c1d2e3f4a60",
"conversation_id": "0199a1b2-c3d4-7e5f-8a9b-0c1d2e3f4a5b",
"sender": {
"id": "01a08944-eff4-7a2a-be01-d699fa649966",
"kind": "member",
"name": "Nathan Rivera",
"avatar_url": null
},
"kind": "message",
"text": "See you at the kickoff.",
"event": null,
"attachments": [],
"reply_to": null,
"reactions": [
{
"emoji": "👍",
"count": 2,
"mine": true
}
],
"pinned": false,
"seen_by_count": 3,
"client_message_id": "7f1c2b9e-launch",
"sent_at": "2026-10-01T15:02:00Z",
"created_at": "2026-10-01T15:01:59Z",
"edited_at": null
},
"meta": {
"request_uuid": "01a0f4fe-de00-75b3-8d8a-b74b0cde8b07",
"timestamp": "2026-10-01T15:04:05Z"
}
}{
"status": 123,
"error": {
"message": "<string>",
"details": {}
},
"meta": {
"request_uuid": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"timestamp": "2023-11-07T05:31:56Z"
}
}{
"status": 123,
"error": {
"message": "<string>",
"details": {}
},
"meta": {
"request_uuid": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"timestamp": "2023-11-07T05:31:56Z"
}
}{
"status": 123,
"error": {
"message": "<string>",
"details": {}
},
"meta": {
"request_uuid": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"timestamp": "2023-11-07T05:31:56Z"
}
}{
"status": 123,
"error": {
"message": "<string>",
"details": {}
},
"meta": {
"request_uuid": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"timestamp": "2023-11-07T05:31:56Z"
}
}