Queue a manual SMS reply
Requires an active Sendblue line and a conversation that is neither blocked nor opted out. Supply nonblank text or unused outbound attachment ids uploaded for this organization. Creates one queued SMS per attachment, attaching text to the first; text-only sends create one message. Attachments are claimed atomically before jobs dispatch. Returns refreshed detail with HTTP 200; queued status does not establish provider delivery, and the worker rechecks donor consent. Conversations and available lines respect line visibility: restricted lines require assignment to the viewer or sms_inbox_manage/group_all. Requires permission: one of sms_inbox_reply, sms_inbox_manage; plus one of beta_features.
curl --request POST \
--url https://api.gratona.com/v1/admin/sms_inbox/conversations/{conversation_id}/messages \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"content": "Content",
"attachment_ids": [
1
]
}
'import requests
url = "https://api.gratona.com/v1/admin/sms_inbox/conversations/{conversation_id}/messages"
payload = {
"content": "Content",
"attachment_ids": [1]
}
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({content: 'Content', attachment_ids: [1]})
};
fetch('https://api.gratona.com/v1/admin/sms_inbox/conversations/{conversation_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.gratona.com/v1/admin/sms_inbox/conversations/{conversation_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([
'content' => 'Content',
'attachment_ids' => [
1
]
]),
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.gratona.com/v1/admin/sms_inbox/conversations/{conversation_id}/messages"
payload := strings.NewReader("{\n \"content\": \"Content\",\n \"attachment_ids\": [\n 1\n ]\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.gratona.com/v1/admin/sms_inbox/conversations/{conversation_id}/messages")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"content\": \"Content\",\n \"attachment_ids\": [\n 1\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.gratona.com/v1/admin/sms_inbox/conversations/{conversation_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 \"content\": \"Content\",\n \"attachment_ids\": [\n 1\n ]\n}"
response = http.request(request)
puts response.read_body{
"conversation": {
"id": 42,
"donor_id": 42,
"donor_name": "Jane Donor",
"participant_phone_e164": "+15551234567",
"routing_status": "matched",
"inbox_status": "open",
"messaging_status": "active",
"assigned_user_id": 42,
"assigned_user_name": "Example",
"sms_line": {
"id": 42,
"phone_number": "+15551234567",
"provider_line_id": "Example",
"label": "Example",
"source": "client_managed_imported",
"status": "active",
"is_default": true,
"line_role": "general",
"assigned_user_id": 42,
"visibility": "shared",
"metadata": {},
"assigned_user_name": "Example"
},
"last_message_at": "2026-10-20T12:00:00Z",
"last_inbound_at": "2026-10-20T12:00:00Z",
"last_outbound_at": "2026-10-20T12:00:00Z",
"last_read_at": "2026-10-20T12:00:00Z",
"unread_count": 0,
"needs_reply": true,
"last_message_preview": "Example",
"last_message_direction": "inbound",
"has_attachments": true,
"messages": [
{
"id": 42,
"direction": "outbound",
"message_kind": "manual",
"user_id": 42,
"sender": {
"id": 42,
"name": "Jane Admin",
"initials": "JA"
},
"content": "Thank you for your support.",
"trigger": "Example",
"provider_status": "QUEUED",
"provider_message_handle": "Example",
"error_code": "Example",
"error_message": "Example",
"to_number": "+15551234567",
"from_number": "+15557654321",
"received_at": "2026-10-20T12:00:00Z",
"created_at": "2026-10-20T12:00:00Z",
"attachments": [
{
"id": 42,
"upload_id": 42,
"original_filename": "school-update.pdf",
"mime_type": "application/pdf",
"file_size_bytes": 10240,
"ingest_status": "ready",
"download_url": "<string>",
"preview_url": "<string>"
}
]
}
]
},
"donor": {
"id": 42,
"name": "Example",
"phone_e164": "+15551234567",
"can_receive_sms": true
},
"messages": [
{
"id": 42,
"direction": "outbound",
"message_kind": "manual",
"user_id": 42,
"sender": {
"id": 42,
"name": "Jane Admin",
"initials": "JA"
},
"content": "Thank you for your support.",
"trigger": "Example",
"provider_status": "QUEUED",
"provider_message_handle": "Example",
"error_code": "Example",
"error_message": "Example",
"to_number": "+15551234567",
"from_number": "+15557654321",
"received_at": "2026-10-20T12:00:00Z",
"created_at": "2026-10-20T12:00:00Z",
"attachments": [
{
"id": 42,
"upload_id": 42,
"original_filename": "school-update.pdf",
"mime_type": "application/pdf",
"file_size_bytes": 10240,
"ingest_status": "ready",
"download_url": "<string>",
"preview_url": "<string>"
}
]
}
],
"pagination": {
"current_page": 1,
"last_page": 1,
"per_page": 50,
"total": 1
},
"reply_eligibility": {
"can_reply": true,
"blocked": true,
"opted_out": true,
"line_active": true
},
"channel": {
"key": "texts",
"label": "Texts"
},
"message": "Message queued."
}{
"message": "Unauthorized",
"status": "error"
}{
"message": "Not Found",
"status": "error"
}{
"errors": {},
"status": "error",
"message": "The given data was invalid."
}Authorizations
Passport bearer token authentication for legacy admin sessions.
Path Parameters
Conversation id in the current organization.
Body
Validated request fields for this operation.
Response
Operation result.
curl --request POST \
--url https://api.gratona.com/v1/admin/sms_inbox/conversations/{conversation_id}/messages \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"content": "Content",
"attachment_ids": [
1
]
}
'import requests
url = "https://api.gratona.com/v1/admin/sms_inbox/conversations/{conversation_id}/messages"
payload = {
"content": "Content",
"attachment_ids": [1]
}
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({content: 'Content', attachment_ids: [1]})
};
fetch('https://api.gratona.com/v1/admin/sms_inbox/conversations/{conversation_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.gratona.com/v1/admin/sms_inbox/conversations/{conversation_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([
'content' => 'Content',
'attachment_ids' => [
1
]
]),
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.gratona.com/v1/admin/sms_inbox/conversations/{conversation_id}/messages"
payload := strings.NewReader("{\n \"content\": \"Content\",\n \"attachment_ids\": [\n 1\n ]\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.gratona.com/v1/admin/sms_inbox/conversations/{conversation_id}/messages")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"content\": \"Content\",\n \"attachment_ids\": [\n 1\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.gratona.com/v1/admin/sms_inbox/conversations/{conversation_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 \"content\": \"Content\",\n \"attachment_ids\": [\n 1\n ]\n}"
response = http.request(request)
puts response.read_body{
"conversation": {
"id": 42,
"donor_id": 42,
"donor_name": "Jane Donor",
"participant_phone_e164": "+15551234567",
"routing_status": "matched",
"inbox_status": "open",
"messaging_status": "active",
"assigned_user_id": 42,
"assigned_user_name": "Example",
"sms_line": {
"id": 42,
"phone_number": "+15551234567",
"provider_line_id": "Example",
"label": "Example",
"source": "client_managed_imported",
"status": "active",
"is_default": true,
"line_role": "general",
"assigned_user_id": 42,
"visibility": "shared",
"metadata": {},
"assigned_user_name": "Example"
},
"last_message_at": "2026-10-20T12:00:00Z",
"last_inbound_at": "2026-10-20T12:00:00Z",
"last_outbound_at": "2026-10-20T12:00:00Z",
"last_read_at": "2026-10-20T12:00:00Z",
"unread_count": 0,
"needs_reply": true,
"last_message_preview": "Example",
"last_message_direction": "inbound",
"has_attachments": true,
"messages": [
{
"id": 42,
"direction": "outbound",
"message_kind": "manual",
"user_id": 42,
"sender": {
"id": 42,
"name": "Jane Admin",
"initials": "JA"
},
"content": "Thank you for your support.",
"trigger": "Example",
"provider_status": "QUEUED",
"provider_message_handle": "Example",
"error_code": "Example",
"error_message": "Example",
"to_number": "+15551234567",
"from_number": "+15557654321",
"received_at": "2026-10-20T12:00:00Z",
"created_at": "2026-10-20T12:00:00Z",
"attachments": [
{
"id": 42,
"upload_id": 42,
"original_filename": "school-update.pdf",
"mime_type": "application/pdf",
"file_size_bytes": 10240,
"ingest_status": "ready",
"download_url": "<string>",
"preview_url": "<string>"
}
]
}
]
},
"donor": {
"id": 42,
"name": "Example",
"phone_e164": "+15551234567",
"can_receive_sms": true
},
"messages": [
{
"id": 42,
"direction": "outbound",
"message_kind": "manual",
"user_id": 42,
"sender": {
"id": 42,
"name": "Jane Admin",
"initials": "JA"
},
"content": "Thank you for your support.",
"trigger": "Example",
"provider_status": "QUEUED",
"provider_message_handle": "Example",
"error_code": "Example",
"error_message": "Example",
"to_number": "+15551234567",
"from_number": "+15557654321",
"received_at": "2026-10-20T12:00:00Z",
"created_at": "2026-10-20T12:00:00Z",
"attachments": [
{
"id": 42,
"upload_id": 42,
"original_filename": "school-update.pdf",
"mime_type": "application/pdf",
"file_size_bytes": 10240,
"ingest_status": "ready",
"download_url": "<string>",
"preview_url": "<string>"
}
]
}
],
"pagination": {
"current_page": 1,
"last_page": 1,
"per_page": 50,
"total": 1
},
"reply_eligibility": {
"can_reply": true,
"blocked": true,
"opted_out": true,
"line_active": true
},
"channel": {
"key": "texts",
"label": "Texts"
},
"message": "Message queued."
}{
"message": "Unauthorized",
"status": "error"
}{
"message": "Not Found",
"status": "error"
}{
"errors": {},
"status": "error",
"message": "The given data was invalid."
}