Send on the member's preferred channel
A message on the member’s preferred channel. Fluid tries their ranked contact methods first, then push, email and SMS, and uses the first one the company has set up and the member can receive. Needs any of outbound_messages.push, .email or .sms (only channels you hold are tried).
curl --request POST \
--url https://api.fluid.app/api/company/v2026-10/messages/preferred \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"member_id": "0199c2d4-8a1e-7b35-9f02-6d4e1a7c3b58",
"message_type": "marketing",
"subject": "New arrivals for fall",
"title": "New arrivals for fall",
"text": "Our fall collection just landed. Take a look before your favourites sell out.",
"url": "/collections/fall"
}
'import requests
url = "https://api.fluid.app/api/company/v2026-10/messages/preferred"
payload = {
"member_id": "0199c2d4-8a1e-7b35-9f02-6d4e1a7c3b58",
"message_type": "marketing",
"subject": "New arrivals for fall",
"title": "New arrivals for fall",
"text": "Our fall collection just landed. Take a look before your favourites sell out.",
"url": "/collections/fall"
}
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({
member_id: '0199c2d4-8a1e-7b35-9f02-6d4e1a7c3b58',
message_type: 'marketing',
subject: 'New arrivals for fall',
title: 'New arrivals for fall',
text: 'Our fall collection just landed. Take a look before your favourites sell out.',
url: '/collections/fall'
})
};
fetch('https://api.fluid.app/api/company/v2026-10/messages/preferred', 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/company/v2026-10/messages/preferred",
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([
'member_id' => '0199c2d4-8a1e-7b35-9f02-6d4e1a7c3b58',
'message_type' => 'marketing',
'subject' => 'New arrivals for fall',
'title' => 'New arrivals for fall',
'text' => 'Our fall collection just landed. Take a look before your favourites sell out.',
'url' => '/collections/fall'
]),
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/company/v2026-10/messages/preferred"
payload := strings.NewReader("{\n \"member_id\": \"0199c2d4-8a1e-7b35-9f02-6d4e1a7c3b58\",\n \"message_type\": \"marketing\",\n \"subject\": \"New arrivals for fall\",\n \"title\": \"New arrivals for fall\",\n \"text\": \"Our fall collection just landed. Take a look before your favourites sell out.\",\n \"url\": \"/collections/fall\"\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/company/v2026-10/messages/preferred")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"member_id\": \"0199c2d4-8a1e-7b35-9f02-6d4e1a7c3b58\",\n \"message_type\": \"marketing\",\n \"subject\": \"New arrivals for fall\",\n \"title\": \"New arrivals for fall\",\n \"text\": \"Our fall collection just landed. Take a look before your favourites sell out.\",\n \"url\": \"/collections/fall\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.fluid.app/api/company/v2026-10/messages/preferred")
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 \"member_id\": \"0199c2d4-8a1e-7b35-9f02-6d4e1a7c3b58\",\n \"message_type\": \"marketing\",\n \"subject\": \"New arrivals for fall\",\n \"title\": \"New arrivals for fall\",\n \"text\": \"Our fall collection just landed. Take a look before your favourites sell out.\",\n \"url\": \"/collections/fall\"\n}"
response = http.request(request)
puts response.read_body{
"message": {
"id": "019a1152-6c5d-7e4f-9a3b-2c1d0e9f8a7b",
"channel": "email",
"message_type": "marketing",
"status": "delivered",
"refusal_code": null,
"provider": "ses",
"provider_message_id": "0100019a11526c5d-2b3c4d5e-6f7a-4b8c-9d0e-1f2a3b4c5d6e-000000",
"recipient": {
"member_id": "0199c2d4-8a1e-7b35-9f02-6d4e1a7c3b58",
"contact_id": null,
"contact_method_id": "0199c2d5-1f3a-7c48-b6e1-9d2a4f7e8c13"
},
"conversation_id": null,
"created_at": "2026-10-23T02:14:09Z",
"updated_at": "2026-10-23T12:00:05Z",
"events": [
{
"status": "scheduled",
"detail": null,
"occurred_at": "2026-10-23T02:14:09Z"
},
{
"status": "sent",
"detail": null,
"occurred_at": "2026-10-23T12:00:01Z"
},
{
"status": "delivered",
"detail": null,
"occurred_at": "2026-10-23T12:00:05Z"
}
],
"send_at": "2026-10-23T12:00:00Z"
},
"status": 200,
"meta": {
"request_uuid": "3b8f1d27-6c4e-4a91-8e5d-2f7c9a1b0e64",
"timestamp": "2026-10-23T14:05:12Z"
}
}{
"message": {
"id": "019a1152-6c5d-7e4f-9a3b-2c1d0e9f8a7b",
"channel": "email",
"message_type": "marketing",
"status": "scheduled",
"refusal_code": null,
"provider": "ses",
"provider_message_id": null,
"recipient": {
"member_id": "0199c2d4-8a1e-7b35-9f02-6d4e1a7c3b58",
"contact_id": null,
"contact_method_id": "0199c2d5-1f3a-7c48-b6e1-9d2a4f7e8c13"
},
"conversation_id": null,
"created_at": "2026-10-23T02:14:09Z",
"updated_at": "2026-10-23T02:14:09Z",
"events": [
{
"status": "scheduled",
"detail": null,
"occurred_at": "2026-10-23T02:14:09Z"
}
],
"send_at": "2026-10-23T12:00:00Z"
},
"status": 202,
"meta": {
"request_uuid": "3b8f1d27-6c4e-4a91-8e5d-2f7c9a1b0e64",
"timestamp": "2026-10-23T14:05:12Z"
}
}{
"error": {
"message": "<string>",
"details": {}
},
"status": 123,
"meta": {
"request_uuid": "<string>",
"timestamp": "2023-11-07T05:31:56Z"
}
}{}{}{
"error": {
"code": "channel_disabled",
"message": "The company messages API isn't switched on for this company yet.",
"channel": "email"
},
"status": 422,
"meta": {
"request_uuid": "00000000-0000-0000-0000-000000000000",
"timestamp": "2026-10-23T12:00:00Z"
}
}Authorizations
An admin session, company API token, droplet token or bot token.
Headers
Use this or idempotency_key in the body.
Body
A message on the member's preferred channel. Fluid tries their ranked contact methods first, then push, email and SMS, and uses the first one the company has set up and the member can receive.
A member's uuid.
The message, used on every channel.
1 - 1600marketing needs the recipient's marketing consent for the channel.
transactional, marketing A key you choose. Sending again with the same key answers with the first message instead of sending twice. You can send it as the Idempotency-Key header instead.
200Used as the email subject.
998Used as the push title.
200Used as the email's HTML body.
Used as the push link.
A marketing message asked for during the recipient's quiet hours (21:00 to 08:00 in their time zone by default) waits and goes out when they end. Pass true to have it refused as quiet_hours with send_at instead.
Response
A repeat of an earlier request with the same idempotency key; the first message is returned and nothing is sent again.
curl --request POST \
--url https://api.fluid.app/api/company/v2026-10/messages/preferred \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"member_id": "0199c2d4-8a1e-7b35-9f02-6d4e1a7c3b58",
"message_type": "marketing",
"subject": "New arrivals for fall",
"title": "New arrivals for fall",
"text": "Our fall collection just landed. Take a look before your favourites sell out.",
"url": "/collections/fall"
}
'import requests
url = "https://api.fluid.app/api/company/v2026-10/messages/preferred"
payload = {
"member_id": "0199c2d4-8a1e-7b35-9f02-6d4e1a7c3b58",
"message_type": "marketing",
"subject": "New arrivals for fall",
"title": "New arrivals for fall",
"text": "Our fall collection just landed. Take a look before your favourites sell out.",
"url": "/collections/fall"
}
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({
member_id: '0199c2d4-8a1e-7b35-9f02-6d4e1a7c3b58',
message_type: 'marketing',
subject: 'New arrivals for fall',
title: 'New arrivals for fall',
text: 'Our fall collection just landed. Take a look before your favourites sell out.',
url: '/collections/fall'
})
};
fetch('https://api.fluid.app/api/company/v2026-10/messages/preferred', 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/company/v2026-10/messages/preferred",
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([
'member_id' => '0199c2d4-8a1e-7b35-9f02-6d4e1a7c3b58',
'message_type' => 'marketing',
'subject' => 'New arrivals for fall',
'title' => 'New arrivals for fall',
'text' => 'Our fall collection just landed. Take a look before your favourites sell out.',
'url' => '/collections/fall'
]),
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/company/v2026-10/messages/preferred"
payload := strings.NewReader("{\n \"member_id\": \"0199c2d4-8a1e-7b35-9f02-6d4e1a7c3b58\",\n \"message_type\": \"marketing\",\n \"subject\": \"New arrivals for fall\",\n \"title\": \"New arrivals for fall\",\n \"text\": \"Our fall collection just landed. Take a look before your favourites sell out.\",\n \"url\": \"/collections/fall\"\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/company/v2026-10/messages/preferred")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"member_id\": \"0199c2d4-8a1e-7b35-9f02-6d4e1a7c3b58\",\n \"message_type\": \"marketing\",\n \"subject\": \"New arrivals for fall\",\n \"title\": \"New arrivals for fall\",\n \"text\": \"Our fall collection just landed. Take a look before your favourites sell out.\",\n \"url\": \"/collections/fall\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.fluid.app/api/company/v2026-10/messages/preferred")
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 \"member_id\": \"0199c2d4-8a1e-7b35-9f02-6d4e1a7c3b58\",\n \"message_type\": \"marketing\",\n \"subject\": \"New arrivals for fall\",\n \"title\": \"New arrivals for fall\",\n \"text\": \"Our fall collection just landed. Take a look before your favourites sell out.\",\n \"url\": \"/collections/fall\"\n}"
response = http.request(request)
puts response.read_body{
"message": {
"id": "019a1152-6c5d-7e4f-9a3b-2c1d0e9f8a7b",
"channel": "email",
"message_type": "marketing",
"status": "delivered",
"refusal_code": null,
"provider": "ses",
"provider_message_id": "0100019a11526c5d-2b3c4d5e-6f7a-4b8c-9d0e-1f2a3b4c5d6e-000000",
"recipient": {
"member_id": "0199c2d4-8a1e-7b35-9f02-6d4e1a7c3b58",
"contact_id": null,
"contact_method_id": "0199c2d5-1f3a-7c48-b6e1-9d2a4f7e8c13"
},
"conversation_id": null,
"created_at": "2026-10-23T02:14:09Z",
"updated_at": "2026-10-23T12:00:05Z",
"events": [
{
"status": "scheduled",
"detail": null,
"occurred_at": "2026-10-23T02:14:09Z"
},
{
"status": "sent",
"detail": null,
"occurred_at": "2026-10-23T12:00:01Z"
},
{
"status": "delivered",
"detail": null,
"occurred_at": "2026-10-23T12:00:05Z"
}
],
"send_at": "2026-10-23T12:00:00Z"
},
"status": 200,
"meta": {
"request_uuid": "3b8f1d27-6c4e-4a91-8e5d-2f7c9a1b0e64",
"timestamp": "2026-10-23T14:05:12Z"
}
}{
"message": {
"id": "019a1152-6c5d-7e4f-9a3b-2c1d0e9f8a7b",
"channel": "email",
"message_type": "marketing",
"status": "scheduled",
"refusal_code": null,
"provider": "ses",
"provider_message_id": null,
"recipient": {
"member_id": "0199c2d4-8a1e-7b35-9f02-6d4e1a7c3b58",
"contact_id": null,
"contact_method_id": "0199c2d5-1f3a-7c48-b6e1-9d2a4f7e8c13"
},
"conversation_id": null,
"created_at": "2026-10-23T02:14:09Z",
"updated_at": "2026-10-23T02:14:09Z",
"events": [
{
"status": "scheduled",
"detail": null,
"occurred_at": "2026-10-23T02:14:09Z"
}
],
"send_at": "2026-10-23T12:00:00Z"
},
"status": 202,
"meta": {
"request_uuid": "3b8f1d27-6c4e-4a91-8e5d-2f7c9a1b0e64",
"timestamp": "2026-10-23T14:05:12Z"
}
}{
"error": {
"message": "<string>",
"details": {}
},
"status": 123,
"meta": {
"request_uuid": "<string>",
"timestamp": "2023-11-07T05:31:56Z"
}
}{}{}{
"error": {
"code": "channel_disabled",
"message": "The company messages API isn't switched on for this company yet.",
"channel": "email"
},
"status": 422,
"meta": {
"request_uuid": "00000000-0000-0000-0000-000000000000",
"timestamp": "2026-10-23T12:00:00Z"
}
}